File Coverage

blib/lib/Acme/Cow/Interpreter.pm
Criterion Covered Total %
statement 173 228 75.8
branch 56 126 44.4
condition 8 24 33.3
subroutine 12 12 100.0
pod 8 8 100.0
total 257 398 64.5


line stmt bran cond sub pod time code
1             # -*- mode: perl; coding: us-ascii-unix; -*-
2             #
3             # Author: Peter John Acklam
4             # Time-stamp: 2010-05-26 13:12:29 +02:00
5             # E-mail: pjacklam@online.no
6             # URL: http://home.online.no/~pjacklam
7              
8             =pod
9              
10             =head1 NAME
11              
12             Acme::Cow::Interpreter - Cow programming language interpreter
13              
14             =head1 SYNOPSIS
15              
16             use Acme::Cow::Interpreter;
17              
18             my $cow = Acme::Cow::Interpreter -> new();
19             $cow -> parse_file($file);
20             $cow -> execute();
21              
22             =head1 ABSTRACT
23              
24             This module implements an interpreter for the Cow programming language.
25              
26             =head1 DESCRIPTION
27              
28             This module implements an interpreter for the Cow programming language. The
29             Cow programming language is a so-called esoteric programming language, with
30             only 12 commands.
31              
32             =cut
33              
34             package Acme::Cow::Interpreter;
35              
36 2     2   104138 use 5.008; # required version of Perl
  2         9  
  2         76  
37 2     2   11 use strict; # restrict unsafe constructs
  2         3  
  2         75  
38 2     2   9 use warnings; # control optional warnings
  2         3  
  2         61  
39             #use utf8; # enable UTF-8 in source code
40              
41 2     2   13 use Carp;
  2         2  
  2         5100  
