File Coverage

blib/lib/Pod/Select.pm
Criterion Covered Total %
statement 12 117 10.2
branch 0 60 0.0
condition 0 24 0.0
subroutine 4 13 30.7
pod 0 7 0.0
total 16 221 7.2


line stmt bran cond sub pod time code
1             #############################################################################
2             # Pod/Select.pm -- function to select portions of POD docs
3             #
4             # Copyright (C) 1996-2000 by Bradford Appleton. All rights reserved.
5             # This file is part of "PodParser". PodParser is free software;
6             # you can redistribute it and/or modify it under the same terms
7             # as Perl itself.
8             #############################################################################
9              
10             package Pod::Select;
11 12     12   69 use strict;
  12         19  
  12         350  
12              
13 12     12   48 use vars qw($VERSION @ISA @EXPORT $MAX_HEADING_LEVEL %myData @section_headings @selected_sections);
  12         27  
  12         1117  
14             $VERSION = '1.65'; ## Current version of this package
15             require 5.005; ## requires this Perl version or later
16              
17             #############################################################################
18              
19             =head1 NAME
20              
21             Pod::Select, podselect() - extract selected sections of POD from input
22              
23             =head1 SYNOPSIS
24              
25             use Pod::Select;
26              
27             ## Select all the POD sections for each file in @filelist
28             ## and print the result on standard output.
29             podselect(@filelist);
30              
31             ## Same as above, but write to tmp.out
32             podselect({-output => "tmp.out"}, @filelist):
33              
34             ## Select from the given filelist, only those POD sections that are
35             ## within a 1st level section named any of: NAME, SYNOPSIS, OPTIONS.
36             podselect({-sections => ["NAME|SYNOPSIS", "OPTIONS"]}, @filelist):
37              
38             ## Select the "DESCRIPTION" section of the PODs from STDIN and write
39             ## the result to STDERR.
40             podselect({-output => ">&STDERR", -sections => ["DESCRIPTION"]}, \*STDIN);
41              
42             or
43              
44             use Pod::Select;
45              
46             ## Create a parser object for selecting POD sections from the input
47             $parser = new Pod::Select();
48              
49             ## Select all the POD sections for each file in @filelist
50             ## and print the result to tmp.out.
51             $parser->parse_from_file("<&STDIN", "tmp.out");
52              
53             ## Select from the given filelist, only those POD sections that are
54             ## within a 1st level section named any of: NAME, SYNOPSIS, OPTIONS.
55             $parser->select("NAME|SYNOPSIS", "OPTIONS");
56             for (@filelist) { $parser->parse_from_file($_); }
57              
58             ## Select the "DESCRIPTION" and "SEE ALSO" sections of the PODs from
59             ## STDIN and write the result to STDERR.
60             $parser->select("DESCRIPTION");
61             $parser->add_selection("SEE ALSO");
62             $parser->parse_from_filehandle(\*STDIN, \*STDERR);
63              
64             =head1 REQUIRES
65              
66             perl5.005, Pod::Parser, Exporter, Carp
67              
68             =head1 EXPORTS
69              
70             podselect()
71              
72             =head1 DESCRIPTION
73              
74             B
75             higher) are going to remove Pod-Parser from core and use L
76             for all things POD.>
77              
78             B is a function which will extract specified sections of
79             pod documentation from an input stream. This ability is provided by the
80             B module which is a subclass of B.
81             B provides a method named B to specify the set of
82             POD sections to select for processing/printing. B merely
83             creates a B object and then invokes the B
84             followed by B.
85              
86             =head1 SECTION SPECIFICATIONS
87              
88             B and B may be given one or more
89             "section specifications" to restrict the text processed to only the
90             desired set of sections and their corresponding subsections. A section
91             specification is a string containing one or more Perl-style regular
92             expressions separated by forward slashes ("/"). If you need to use a
93             forward slash literally within a section title you can escape it with a
94             backslash ("\/").
95              
96             The formal syntax of a section specification is:
97              
98             =over 4
99              
100             =item *
101              
102             I/I/...
103              
104             =back
105              
106             Any omitted or empty regular expressions will default to ".*".
107             Please note that each regular expression given is implicitly
108             anchored by adding "^" and "$" to the beginning and end. Also, if a
109             given regular expression starts with a "!" character, then the
110             expression is I (so C would match anything I
111             C).
112              
113             Some example section specifications follow.
114              
115             =over 4
116              
117             =item *
118              
119             Match the C and C sections and all of their subsections:
120              
121             C
122              
123             =item *
124              
125             Match only the C and C subsections of the C
126             section:
127              
128             C
129              
130             =item *
131              
132             Match the C subsection of I sections:
133              
134             C
135              
136             =item *
137              
138             Match all subsections of C I for C:
139              
140             C
141              
142             =item *
143              
144             Match the C section but do I match any of its subsections:
145              
146             C
147              
148             =item *
149              
150             Match all top level sections but none of their subsections:
151              
152             C
153              
154             =back
155              
156             =begin _NOT_IMPLEMENTED_
157              
158             =head1 RANGE SPECIFICATIONS
159              
160             B and B may be given one or more
161             "range specifications" to restrict the text processed to only the
162             desired ranges of paragraphs in the desired set of sections. A range
163             specification is a string containing a single Perl-style regular
164             expression (a regex), or else two Perl-style regular expressions
165             (regexs) separated by a ".." (Perl's "range" operator is "..").
166             The regexs in a range specification are delimited by forward slashes
167             ("/"). If you need to use a forward slash literally within a regex you
168             can escape it with a backslash ("\/").
169              
170             The formal syntax of a range specification is:
171              
172             =over 4
173              
174             =item *
175              
176             /I/[../I/]
177              
178             =back
179              
180             Where each the item inside square brackets (the ".." followed by the
181             end-range-regex) is optional. Each "range-regex" is of the form:
182              
183             =cmd-expr text-expr
184              
185             Where I is intended to match the name of one or more POD
186             commands, and I is intended to match the paragraph text for
187             the command. If a range-regex is supposed to match a POD command, then
188             the first character of the regex (the one after the initial '/')
189             absolutely I be a single '=' character; it may not be anything
190             else (not even a regex meta-character) if it is supposed to match
191             against the name of a POD command.
192              
193             If no I<=cmd-expr> is given then the text-expr will be matched against
194             plain textblocks unless it is preceded by a space, in which case it is
195             matched against verbatim text-blocks. If no I is given then
196             only the command-portion of the paragraph is matched against.
197              
198             Note that these two expressions are each implicitly anchored. This
199             means that when matching against the command-name, there will be an
200             implicit '^' and '$' around the given I<=cmd-expr>; and when matching
201             against the paragraph text there will be an implicit '\A' and '\Z'
202             around the given I.
203              
204             Unlike with section-specs, the '!' character does I have any special
205             meaning (negation or otherwise) at the beginning of a range-spec!
206              
207             Some example range specifications follow.
208              
209             =over 4
210              
211             =item
212             Match all C<=for html> paragraphs:
213              
214             C
215              
216             =item
217             Match all paragraphs between C<=begin html> and C<=end html>
218             (note that this will I work correctly if such sections
219             are nested):
220              
221             C
222              
223             =item
224             Match all paragraphs between the given C<=item> name until the end of the
225             current section:
226              
227             C
228              
229             =item
230             Match all paragraphs between the given C<=item> until the next item, or
231             until the end of the itemized list (note that this will I work as
232             desired if the item contains an itemized list nested within it):
233              
234             C
235              
236             =back
237              
238             =end _NOT_IMPLEMENTED_
239              
240             =cut
241              
242             #############################################################################
243              
244             #use diagnostics;
245 12     12   57 use Carp;
  12         19  
  12         648  
246 12     12   67 use Pod::Parser 1.04;
  12         382  
  12         17927  
247              
248             @ISA = qw(Pod::Parser);
249             @EXPORT = qw(&podselect);
250              
251             ## Maximum number of heading levels supported for '=headN' directives
252             *MAX_HEADING_LEVEL = \3;
253              
254             #############################################################################
255              
256             =head1 OBJECT METHODS
257              
258             The following methods are provided in this module. Each one takes a
259             reference to the object itself as an implicit first parameter.
260              
261             =cut
262              
263             ##---------------------------------------------------------------------------
264              
265             ## =begin _PRIVATE_
266             ##
267             ## =head1 B<_init_headings()>
268             ##
269             ## Initialize the current set of active section headings.
270             ##
271             ## =cut
272             ##
273             ## =end _PRIVATE_
274              
275             sub _init_headings {
276 0     0     my $self = shift;
277 0           local *myData = $self;
278              
279             ## Initialize current section heading titles if necessary
280 0 0         unless (defined $myData{_SECTION_HEADINGS}) {
281 0           local *section_headings = $myData{_SECTION_HEADINGS} = [];
282 0           for (my $i = 0; $i < $MAX_HEADING_LEVEL; ++$i) {
283 0           $section_headings[$i] = '';
284             }
285             }
286             }
287              
288             ##---------------------------------------------------------------------------
289              
290             =head1 B
291              
292             ($head1, $head2, $head3, ...) = $parser->curr_headings();
293             $head1 = $parser->curr_headings(1);
294              
295             This method returns a list of the currently active section headings and
296             subheadings in the document being parsed. The list of headings returned
297             corresponds to the most recently parsed paragraph of the input.
298              
299             If an argument is given, it must correspond to the desired section
300             heading number, in which case only the specified section heading is
301             returned. If there is no current section heading at the specified
302             level, then C is returned.
303              
304             =cut
305              
306             sub curr_headings {
307 0     0 0   my $self = shift;
308 0 0         $self->_init_headings() unless (defined $self->{_SECTION_HEADINGS});
309 0           my @headings = @{ $self->{_SECTION_HEADINGS} };
  0            
310 0 0 0       return (@_ > 0 and $_[0] =~ /^\d+$/) ? $headings[$_[0] - 1] : @headings;
311             }
312              
313             ##---------------------------------------------------------------------------
314              
315             =head1 B
316              
317             $parser->select($section_spec1,$section_spec2,...);
318              
319             This method is used to select the particular sections and subsections of
320             POD documentation that are to be printed and/or processed. The existing
321             set of selected sections is I with the given set of sections.
322             See B for adding to the current set of selected
323             sections.
324              
325             Each of the C<$section_spec> arguments should be a section specification
326             as described in L<"SECTION SPECIFICATIONS">. The section specifications
327             are parsed by this method and the resulting regular expressions are
328             stored in the invoking object.
329              
330             If no C<$section_spec> arguments are given, then the existing set of
331             selected sections is cleared out (which means C sections will be
332             processed).
333              
334             This method should I normally be overridden by subclasses.
335              
336             =cut
337              
338             sub select {
339 0     0 0   my ($self, @sections) = @_;
340 0           local *myData = $self;
341 0           local $_;
342              
343             ### NEED TO DISCERN A SECTION-SPEC FROM A RANGE-SPEC (look for m{^/.+/$}?)
344              
345             ##---------------------------------------------------------------------
346             ## The following is a blatant hack for backward compatibility, and for
347             ## implementing add_selection(). If the *first* *argument* is the
348             ## string "+", then the remaining section specifications are *added*
349             ## to the current set of selections; otherwise the given section
350             ## specifications will *replace* the current set of selections.
351             ##
352             ## This should probably be fixed someday, but for the present time,
353             ## it seems incredibly unlikely that "+" would ever correspond to
354             ## a legitimate section heading
355             ##---------------------------------------------------------------------
356 0 0         my $add = ($sections[0] eq '+') ? shift(@sections) : '';
357              
358             ## Reset the set of sections to use
359 0 0         unless (@sections) {
360 0 0         delete $myData{_SELECTED_SECTIONS} unless ($add);
361 0           return;
362             }
363             $myData{_SELECTED_SECTIONS} = []
364 0 0 0       unless ($add && exists $myData{_SELECTED_SECTIONS});
365 0           local *selected_sections = $myData{_SELECTED_SECTIONS};
366              
367             ## Compile each spec
368 0           for my $spec (@sections) {
369 0 0         if ( defined($_ = _compile_section_spec($spec)) ) {
370             ## Store them in our sections array
371 0           push(@selected_sections, $_);
372             }
373             else {
374 0           carp qq{Ignoring section spec "$spec"!\n};
375             }
376             }
377             }
378              
379             ##---------------------------------------------------------------------------
380              
381             =head1 B
382              
383             $parser->add_selection($section_spec1,$section_spec2,...);
384              
385             This method is used to add to the currently selected sections and
386             subsections of POD documentation that are to be printed and/or
387             processed. See for replacing the currently selected sections.
388              
389             Each of the C<$section_spec> arguments should be a section specification
390             as described in L<"SECTION SPECIFICATIONS">. The section specifications
391             are parsed by this method and the resulting regular expressions are
392             stored in the invoking object.
393              
394             This method should I normally be overridden by subclasses.
395              
396             =cut
397              
398             sub add_selection {
399 0     0 0   my $self = shift;
400 0           return $self->select('+', @_);
401             }
402              
403             ##---------------------------------------------------------------------------
404              
405             =head1 B
406              
407             $parser->clear_selections();
408              
409             This method takes no arguments, it has the exact same effect as invoking
410             with no arguments.
411              
412             =cut
413              
414             sub clear_selections {
415 0     0 0   my $self = shift;
416 0           return $self->select();
417             }
418              
419             ##---------------------------------------------------------------------------
420              
421             =head1 B
422              
423             $boolean = $parser->match_section($heading1,$heading2,...);
424              
425             Returns a value of true if the given section and subsection heading
426             titles match any of the currently selected section specifications in
427             effect from prior calls to B and B (or if
428             there are no explicitly selected/deselected sections).
429              
430             The arguments C<$heading1>, C<$heading2>, etc. are the heading titles of
431             the corresponding sections, subsections, etc. to try and match. If
432             C<$headingN> is omitted then it defaults to the current corresponding
433             section heading title in the input.
434              
435             This method should I normally be overridden by subclasses.
436              
437             =cut
438              
439             sub match_section {
440 0     0 0   my $self = shift;
441 0           my (@headings) = @_;
442 0           local *myData = $self;
443              
444             ## Return true if no restrictions were explicitly specified
445             my $selections = (exists $myData{_SELECTED_SECTIONS})
446 0 0         ? $myData{_SELECTED_SECTIONS} : undef;
447 0 0 0       return 1 unless ((defined $selections) && @{$selections});
  0            
448              
449             ## Default any unspecified sections to the current one
450 0           my @current_headings = $self->curr_headings();
451 0           for (my $i = 0; $i < $MAX_HEADING_LEVEL; ++$i) {
452 0 0         (defined $headings[$i]) or $headings[$i] = $current_headings[$i];
453             }
454              
455             ## Look for a match against the specified section expressions
456 0           for my $section_spec ( @{$selections} ) {
  0            
457             ##------------------------------------------------------
458             ## Each portion of this spec must match in order for
459             ## the spec to be matched. So we will start with a
460             ## match-value of 'true' and logically 'and' it with
461             ## the results of matching a given element of the spec.
462             ##------------------------------------------------------
463 0           my $match = 1;
464 0           for (my $i = 0; $i < $MAX_HEADING_LEVEL; ++$i) {
465 0           my $regex = $section_spec->[$i];
466 0           my $negated = ($regex =~ s/^\!//);
467 0 0         $match &= ($negated ? ($headings[$i] !~ /${regex}/)
468             : ($headings[$i] =~ /${regex}/));
469 0 0         last unless ($match);
470             }
471 0 0         return 1 if ($match);
472             }
473 0           return 0; ## no match
474             }
475              
476             ##---------------------------------------------------------------------------
477              
478             =head1 B
479              
480             $boolean = $parser->is_selected($paragraph);
481              
482             This method is used to determine if the block of text given in
483             C<$paragraph> falls within the currently selected set of POD sections
484             and subsections to be printed or processed. This method is also
485             responsible for keeping track of the current input section and
486             subsections. It is assumed that C<$paragraph> is the most recently read
487             (but not yet processed) input paragraph.
488              
489             The value returned will be true if the C<$paragraph> and the rest of the
490             text in the same section as C<$paragraph> should be selected (included)
491             for processing; otherwise a false value is returned.
492              
493             =cut
494              
495             sub is_selected {
496 0     0 0   my ($self, $paragraph) = @_;
497 0           local $_;
498 0           local *myData = $self;
499              
500 0 0         $self->_init_headings() unless (defined $myData{_SECTION_HEADINGS});
501              
502             ## Keep track of current sections levels and headings
503 0           $_ = $paragraph;
504 0 0         if (/^=((?:sub)*)(?:head(?:ing)?|sec(?:tion)?)(\d*)\s+(.*?)\s*$/)
505             {
506             ## This is a section heading command
507 0           my ($level, $heading) = ($2, $3);
508 0 0 0       $level = 1 + (length($1) / 3) if ((! length $level) || (length $1));
509             ## Reset the current section heading at this level
510 0           $myData{_SECTION_HEADINGS}->[$level - 1] = $heading;
511             ## Reset subsection headings of this one to empty
512 0           for (my $i = $level; $i < $MAX_HEADING_LEVEL; ++$i) {
513 0           $myData{_SECTION_HEADINGS}->[$i] = '';
514             }
515             }
516              
517 0           return $self->match_section();
518             }
519              
520             #############################################################################
521              
522             =head1 EXPORTED FUNCTIONS
523              
524             The following functions are exported by this module. Please note that
525             these are functions (not methods) and therefore C take an
526             implicit first argument.
527              
528             =cut
529              
530             ##---------------------------------------------------------------------------
531              
532             =head1 B
533              
534             podselect(\%options,@filelist);
535              
536             B will print the raw (untranslated) POD paragraphs of all
537             POD sections in the given input files specified by C<@filelist>
538             according to the options given in C<\%options>.
539              
540             If any argument to B is a reference to a hash
541             (associative array) then the values with the following keys are
542             processed as follows:
543              
544             =over 4
545              
546             =item B<-output>
547              
548             A string corresponding to the desired output file (or ">&STDOUT"
549             or ">&STDERR"), or a filehandle to write on. The default is to use
550             standard output.
551              
552             =item B<-sections>
553              
554             A reference to an array of sections specifications (as described in
555             L<"SECTION SPECIFICATIONS">) which indicate the desired set of POD
556             sections and subsections to be selected from input. If no section
557             specifications are given, then all sections of the PODs are used.
558              
559             =begin _NOT_IMPLEMENTED_
560              
561             =item B<-ranges>
562              
563             A reference to an array of range specifications (as described in
564             L<"RANGE SPECIFICATIONS">) which indicate the desired range of POD
565             paragraphs to be selected from the desired input sections. If no range
566             specifications are given, then all paragraphs of the desired sections
567             are used.
568              
569             =end _NOT_IMPLEMENTED_
570              
571             =back
572              
573             All other arguments are optional and should correspond to filehandles to
574             read from or the names of input files containing POD sections. A file name
575             of "", "-" or "<&STDIN" will be interpreted to mean standard input (which
576             is the default if no arguments are given).
577              
578             =cut
579              
580             sub podselect {
581 0     0 0   my(@argv) = @_;
582 0           my %defaults = ();
583 0           my $pod_parser = new Pod::Select(%defaults);
584 0           my $num_inputs = 0;
585 0           my $output = '>&STDOUT';
586 0           my %opts;
587 0           local $_;
588 0           for (@argv) {
589 0           my $ref = ref($_);
590 0 0 0       if ($ref && $ref eq 'HASH') {
    0 0        
591 0           %opts = (%defaults, %{$_});
  0            
592              
593             ##-------------------------------------------------------------
594             ## Need this for backward compatibility since we formerly used
595             ## options that were all uppercase words rather than ones that
596             ## looked like Unix command-line options.
597             ## to be uppercase keywords)
598             ##-------------------------------------------------------------
599             %opts = map {
600 0           my ($key, $val) = (lc $_, $opts{$_});
  0            
601 0           $key =~ s/^(?=\w)/-/;
602 0 0         $key =~ /^-se[cl]/ and $key = '-sections';
603             #! $key eq '-range' and $key .= 's';
604 0           ($key => $val);
605             } (keys %opts);
606              
607             ## Process the options
608 0 0         (exists $opts{'-output'}) and $output = $opts{'-output'};
609              
610             ## Select the desired sections
611 0           $pod_parser->select(@{ $opts{'-sections'} })
612             if ( (defined $opts{'-sections'})
613 0 0 0       && ((ref $opts{'-sections'}) eq 'ARRAY') );
614              
615             #! ## Select the desired paragraph ranges
616             #! $pod_parser->select(@{ $opts{'-ranges'} })
617             #! if ( (defined $opts{'-ranges'})
618             #! && ((ref $opts{'-ranges'}) eq 'ARRAY') );
619             }
620             elsif(!$ref || $ref eq 'GLOB') {
621 0           $pod_parser->parse_from_file($_, $output);
622 0           ++$num_inputs;
623             }
624             else {
625 0           croak "Input from $ref reference not supported!\n";
626             }
627             }
628 0 0         $pod_parser->parse_from_file('-') unless ($num_inputs > 0);
629             }
630              
631             #############################################################################
632              
633             =head1 PRIVATE METHODS AND DATA
634              
635             B makes uses a number of internal methods and data fields
636             which clients should not need to see or use. For the sake of avoiding
637             name collisions with client data and methods, these methods and fields
638             are briefly discussed here. Determined hackers may obtain further
639             information about them by reading the B source code.
640              
641             Private data fields are stored in the hash-object whose reference is
642             returned by the B constructor for this class. The names of all
643             private methods and data-fields used by B begin with a
644             prefix of "_" and match the regular expression C.
645              
646             =cut
647              
648             ##---------------------------------------------------------------------------
649              
650             =begin _PRIVATE_
651              
652             =head1 B<_compile_section_spec()>
653              
654             $listref = $parser->_compile_section_spec($section_spec);
655              
656             This function (note it is a function and I a method) takes a
657             section specification (as described in L<"SECTION SPECIFICATIONS">)
658             given in C<$section_sepc>, and compiles it into a list of regular
659             expressions. If C<$section_spec> has no syntax errors, then a reference
660             to the list (array) of corresponding regular expressions is returned;
661             otherwise C is returned and an error message is printed (using
662             B) for each invalid regex.
663              
664             =end _PRIVATE_
665              
666             =cut
667              
668             sub _compile_section_spec {
669 0     0     my ($section_spec) = @_;
670 0           my (@regexs, $negated);
671              
672             ## Compile the spec into a list of regexs
673 0           local $_ = $section_spec;
674 0           s{\\\\}{\001}g; ## handle escaped backward slashes
675 0           s{\\/}{\002}g; ## handle escaped forward slashes
676              
677             ## Parse the regexs for the heading titles
678 0           @regexs = split(/\//, $_, $MAX_HEADING_LEVEL);
679              
680             ## Set default regex for omitted levels
681 0           for (my $i = 0; $i < $MAX_HEADING_LEVEL; ++$i) {
682 0 0 0       $regexs[$i] = '.*' unless ((defined $regexs[$i])
683             && (length $regexs[$i]));
684             }
685             ## Modify the regexs as needed and validate their syntax
686 0           my $bad_regexs = 0;
687 0           for (@regexs) {
688 0 0         $_ .= '.+' if ($_ eq '!');
689 0           s{\001}{\\\\}g; ## restore escaped backward slashes
690 0           s{\002}{\\/}g; ## restore escaped forward slashes
691 0           $negated = s/^\!//; ## check for negation
692 0           eval "m{$_}"; ## check regex syntax
693 0 0         if ($@) {
694 0           ++$bad_regexs;
695 0           carp qq{Bad regular expression /$_/ in "$section_spec": $@\n};
696             }
697             else {
698             ## Add the forward and rear anchors (and put the negator back)
699 0 0         $_ = '^' . $_ unless (/^\^/);
700 0 0         $_ = $_ . '$' unless (/\$$/);
701 0 0         $_ = '!' . $_ if ($negated);
702             }
703             }
704 0 0         return (! $bad_regexs) ? [ @regexs ] : undef;
705             }
706              
707             ##---------------------------------------------------------------------------
708              
709             =begin _PRIVATE_
710              
711             =head2 $self->{_SECTION_HEADINGS}
712              
713             A reference to an array of the current section heading titles for each
714             heading level (note that the first heading level title is at index 0).
715              
716             =end _PRIVATE_
717              
718             =cut
719              
720             ##---------------------------------------------------------------------------
721              
722             =begin _PRIVATE_
723              
724             =head2 $self->{_SELECTED_SECTIONS}
725              
726             A reference to an array of references to arrays. Each subarray is a list
727             of anchored regular expressions (preceded by a "!" if the expression is to
728             be negated). The index of the expression in the subarray should correspond
729             to the index of the heading title in C<$self-E{_SECTION_HEADINGS}>
730             that it is to be matched against.
731              
732             =end _PRIVATE_
733              
734             =cut
735              
736             #############################################################################
737              
738             =head1 SEE ALSO
739              
740             L
741              
742             =head1 AUTHOR
743              
744             Please report bugs using L.
745              
746             Brad Appleton Ebradapp@enteract.comE
747              
748             Based on code for B written by
749             Tom Christiansen Etchrist@mox.perl.comE
750              
751             B is part of the L distribution.
752              
753             =cut
754              
755             1;
756             # vim: ts=4 sw=4 et