File Coverage

blib/lib/Module/Starter/Plugin/CGIApp.pm
Criterion Covered Total %
statement 276 288 95.8
branch 25 46 54.3
condition 5 14 35.7
subroutine 38 38 100.0
pod 25 25 100.0
total 369 411 89.7


line stmt bran cond sub pod time code
1             =head1 NAME
2              
3             Module::Starter::Plugin::CGIApp - template based module starter for CGI apps.
4              
5             =head1 SYNOPSIS
6              
7             use Module::Starter qw(
8             Module::Starter::Plugin::CGIApp
9             );
10              
11             Module::Starter->create_distro(%args);
12              
13             =head1 ABSTRACT
14              
15             This is a plugin for L that builds you a skeleton
16             L module with all the extra files needed to package it for
17             CPAN. You can customize the output using L.
18              
19             =cut
20              
21             package Module::Starter::Plugin::CGIApp;
22              
23 4     4   93983 use base 'Module::Starter::Simple';
  4         10  
  4         3969  
24 4     4   47463 use warnings;
  4         7  
  4         106  
25 4     4   18 use strict;
  4         8  
  4         84  
26 4     4   18 use Carp qw( croak );
  4         7  
  4         189  
27 4     4   882 use English qw( -no_match_vars );
  4         4911  
  4         25  
28 4     4   1763 use File::Basename;
  4         7  
  4         249  
29 4     4   18 use File::Path qw( mkpath );
  4         6  
  4         170  
30 4     4   16 use File::Spec ();
  4         8  
  4         56  
31 4     4   16 use Module::Starter::BuilderSet;
  4         6  
  4         82  
32 4     4   6128 use HTML::Template;
  4         58077  
  4         12184  
