1
2
3#
4# This is a template file, intended to be used as a startup frame when writing new formatters.
5# Search for TODO remarks and follow the instructions therein.
6#
7# Optional methods are marked.
8#
9
10
11# = HISTORY SECTION =====================================================================
12
13# ---------------------------------------------------------------------------------------
14# version | date     | author   | changes
15# ---------------------------------------------------------------------------------------
16# 0.01    |<data>    | <author> | new.
17# ---------------------------------------------------------------------------------------
18
19# = POD SECTION =========================================================================
20
21=head1 NAME
22
23B<PerlPoint::Generator::LANGUAGE::Formatter> - generates Formatter formatted LANGUAGE files
24
25=head1 VERSION
26
27This manual describes version B<0.01>.
28
29=head1 SYNOPSIS
30
31
32
33=head1 DESCRIPTION
34
35
36=head1 METHODS
37
38=cut
39
40
41
42
43# check perl version
44require 5.00503;
45
46# = PACKAGE SECTION (internal helper package) ==========================================
47
48# declare package
49package PerlPoint::Generator::LANGUAGE::Formatter;
50
51# declare package version
52$VERSION=0.01;
53$AUTHOR='<author> (<mail>), <(c)-year>';
54
55
56
57# = PRAGMA SECTION =======================================================================
58
59# set pragmata
60use strict;
61
62# inherit from common generator class
63use base qw(PerlPoint::Generator::LANGUAGE);
64
65# declare object data fields
66use fields qw(
67              # TODO: insert the fields you need
68             );
69
70
71# = LIBRARY SECTION ======================================================================
72
73# load modules
74use Carp;
75use PerlPoint::Constants;
76use PerlPoint::Converters;
77use PerlPoint::Generator::LANGUAGE;  # older perls need this, newer perls do it with "use base"
78
79# = CODE SECTION =========================================================================
80
81
82=pod
83
84=head2 new()
85
86
87B<Parameters:>
88
89=over 4
90
91=item class
92
93The class name.
94
95=back
96
97B<Returns:> the new object.
98
99B<Example:>
100
101
102=cut
103sub new
104 {
105  # get parameter
106  my ($class, %params)=@_;
107
108  # check parameters
109  confess "[BUG] Missing class name.\n" unless $class;
110  confess "[BUG] Missing options hash.\n" unless exists $params{options};
111
112  # build object
113  my $me;
114  $me=fields::new($class);
115
116  # store options of interest (really necessary?)
117  $me->{options}{$_}=$params{options}{$_}
118   for grep(exists $params{options}{$_}, qw(
119                                           ),
120           );
121
122  # supply new object
123  $me;
124 }
125
126
127# provide option declarations
128sub declareOptions
129 {
130  # get and check parameters
131  (my __PACKAGE__ $me)=@_;
132  confess "[BUG] Missing object parameter.\n" unless $me;
133  confess "[BUG] Object parameter is no ", __PACKAGE__, " object.\n" unless ref $me and $me->isa(__PACKAGE__);
134
135  # start with the base options
136  $me->readOptions($me->SUPER::declareOptions);
137
138  # now add your own
139  (
140   [
141    # TODO: add options used by this formatter, in Getopt::Long syntax.
142    #       Remember to supply help for your options in help(), see below.
143    "example=s",                 # an example option;
144   ],
145
146   # and base options that we ignore
147   [
148    # TODO: list options of base classes that become *invalid* by using this formatter.
149    qw(
150       baseexample
151      ),
152   ],
153  );
154 }
155
156
157# provide help portions
158sub help
159 {
160  # to get a flexible tool, help texts are supplied in portions
161  {
162   # supply the options part
163   OPTIONS => {
164               # TODO: supply help for all options that were added by this module
165               #       (see declareOptions() above). Use the option name as keys
166               #       and the help texts as values of your entries. You may embed
167               #       POD markup, but please dont use headlines and lists.
168               example => qq(an example option),
169              },
170
171   # supply synopsis part
172   # TODO: add a *formatter specific* part of the SYNOPSIS that is displayed when
173   #       a user specifies -help. Your part will be mixed with others, hierarchically.
174   #       Make sure to check the result.
175   SYNOPSIS => <<EOS,
176
177According to your formatter choice, the LANGUAGE produced will be formatted by I<Formatter>.
178
179EOS
180  }
181 }
182
183
184# provide source filter declarations
185#
186# TODO: adapt this method to reply a list of patterns for languages that can be embedded into
187#       PerlPoint sources when using this formatter. Please note that both base classes can
188#       provide a list already, which you might want to extend or restrict.
189#
190# OPTIONAL METHOD: if you don't want to modify the inherited list, just remove this method.
191#
192sub sourceFilters
193 {
194  # get and check parameters
195  (my __PACKAGE__ $me)=@_;
196  confess "[BUG] Missing object parameter.\n" unless $me;
197  confess "[BUG] Object parameter is no ", __PACKAGE__, " object.\n" unless ref $me and $me->isa(__PACKAGE__);
198
199  # get the common parent class list, replace a few items and provide the result
200  (
201   grep($_!~/^example$/i, $me->SUPER::sourceFilters),  # parent class list, but we do not support pure EXAMPLE
202   "myown",                                            # embedded MYOWN;
203  );
204 }
205
206# check usage
207sub checkUsage
208 {
209  # get and check parameters
210  (my __PACKAGE__ $me)=@_;
211  confess "[BUG] Missing object parameter.\n" unless $me;
212  confess "[BUG] Object parameter is no ", __PACKAGE__, " object.\n" unless ref $me and $me->isa(__PACKAGE__);
213
214  # don't forget the base class (checks translations as well)
215  $me->SUPER::checkUsage;
216
217  # adapt tag translations (allows to use several standard XML converters)
218  $me->{options}{tagtrans}=[
219                            qw(
220                               TABLE_COL:td
221                               TABLE_HL:th
222                               TABLE_ROW:tr
223                               anchor:a
224                               dlist:dl
225                               dpointitem:dt
226                               dpointtext:dd
227                               example:pre
228                               olist:ol
229                               opoint:li
230                               text:p
231                               ulist:ul
232                               upoint:li
233                              )
234                           ];
235
236  # check your own options
237  die "[Fatal] Please specify the name of the result file by -xmlfile.\n" unless exists $me->{options}{xmlfile};
238  not -e $me->{options}{xmlfile} or -w _ or die "[Fatal] XML file $me->{options}{xmlfile} cannot be written.\n";
239 }
240
241
242# sub bootstrap
243#  {
244#   # get and check parameters
245#   (my __PACKAGE__ $me)=@_;
246#   confess "[BUG] Missing object parameter.\n" unless $me;
247#   confess "[BUG] Object parameter is no ", __PACKAGE__, " object.\n" unless ref $me and $me->isa(__PACKAGE__);
248
249#   # don't forget the base class
250#   $me->SUPER::bootstrap;
251#  }
252
253
254
255# initializations done when a backend is available
256sub initBackend
257 {
258  # get and check parameters
259  (my __PACKAGE__ $me)=@_;
260  confess "[BUG] Missing object parameter.\n" unless $me;
261  confess "[BUG] Object parameter is no ", __PACKAGE__, " object.\n" unless ref $me and $me->isa(__PACKAGE__);
262
263  # don't forget the base class
264  $me->SUPER::initBackend;
265
266  # open result file
267  my $handle=$me->{targethandle}=new IO::File(">$me->{options}{xmlfile}");
268
269  # start the page
270  # print $handle $me->{xml}->xmldecl({version => 1.0,});
271  print $handle $me->{xml}->xmldtd(
272                                   [
273                                    # document type (needs to match the root element)
274                                    'html',
275
276                                    # external id
277                                    qq(PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"),
278
279                                    # DTD
280                                    qq("http://www.w3c.org/TR/xhtml1/DTD/xhtml1-strict.dtd"),
281                                   ]
282                                  ), "\n\n";
283 }
284
285# headline formatter
286sub formatHeadline
287 {
288  # get and check parameters
289  ((my __PACKAGE__ $me), my ($page, $item))=@_;
290  confess "[BUG] Missing object parameter.\n" unless $me;
291  confess "[BUG] Object parameter is no ", __PACKAGE__, " object.\n" unless ref $me and $me->isa(__PACKAGE__);
292  confess "[BUG] Missing page data parameter.\n" unless $page;
293  confess "[BUG] Missing item parameter.\n" unless defined $item;
294
295  # build the tag name and a path
296  my $tag="h$item->{cfg}{data}{level}";
297  my $path=$page->path(type=>'fpath', mode=>'full', delimiter=>'|');
298
299  # build the headline, store it with anchors
300  (
301   $me->{xml}->a({name=>$item->{cfg}{data}{full}}),
302   $path ne $item->{cfg}{data}{full} ? $me->{xml}->a({name=>$path}) : (),
303   $me->{xml}->$tag(@{$item->{parts}}),
304  )
305 }
306
307
308# tag formatter
309sub formatTag
310 {
311  # get and check parameters
312  ((my __PACKAGE__ $me), my ($page, $item))=@_;
313  confess "[BUG] Missing object parameter.\n" unless $me;
314  confess "[BUG] Object parameter is no ", __PACKAGE__, " object.\n" unless ref $me and $me->isa(__PACKAGE__);
315  confess "[BUG] Missing page data parameter.\n" unless $page;
316  confess "[BUG] Missing item parameter.\n" unless defined $item;
317
318  # declarations
319  my ($directive, $xmltag, @results)=('');
320
321  # handle the various tags
322  if ($item->{cfg}{data}{name} eq 'INDEX')
323    {
324     # scopies
325     my (%index, %anchors);
326
327     # index: get data structure
328     my $anchors=$item->{cfg}{data}{options}{__anchors};
329
330     # start with an anchor and a navigation bar ...
331     push(@results, $me->{xml}->a({name=>(my $bar)=$me->{anchorfab}->generic}));
332     push(@results, map {$anchors{$_}=$me->{anchorfab}->generic; $me->{xml}->a({href=>"#$anchors{$_}"}, $_)} sort keys %$anchors);
333
334     # now, traverse all groups and build their index
335     foreach my $group (sort keys %$anchors)
336       {
337        # make the character a "headline", linking back to the navigation bar
338        push(@results, $me->{xml}->p($me->{xml}->strong($me->{xml}->a({href=>"#$bar"}, $group))));
339
340        # now add all the index entries
341        push(
342             @results,
343             $me->{xml}->div(
344                             {class => 'indexgroup'},
345                             map
346                              {
347                               (
348                                # first, the entry string
349                                $me->{xml}->div(
350                                                {class => 'indexitem'},
351                                                $_->[0],
352                                               ),
353
354                                # then, the list of occurences
355                                $me->{xml}->div(
356                                                {class => 'indexreflist'},
357                                                map
358                                                 {
359                                                  # an occurence reference
360                                                  $me->{xml}->a({href=>"#$_->[0]"}, $_->[1]),
361                                                 } grep(ref($_), @{$_->[1]}) # TODO: check the structure! Why (doubled) scalars?
362                                               ),
363                               )
364                              } @{$anchors->{$group}},
365                            ),
366            );
367       }
368    }
369  elsif ($item->{cfg}{data}{name} eq 'L')
370    {
371     # link: build it
372     @results=$me->{xml}->a(
373                            {
374                             href => $item->{cfg}{data}{options}{url},
375                            },
376                            @{$item->{parts}},
377                           );
378    }
379  elsif ($item->{cfg}{data}{name} eq 'LOCALTOC')
380    {
381     # local toc: subchapters defined?
382     if (exists $item->{cfg}{data}{options}{__rawtoc__} and @{$item->{cfg}{data}{options}{__rawtoc__}})
383       {
384        # get type flag, store it more readable
385        my $plain=($item->{cfg}{data}{options}{type} eq 'plain');
386
387        # make a temporary headline path array copy
388        my @localHeadlinePath=@{$page->path(type=>'fpath', mode=>'array')};
389
390        # prepare a subroutine to build links, if necessary
391        my $link;
392        unless ($plain)
393          {
394           $link=sub
395                  {
396                   # take parameters
397                   my ($level, $title)=@_;
398
399                   # update headline path (so that it describes the complete
400                   # path of the future chapter then)
401                   $localHeadlinePath[$level-1]=$title;
402
403                   # supply the path of the upcoming chapter
404                   @results=$me->{xml}->a(
405                                          {
406                                           href => join('', '#',
407                                                        join('|',
408                                                             map {defined($_) ? $_ : ''} @localHeadlinePath[0..$level-1],
409                                                            ),
410                                                       ),
411                                          },
412                                          $title,
413                                         );
414                  }
415          }
416
417        # use a more readable toc variable
418        my $toc=$item->{cfg}{data}{options}{__rawtoc__};
419
420        # make it a list of the requested format
421        if ($item->{cfg}{data}{options}{format}=~/^(bullets|enumerated|numbers)$/)
422          {
423           # start a stack of intermediate level results
424           my @buffered;
425
426           # setup method name to build a (partial) list
427           my $listMethodName=$item->{cfg}{data}{options}{format}=~/^(bullets|numbers)$/ ? 'ul' : 'ol';
428
429           # make a temporary headline number array copy (used for numbered lists)
430           my @localHeadlineNumbers=@{$page->path(type=>'npath', mode=>'array')};
431
432           # calculate initial level depth for indentation (real headline levels should
433           # not be reflected in a TOC listing them - a TOC *list* should start at level 1)
434           my $startLevel=@localHeadlineNumbers;
435
436           # traverse TOC entries
437           foreach (@$toc)
438             {
439              # get level and title
440              my ($level, $title)=@$_;
441
442              # update headline numbering
443              $localHeadlineNumbers[$level-1]++;
444
445              # previous level closed?
446              if ($level<@buffered)
447                {
448                 # complete closed levels and integrate them as lists
449                 push(@{$buffered[$_-1]}, $me->{xml}->$listMethodName(@{$buffered[$_]})),
450                   for reverse $level..@buffered-1;
451
452                 # delete all buffer levels which were integrated,
453                 # delete headline numbers of the levels that were closed
454                 $#buffered=$#localHeadlineNumbers=$level-1;
455                }
456
457              # buffer item on current level
458              push(@{$buffered[$level-1]}, $me->{xml}->li(
459                                                          # write numbers if we are building a numbered lists
460                                                          $item->{cfg}{data}{options}{format} eq 'numbers' ? join('', join('.', @localHeadlineNumbers[0..$level-1]), '. ') : (),
461                                                          $plain ? $title : $link->(@$_)
462                                                         )
463                  );
464             }
465
466           # close open lists (down to the initial level depth)
467           push(@{$buffered[$_-1]}, $me->{xml}->$listMethodName(@{$buffered[$_]})),
468             for reverse $startLevel+1 .. @buffered-1;
469
470           # finally, build the list (on startup level), including nested lists eventually
471           @results=$me->{xml}->$listMethodName(@{$buffered[$startLevel]});
472          }
473        else
474          {die "[BUG] Unhandled case $item->{cfg}{data}{options}{format}."}
475       }
476     else
477       {
478        # oops - there are no subchapters
479        @results=();
480       }
481    }
482  elsif ($item->{cfg}{data}{name} eq 'REF')
483    {
484     # scopies
485     my ($label);
486
487     # catch target
488     my $target=$item->{cfg}{data}{options}{name};
489
490     # get the upcoming chapters data
491     my @chapters=$me->getChapterByPath($target);
492
493     # Anything found? Otherwise search for an anchor of the target name and get its page data
494     unless ($chapters[0][0])
495       {
496        # get value and page
497        my $data=$me->getAnchorData($target);
498
499        # anything found?
500        if (defined $data)
501          {
502           # get chapter data
503           @chapters=$me->getChapterByPagenr($data->[1]);
504
505           # set up local link
506           $label=$target;
507          }
508       }
509
510     # build text to display: is there a body?
511     if ($item->{cfg}{data}{options}{__body__})
512       {
513        # yes: the tag body is our text
514        @results=@{$item->{parts}};
515       }
516     else
517       {
518        # no body: what we display depends on option "valueformat"
519        if ($item->{cfg}{data}{options}{valueformat} eq 'pure')
520          {
521           # display the value of the requested object
522           @results=$item->{cfg}{data}{options}{__value__};
523          }
524        elsif ($item->{cfg}{data}{options}{valueformat} eq 'pagetitle')
525          {
526           # display the objects page title, to be found in target data
527           @results=$chapters[0][2];
528          }
529        elsif ($item->{cfg}{data}{options}{valueformat} eq 'pagenr')
530          {
531           # display the objects page number (for more generic or configurable numbers,
532           # this could be done by a function)
533           @results=join('.', @{$chapters[0][7]}, '');
534          }
535        else
536          {die "[BUG] Unhandled case $item->{cfg}{data}{options}{valueformat}."}
537       }
538
539     # if we do not build a link, we are already done now, otherwise, we have to
540     # add link syntax
541     if ($item->{cfg}{data}{options}{type} eq 'linked')
542       {
543        # build target chapter file name, using the absolute page number
544        my $link=$me->_buildFilename($chapters[0][0]);
545
546        # add lokal link, if necessary
547        $link=join('#', $link, $label) if $label;
548
549        # now build the link
550        @results=$me->{xml}->a({href => $link}, @results);
551       }
552    }
553  elsif ($item->{cfg}{data}{name} eq 'SEQ')
554    {
555     # sequence: pure text for now, possibly anchored
556     # (what's best to keep the sequence type?)
557     if (exists $item->{cfg}{data}{options}{name})
558       {
559        @results=$me->{xml}->A(
560                               {
561                                name => $item->{cfg}{data}{options}{name},
562                               },
563                               $item->{cfg}{data}{options}{__nr__},
564                              );
565       }
566     else
567       {@results=$item->{cfg}{data}{options}{__nr__};}
568    }
569  elsif ($item->{cfg}{data}{name} eq 'TABLE')
570    {
571     # build the table
572     @results=$me->{xml}->table(@{$item->{parts}});
573    }
574  elsif ($item->{cfg}{data}{name} eq 'TABLE_COL')
575    {
576     # build the cell
577     @results=$me->{xml}->td(
578                             {
579                             },
580                             @{$item->{parts}} ? @{$item->{parts}} : '&nbsp;'
581                            );
582    }
583  elsif ($item->{cfg}{data}{name} eq 'X')
584    {
585     # index entry: transform it into an anchor
586     @results=$me->{xml}->a(
587                            {
588                             name => $item->{cfg}{data}{options}{__anchor},
589                            },
590                            @{$item->{parts}},
591                           );
592    }
593  else
594    {
595     # invoke base method
596     return $me->SUPER::formatTag(@_[1..$#_]);
597    }
598
599  # supply results
600  # warn @results;
601  @results;
602 }
603
604
605# docstream entry formatter
606sub formatDStreamEntrypoint
607 {
608  # get and check parameters
609  ((my __PACKAGE__ $me), my ($page, $item))=@_;
610  confess "[BUG] Missing object parameter.\n" unless $me;
611  confess "[BUG] Object parameter is no ", __PACKAGE__, " object.\n" unless ref $me and $me->isa(__PACKAGE__);
612  confess "[BUG] Missing page data parameter.\n" unless $page;
613  confess "[BUG] Missing item parameter.\n" unless $item;
614
615  # provide the parts
616  $me->{xml}->div({class=>$item->{cfg}{data}{name}}, @{$item->{parts}});
617 }
618
619
620
621# docstream frame formatter
622sub formatDStreamFrame
623 {
624  # get and check parameters
625  ((my __PACKAGE__ $me), my ($page, $item))=@_;
626  confess "[BUG] Missing object parameter.\n" unless $me;
627  confess "[BUG] Object parameter is no ", __PACKAGE__, " object.\n" unless ref $me and $me->isa(__PACKAGE__);
628  confess "[BUG] Missing page data parameter.\n" unless $page;
629  confess "[BUG] Missing item parameter.\n" unless $item;
630
631  # provide the parts
632  $me->{xml}->div({class=>'streamFrame'}, @{$item->{parts}});
633 }
634
635
636# page formatter
637sub formatPage
638 {
639  # get and check parameters
640  ((my __PACKAGE__ $me), my ($page, $item))=@_;
641  confess "[BUG] Missing object parameter.\n" unless $me;
642  confess "[BUG] Object parameter is no ", __PACKAGE__, " object.\n" unless ref $me and $me->isa(__PACKAGE__);
643  confess "[BUG] Missing page data parameter.\n" unless $page;
644  confess "[BUG] Missing item parameter.\n" unless $item;
645
646  # store this slide - note that there is no frame in XHTML,
647  # a slide just starts with its headline
648  push(@{$me->{slides}}, @{$item->{parts}})
649    if @{$item->{parts}} and grep(ref($_)!~/::comment$/, @{$item->{parts}});
650
651  # supply nothing directly
652  '';
653 }
654
655# finish
656sub finish
657 {
658  # get and check parameters
659  (my __PACKAGE__ $me)=@_;
660  confess "[BUG] Missing object parameter.\n" unless $me;
661  confess "[BUG] Object parameter is no ", __PACKAGE__, " object.\n" unless ref $me and $me->isa(__PACKAGE__);
662
663  # don't forget the base class
664  $me->SUPER::finish;
665
666  # write document
667  my ($handle)=($me->{targethandle});
668  print $handle $me->{xml}->html(
669                                 {
670                                  #xmlns      => qq("http://www.w3c.org/1999/xhtml"),
671                                  #'xml:lang' => qq("en"),
672                                  #lang       => qq("en"),
673                                 },
674
675                                 # add meta data part
676                                 $me->{xml}->head(
677                                                  # title (mandatory) ...
678                                                  $me->{xml}->title($me->{options}{doctitle}),
679
680                                                  # stylesheets
681                                                  exists $me->{options}{css} ? map
682                                                   {
683                                                    # extract title and filename
684                                                    my ($file, $title)=split(':', $me->{options}{css}[$_], 2);
685                                                    $title="unnamed $_" if $_ and not $title;
686
687                                                    $me->{xml}->link(
688                                                                     {
689                                                                      href => $file,
690                                                                      $_ ? (title=>$title) : (),
691                                                                      rel  => $_<2 ? 'stylesheet' : 'alternate stylesheet',
692                                                                      type => 'text/css',
693                                                                     },
694                                                                    )
695                                                    } 0..$#{$me->{options}{css}} : (),
696
697                                                  # the "doc..." options are reserved for further data
698                                                  # ... stored in meta tags
699                                                  map
700                                                   {
701                                                    /^doc(.+)$/;
702                                                    my $tag=$me->elementName("_$1");
703                                                    $me->{xml}->meta({name=>$tag, contents=>$me->{options}{$_}}),
704                                                   } sort grep((/^doc/ and not /^doctitle/), keys %{$me->{options}}),
705                                                 ),
706
707                                 # embed slides into a special section
708                                 $me->{xml}->body(@{$me->{slides}}),
709                                ), "\n\n";
710
711
712  # close document
713  close($handle);
714 }
715
716
717# flag successfull loading
7181;
719
720
721# = POD TRAILER SECTION =================================================================
722
723=pod
724
725=head1 NOTES
726
727
728=head1 SEE ALSO
729
730=over 4
731
732=item Base formatters
733
734This formatter inherits from C<PerlPoint::Generator> and C<PerlPoint::Generator::XML>.
735
736=back
737
738
739=head1 SUPPORT
740
741A PerlPoint mailing list is set up to discuss usage, ideas,
742bugs, suggestions and translator development. To subscribe,
743please send an empty message to perlpoint-subscribe@perl.org.
744
745If you prefer, you can contact me via perl@jochen-stenzel.de
746as well.
747
748=head1 AUTHOR
749
750Copyright (c) Jochen Stenzel (perl@jochen-stenzel.de), 2003-2004.
751All rights reserved.
752
753This module is free software, you can redistribute it and/or modify it
754under the terms of the Artistic License distributed with Perl version
7555.003 or (at your option) any later version. Please refer to the
756Artistic License that came with your Perl distribution for more
757details.
758
759The Artistic License should have been included in your distribution of
760Perl. It resides in the file named "Artistic" at the top-level of the
761Perl source tree (where Perl was downloaded/unpacked - ask your
762system administrator if you dont know where this is).  Alternatively,
763the current version of the Artistic License distributed with Perl can
764be viewed on-line on the World-Wide Web (WWW) from the following URL:
765http://www.perl.com/perl/misc/Artistic.html
766
767
768=head1 DISCLAIMER
769
770This software is distributed in the hope that it will be useful, but
771is provided "AS IS" WITHOUT WARRANTY OF ANY KIND, either expressed or
772implied, INCLUDING, without limitation, the implied warranties of
773MERCHANTABILITY and FITNESS FOR A PARTICULAR PURPOSE.
774
775The ENTIRE RISK as to the quality and performance of the software
776IS WITH YOU (the holder of the software).  Should the software prove
777defective, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR
778CORRECTION.
779
780IN NO EVENT WILL ANY COPYRIGHT HOLDER OR ANY OTHER PARTY WHO MAY CREATE,
781MODIFY, OR DISTRIBUTE THE SOFTWARE BE LIABLE OR RESPONSIBLE TO YOU OR TO
782ANY OTHER ENTITY FOR ANY KIND OF DAMAGES (no matter how awful - not even
783if they arise from known or unknown flaws in the software).
784
785Please refer to the Artistic License that came with your Perl
786distribution for more details.
787
788