Add built local::lib
[catagits/Gitalist.git] / local-lib5 / lib / perl5 / Text / Diff.pm
1 package Text::Diff;
2
3 use 5.00503;
4 use strict;
5 use Carp;
6 use Exporter        ();
7 use Algorithm::Diff ();
8 use vars qw{$VERSION @ISA @EXPORT};
9 BEGIN {
10         $VERSION = '1.37';
11         @ISA     = 'Exporter';
12         @EXPORT  = 'diff';
13 };
14
15 ## Hunks are made of ops.  An op is the starting index for each
16 ## sequence and the opcode:
17 use constant A       => 0;   # Array index before match/discard
18 use constant B       => 1;
19 use constant OPCODE  => 2;   # "-", " ", "+"
20 use constant FLAG    => 3;   # What to display if not OPCODE "!"
21
22 my %internal_styles = (
23     Unified  => undef,
24     Context  => undef,
25     OldStyle => undef,
26     Table    => undef,   ## "internal", but in another module
27 );
28
29 sub diff {
30     my @seqs    = ( shift, shift );
31     my $options = shift || {};
32
33     for my $i ( 0 .. 1 ) {
34         my $seq = $seqs[$i];
35         my $type = ref $seq;
36
37         while ( $type eq "CODE" ) {
38             $seqs[$i] = $seq = $seq->( $options );
39             $type = ref $seq;
40         }
41
42         my $AorB = !$i ? "A" : "B";
43
44         if ( $type eq "ARRAY" ) {
45             ## This is most efficient :)
46             $options->{"OFFSET_$AorB"} = 0
47                 unless defined $options->{"OFFSET_$AorB"};
48         }
49         elsif ( $type eq "SCALAR" ) {
50             $seqs[$i] = [split( /^/m, $$seq )];
51             $options->{"OFFSET_$AorB"} = 1
52                 unless defined $options->{"OFFSET_$AorB"};
53         }
54         elsif ( ! $type ) {
55             $options->{"OFFSET_$AorB"} = 1
56                 unless defined $options->{"OFFSET_$AorB"};
57             $options->{"FILENAME_$AorB"} = $seq
58                 unless defined $options->{"FILENAME_$AorB"};
59             $options->{"MTIME_$AorB"} = (stat($seq))[9]
60                 unless defined $options->{"MTIME_$AorB"};
61
62             local $/ = "\n";
63             open F, "<$seq" or carp "$!: $seq";
64             $seqs[$i] = [<F>];
65             close F;
66
67         }
68         elsif ( $type eq "GLOB" || UNIVERSAL::isa( $seq, "IO::Handle" ) ) {
69             $options->{"OFFSET_$AorB"} = 1
70                 unless defined $options->{"OFFSET_$AorB"};
71             local $/ = "\n";
72             $seqs[$i] = [<$seq>];
73         }
74         else {
75             confess "Can't handle input of type ", ref;
76         }
77     }
78
79     ## Config vars
80     my $output;
81     my $output_handler = $options->{OUTPUT};
82     my $type = ref $output_handler ;
83     if ( ! defined $output_handler ) {
84         $output = "";
85         $output_handler = sub { $output .= shift };
86     }
87     elsif ( $type eq "CODE" ) {
88         ## No problems, mate.
89     }
90     elsif ( $type eq "SCALAR" ) {
91         my $out_ref = $output_handler;
92         $output_handler = sub { $$out_ref .= shift };
93     }
94     elsif ( $type eq "ARRAY" ) {
95         my $out_ref = $output_handler;
96         $output_handler = sub { push @$out_ref, shift };
97     }
98     elsif ( $type eq "GLOB" || UNIVERSAL::isa $output_handler, "IO::Handle" ) {
99         my $output_handle = $output_handler;
100         $output_handler = sub { print $output_handle shift };
101     }
102     else {
103         croak "Unrecognized output type: $type";
104     }
105
106     my $style  = $options->{STYLE};
107     $style = "Unified" unless defined $options->{STYLE};
108     $style = "Text::Diff::$style" if exists $internal_styles{$style};
109
110     if ( ! $style->can( "hunk" ) ) {
111         eval "require $style; 1" or die $@;
112     }
113
114     $style = $style->new
115         if ! ref $style && $style->can( "new" );
116
117     my $ctx_lines = $options->{CONTEXT};
118     $ctx_lines = 3 unless defined $ctx_lines;
119     $ctx_lines = 0 if $style->isa( "Text::Diff::OldStyle" );
120
121     my @keygen_args = $options->{KEYGEN_ARGS}
122         ? @{$options->{KEYGEN_ARGS}}
123         : ();
124
125     ## State vars
126     my $diffs = 0; ## Number of discards this hunk
127     my $ctx   = 0; ## Number of " " (ctx_lines) ops pushed after last diff.
128     my @ops;       ## ops (" ", +, -) in this hunk
129     my $hunks = 0; ## Number of hunks
130
131     my $emit_ops = sub {
132         $output_handler->( $style->file_header( @seqs,     $options ) )
133             unless $hunks++;
134         $output_handler->( $style->hunk_header( @seqs, @_, $options ) );
135         $output_handler->( $style->hunk       ( @seqs, @_, $options ) );
136         $output_handler->( $style->hunk_footer( @seqs, @_, $options ) );
137     };
138
139     ## We keep 2*ctx_lines so that if a diff occurs
140     ## at 2*ctx_lines we continue to grow the hunk instead
141     ## of emitting diffs and context as we go. We
142     ## need to know the total length of both of the two
143     ## subsequences so the line count can be printed in the
144     ## header.
145     my $dis_a = sub {push @ops, [@_[0,1],"-"]; ++$diffs ; $ctx = 0 };
146     my $dis_b = sub {push @ops, [@_[0,1],"+"]; ++$diffs ; $ctx = 0 };
147
148     Algorithm::Diff::traverse_sequences(
149         @seqs,
150         {
151             MATCH => sub {
152                 push @ops, [@_[0,1]," "];
153
154                 if ( $diffs && ++$ctx > $ctx_lines * 2 ) {
155                    $emit_ops->( [ splice @ops, 0, $#ops - $ctx_lines ] );
156                    $ctx = $diffs = 0;
157                 }
158
159                 ## throw away context lines that aren't needed any more
160                 shift @ops if ! $diffs && @ops > $ctx_lines;
161             },
162             DISCARD_A => $dis_a,
163             DISCARD_B => $dis_b,
164         },
165         $options->{KEYGEN},  # pass in user arguments for key gen function
166         @keygen_args,
167     );
168
169     if ( $diffs ) {
170         $#ops -= $ctx - $ctx_lines if $ctx > $ctx_lines;
171         $emit_ops->( \@ops );
172     }
173
174     $output_handler->( $style->file_footer( @seqs, $options ) ) if $hunks;
175
176     return defined $output ? $output : $hunks;
177 }
178
179 sub _header {
180     my ( $h ) = @_;
181     my ( $p1, $fn1, $t1, $p2, $fn2, $t2 ) = @{$h}{
182         "FILENAME_PREFIX_A",
183         "FILENAME_A",
184         "MTIME_A",
185         "FILENAME_PREFIX_B",
186         "FILENAME_B",
187         "MTIME_B"
188     };
189
190     ## remember to change Text::Diff::Table if this logic is tweaked.
191     return "" unless defined $fn1 && defined $fn2;
192
193     return join( "",
194         $p1, " ", $fn1, defined $t1 ? "\t" . localtime $t1 : (), "\n",
195         $p2, " ", $fn2, defined $t2 ? "\t" . localtime $t2 : (), "\n",
196     );
197 }
198
199 ## _range encapsulates the building of, well, ranges.  Turns out there are
200 ## a few nuances.
201 sub _range {
202     my ( $ops, $a_or_b, $format ) = @_;
203
204     my $start = $ops->[ 0]->[$a_or_b];
205     my $after = $ops->[-1]->[$a_or_b];
206
207     ## The sequence indexes in the lines are from *before* the OPCODE is
208     ## executed, so we bump the last index up unless the OP indicates
209     ## it didn't change.
210     ++$after
211         unless $ops->[-1]->[OPCODE] eq ( $a_or_b == A ? "+" : "-" );
212
213     ## convert from 0..n index to 1..(n+1) line number.  The unless modifier
214     ## handles diffs with no context, where only one file is affected.  In this
215     ## case $start == $after indicates an empty range, and the $start must
216     ## not be incremented.
217     my $empty_range = $start == $after;
218     ++$start unless $empty_range;
219
220     return
221         $start == $after
222             ? $format eq "unified" && $empty_range
223                 ? "$start,0"
224                 : $start
225             : $format eq "unified"
226                 ? "$start,".($after-$start+1)
227                 : "$start,$after";
228 }
229
230 sub _op_to_line {
231     my ( $seqs, $op, $a_or_b, $op_prefixes ) = @_;
232
233     my $opcode = $op->[OPCODE];
234     return () unless defined $op_prefixes->{$opcode};
235
236     my $op_sym = defined $op->[FLAG] ? $op->[FLAG] : $opcode;
237     $op_sym = $op_prefixes->{$op_sym};
238     return () unless defined $op_sym;
239
240     $a_or_b = $op->[OPCODE] ne "+" ? 0 : 1 unless defined $a_or_b;
241     return ( $op_sym, $seqs->[$a_or_b][$op->[$a_or_b]] );
242 }
243
244 SCOPE: {
245     package Text::Diff::Base;
246
247     sub new         {
248         my $proto = shift;
249         return bless { @_ }, ref $proto || $proto;
250     }
251
252     sub file_header { return "" }
253
254     sub hunk_header { return "" }
255
256     sub hunk        { return "" }
257
258     sub hunk_footer { return "" }
259
260     sub file_footer { return "" }
261 }
262
263 @Text::Diff::Unified::ISA = qw( Text::Diff::Base );
264
265 sub Text::Diff::Unified::file_header {
266     shift; ## No instance data
267     my $options = pop ;
268
269     _header(
270         { FILENAME_PREFIX_A => "---", FILENAME_PREFIX_B => "+++", %$options }
271     );
272 }
273
274 sub Text::Diff::Unified::hunk_header {
275     shift; ## No instance data
276     pop; ## Ignore options
277     my $ops = pop;
278
279     return join( "",
280         "@@ -",
281         _range( $ops, A, "unified" ),
282         " +",
283         _range( $ops, B, "unified" ),
284         " @@\n",
285     );
286 }
287
288 sub Text::Diff::Unified::hunk {
289     shift; ## No instance data
290     pop; ## Ignore options
291     my $ops = pop;
292
293     my $prefixes = { "+" => "+", " " => " ", "-" => "-" };
294
295     return join "", map _op_to_line( \@_, $_, undef, $prefixes ), @$ops
296 }
297
298 @Text::Diff::Context::ISA = qw( Text::Diff::Base );
299
300 sub Text::Diff::Context::file_header {
301     _header { FILENAME_PREFIX_A=>"***", FILENAME_PREFIX_B=>"---", %{$_[-1]} };
302 }
303
304 sub Text::Diff::Context::hunk_header {
305     return "***************\n";
306 }
307
308 sub Text::Diff::Context::hunk {
309     shift; ## No instance data
310     pop; ## Ignore options
311     my $ops = pop;
312     ## Leave the sequences in @_[0,1]
313
314     my $a_range = _range( $ops, A, "" );
315     my $b_range = _range( $ops, B, "" );
316
317     ## Sigh.  Gotta make sure that differences that aren't adds/deletions
318     ## get prefixed with "!", and that the old opcodes are removed.
319     my $after;
320     for ( my $start = 0; $start <= $#$ops ; $start = $after ) {
321         ## Scan until next difference
322         $after = $start + 1;
323         my $opcode = $ops->[$start]->[OPCODE];
324         next if $opcode eq " ";
325
326         my $bang_it;
327         while ( $after <= $#$ops && $ops->[$after]->[OPCODE] ne " " ) {
328             $bang_it ||= $ops->[$after]->[OPCODE] ne $opcode;
329             ++$after;
330         }
331
332         if ( $bang_it ) {
333             for my $i ( $start..($after-1) ) {
334                 $ops->[$i]->[FLAG] = "!";
335             }
336         }
337     }
338
339     my $b_prefixes = { "+" => "+ ",  " " => "  ", "-" => undef, "!" => "! " };
340     my $a_prefixes = { "+" => undef, " " => "  ", "-" => "- ",  "!" => "! " };
341
342     return join( "",
343         "*** ", $a_range, " ****\n",
344         map( _op_to_line( \@_, $_, A, $a_prefixes ), @$ops ),
345         "--- ", $b_range, " ----\n",
346         map( _op_to_line( \@_, $_, B, $b_prefixes ), @$ops ),
347     );
348 }
349
350 @Text::Diff::OldStyle::ISA = qw( Text::Diff::Base );
351
352 sub _op {
353     my $ops = shift;
354     my $op = $ops->[0]->[OPCODE];
355     $op = "c" if grep $_->[OPCODE] ne $op, @$ops;
356     $op = "a" if $op eq "+";
357     $op = "d" if $op eq "-";
358     return $op;
359 }
360
361 sub Text::Diff::OldStyle::hunk_header {
362     shift; ## No instance data
363     pop; ## ignore options
364     my $ops = pop;
365
366     my $op = _op $ops;
367
368     return join "", _range( $ops, A, "" ), $op, _range( $ops, B, "" ), "\n";
369 }
370
371 sub Text::Diff::OldStyle::hunk {
372     shift; ## No instance data
373     pop; ## ignore options
374     my $ops = pop;
375     ## Leave the sequences in @_[0,1]
376
377     my $a_prefixes = { "+" => undef,  " " => undef, "-" => "< "  };
378     my $b_prefixes = { "+" => "> ",   " " => undef, "-" => undef };
379
380     my $op = _op $ops;
381
382     return join( "",
383         map( _op_to_line( \@_, $_, A, $a_prefixes ), @$ops ),
384         $op eq "c" ? "---\n" : (),
385         map( _op_to_line( \@_, $_, B, $b_prefixes ), @$ops ),
386     );
387 }
388
389 1;
390
391 __END__
392
393 =head1 NAME
394
395 Text::Diff - Perform diffs on files and record sets
396
397 =head1 SYNOPSIS
398
399     use Text::Diff;
400
401     ## Mix and match filenames, strings, file handles, producer subs,
402     ## or arrays of records; returns diff in a string.
403     ## WARNING: can return B<large> diffs for large files.
404     my $diff = diff "file1.txt", "file2.txt", { STYLE => "Context" };
405     my $diff = diff \$string1,   \$string2,   \%options;
406     my $diff = diff \*FH1,       \*FH2;
407     my $diff = diff \&reader1,   \&reader2;
408     my $diff = diff \@records1,  \@records2;
409
410     ## May also mix input types:
411     my $diff = diff \@records1,  "file_B.txt";
412
413 =head1 DESCRIPTION
414
415 C<diff()> provides a basic set of services akin to the GNU C<diff> utility.  It
416 is not anywhere near as feature complete as GNU C<diff>, but it is better
417 integrated with Perl and available on all platforms.  It is often faster than
418 shelling out to a system's C<diff> executable for small files, and generally
419 slower on larger files.
420
421 Relies on L<Algorithm::Diff> for, well, the algorithm.  This may not produce
422 the same exact diff as a system's local C<diff> executable, but it will be a
423 valid diff and comprehensible by C<patch>.  We haven't seen any differences
424 between Algorithm::Diff's logic and GNU diff's, but we have not examined them
425 to make sure they are indeed identical.
426
427 B<Note>: If you don't want to import the C<diff> function, do one of the
428 following:
429
430    use Text::Diff ();
431
432    require Text::Diff;
433
434 That's a pretty rare occurence, so C<diff()> is exported by default.
435 =head1 OPTIONS
436
437 diff() takes two parameters from which to draw input and a set of
438 options to control it's output.  The options are:
439
440 =over
441
442 =item FILENAME_A, MTIME_A, FILENAME_B, MTIME_B
443
444 The name of the file and the modification time "files"
445
446 These are filled in automatically for each file when diff() is passed a
447 filename, unless a defined value is passed in.
448
449 If a filename is not passed in and FILENAME_A and FILENAME_B are not provided
450 or C<undef>, the header will not be printed.
451
452 Unused on C<OldStyle> diffs.
453
454 =item OFFSET_A, OFFSET_B
455
456 The index of the first line / element.  These default to 1 for all
457 parameter types except ARRAY references, for which the default is 0.  This
458 is because ARRAY references are presumed to be data structures, while the
459 others are line oriented text.
460
461 =item STYLE
462
463 "Unified", "Context", "OldStyle", or an object or class reference for a class
464 providing C<file_header()>, C<hunk_header()>, C<hunk()>, C<hunk_footer()> and
465 C<file_footer()> methods.  The two footer() methods are provided for
466 overloading only; none of the formats provide them.
467
468 Defaults to "Unified" (unlike standard C<diff>, but Unified is what's most
469 often used in submitting patches and is the most human readable of the three.
470
471 If the package indicated by the STYLE has no hunk() method, c<diff()> will
472 load it automatically (lazy loading).  Since all such packages should inherit
473 from Text::Diff::Base, this should be marvy.
474
475 Styles may be specified as class names (C<STYLE => "Foo"), in which case they
476 will be C<new()>ed with no parameters, or as objects (C<STYLE => Foo->new>).
477
478 =item CONTEXT
479
480 How many lines before and after each diff to display.  Ignored on old-style
481 diffs.  Defaults to 3.
482
483 =item OUTPUT
484
485 Examples and their equivalent subroutines:
486
487     OUTPUT   => \*FOOHANDLE,   # like: sub { print FOOHANDLE shift() }
488     OUTPUT   => \$output,      # like: sub { $output .= shift }
489     OUTPUT   => \@output,      # like: sub { push @output, shift }
490     OUTPUT   => sub { $output .= shift },
491
492 If no C<OUTPUT> is supplied, returns the diffs in a string.  If
493 C<OUTPUT> is a C<CODE> ref, it will be called once with the (optional)
494 file header, and once for each hunk body with the text to emit.  If
495 C<OUTPUT> is an L<IO::Handle>, output will be emitted to that handle.
496
497 =item FILENAME_PREFIX_A, FILENAME_PREFIX_B
498
499 The string to print before the filename in the header. Unused on C<OldStyle>
500 diffs.  Defaults are C<"---">, C<"+++"> for Unified and C<"***">, C<"+++"> for
501 Context.
502
503 =item KEYGEN, KEYGEN_ARGS
504
505 These are passed to L<Algorithm::Diff/traverse_sequences>.
506
507 =back
508
509 B<Note>: if neither C<FILENAME_> option is defined, the header will not be
510 printed.  If at one is present, the other and both MTIME_ options must be
511 present or "Use of undefined variable" warnings will be generated (except
512 on C<OldStyle> diffs, which ignores these options).
513
514 =head1 Formatting Classes
515
516 These functions implement the output formats.  They are grouped in to classes
517 so diff() can use class names to call the correct set of output routines and so
518 that you may inherit from them easily.  There are no constructors or instance
519 methods for these classes, though subclasses may provide them if need be.
520
521 Each class has file_header(), hunk_header(), hunk(), and footer() methods
522 identical to those documented in the Text::Diff::Unified section.  header() is
523 called before the hunk() is first called, footer() afterwards.  The default
524 footer function is an empty method provided for overloading:
525
526     sub footer { return "End of patch\n" }
527
528 Some output formats are provided by external modules (which are loaded
529 automatically), such as L<Text::Diff::Table>.  These are
530 are documented here to keep the documentation simple.
531
532 =head2 Text::Diff::Base
533
534 Returns "" for all methods (other than C<new()>).
535
536 =head2 Text::Diff::Unified
537
538   --- A   Mon Nov 12 23:49:30 2001
539   +++ B   Mon Nov 12 23:49:30 2001
540   @@ -2,13 +2,13 @@
541    2
542    3
543    4
544   -5d
545   +5a
546    6
547    7
548    8
549    9
550   +9a
551    10
552    11
553   -11d
554    12
555    13
556
557 =over
558
559 =item file_header
560
561   $s = Text::Diff::Unified->file_header( $options );
562
563 Returns a string containing a unified header.  The sole parameter is the
564 options hash passed in to diff(), containing at least:
565
566   FILENAME_A  => $fn1,
567   MTIME_A     => $mtime1,
568   FILENAME_B  => $fn2,
569   MTIME_B     => $mtime2
570
571 May also contain
572
573   FILENAME_PREFIX_A    => "---",
574   FILENAME_PREFIX_B    => "+++",
575
576 to override the default prefixes (default values shown).
577
578 =item hunk_header
579
580   Text::Diff::Unified->hunk_header( \@ops, $options );
581
582 Returns a string containing the output of one hunk of unified diff.
583
584 =item Text::Diff::Unified::hunk
585
586   Text::Diff::Unified->hunk( \@seq_a, \@seq_b, \@ops, $options );
587
588 Returns a string containing the output of one hunk of unified diff.
589
590 =back
591
592 =head2 Text::Diff::Table
593
594   +--+----------------------------------+--+------------------------------+
595   |  |../Test-Differences-0.2/MANIFEST  |  |../Test-Differences/MANIFEST  |
596   |  |Thu Dec 13 15:38:49 2001          |  |Sat Dec 15 02:09:44 2001      |
597   +--+----------------------------------+--+------------------------------+
598   |  |                                  * 1|Changes                       *
599   | 1|Differences.pm                    | 2|Differences.pm                |
600   | 2|MANIFEST                          | 3|MANIFEST                      |
601   |  |                                  * 4|MANIFEST.SKIP                 *
602   | 3|Makefile.PL                       | 5|Makefile.PL                   |
603   |  |                                  * 6|t/00escape.t                  *
604   | 4|t/00flatten.t                     | 7|t/00flatten.t                 |
605   | 5|t/01text_vs_data.t                | 8|t/01text_vs_data.t            |
606   | 6|t/10test.t                        | 9|t/10test.t                    |
607   +--+----------------------------------+--+------------------------------+
608
609 This format also goes to some pains to highlight "invisible" characters on
610 differing elements by selectively escaping whitespace:
611
612   +--+--------------------------+--------------------------+
613   |  |demo_ws_A.txt             |demo_ws_B.txt             |
614   |  |Fri Dec 21 08:36:32 2001  |Fri Dec 21 08:36:50 2001  |
615   +--+--------------------------+--------------------------+
616   | 1|identical                 |identical                 |
617   * 2|        spaced in         |        also spaced in    *
618   * 3|embedded space            |embedded        tab       *
619   | 4|identical                 |identical                 |
620   * 5|        spaced in         |\ttabbed in               *
621   * 6|trailing spaces\s\s\n     |trailing tabs\t\t\n       *
622   | 7|identical                 |identical                 |
623   * 8|lf line\n                 |crlf line\r\n             *
624   * 9|embedded ws               |embedded\tws              *
625   +--+--------------------------+--------------------------+
626
627 See L</Text::Diff::Table> for more details, including how the whitespace
628 escaping works.
629
630 =head2 Text::Diff::Context
631
632     *** A   Mon Nov 12 23:49:30 2001
633     --- B   Mon Nov 12 23:49:30 2001
634     ***************
635     *** 2,14 ****
636       2
637       3
638       4
639     ! 5d
640       6
641       7
642       8
643       9
644       10
645       11
646     - 11d
647       12
648       13
649     --- 2,14 ----
650       2
651       3
652       4
653     ! 5a
654       6
655       7
656       8
657       9
658     + 9a
659       10
660       11
661       12
662       13
663
664 Note: hunk_header() returns only "***************\n".
665
666 =head2 Text::Diff::OldStyle
667
668     5c5
669     < 5d
670     ---
671     > 5a
672     9a10
673     > 9a
674     12d12
675     < 11d
676
677 Note: no file_header().
678
679 =head1 LIMITATIONS
680
681 Must suck both input files entirely in to memory and store them with a normal
682 amount of Perlish overhead (one array location) per record.  This is implied by
683 the implementation of Algorithm::Diff, which takes two arrays.  If
684 Algorithm::Diff ever offers an incremental mode, this can be changed (contact
685 the maintainers of Algorithm::Diff and Text::Diff if you need this; it
686 shouldn't be too terribly hard to tie arrays in this fashion).
687
688 Does not provide most of the more refined GNU diff options: recursive directory
689 tree scanning, ignoring blank lines / whitespace, etc., etc.  These can all be
690 added as time permits and need arises, many are rather easy; patches quite
691 welcome.
692
693 Uses closures internally, this may lead to leaks on C<perl> versions 5.6.1 and
694 prior if used many times over a process' life time.
695
696 =head1 AUTHOR
697
698 Adam Kennedy E<lt>adamk@cpan.orgE<gt>
699
700 Barrie Slaymaker E<lt>barries@slaysys.comE<gt>
701
702 =head1 COPYRIGHT
703
704 Some parts copyright 2009 Adam Kennedy.
705
706 Copyright 2001 Barrie Slaymaker.  All Rights Reserved.
707
708 You may use this under the terms of either the Artistic License or GNU Public
709 License v 2.0 or greater.
710
711 =cut
712
713 1;