33              
34             =head1 VERSION
35              
36             This document describes version 0.44
37              
38             =cut
39              
40             our $VERSION = '0.44';
41              
42             =head1 DESCRIPTION
43              
44             This module subclasses L and
45             includes functionality similar to L.
46             This document only describes the methods which are overridden from those modules or are new.
47              
48             Only developers looking to extend this module need to read this. If you just
49             want to use L, read the docs for
50             L or L instead.
51              
52             =head1 METHODS
53              
54             =head2 new ( %args )
55              
56             This method calls the C supermethod from
57             L and then
58             initializes the template store. (See C.)
59              
60             =cut
61              
62             sub new {
63 3     3 1 16 my ( $proto, %opts ) = @_;
64 3   33     50 my $class = ref $proto || $proto;
65              
66 3         80 my $self = $class->SUPER::new(%opts);
67 3         104 $self->{templates} = { $self->templates };
68              
69 3         24 return bless $self => $class;
70             }
71              
72             =head2 create_distro ( %args )
73              
74             This method works as advertised in L.
75              
76             =cut
77              
78             sub create_distro {
79 3     3 1 82495 my ( $either, %opts ) = @_;
80 3 50       98 ( ref $either ) or $either = $either->new(%opts);
81 3         6 my $self = $either;
82              
83             # Supposedly the *-starter scripts can handle multiple --builder options
84             # but this doesn't work (and IMO doesn't make sense anyway.) So in the
85             # case multiple builders were specified, we just pick the first one.
86 3 50       19 if ( ref $self->{builder} eq 'ARRAY' ) {
87 0         0 $self->{builder} = $self->{builder}->[0];
88             }
89              
90 3         6 my @modules;
91 3         7 foreach my $arg ( @{ $self->{modules} } ) {
  3         16  
92 6         23 push @modules, ( split /[,]/msx, $arg );
93             }
94 3 50       18 if ( !@modules ) {
95 0         0 croak "No modules specified.\n";
96             }
97 3         106 for (@modules) {
98 6 50       48 if ( !/\A [[:alpha:]_] \w* (?: [:] [:] [\w]+ )* \Z /imsx ) {
99 0         0 croak "Invalid module name: $_";
100             }
101             }
102 3         8 $self->{modules} = \@modules;
103              
104 3 50       14 if ( !$self->{author} ) {
105 0         0 croak "Must specify an author\n";
106             }
107 3 50       10 if ( !$self->{email} ) {
108 0         0 croak "Must specify an email address\n";
109             }
110 3         30 ( $self->{email_obfuscated} = $self->{email} ) =~ s/@/ at /msx;
111              
112 3   50     30 $self->{license} ||= 'perl';
113              
114 3         11 $self->{main_module} = $self->{modules}->[0];
115 3 50       12 if ( !$self->{distro} ) {
116 0         0 $self->{distro} = $self->{main_module};
117 0         0 $self->{distro} =~ s/::/-/gmsx;
118             }
119              
120 3   33     15 $self->{basedir} = $self->{dir} || $self->{distro};
121 3         42 $self->create_basedir;
122              
123 3         818 my @files;
124 3         9 push @files, $self->create_modules( @{ $self->{modules} } );
  3         46  
125              
126 3         8 push @files, $self->create_t( @{ $self->{modules} } );
  3         44  
127 3         7 push @files, $self->create_xt( @{ $self->{modules} } );
  3         35  
128 3         33 push @files, $self->create_tmpl();
129 3         90 my %build_results = $self->create_build();
130 3         1076 push @files, @{ $build_results{files} };
  3         14  
131              
132 3         58 push @files, $self->create_Changes;
133 3         829 push @files, $self->create_LICENSE;
134 3         38 push @files, $self->create_README( $build_results{instructions} );
135 3         1024 push @files, $self->create_MANIFEST_SKIP;
136 3         34 push @files, $self->create_perlcriticrc;
137 3         34 push @files, $self->create_server_pl;
138 3         10 push @files, 'MANIFEST';
139 3     3   58 $self->create_MANIFEST( sub { _create_manifest( $self, @files ) } );
  3         65  
140              
141 3         1211 return;
142             }
143              
144             sub _create_manifest {
145 3     3   16 my ( $self, @files ) = @_;
146              
147 3         30 my $file = File::Spec->catfile( $self->{basedir}, 'MANIFEST' );
148 3 50       211 open my $fh, '>', $file or croak "Can't open file $file: $OS_ERROR\n";
149 3         49 foreach my $file ( sort @files ) {
150 57 50       64 print {$fh} "$file\n" or croak "$OS_ERROR\n";
  57         169  
151             }
152 3 50       110 close $fh or croak "Can't close file $file: $OS_ERROR\n";
153              
154 3         23 return;
155             }
156              
157             =head2 create_LICENSE( )
158              
159             This method creates a C file in the distribution's directory which
160             can hold the distribution's license terms.
161              
162             =cut
163              
164             sub create_LICENSE { ## no critic 'NamingConventions::Capitalization'
165 3     3 1 10 my $self = shift;
166              
167 3         49 my $fname = File::Spec->catfile( $self->{basedir}, 'LICENSE' );
168 3         35 $self->create_file( $fname, $self->LICENSE_guts() );
169 3         660 $self->progress("Created $fname");
170              
171 3         26 return 'LICENSE';
172             }
173              
174             =head2 create_MANIFEST_SKIP( )
175              
176             This method creates a C file in the distribution's directory so
177             that unneeded files can be skipped from inclusion in the distribution.
178              
179             =cut
180              
181             sub create_MANIFEST_SKIP { ## no critic 'NamingConventions::Capitalization'
182 3     3 1 8 my $self = shift;
183              
184 3         40 my $fname = File::Spec->catfile( $self->{basedir}, 'MANIFEST.SKIP' );
185 3         28 $self->create_file( $fname, $self->MANIFEST_SKIP_guts() );
186 3         475 $self->progress("Created $fname");
187              
188 3         24 return 'MANIFEST.SKIP';
189             }
190              
191             =head2 create_modules( @modules )
192              
193             This method will create a starter module file for each module named in
194             I<@modules>. It is only subclassed from L here
195             so we can change the I tmpl_var to be the distro name instead of
196             the module name.
197              
198             =cut
199              
200             sub create_modules {
201 3     3 1 11 my ( $self, @modules ) = @_;
202              
203 3         6 my @files;
204              
205 3         10 my $rtname = lc $self->{distro};
206 3         23 for my $module (@modules) {
207 6         1480 push @files, $self->_create_module( $module, $rtname );
208             }
209              
210 3         1145 return @files;
211             }
212              
213             =head2 create_perlcriticrc( )
214              
215             This method creates a C in the distribution's author test
216             directory so that the behavior of C can be modified.
217              
218             =cut
219              
220             sub create_perlcriticrc {
221 3     3 1 6 my $self = shift;
222              
223 3         17 my @dirparts = ( $self->{basedir}, 'xt' );
224 3         30 my $tdir = File::Spec->catdir(@dirparts);
225 3 50       75 if ( not -d $tdir ) {
226 0         0 mkpath($tdir);
227 0         0 $self->progress("Created $tdir");
228             }
229              
230 3         31 my $fname = File::Spec->catfile( @dirparts, 'perlcriticrc' );
231 3         27 $self->create_file( $fname, $self->perlcriticrc_guts() );
232 3         472 $self->progress("Created $fname");
233              
234 3         25 return 'xt/perlcriticrc';
235             }
236              
237             =head2 create_server_pl( )
238              
239             This method creates C in the distribution's root directory.
240              
241             =cut
242              
243             sub create_server_pl {
244 3     3 1 6 my $self = shift;
245              
246 3         39 my $fname = File::Spec->catfile( $self->{basedir}, 'server.pl' );
247 3         23 $self->create_file( $fname, $self->server_pl_guts() );
248 3         546 $self->progress("Created $fname");
249              
250 3         23 return 'server.pl';
251             }
252              
253             =head2 create_t( @modules )
254              
255             This method creates a bunch of *.t files. I<@modules> is a list of all modules
256             in the distribution.
257              
258             =cut
259              
260             sub create_t {
261 3     3 1 10 my ( $self, @modules ) = @_;
262              
263 3         35 my %t_files = $self->t_guts(@modules);
264              
265 3         11 my @files = map { $self->_create_t( 't', $_, $t_files{$_} ) } keys %t_files;
  12         1993  
266              
267             # This next part is for the static files dir t/www
268 3         459 my @dirparts = ( $self->{basedir}, 't', 'www' );
269 3         28 my $twdir = File::Spec->catdir(@dirparts);
270 3 50       89 if ( not -d $twdir ) {
271 3         399 mkpath($twdir);
272 3         17 $self->progress("Created $twdir");
273             }
274 3         47 my $placeholder =
275             File::Spec->catfile( @dirparts, 'PUT.STATIC.CONTENT.HERE' );
276 3         18 $self->create_file( $placeholder, q{ } );
277 3         346 $self->progress("Created $placeholder");
278 3         23 push @files, 't/www/PUT.STATIC.CONTENT.HERE';
279              
280 3         20 return @files;
281             }
282              
283             =head2 create_tmpl( )
284              
285             This method takes all the template files ending in .html (representing
286             L's and installs them into a directory under the distro tree.
287             For instance if the distro was called C, the templates would be
288             installed in C.
289              
290             Note the files will just be copied over not rendered.
291              
292             =cut
293              
294             sub create_tmpl {
295 3     3 1 8 my $self = shift;
296              
297 3         27 return $self->tmpl_guts();
298             }
299              
300             =head2 create_xt( @modules )
301              
302             This method creates a bunch of *.t files for author tests. I<@modules> is a
303             list of all modules in the distribution.
304              
305             =cut
306              
307             sub create_xt {
308 3     3 1 9 my ( $self, @modules ) = @_;
309              
310 3         37 my %xt_files = $self->xt_guts(@modules);
311              
312 3         10 my @files = map { $self->_create_t( 'xt', $_, $xt_files{$_} ) } keys %xt_files;
  9         1518  
313              
314 3         500 return @files;
315             }
316              
317             =head2 render( $template, \%options )
318              
319             This method is given an L and options and
320             returns the resulting document.
321              
322             Data in the C object which represents a reference to an array
323             @foo is transformed into an array of hashes with one key called
324             C<$foo_item> in order to make it usable in an L C.
325             For example:
326              
327             $data = ['a'. 'b', 'c'];
328              
329             would become:
330              
331             $data = [
332             { data_item => 'a' },
333             { data_item => 'b' },
334             { data_item => 'c' },
335             ];
336            
337             so that in the template you could say:
338              
339            
340            
341            
342            
343             =cut
344              
345             sub render {
346 48     48 1 100 my ( $self, $template, $options ) = @_;
347              
348             # we need a local copy of $options otherwise we get recursion in loops
349             # because of [1]
350 48         58 my %opts = %{$options};
  48         170  
351              
352 48         68 $opts{nummodules} = scalar @{ $self->{modules} };
  48         108  
353 48         178 $opts{year} = $self->_thisyear();
354 48         954 $opts{license_blurb} = $self->_license_blurb();
355 48         127 $opts{datetime} = scalar localtime;
356             $opts{buildscript} =
357 48         960 Module::Starter::BuilderSet->new()->file_for_builder( $self->{builder} );
358              
359 48         1856 foreach my $key ( keys %{$self} ) {
  48         199  
360 576 100       1097 next if defined $opts{$key};
361 549         1001 $opts{$key} = $self->{$key};
362             }
363              
364             # [1] HTML::Templates wants loops to be arrays of hashes not plain arrays
365 48         206 foreach my $key ( keys %opts ) {
366 876 100       1893 if ( ref $opts{$key} eq 'ARRAY' ) {
367 90         158 my @temp = ();
368 90         100 for my $option ( @{ $opts{$key} } ) {
  90         173  
369 138         386 push @temp, { "${key}_item" => $option };
370             }
371 90         311 $opts{$key} = [@temp];
372             }
373             }
374 48 50       316 my $t = HTML::Template->new(
375             die_on_bad_params => 0,
376             scalarref => \$template,
377             ) or croak "Can't create template $template";
378 48         32203 $t->param( \%opts );
379 48         6914 return $t->output;
380             }
381              
382             =head2 templates ( )
383              
384             This method reads in the template files and populates the object's templates
385             attribute. The module template directory is found by checking the
386             C environment variable and then the config option
387             C.
388              
389             =cut
390              
391             sub templates {
392 3     3 1 8 my ($self) = @_;
393 3         9 my %template;
394              
395             my $template_dir = ( $ENV{MODULE_TEMPLATE_DIR} || $self->{template_dir} )
396 3 50 33     53 or croak 'template dir not defined';
397 3 50       57 if ( !-d $template_dir ) {
398 0         0 croak "template dir does not exist: $template_dir";
399             }
400              
401 3         742 foreach ( glob "$template_dir/*" ) {
402 57         1230 my $basename = basename $_;
403 57 50 33     765 next if ( not -f $_ ) or ( $basename =~ /\A [.]/msx );
404 57 50       1286 open my $template_file, '<', $_
405             or croak "couldn't open template: $_";
406 57         68 $template{$basename} = do {
407 57         175 local $RS = undef;
408 57         939 <$template_file>;
409             };
410 57 50       439 close $template_file or croak "couldn't close template: $_";
411             }
412              
413 3         81 return %template;
414             }
415              
416             =head2 Build_PL_guts($main_module, $main_pm_file)
417              
418             This method is called by L and returns text used to populate
419             Build.PL when the builder is L; I<$main_pm_file>
420             is the filename of the distribution's main module, I<$main_module>.
421              
422             =cut
423              
424             sub Build_PL_guts { ## no critic 'NamingConventions::Capitalization'
425 1     1 1 228 my ( $self, $main_module, $main_pm_file ) = @_;
426 1         2 my %options;
427 1         2 $options{main_module} = $main_module;
428 1         4 $options{main_pm_file} = $main_pm_file;
429              
430 1         2 my $template = $self->{templates}{'Build.PL'};
431 1         6 return $self->render( $template, \%options );
432             }
433              
434             =head2 Changes_guts
435              
436             Implements the creation of a C file.
437              
438             =cut
439              
440             sub Changes_guts { ## no critic 'NamingConventions::Capitalization'
441 3     3 1 87 my $self = shift;
442 3         7 my %options;
443              
444 3         11 my $template = $self->{templates}{Changes};
445 3         13 return $self->render( $template, \%options );
446             }
447              
448             =head2 LICENSE_guts
449              
450             Implements the creation of a C file.
451              
452             =cut
453              
454             sub LICENSE_guts { ## no critic 'NamingConventions::Capitalization'
455 3     3 1 10 my $self = shift;
456 3         7 my %options;
457              
458 3         10 my $template = $self->{templates}{LICENSE};
459 3         13 return $self->render( $template, \%options );
460             }
461              
462             sub _license_blurb {
463 48     48   74 my $self = shift;
464 48         55 my $license_blurb;
465 48         157 my $license_record = $self->_license_record();
466              
467 48 50       255 if ( defined $license_record ) {
468 48 50       120 if ( $license_record->{license} eq 'perl' ) {
469 48         1081 $license_blurb = <<'EOT';
470             This distribution is free software; you can redistribute it and/or modify it
471             under the terms of either:
472              
473             a) the GNU General Public License as published by the Free Software
474             Foundation; either version 1, or (at your option) any later version, or
475              
476             b) the Artistic License version 1.0 or a later version.
477             EOT
478             }
479             else {
480 0         0 $license_blurb = $license_record->{blurb};
481             }
482             }
483             else {
484 0         0 $license_blurb = <<"EOT";
485             This program is released under the following license: $self->{license}
486             EOT
487             }
488 48         119 chomp $license_blurb;
489 48         126 return $license_blurb;
490             }
491              
492             =head2 Makefile_PL_guts($main_module, $main_pm_file)
493              
494             This method is called by L and returns text used to populate
495             Makefile.PL when the builder is L;
496             I<$main_pm_file> is the filename of the distribution's main module,
497             I<$main_module>.
498              
499             =cut
500              
501             sub Makefile_PL_guts { ## no critic 'NamingConventions::Capitalization'
502 1     1 1 212 my ( $self, $main_module, $main_pm_file ) = @_;
503 1         2 my %options;
504 1         2 $options{main_module} = $main_module;
505 1         3 $options{main_pm_file} = $main_pm_file;
506              
507 1         3 my $template = $self->{templates}{'Makefile.PL'};
508 1         9 return $self->render( $template, \%options );
509             }
510              
511             =head2 MANIFEST_SKIP_guts
512              
513             Implements the creation of a C file.
514              
515             =cut
516              
517             sub MANIFEST_SKIP_guts { ## no critic 'NamingConventions::Capitalization'
518 3     3 1 10 my $self = shift;
519 3         6 my %options;
520              
521 3         9 my $template = $self->{templates}{'MANIFEST.SKIP'};
522 3         13 return $self->render( $template, \%options );
523             }
524              
525             =head2 MI_Makefile_PL_guts($main_module, $main_pm_file)
526              
527             This method is called by L and returns text used to populate
528             Makefile.PL when the builder is L;
529             I<$main_pm_file> is the filename of the distribution's main module,
530             I<$main_module>.
531              
532             =cut
533              
534             sub MI_Makefile_PL_guts { ## no critic 'NamingConventions::Capitalization'
535 1     1 1 452 my ( $self, $main_module, $main_pm_file ) = @_;
536 1         5 my %options;
537 1         5 $options{main_module} = $main_module;
538 1         5 $options{main_pm_file} = $main_pm_file;
539              
540 1         6 my $template = $self->{templates}{'MI_Makefile.PL'};
541 1         16 return $self->render( $template, \%options );
542             }
543              
544             =head2 module_guts($module, $rtname)
545              
546             Implements the creation of a C file.
547              
548             =cut
549              
550             sub module_guts {
551 6     6 1 1511 my ( $self, $module, $rtname ) = @_;
552 6         14 my %options;
553 6         27 $options{module} = $module;
554 6         40 $options{rtname} = $rtname;
555              
556 6         15 my $template = $self->{templates}{'Module.pm'};
557 6         38 return $self->render( $template, \%options );
558             }
559              
560             =head2 README_guts($build_instructions)
561              
562             Implements the creation of a C file.
563              
564             =cut
565              
566             sub README_guts { ## no critic 'NamingConventions::Capitalization'
567 3     3 1 76 my ( $self, $build_instructions ) = @_;
568 3         6 my %options;
569 3         12 $options{build_instructions} = $build_instructions;
570              
571 3         9 my $template = $self->{templates}{'README'};
572 3         14 return $self->render( $template, \%options );
573             }
574              
575             =head2 perlcriticrc_guts
576              
577             Implements the creation of a C file.
578            
579             =cut
580              
581             sub perlcriticrc_guts {
582 3     3 1 7 my $self = shift;
583 3         6 my %options;
584              
585 3         9 my $template = $self->{templates}{perlcriticrc};
586 3         34 return $self->render( $template, \%options );
587             }
588              
589             =head2 server_pl_guts
590              
591             Implements the creation of a C file.
592              
593             =cut
594              
595             sub server_pl_guts {
596 3     3 1 6 my $self = shift;
597 3         6 my %options;
598 3         10 $options{main_module} = $self->{main_module};
599              
600 3         6 my $template = $self->{templates}{'server.pl'};
601 3         11 return $self->render( $template, \%options );
602             }
603              
604             =head2 t_guts(@modules)
605              
606             Implements the creation of test files. I<@modules> is a list of all the modules
607             in the distribution.
608              
609             =cut
610              
611             sub t_guts {
612 3     3 1 10 my ( $self, @opts ) = @_;
613 3         6 my %options;
614 3         15 $options{modules} = [@opts];
615 3         17 $options{modulenames} = [];
616 3         7 foreach ( @{ $options{modules} } ) {
  3         11  
617 6         91 push @{ $options{module_pm_files} }, $self->_module_to_pm_file($_);
  6         54  
618             }
619              
620 3         53 my %t_files;
621              
622 3         8 foreach ( grep { /[.]t\z/msx } keys %{ $self->{templates} } ) {
  57         427  
  3         23  
623 12         2353 my $template = $self->{templates}{$_};
624 12         36 $t_files{$_} = $self->render( $template, \%options );
625             }
626              
627 3         137 return %t_files;
628             }
629              
630             =head2 tmpl_guts
631              
632             Implements the creation of template files.
633              
634             =cut
635              
636             sub tmpl_guts {
637 3     3 1 7 my ($self) = @_;
638 3         7 my %options; # unused in this function.
639              
640 3         17 my @dirparts = ( $self->{basedir}, 'share', 'templates' );
641 3         26 my $tdir = File::Spec->catdir(@dirparts);
642 3 50       78 if ( not -d $tdir ) {
643 3         774072 mkpath($tdir);
644 3         49 $self->progress("Created $tdir");
645             }
646              
647 3         48 my @t_files;
648 3         9 foreach
649 57         202 my $filename ( grep { /[.]html \z/msx } keys %{ $self->{templates} } )
  3         35  
650             {
651 3         14 my $template = $self->{templates}{$filename};
652 3         65 my $fname = File::Spec->catfile( @dirparts, $filename );
653 3         25 $self->create_file( $fname, $template );
654 3         720 $self->progress("Created $fname");
655 3         37 push @t_files, "share/templates/$filename";
656             }
657              
658 3         25 return @t_files;
659             }
660              
661             =head2 xt_guts(@modules)
662              
663             Implements the creation of test files for author tests. I<@modules> is a list
664             of all the modules in the distribution.
665              
666             =cut
667              
668             sub xt_guts {
669 3     3 1 10 my ( $self, @opts ) = @_;
670 3         5 my %options;
671 3         12 $options{modules} = [@opts];
672 3         8 $options{modulenames} = [];
673 3         7 foreach ( @{ $options{modules} } ) {
  3         10  
674 6         63 push @{ $options{module_pm_files} }, $self->_module_to_pm_file($_);
  6         22  
675             }
676              
677 3         46 my %xt_files;
678              
679 3         8 foreach ( grep { /[.]xt\z/msx } keys %{ $self->{templates} } ) {
  57         120  
  3         17  
680 9         896 my $template = $self->{templates}{$_};
681 9         39 $_ =~ s/[.]xt\z/.t/msx; # change *.xt back to *.t
682 9         26 $xt_files{$_} = $self->render( $template, \%options );
683             }
684              
685 3         132 return %xt_files;
686             }
687              
688             =head1 BUGS
689              
690             Please report any bugs or feature requests to
691             C, or through the web
692             interface at L. I will be notified, and then you'll
693             automatically be notified of progress on your bug as I make changes.
694              
695             =head1 AUTHOR
696              
697             Jaldhar H. Vyas, Ejaldhar at braincells.comE
698              
699             =head1 COPYRIGHT
700              
701             Copyright (C) 2015, Consolidated Braincells Inc. All Rights Reserved.
702              
703             This distribution is free software; you can redistribute it and/or modify it
704             under the terms of either:
705              
706             a) the GNU General Public License as published by the Free Software
707             Foundation; either version 1, or (at your option) any later version, or
708              
709             b) the Artistic License version 1.0 or a later version.
710              
711             The full text of the license can be found in the LICENSE file included
712             with this distribution.
713              
714             =head1 SEE ALSO
715              
716             L, L, L,
717             L, L.
718             L, L, L
719              
720             =cut
721              
722             1;