home *** CD-ROM | disk | FTP | other *** search
/ PC Professionell 2004 December / PCpro_2004_12.ISO / files / webserver / tsw / TSW_3.4.0.exe / Apache2 / perl / Clean.pm < prev    next >
Encoding:
Perl POD Document  |  2002-06-14  |  16.0 KB  |  692 lines

  1. package HTML::Clean;
  2.  
  3. use Carp;
  4. use IO;
  5. use Fcntl;
  6. use strict;
  7. require 5.004;
  8.  
  9. use vars qw($VERSION @ISA @EXPORT @EXPORT_OK);
  10.  
  11. require Exporter;
  12. require AutoLoader;
  13.  
  14. # Items to export to callers namespace
  15. @EXPORT = qw();
  16.  
  17. $VERSION = '0.8';
  18.  
  19. =head1 NAME
  20.  
  21. HTML::Clean - Cleans up HTML code for web browsers, not humans
  22.  
  23. =head1 SYNOPSIS
  24.  
  25.   use HTML::Clean;
  26.   $h = new HTML::Clean($filename); # or..
  27.   $h = new HTML::Clean($htmlcode);
  28.  
  29.   $h->compat();
  30.   $h->strip();
  31.   $data = $h->data();
  32.   print $$data;
  33.  
  34. =head1 DESCRIPTION
  35.  
  36. The HTML::Clean module encapsulates a number of common techniques for
  37. minimizing the size of HTML files.  You can typically save between
  38. 10% and 50% of the size of a HTML file using these methods.
  39. It provides the following features:
  40.  
  41. =over 8
  42.  
  43. =item Remove unneeded whitespace (begining of line, etc)
  44.  
  45. =item Remove unneeded META elements.
  46.  
  47. =item Remove HTML comments (except for styles, javascript and SSI)
  48.  
  49. =item Replace tags with equivilant shorter tags (<strong> --> <b>)
  50.  
  51. =item etc.
  52.  
  53. =back
  54.  
  55. The entire proces is configurable, so you can pick and choose what you want
  56. to clean.
  57.  
  58. =head1 THE HTML::Clean CLASS
  59.  
  60. =over 4
  61.  
  62. =cut
  63.  
  64.  
  65. ######################################################################
  66.  
  67. =head2 $h = new HTML::Clean($dataorfile, [$level]);
  68.  
  69. This creates a new HTML::Clean object.  A Prerequisite for all other
  70. functions in this module.
  71.  
  72. The $dataorfile parameter supplies the input HTML, either a filename,
  73. or a reference to a scalar value holding the HTML, for example:
  74.  
  75.   $h = new HTML::Clean("/htdocs/index.html");
  76.   $html = "<strong>Hello!</strong>";
  77.   $h = new HTML::Clean(\$html);
  78.  
  79. An optional 'level' parameter controls the level of optimization
  80. performed.  Levels range from 1 to 9.  Level 1 includes only simple
  81. fast optimizations.  Level 9 includes all optimizations.
  82.  
  83. =cut
  84.  
  85. sub new {
  86.   my $this = shift;
  87.   my $class = ref($this) || $this;
  88.   my $self = {};
  89.   bless $self, $class;
  90.   
  91.   my $data = shift;
  92.   my $level = shift;
  93.  
  94.   if ($self->initialize($data)) {
  95.     # set the default level
  96.     $level = 9 if (!$level);
  97.     $self->level($level);
  98.     return $self;
  99.   } else {
  100.     undef $self;
  101.     return undef;
  102.   }
  103. }
  104.   
  105.      
  106. #
  107. # Set up the data in the self hash..
  108. #
  109.  
  110. =head2 $h->initialize($dataorfile)
  111.  
  112. This function allows you to reinitialize the HTML data used by the
  113. current object.  This is useful if you are processing many files.
  114.  
  115. $dataorfile has the same usage as the new method.
  116.  
  117. Return 0 for an error, 1 for success.
  118.  
  119. =cut
  120.  
  121. sub initialize {
  122.   my($self, $data) = @_;
  123.   $self->{'DATA'} = undef;
  124.  
  125.   # Not defined?  Just return true.  
  126.   return(1) if (!$data); 
  127.  
  128.   # Check if it's a ref
  129.   if (ref($data)) {
  130.     $self->{DATA} = $data;
  131.     return(1);
  132.   }
  133.   
  134.   # Newline char, really an error, but just go with it..
  135.   if ($data =~ /\n/) {
  136.     $self->{'DATA'} = \$data;
  137.   }
  138.   
  139.   # No newline?  Must be a filename
  140.   if (-f $data) {
  141.     my $storage;
  142.  
  143.     sysopen(IN, "$data", O_RDONLY) || return(0);
  144.     while (<IN>) {
  145.       $storage .= $_;
  146.     }
  147.     close(IN);
  148.     $self->{'DATA'} = \$storage;
  149.     return(1);
  150.   }
  151.  
  152.   return(0);  # file not found?
  153. }
  154.  
  155.  
  156. =head2 $h->level([$level])
  157.  
  158. Get/set the optimization level.  $level is a number from 1 to 9.
  159.  
  160. =cut
  161.  
  162. sub level {
  163.   my($self, $level) = @_;
  164.  
  165.   if (defined($level) && ($level > 0) && ($level < 10)) {
  166.     $self->{'LEVEL'} = $level
  167.   }
  168.   return($self->{'LEVEL'});
  169. }
  170.  
  171. =head2 $myref = $h->data()
  172.  
  173. Returns the current HTML data as a scalar reference.
  174.  
  175. =cut
  176.  
  177. sub data {
  178.   my($self) = @_;
  179.  
  180.   return $self->{'DATA'};
  181. }
  182.  
  183.  
  184. # Junk HTML comments (INTERNAL)
  185.  
  186. sub _commentcheck($) {
  187.   my($comment) = @_;
  188.  
  189.   $_ = $comment;
  190.   
  191.   # Server side include
  192.   return($comment) if (m,^<!--\#,si);
  193.  
  194.   # ITU Hack..  preserve some frontpage components
  195.   return($comment) if (m,^<!-- %,si);
  196.   return($comment) if (m,bot="(SaveResults|Search|ConfirmationField)",si);
  197.  
  198.   # Javascript
  199.   return($comment) if (m,//.*-->$,si);
  200.   return($comment) if (m,navigator\.app(name|version),si);
  201.  
  202.   # Stylesheet
  203.   return($comment) if (m,[A-z0-9]+\:[A-z0-9]+\s*\{.*\},si);
  204.   return('');
  205. }
  206.  
  207.  
  208. # Remove javascript comments (INTERNAL)
  209.  
  210. sub _jscomments {
  211.   my($js) = @_;
  212.  
  213.   $js =~ s,\n\s*//.*?\n,\n,sig;
  214.   $js =~ s,\s+//.*?\n,\n,sig;
  215.  
  216.   # insure javascript is hidden
  217.   
  218.   if ($js =~ m,<!--,) {
  219.      $js =~ s,</script>,// -->\n</script>,si;
  220.   }
  221.   return($js);
  222. }
  223.  
  224. # Clean up other javascript stuff..
  225.  
  226. sub _javascript {
  227.   my($js) = @_;
  228.  
  229.   # remove excess whitespace at the beginning and end of lines
  230.   $js =~ s,\s*\n+\s*,\n,sig;
  231.   
  232.   # braces/semicolon at end of line, join next line
  233.   $js =~ s,([;{}])\n,$1,sig;
  234.  
  235.   # What else is safe to do?
  236.  
  237.   return($js);
  238. }
  239.  
  240. # replace #000000 -> black, etc..
  241. # Does the browser render faster with RGB?  You would think so..
  242.  
  243. sub _defcolorcheck ($) {
  244.   my($c) = @_;
  245.  
  246.   $c =~ s/\#000000/black/;
  247.   $c =~ s/\#c0c0c0/silver/i;
  248.   $c =~ s/\#808080/gray/;
  249.   $c =~ s/\#ffffff/white/i;
  250.   $c =~ s/\#800000/maroon/;
  251.   $c =~ s/\#ff0000/red/i;
  252.   $c =~ s/\#800080/purple/;
  253.   $c =~ s/\#ff00ff/fuchsia/i;
  254.   $c =~ s/\#ff00ff/fuchsia/i;
  255.   $c =~ s/\#008000/green/;
  256.   $c =~ s/\#00ff00/lime/i;
  257.   $c =~ s/\#808000/olive/;
  258.   $c =~ s/\#ffff00/yellow/i;
  259.   $c =~ s/\#000080/navy/;
  260.   $c =~ s/\#0000ff/blue/i;
  261.   $c =~ s/\#008080/teal/i;
  262.   $c =~ s/\#00ffff/aqua/i;
  263.   return($c);
  264. }
  265.  
  266. # For replacing entities with numerics 
  267. use vars qw/ %_ENTITIES/;
  268. %_ENTITIES =  (
  269.    'Agrave' => 192,
  270.    'Aacute' => 193,
  271.    'Acirc' => 194,
  272.    'Atilde' => 195,
  273.    'Auml' => 196,
  274.    'Aring' => 197,
  275.    'AElig' => 198,
  276.    'Ccedil' => 199,
  277.    'Egrave' => 200,
  278.    'Eacute' => 201,
  279.    'Ecirc' => 202,
  280.    'Euml' => 203,
  281.    'Igrave' => 204,
  282.    'Iacute' => 205,
  283.    'Icirc' => 206,
  284.    'Iuml' => 207,
  285.    'ETH' => 208,
  286.    'Ntilde' => 209,
  287.    'Ograve' => 210,
  288.    'Oacute' => 211,
  289.    'Ocirc' => 212,
  290.    'Otilde' => 213,
  291.    'Ouml' => 214,
  292.    'Oslash' => 216,
  293.    'Ugrave' => 217,
  294.    'Uacute' => 218,
  295.    'Ucirc' => 219,
  296.    'Uuml' => 220,
  297.    'Yacute' => 221,
  298.    'THORN' => 222,
  299.    'szlig' => 223,
  300.    'agrave' => 224,
  301.    'aacute' => 225,
  302.    'acirc' => 226,
  303.    'atilde' => 227,
  304.    'auml' => 228,
  305.    'aring' => 229,
  306.    'aelig' => 230,
  307.    'ccedil' => 231,
  308.    'egrave' => 232,
  309.    'eacute' => 233,
  310.    'ecirc' => 234,
  311.    'euml' => 235,
  312.    'igrave' => 236,
  313.    'iacute' => 237,
  314.    'icirc' => 238,
  315.    'iuml' => 239,
  316.    'eth' => 240,
  317.    'ntilde' => 241,
  318.    'ograve' => 242,
  319.    'oacute' => 243,
  320.    'ocirc' => 244,
  321.    'otilde' => 245,
  322.    'ouml' => 246,
  323.    'oslash' => 248,
  324.    'ugrave' => 249,
  325.    'uacute' => 250,
  326.    'ucirc' => 251,
  327.    'uuml' => 252,
  328.    'yacute' => 253,
  329.    'thorn' => 254,
  330.    'yuml' => 255
  331. );
  332.  
  333. =head2 strip(\%options);
  334.  
  335. Removes excess space from HTML
  336.  
  337. You can control the optimizations used by specifying them in the
  338. %options hash reference.
  339.  
  340. The following options are recognized:
  341.  
  342. =over 8
  343.  
  344. =item boolean values (0 or 1 values)
  345.  
  346.   whitespace    Remove excess whitespace
  347.   shortertags   <strong> -> <b>, etc..
  348.   blink         No blink tags.
  349.   contenttype   Remove default contenttype.
  350.   comments      Remove excess comments.
  351.   entities      " -> ", etc.
  352.   dequote       remove quotes from tag parameters where possible.
  353.   defcolor      recode colors in shorter form. (#ffffff -> white, etc.)
  354.   javascript    remove excess spaces and newlines in javascript code.
  355.   htmldefaults  remove default values for some html tags
  356.   lowercasetags translate all HTML tags to lowercase
  357.  
  358. =item parameterized values
  359.  
  360.   meta        Takes a space separated list of meta tags to remove,
  361.               default "GENERATOR FORMATTER"
  362.  
  363.   emptytags   Takes a space separated list of tags to remove when there is no
  364.               content between the start and end tag, like this: <b></b>.
  365.               The default is 'b i font center'
  366.  
  367. =back
  368.  
  369. =cut
  370.  
  371. use vars qw/
  372.       $do_whitespace 
  373.       $do_shortertags  
  374.       $do_meta       
  375.       $do_blink 
  376.       $do_contenttype 
  377.       $do_comments 
  378.       $do_entities 
  379.       $do_dequote
  380.           $do_defcolor
  381.           $do_emptytags
  382.           $do_javascript
  383.           $do_htmldefaults
  384.           $do_lowercasetags
  385.           $do_defbaseurl
  386.   /; 
  387.  
  388. $do_whitespace  = 1;
  389. $do_shortertags = 1;
  390. $do_meta        = "generator formatter";
  391. $do_blink       = 1;
  392. $do_contenttype = 1;
  393. $do_comments    = 1;
  394. $do_entities    = 1;
  395. $do_dequote     = 1;
  396. $do_defcolor    = 1;
  397. $do_emptytags   = 'b i font center';
  398. $do_javascript  = 1;
  399. $do_htmldefaults  = 1;
  400. $do_lowercasetags = 1;
  401. $do_defbaseurl  = '';
  402.  
  403. sub strip {
  404.   my($self, $options) = @_;
  405.  
  406.   my $h = $self->{'DATA'};
  407.   my $level = $self->{'LEVEL'};
  408.  
  409.   # Select a set of options based on $level, and then modify based on 
  410.   # user supplied options.
  411.  
  412.   _level_defaults($level);
  413.  
  414.   if(defined($options)) {
  415.     no strict 'refs';
  416.     for (keys(%$options)) {
  417.       ${"do_" . lc($_)} = $options->{$_} if defined ${"do_" . lc($_)};
  418.     }
  419.   }
  420.  
  421.   if ($do_shortertags) {
  422.     $$h =~ s,<strong>,<b>,sgi;
  423.     $$h =~ s,</strong>,</b>,sgi;
  424.     $$h =~ s,<em>,<i>,sgi;
  425.     $$h =~ s,</em>,</i>,sgi;
  426.   }
  427.  
  428.   if ($do_whitespace) {
  429.     $$h =~ s,[\r\n]+,\n,sg; # Carriage/LF -> LF
  430.     $$h =~ s,\s+\n,\n,sg;   # empty line
  431.     $$h =~ s,\n\s+<,\n<,sg; # space before tag
  432.     $$h =~ s,\n\s+,\n ,sg;  # other spaces
  433.  
  434.     $$h =~ s,>\n\s*<,><,sg; # LF/spaces between tags..
  435.  
  436.     # Remove excess spaces within tags.. note, we could parse out the elements
  437.     # and rewrite for excess spaces between elements.  perhaps next version.
  438.     # removed due to problems with > and < in tag elements..
  439.     #$$h =~ s,\s+>,>,sg;
  440.     #$$h =~ s,<\s+,<,sg;
  441.     # do this again later..
  442.   }
  443.  
  444.   if ($do_entities) {
  445.     $$h =~ s,",\",sg;
  446.     # Simplify long entity names if using default charset...
  447.     $$h =~ m,charset=([^\"]+)\",;
  448.     if (!defined($1) || ($1 eq 'iso-8859-1')) {
  449.       $$h =~ s,&([A-z]+);,($_ENTITIES{$1}) ? chr($_ENTITIES{$1}) : $&,sige;
  450.     }
  451.   }
  452.  
  453.   if ($do_meta) {
  454.     foreach my $m (split(/\s+/, $do_meta)) {
  455.       $$h =~ s,<meta name="$m"[^>]*?>,,sig;
  456.     }
  457.   }
  458.   if ($do_contenttype) {
  459.     # Don't need this, since it is the default for most web servers
  460.     # Also gets rid of 'blinking pages' in older versions of netscape.
  461.     $$h =~ s,<meta http-equiv="Content-Type".*?content="text/html;.*?charset=iso-8859-1">,,sig;
  462.   }
  463.  
  464.   if ($do_defcolor) {
  465.     $$h =~ s,(<[^<]+?color=['"]?\#[0-9A-Fa-f]+["']?),_defcolorcheck($&),sige;
  466.   }
  467.   if ($do_comments) {
  468.     # don't strip server side includes..
  469.     # try not to get javascript, or styles...
  470.     $$h =~ s,<!--.*?-->,_commentcheck($&),sige;
  471.  
  472.     # Remove javascript comments
  473.     $$h =~ s,<script[^>]*(java|ecma)script[^>]*>.*?</script>,_jscomments($&),sige;
  474.   }
  475.  
  476.   if ($do_javascript) {
  477.     #
  478.     $$h =~ s,<script[^>]*(java|ecma)script[^>]*>.*?</script>,_javascript($&),sige;
  479.   }
  480.  
  481.   if ($do_blink) {
  482.     $$h =~ s,<BLINK>,,sgi;
  483.     $$h =~ s,</BLINK>,,sgi;
  484.   }
  485.  
  486.   if ($do_dequote) {
  487.     while ($$h =~ s,<([A-z]+ [A-z]+=)(['"])([A-z0-9]+)\2(\s*?[^>]*?>),<$1$3$4,sig)
  488.       {
  489.     # Remove alphanumeric quotes.  Note, breaks DTD..
  490.     ;
  491.       }
  492.   }
  493.   # remove <b></b>, etc..
  494.   if ($do_emptytags) {
  495.      my $pat = $do_emptytags;
  496.      $pat =~ s/\s+/|/g;
  497.  
  498.      while ($$h =~ s,<($pat)(\s+[^>]*?)?>\s*</\1>,,siog){}
  499.  
  500.   }
  501.   if ($do_htmldefaults) {
  502.      # Tables
  503.      # seems to break things..
  504.      #$$h =~ s,(<table[^>]*)\s+border=0([^>]*>),$1$2,sig;
  505.      $$h =~ s,(<td[^>]*)\s+rowspan=1([^>]*>),$1$2,sig;
  506.      $$h =~ s,(<td[^>]*)\s+colspan=1([^>]*>),$1$2,sig;
  507.  
  508.      #
  509.  
  510.      # P, TABLE tags are default left aligned..
  511.      # lynx is inconsistent in this manner though..
  512.  
  513.      $$h =~ s,<(P|table|td)( [^>]*)align=\"?left\"?([^>]*)>,<$1$2$3>,sig;
  514.  
  515.      # OL start=1
  516.      $$h =~ s,(<OL [^>]*)start=\"?1\"?([^>]*>),$1$2,sig;
  517.  
  518.      # FORM
  519.      $$h =~ s,(<form [^>]*)method=\"?get\"?([^>]*>),$1$2,sig;
  520.      $$h =~ s,(<form [^>]*)enctype=\"application/x-www-form-urlencoded\"([^>]*>),$1$2,sig;
  521.  
  522.      # hr
  523.      $$h =~ s,(<hr [^>]*)align=\"?center\"?([^>]*>),$1$2,sig;
  524.      $$h =~ s,(<hr [^>]*)width=\"?100%\"?([^>]*>),$1$2,sig;
  525.  
  526.      # URLs
  527.      $$h =~ s,(href|src)(=\"?http://[^/:]+):80/,$1$2/,sig;
  528.   }
  529.  
  530.   if ($do_whitespace) {
  531.     # remove space within tags <center  > becomes <center>
  532.     $$h =~ s,\s+>,>,sg;
  533.     $$h =~ s,<\s+,<,sg;
  534.     # join lines with a space at the beginning/end of the line
  535.     # and a line that begins with a tag
  536.     $$h =~ s,>\n ,> ,sig;
  537.     $$h =~ s, \n<, <,sig;
  538.   }
  539.  
  540.   if ($do_lowercasetags) {
  541.     # translate tags to lowercase to (hopefully) improve compressability..
  542.  
  543.     # simple tags <H1>, </H1> etc.
  544.     $$h =~ s,(<[/]?[a-zA-Z][a-zA-Z0-9_-]*\s*>),\L$1\E,sg;
  545.  
  546.     # the rest..
  547.     $$h =~ s/(<[a-zA-Z][a-zA-Z0-9_-]*)(\s+.*?>)/_lowercasetag($1,$2)/sge;
  548.   }
  549. }
  550.  
  551. sub _lowercasetag {
  552.   my($prefix, $body) = @_;
  553.   $prefix =~ s/^(.+)$/\L$1\E/;
  554.   $body =~ s/(\s+[a-zA-Z][a-zA-Z0-9_-]*)(\s*=\s*[^"\s]+|\s*=\s*"[^"]*"|>|\s)/\L$1\E$2/sg;
  555.   return $prefix.$body;
  556. }
  557.  
  558. # set options based on the level provided.. INTERNAL
  559.  
  560. sub _level_defaults($) {
  561.   my ($level) = @_;
  562.  
  563.   $do_whitespace  = 1; # always do this...
  564.  
  565.   # level 2
  566.   $do_shortertags = ($level > 1) ? 1 : 0;
  567.   $do_meta        = ($level > 1) ? "generator formatter" : "";
  568.   $do_contenttype = ($level > 1) ? 1 : 0;
  569.  
  570.   # level 3
  571.   $do_entities    = ($level > 2) ? 1 : 0;
  572.   $do_blink       = ($level > 2) ? 1 : 0;
  573.  
  574.   # level 4
  575.   $do_comments    = ($level > 3) ? 1 : 0;
  576.   $do_dequote     = ($level > 3) ? 1 : 0;
  577.   $do_defcolor    = ($level > 3) ? 1 : 0;
  578.   $do_emptytags   = ($level > 3) ? 'b i font center' : 0; 
  579.   $do_javascript  = ($level > 3) ? 1 : 0;
  580.   $do_htmldefaults = ($level > 3) ? 1 : 0; 
  581.   $do_lowercasetags = ($level > 3) ? 1 : 0; 
  582.  
  583.   # higher levels reserved for more intensive optimizations.
  584. }
  585.  
  586. ######################################################################
  587.  
  588. =head2 compat()
  589.  
  590. This function improves the cross-platform compatibility of your HTML.
  591. Currently checks for the following problems:
  592.  
  593. =over 8
  594.  
  595. =item Insuring all IMG tags have ALT elements.
  596.  
  597. =item Use of Arial, Futura, or Verdana as a font face.
  598.  
  599. =item Positioning the <TITLE> tag immediately after the <head> tag.
  600.  
  601. =back
  602.  
  603. =cut
  604.  
  605. sub compat {
  606.   my($self, $level, $options) = @_;
  607.  
  608.   my $h = $self->{'DATA'};
  609.  
  610.   $$h =~ s/face="arial"/face="arial,helvetica,sansserif"/sgi;
  611.   $$h =~ s/face="(verdana|futura)"/face="$1,arial,helvetica,sansserif"/sgi;
  612.  
  613.   # insure that <title> tag is directly after the <head> tag
  614.   # Some search engines only search the first N chars. (PLweb for instance..)
  615.  
  616.   if ($$h =~ s,<title>(.*)</title>,,si) {
  617.     my $title = $1;
  618.     $$h =~ s,<head>,<head><title>$title</title>,si;
  619.   }
  620.  
  621.   # Look for IMG without ALT tags.
  622.   $$h =~ s/(<img[^>]+>)/_imgalt($1)/segi;
  623. }
  624.  
  625. sub _imgalt {
  626.   my($tag) = @_;
  627.  
  628.   $tag =~ s/>/ alt="">/ if ($tag !~ /alt=/i);
  629.   return($tag);
  630. }  
  631.  
  632. =head2 defrontpage();
  633.  
  634. This function converts pages created with Microsoft Frontpage to
  635. something a Unix server will understand a bit better.  This function
  636. currently does the following:
  637.  
  638. =over 8
  639.  
  640. =item Converts Frontpage 'hit counters' into a unix specific format.
  641.  
  642. =item Removes some frontpage specific html comments
  643.  
  644. =back
  645.  
  646. =cut
  647.  
  648.  
  649. sub defrontpage {
  650.   my($self) = @_;
  651.  
  652.   my $h = $self->{'DATA'};
  653.  
  654.   while ($$h =~ s,<img\sSRC="[\./]*_vti_bin/fpcount.exe(/.*/).Page=(.*?)\|.*?\s(.*?)>,<img src="/counter?link=$1$2" $3>,xis) {
  655.       print "Converted a Hitcounter.. $1, $2, $3\n";
  656.   }
  657.   $$h =~ s,<!--(mstheme|msthemeseparator|msnavigation)-->,,sgx;
  658. }
  659.  
  660. =back
  661.  
  662. =head1 SEE ALSO
  663.  
  664. =head2 Modules
  665.  
  666. FrontPage::Web, FrontPage::File
  667.  
  668. =head2 Web Sites
  669.  
  670. =over 6
  671.  
  672. =item Distribution Site - http://people.itu.int/~lindner/
  673.  
  674. =back
  675.  
  676. =head1 AUTHORS
  677.  
  678. Paul Lindner for the International Telecommunication Union (ITU)
  679.  
  680. =head1 COPYRIGHT
  681.  
  682. The HTML::Strip module is Copyright (c) 1998,99 by the ITU, Geneva Switzerland.
  683. All rights reserved.
  684.  
  685. You may distribute under the terms of either the GNU General Public
  686. License or the Artistic License, as specified in the Perl README file.
  687.  
  688. =cut
  689.  
  690. 1;
  691. __END__
  692.