42              
43             our $VERSION = '0.01';
44              
45             # This hash maps each of the 12 command (used in the source code) to the
46             # corresponding numerical code, from 0 to 11.
47              
48             my $cmd2code =
49             {
50             moo => 0,
51             mOo => 1,
52             moO => 2,
53             mOO => 3,
54             Moo => 4,
55             MOo => 5,
56             MoO => 6,
57             MOO => 7,
58             OOO => 8,
59             MMM => 9,
60             OOM => 10,
61             oom => 11,
62             };
63              
64             # This array maps each of the 12 numerical codes to the corresponding
65             # command (used in source code).
66              
67             my $code2cmd =
68             [
69             'moo',
70             'mOo',
71             'moO',
72             'mOO',
73             'Moo',
74             'MOo',
75             'MoO',
76             'MOO',
77             'OOO',
78             'MMM',
79             'OOM',
80             'oom',
81             ];
82              
83             # This regular expression matches all the 12 valid commands.
84              
85             my $cmd_regex = '(?:[Mm][Oo][Oo]|MMM|OO[MO]|oom)';
86              
87             =pod
88              
89             =head1 METHODS
90              
91             =over 4
92              
93             =item new ()
94              
95             Return a new Cow interpreter.
96              
97             =cut
98              
99             sub new {
100 1     1 1 54 my $proto = shift;
101 1         2 my $protoref = ref $proto;
102 1   33     6 my $class = $protoref || $proto;
103 1         2 my $name = 'new';
104              
105             # Check how the method is called.
106              
107 1 50       4 croak "$name() is a class method, not an instance/object method"
108             if $protoref;
109              
110             # The new self.
111              
112 1         2 my $self = {};
113              
114             # Bless the reference into an object.
115              
116 1         2 bless $self, $class;
117              
118             # Initialize it. The return value of init() is the object itself.
119              
120 1         4 $self -> init();
121             }
122              
123             =pod
124              
125             =item init ()
126              
127             Initialize an object instance. Clears the memory and register and sets the
128             memory pointer to zero. Also, the internally stored program source is
129             cleared.
130              
131             =cut
132              
133             sub init {
134 5     5 1 7 my $self = shift;
135 5         11 my $selfref = ref $self;
136 5   33     20 my $class = $selfref || $self;
137 5         6 my $name = 'init';
138              
139             # Check how the method is called.
140              
141 5 50       10 croak "$name() is an instance/object method, not a class method"
142             unless $selfref;
143              
144             # Check number of arguments.
145              
146             #croak "$name(): Not enough input arguments" if @_ < 0;
147 5 50       16 croak "$name(): Too many input arguments" if @_ > 0;
148              
149 5         12 $self -> {prog} = []; # program; array of codes
150 5         22 $self -> {mem} = [0]; # memory
151 5         11 $self -> {reg} = undef; # register
152 5         16 $self -> {prog_pos} = 0; # index of current program code
153 5         6 $self -> {mem_pos} = 0; # index of current memory block
154              
155 5         20 return $self;
156             }
157              
158             =pod
159              
160             =item copy ()
161              
162             Copy (clone) an Acme::Cow::Interpreter object.
163              
164             =cut
165              
166             sub copy {
167 1     1 1 2 my $self = shift;
168 1         3 my $selfref = ref $self;
169 1   33     5 my $class = $selfref || $self;
170 1         3 my $name = 'copy';
171              
172             # Check how the method is called.
173              
174 1 50       3 croak "$name() is an instance/object method, not a class method"
175             unless $selfref;
176              
177             # Check number of arguments.
178              
179             #croak "$name(): Not enough input arguments" if @_ < 0;
180 1 50       37 croak "$name(): Too many input arguments" if @_ > 0;
181              
182 1         4 my $copy = {};
183 1         4 for my $key (keys %$self) {
184 5         8 my $ref = ref $self -> {$key};
185 5 100       13 if ($ref eq 'ARRAY') {
186 2         1 @{ $copy -> {$key} } = @{ $self -> {$key} };
  2         9  
  2         5  
187             } else {
188 3         9 $copy -> {$key} = $self -> {$key};
189             }
190             }
191              
192             # Bless the copy into an object.
193              
194 1         8 bless $copy, $class;
195             }
196              
197             =pod
198              
199             =item parse_string ( STRING )
200              
201             Parses the given string and stores the resulting list of codes in the
202             object. The return value is the object itself.
203              
204             =cut
205              
206             sub parse_string {
207 2     2 1 5 my $self = shift;
208 2         4 my $selfref = ref $self;
209 2   33     8 my $class = $selfref || $self;
210 2         4 my $name = 'parse_string';
211              
212             # Check how the method is called.
213              
214 2 50       5 croak "$name() is an instance/object method, not a class method"
215             unless $selfref;
216              
217             # Check number of arguments.
218              
219 2 50       6 croak "$name(): Not enough input arguments" if @_ < 1;
220 2 50       6 croak "$name(): Too many input arguments" if @_ > 1;
221              
222             # There is no way the parser can fail. The worst thing that could happen
223             # is that there are no commands in the string.
224              
225 2 50       4 my $string = shift; croak "$name(): Input argument is undefined"
  2         11  
226             unless defined $string;
227              
228             # Reset, i.e., initialize, the invocand object.
229              
230 2         8 $self -> init();
231              
232             # Find the string commands, and convert them to numerical codes.
233              
234 333         437 $self -> {prog} = [
235 2         318 map { $cmd2code -> {$_} }
236             $string =~ /($cmd_regex)/go
237             ];
238              
239 2         41 return $self;
240             }
241              
242             =pod
243              
244             =item parse_file ( FILENAME )
245              
246             Parses the contents of the given file and stores the resulting list of codes
247             in the object. The return value is the object itself.
248              
249             =cut
250              
251             sub parse_file {
252 1     1 1 2 my $self = shift;
253 1         4 my $selfref = ref $self;
254 1   33     8 my $class = $selfref || $self;
255 1         2 my $name = 'parse_file';
256              
257             # Check how the method is called.
258              
259 1 50       3 croak "$name() is an instance/object method, not a class method"
260             unless $selfref;
261              
262             # Check number of arguments.
263              
264 1 50       4 croak "$name(): Not enough input arguments" if @_ < 1;
265 1 50       4 croak "$name(): Too many input arguments" if @_ > 1;
266              
267             # Reset, i.e., initialize, the invocand object.
268              
269 1         4 $self -> init();
270              
271             # Get the file name argument.
272              
273 1         2 my $file = shift;
274              
275 1 50       41 open FILE, $file or croak "$file: can't open file for reading: $!";
276              
277             # Iterate over each line, find the string commands, and convert them to
278             # numerical codes.
279              
280 1         30 while () {
281 178         984 push @{ $self -> {prog} },
  323         549  
282 178         153 map { $cmd2code -> {$_} }
283             /($cmd_regex)/go;
284             }
285              
286 1 50       26 close FILE or croak "$file: can't close file after reading: $!";
287              
288 1         11 return $self;
289             }
290              
291             =pod
292              
293             =item dump_mem ( )
294              
295             Returns a nicely formatted string showing the current memory state.
296              
297             =cut
298              
299             sub dump_mem {
300 1     1 1 3 my $self = shift;
301 1         2 my $selfref = ref $self;
302 1   33     3 my $class = $selfref || $self;
303 1         2 my $name = 'dump_mem';
304              
305             # Check how the method is called.
306              
307 1 50       4 croak "$name() is an instance/object method, not a class method"
308             unless $selfref;
309              
310             # Check number of arguments.
311              
312             #croak "$name(): Not enough input arguments" if @_ < 0;
313 1 50       5 croak "$name(): Too many input arguments" if @_ > 0;
314              
315 1         2 my $mem = $self -> {mem};
316 1         11 my $mem_pos = $self -> {mem_pos};
317 1         2 my $reg = $self -> {reg};
318              
319 1         4 my $str = '';
320              
321             # Print the contents of the memory, showing the block which the memory
322             # points at.
323              
324 1         5 for (my $i = $#$mem ; $i >= 0 ; -- $i) {
325 3         12 $str .= sprintf "Memory block %6u: %12d", $i, $mem->[$i];
326 3 100       9 if ($i == $mem_pos) {
327 1         1 $str .= " <<<";
328             }
329 3         7 $str .= "\n";
330             }
331              
332             # Print the contents of the register.
333              
334 1         2 $str .= "\n";
335 1 50       5 $str .= sprintf "Register block: %17s", defined $reg ? $reg : '';
336 1         3 $str .= "\n";
337              
338 1         5 return $str;
339             }
340              
341             =pod
342              
343             =item dump_obj ( )
344              
345             Returns a text version of object structure.
346              
347             =cut
348              
349             sub dump_obj {
350 1     1 1 2 my $self = shift;
351 1         2 my $selfref = ref $self;
352 1   33     4 my $class = $selfref || $self;
353 1         1 my $name = 'dump';
354              
355             # Check how the method is called.
356              
357 1 50       3 croak "$name() is an instance/object method, not a class method"
358             unless $selfref;
359              
360             # Check number of arguments.
361              
362             #croak "$name(): Not enough input arguments" if @_ < 0;
363 1 50       7 croak "$name(): Too many input arguments" if @_ > 0;
364              
365 1         2 my $prog = $self -> {prog};
366 1         2 my $mem = $self -> {mem};
367 1         2 my $reg = $self -> {reg};
368 1         3 my $prog_pos = $self -> {prog_pos};
369 1         1 my $mem_pos = $self -> {mem_pos};
370              
371 1         2 my $str;
372              
373 1         3 $str .= '$obj -> {prog} = [';
374 1         5 $str .= join(', ', @$prog);
375 1         2 $str .= "];\n";
376              
377 1         1 $str .= '$obj -> {prog_pos} = ';
378 1         3 $str .= $prog_pos;
379 1         1 $str .= ";\n";
380              
381 1         2 $str .= '$obj -> {mem} = [';
382 1         2 $str .= join(', ', @$mem);
383 1         2 $str .= "];\n";
384              
385 1         2 $str .= '$obj -> {mem_pos} = ';
386 1         2 $str .= $mem_pos;
387 1         1 $str .= ";\n";
388 1         2 $str .= '$obj -> {reg} = ';
389 1 50       3 $str .= defined $reg ? $reg : '';
390 1         1 $str .= ";\n";
391              
392 1         7 return $str;
393             }
394              
395             =pod
396              
397             =item execute ( )
398              
399             Executes the source code. The return value is the object itself.
400              
401             =cut
402              
403             sub execute {
404 3     3 1 2679 my $self = shift;
405 3         5 my $selfref = ref $self;
406 3   33     14 my $class = $selfref || $self;
407 3         5 my $name = 'execute';
408              
409             # Check how the method is called.
410              
411 3 50       31 croak "$name() is an instance/object method, not a class method"
412             unless $selfref;
413              
414             # Check number of arguments.
415              
416             #croak "$name(): Not enough input arguments" if @_ < 0;
417 3 50       8 croak "$name(): Too many input arguments" if @_ > 0;
418              
419             # These variables are merely for convenience. They make the code below a
420             # bit cleaner.
421              
422 3         7 my $prog = $self -> {prog};
423 3         6 my $mem = $self -> {mem};
424 3         4 my $prog_pos = \$self -> {prog_pos};
425 3         6 my $mem_pos = \$self -> {mem_pos};
426 3         5 my $reg = \$self -> {reg};
427              
428             # Quick exit if there are no commands (program is void).
429              
430 3 50       8 return 1 unless @$prog;
431              
432             # The code to be executed.
433              
434 3         6 my $code = $prog -> [$$prog_pos];
435              
436             # Main loop. Each round executes one instruction.
437              
438             {
439              
440             #print "-" x 72, "\n";
441             #print "prog ...:";
442             #printf " %3s", $code2cmd -> [$_] for @$prog;
443             #print "\n";
444             #print "ppos ...:", " " x $$prog_pos, " ^^^\n";
445             ##print "ppos ...: $$prog_pos\n";
446             #print "code ...: $code ($code2cmd -> [$code])\n";
447             #print "\n";
448             #print "mem ....:";
449             #printf " %4d", $_ for @$mem;
450             #print "\n";
451             #print "mpos ...:", " " x $$mem_pos, " ^^^^\n";
452             #print "reg ....: ", defined $$reg ? $$reg : "", "\n";
453             #;
454              
455             # Code: moo
456              
457 3 50       3 if ($code == 0) {
  656 100       2427  
    100          
    50          
    100          
    100          
    100          
    50          
    100          
    50          
    0          
    0          
458              
459             # Remember where we started searching for matching 'MOO'.
460              
461 0         0 my $init_pos = $$prog_pos;
462              
463             # Skip previous instruction when looking for matching 'MOO'.
464              
465 0         0 $$prog_pos --;
466              
467 0         0 my $level = 1;
468 0         0 while ($level > 0) {
469              
470 0 0       0 if ($$prog_pos == 0) {
471 0         0 croak "No previous 'MOO' command matching 'moo'",
472             " command. Failed at instruction number $init_pos.";
473             #last;
474             #return 0;
475             }
476              
477 0         0 $$prog_pos --;
478              
479 0 0       0 if ($prog -> [$$prog_pos] == 0) { # if "moo"
    0          
480 0         0 $level ++;
481             } elsif ($prog -> [$$prog_pos] == 7) { # if "MOO"
482 0         0 $level --;
483             }
484             }
485              
486             # This if-test is necessary if we use 'last' rather than 'croak'
487             # in the if-test inside the while-loop above.
488             #
489             #if ($level != 0) {
490             # croak "No previous 'MOO' command matching 'moo'",
491             # " command (instruction number $init_pos).";
492             #}
493              
494 0         0 $code = $prog -> [$$prog_pos];
495              
496             }
497              
498             # Code: mOo
499              
500             elsif ($code == 1) {
501              
502 1 50       3 if ($$mem_pos == 0) {
503 0         0 croak "Can't move memory pointer behind memory block 0.",
504             " Failed at command number $$prog_pos.";
505             }
506 1         1 $$mem_pos --;
507              
508 1 50       4 last if $$prog_pos == $#$prog;
509 0         0 $$prog_pos ++;
510 0         0 $code = $prog -> [$$prog_pos];
511              
512             }
513              
514             # Code: moO
515              
516             elsif ($code == 2) {
517              
518 2         2 $$mem_pos ++;
519 2 50       5 if ($$mem_pos > $#$mem) {
520 2         5 push @$mem, 0;
521             }
522              
523 2 50       4 last if $$prog_pos == $#$prog;
524 2         3 $$prog_pos ++;
525 2         3 $code = $prog -> [$$prog_pos];
526              
527             }
528              
529             # Code: mOO
530              
531             elsif ($code == 3) {
532              
533 0 0       0 if ($mem -> [$$mem_pos] == 3) {
534 0         0 croak "Invalid instruction at this point (would cause",
535             " infinite loop). Failed at instruction number $$prog_pos.";
536             }
537              
538             # We don't need to check for any other invalid instruction
539             # (which exits the program), since this will be taken care of in
540             # the next round.
541              
542 0         0 $code = $mem -> [$$mem_pos];
543              
544             }
545              
546             # Code: Moo
547              
548             elsif ($code == 4) {
549              
550 28 50       44 if ($mem -> [$$mem_pos] == 0) {
551 0         0 my $chr;
552 0         0 read(STDIN, $chr, 1);
553 0         0 $mem -> [$$mem_pos] = ord($chr);
554             } else {
555 28         503 printf "%c", $mem -> [$$mem_pos];
556             }
557              
558 28 100       75 last if $$prog_pos == $#$prog;
559 26         26 $$prog_pos ++;
560 26         33 $code = $prog -> [$$prog_pos];
561              
562             }
563              
564             # Code: MOo
565              
566             elsif ($code == 5) {
567              
568 52         55 $mem -> [$$mem_pos] --;
569              
570 52 50       99 last if $$prog_pos == $#$prog;
571 52         85 $$prog_pos ++;
572 52         68 $code = $prog -> [$$prog_pos];
573              
574             }
575              
576             # Code: MoO
577              
578             elsif ($code == 6) {
579              
580 563         555 $mem -> [$$mem_pos] ++;
581              
582 563 50       1047 last if $$prog_pos == $#$prog;
583 563         542 $$prog_pos ++;
584 563         664 $code = $prog -> [$$prog_pos];
585              
586             }
587              
588             # Code: MOO
589              
590             elsif ($code == 7) {
591              
592 0 0       0 if ($mem -> [$$mem_pos] == 0) {
593              
594             # Remember where we started searching for matching 'moo'.
595              
596 0         0 my $init_pos = $$prog_pos;
597              
598             # Skip next instruction when looking for matching 'moo'.
599              
600 0         0 $$prog_pos ++;
601              
602 0         0 my $level = 1;
603 0         0 my $prev_code;
604              
605 0         0 while ($level > 0) {
606              
607 0 0       0 if ($$prog_pos == $#$prog) {
608 0         0 croak "No following 'moo' command matching 'MOO'",
609             " command. Failed at instruction number $init_pos.";
610             }
611              
612 0         0 $prev_code = $prog -> [$$prog_pos];
613 0         0 $$prog_pos ++;
614              
615 0 0       0 if ($prog -> [$$prog_pos] == 7) { # if "MOO"
    0          
616 0         0 $level ++;
617             } elsif ($prog -> [$$prog_pos] == 0) { # if "moo"
618 0         0 $level --;
619 0 0       0 if ($prev_code == 7) {
620 0         0 $level --;
621             }
622             }
623             }
624              
625             # This if-test is necessary if we use 'last' rather than
626             # 'croak' in the if-test inside the while-loop above.
627             #
628             #if ($level != 0 ) {
629             # croak "No following 'moo' command matching 'MOO'",
630             # " command. Failed at instruction number $init_pos.";
631             #}
632              
633 0 0       0 last if $$prog_pos == $#$prog;
634 0         0 $$prog_pos ++;
635 0         0 $code = $prog -> [$$prog_pos];
636              
637             } else {
638              
639 0 0       0 last if $$prog_pos == $#$prog;
640 0         0 $$prog_pos ++;
641 0         0 $code = $prog -> [$$prog_pos];
642              
643             }
644              
645             }
646              
647             # Code: OOO
648              
649             elsif ($code == 8) {
650              
651 6         8 $mem -> [$$mem_pos] = 0;
652              
653 6 50       12 last if $$prog_pos == $#$prog;
654 6         9 $$prog_pos ++;
655 6         7 $code = $prog -> [$$prog_pos];
656              
657             }
658              
659             # Code: MMM
660              
661             elsif ($code == 9) {
662              
663 4 100       7 if (defined $$reg) {
664 2         3 $mem -> [$$mem_pos] = $$reg;
665 2         1 $$reg = undef;
666             } else {
667 2         5 $$reg = $mem -> [$$mem_pos];
668             }
669              
670 4 50       8 last if $$prog_pos == $#$prog;
671 4         5 $$prog_pos ++;
672 4         4 $code = $prog -> [$$prog_pos];
673              
674             }
675              
676             # Code: OOM
677              
678             elsif ($code == 10) {
679              
680 0         0 printf "%d\n", $mem -> [$$mem_pos];
681              
682 0 0       0 last if $$prog_pos == $#$prog;
683 0         0 $$prog_pos ++;
684 0         0 $code = $prog -> [$$prog_pos];
685              
686             }
687              
688             # Code: oom
689              
690             elsif ($code == 11) {
691              
692 0         0 my $input = ;
693 0 0       0 croak "Input was undefined\n"
694             unless defined $input;
695 0         0 $input =~ s/^\s+//;
696 0         0 $input =~ s/\s+$//;
697 0 0       0 croak "Input was not an integer -- $input\n"
698             unless $input =~ /^[+-]?\d+/;
699              
700 0         0 $mem -> [$$mem_pos] = $input;
701              
702 0 0       0 last if $$prog_pos == $#$prog;
703 0         0 $$prog_pos ++;
704 0         0 $code = $prog -> [$$prog_pos];
705              
706             }
707              
708             # An invalid instruction exits the running program.
709              
710             else {
711 0         0 return 1;
712             }
713              
714 653         597 redo;
715             }
716              
717 3         23 return $self;
718             }
719              
720             =pod
721              
722             =back
723              
724             =head1 NOTES
725              
726             =head2 The Cow Language
727              
728             The Cow language has 12 instruction. The commands and their corresponding
729             code numbers are:
730              
731             =over 4
732              
733             =item moo (0)
734              
735             This command is connected to the B command. When encountered during
736             normal execution, it searches the program code in reverse looking for a
737             matching B command and begins executing again starting from the found
738             B command. When searching, it skips the command that is immediately
739             before it (see B).
740              
741             =item mOo (1)
742              
743             Moves current memory position back one block.
744              
745             =item moO (2)
746              
747             Moves current memory position forward one block.
748              
749             =item mOO (3)
750              
751             Execute value in current memory block as if it were an instruction. The
752             command executed is based on the instruction code value (for example, if the
753             current memory block contains a 2, then the B command is executed). An
754             invalid command exits the running program. Value 3 is invalid as it would
755             cause an infinite loop.
756              
757             =item Moo (4)
758              
759             If current memory block has a 0 in it, read a single ASCII character from
760             the standard input and store it in the current memory block. If the current
761             memory block is not 0, then print the ASCII character that corresponds to
762             the value in the current memory block to the standard output.
763              
764             =item MOo (5)
765              
766             Decrement current memory block value by 1.
767              
768             =item MoO (6)
769              
770             Increment current memory block value by 1.
771              
772             =item MOO (7)
773              
774             If current memory block value is 0, skip next command and resume execution
775             after the next matching B command. If current memory block value is not
776             0, then continue with next command. Note that the fact that it skips the
777             command immediately following it has interesting ramifications for where the
778             matching B command really is. For example, the following will match the
779             second and not the first B: B B B B
780              
781             =item OOO (8)
782              
783             Set current memory block value to 0.
784              
785             =item MMM (9)
786              
787             If no current value in register, copy current memory block value. If there
788             is a value in the register, then paste that value into the current memory
789             block and clear the register.
790              
791             =item OOM (10)
792              
793             Print value of current memory block to the standard output as an integer.
794              
795             =item oom (11)
796              
797             Read an integer from the standard input and put it into the current memory
798             block.
799              
800             =back
801              
802             =head1 TODO
803              
804             Add more tests. The module is far from being tested thoroughly.
805              
806             =head1 BUGS
807              
808             There are currently no known bugs.
809              
810             Please report any bugs or feature requests to
811             C, or through the web interface at
812             L.
813             I will be notified, and then you'll automatically be notified of progress on
814             your bug as I make changes.
815              
816             =head1 SUPPORT
817              
818             You can find documentation for this module with the perldoc command.
819              
820             perldoc Acme::Cow::Interpreter
821              
822             You can also look for information at:
823              
824             =over 4
825              
826             =item * RT: CPAN's request tracker
827              
828             L
829              
830             =item * CPAN Ratings
831              
832             L
833              
834             =item * Search CPAN
835              
836             L
837              
838             =item * CPAN Testers PASS Matrix
839              
840             L
841              
842             =item * CPAN Testers Reports
843              
844             L
845              
846             =item * CPAN Testers Matrix
847              
848             L
849              
850             =back
851              
852             =head1 REFERENCES
853              
854             =over 4
855              
856             =item * L
857              
858             =back
859              
860             =head1 AUTHOR
861              
862             Peter John Acklam Epjacklam@online.noE
863              
864             =head1 COPYRIGHT & LICENSE
865              
866             Copyright 2007-2010 Peter John Acklam.
867              
868             This library is free software; you can redistribute it and/or modify
869             it under the same terms as Perl itself, either Perl version 5.8.0 or,
870             at your option, any later version of Perl 5 you may have available.
871              
872             =cut
873              
874             1;