File Coverage

blib/lib/Toader/Entry.pm
Criterion Covered Total %
statement 27 593 4.5
branch 0 222 0.0
condition 0 15 0.0
subroutine 9 44 20.4
pod 35 35 100.0
total 71 909 7.8


line stmt bran cond sub pod time code
1             package Toader::Entry;
2              
3 7     7   45125 use warnings;
  7         13  
  7         198  
4 7     7   36 use strict;
  7         28  
  7         191  
5 7     7   6576 use Email::MIME;
  7         507056  
  7         208  
6 7     7   6475 use File::MimeInfo;
  7         35576  
  7         3758  
7 7     7   1667 use Toader::Entry::Helper;
  7         571  
  7         711  
8 7     7   225 use File::Path qw(make_path);
  7         16  
  7         1611  
9 7     7   39 use base 'Error::Helper';
  7         17  
  7         855  
10 7     7   42 use Toader::pathHelper;
  7         16  
  7         150  
11 7     7   6308 use Text::Tags::Parser;
  7         11565  
  7         36108  
12              
13             =head1 NAME
14              
15             Toader::Entry - This holds a blog/article/whatever entry.
16              
17             =head1 VERSION
18              
19             Version 1.0.0
20              
21             =cut
22              
23             our $VERSION = '1.0.0';
24              
25             =head1 SYNOPSIS
26              
27             For information on the storage and rendering of entries,
28             please see 'Documentation/Entry.pod'.
29              
30             =head1 NEW METHODS
31              
32             If any of the new methods error, the error is permanent.
33              
34             =head2 new
35              
36             This creates the a object that represents a entry.
37              
38             One argument is taken and it s a hash reference.
39              
40             =head3 args hash
41              
42             =head4 renderer
43              
44             This is the rendering engine the body should use.
45              
46             If not defined, html will be used.
47              
48             =head4 body
49              
50             This is the body.
51              
52             =head4 title
53              
54             This is the title of the entry.
55              
56             =head4 from
57              
58             This is the from address to use.
59              
60             =head4 publish
61              
62             If it should be published or not.
63              
64             The default value is '1'.
65              
66             =head4 summary
67              
68             This is a summary of the entry.
69              
70             =head4 tags
71              
72             This is a L parsable string for the tags.
73              
74             =head4 files
75              
76             This is a list of files that will be made available with this entry.
77              
78             =head4 toader
79              
80             This is a L object.
81              
82             my $foo = Toader::Entry->new(\%args);
83             if ($foo->error){
84             warn('Error:'.$foo->error.': '.$foo->errorString);
85             }
86              
87             =cut
88              
89             sub new{
90 0     0 1   my %args;
91 0 0         if(defined($_[1])){
92 0           %args= %{$_[1]};
  0            
93             };
94              
95 0           my $self={
96             error=>undef,
97             errorString=>'',
98             perror=>undef,
99             dir=>undef,
100             entryName=>undef,
101             errorExtra=>{
102             flags=>{
103             1=>'noNameSpecified',
104             2=>'emailMIMEerror',
105             3=>'notAnArray',
106             4=>'fileDoesNotExist',
107             5=>'MIMEinfoError',
108             6=>'unableToOpenFile',
109             7=>'emailMIMEerror',
110             8=>'noBody',
111             9=>'invalidEntryName',
112             10=>'notAtoaderDir',
113             11=>'noDirSpecified',
114             12=>'noDirSet',
115             13=>'noLongerAtoaderDir',
116             14=>'noEntryDir',
117             15=>'noSummarySpecified',
118             16=>'noEntryNameSet',
119             17=>'dirDNEorNAD',
120             18=>'noFileSpecified',
121             19=>'publishValError',
122             20=>'getVCSerrored',
123             21=>'VCSusableErrored',
124             22=>'underVCSerrored',
125             23=>'VCSaddErrored',
126             24=>'notAtoaderObj',
127             25=>'noToaderObj',
128             },
129             },
130             VCSusable=>0,
131             };
132 0           bless $self;
133              
134 0 0         if (!defined($args{renderer})) {
135 0           $args{renderer}='html';
136             }
137              
138 0 0         if (!defined($args{title})) {
139 0           $self->{error}=1;
140 0           $self->{perror}=1;
141 0           $self->{errorString}='No title specified';
142 0           $self->warn;
143 0           return $self;
144             }
145              
146 0 0         if (!defined($args{from})) {
147 0           $self->{error}=9;
148 0           $self->{perror}=1;
149 0           $self->{errorString}='No from specified';
150 0           $self->warn;
151 0           return $self;
152             }
153              
154 0 0         if (!defined($args{body})) {
155 0           $args{body}='';
156             }
157              
158 0 0         if (!defined($args{publish})) {
159 0           $args{publish}='1';
160             }
161              
162             #makes sure the publish value is
163 0 0 0       if (
164             ( $args{publish} ne "0" ) &&
165             ( $args{publish} ne "1" )
166             ){
167 0           $self->{perror}=1;
168 0           $self->{error}=19;
169 0           $self->{errorString}='"'.$args{publish}.'" is not a recognized boolean value';
170 0           $self->warn;
171 0           return $self;
172             }
173              
174 0 0         if ( !defined( $args{summary} ) ){
175 0           $args{summary}='';
176             }
177              
178             #this will hold the various parts
179 0           my @parts;
180 0           my $int=0;
181 0 0         if (defined($args{files})) {
182 0 0         if ( ref( $args{files} ne "ARRAY" ) ) {
183 0           $self->{perror}=1;
184 0           $self->{error}=3;
185 0           $self->{errorString}="Has files specified, but the passed object is not a array";
186 0           $self->warn;
187 0           return $self;
188             }
189              
190             #puts all the parts together
191 0           while (defined( $args{files}[$int] )) {
192 0 0         if (! -f $args{files}[$int] ) {
193 0           $self->{error}=4;
194 0           $self->{perror}=1;
195 0           $self->{errorString}="'".$args{files}[$int]."' is not a file or does not exist";
196 0           $self->warn;
197 0           return $self;
198             }
199              
200             #gets the MIME type
201 0           my $mimetype=mimetype( $args{files}[$int] );
202              
203             #makes sure it is a mimetype
204 0 0         if ( !defined( $mimetype ) ) {
205 0           $self->{error}=5;
206 0           $self->{perror}=1;
207 0           $self->{errorString}="'".$args{files}[$int]."' could not be read or does not exist";
208 0           $self->warn;
209 0           return $self;
210             }
211              
212             #open and read the file
213 0           my $fh;
214 0 0         if ( ! open( $fh, '<', $args{files}[$int] ) ) {
215 0           $self->{error}=6;
216 0           $self->{perror}=1;
217 0           $self->{errorString}="unable to open '".$args{files}[$int]."'";
218 0           $self->warn;
219 0           return $self;
220             }
221 0           my $file=join('',<$fh>);
222 0           close $fh;
223              
224             #create a short name for it... removing the path
225 0           my $filename=$args{files}[$int];
226 0           $filename=~s/.*\///g;
227            
228 0           my $part=Email::MIME->create(attributes=>{
229             filename=>$filename,
230             content_type=>$mimetype,
231             encode=>"base64",
232             },
233             body=>$file,
234             );
235              
236 0 0         if (!defined( $part )) {
237 0           $self->{error}=7;
238 0           $self->{perror}=1;
239 0           $self->{errorString}='Unable to create a MIME object for one of the files';
240 0           $self->warn;
241 0           return $self;
242             }
243              
244 0           push(@parts, $part);
245              
246 0           $int++;
247             }
248              
249             }
250              
251             #blank the tags value if not defined
252 0 0         if ( ! defined( $args{tags} ) ){
253 0           $args{tags}='';
254             }
255             #clean the tag string
256 0           my @tags=Text::Tags::Parser->new->parse_tags( $args{tags} );
257 0           $args{tags}=Text::Tags::Parser->new->join_tags( @tags );
258            
259              
260             #creates it
261 0           my $mime=Email::MIME->create(
262             header=>[
263             renderer=>$args{renderer},
264             title=>$args{title},
265             summary=>$args{summary},
266             From=>$args{from},
267             publish=>$args{publish},
268             tags=>$args{tags},
269             ],
270             body=>$args{body},
271             );
272             #this sets the parts if needed
273 0 0         if ( defined( $parts[0] ) ){
274 0           $mime->set_parts( \@parts );
275             }
276            
277 0 0         if (!defined($mime)) {
278 0           $self->{error}=2;
279 0           $self->{perror}=1;
280 0           $self->{errorString}='Unable to create Email::MIME object';
281 0           $self->warn;
282 0           return $self;
283             }
284              
285 0           $self->{mime}=$mime;
286              
287             #if we have a Toader object, reel it in
288 0 0         if ( ! defined( $args{toader} ) ){
289 0           $self->{perror}=1;
290 0           $self->{error}=25;
291 0           $self->{errorString}='No Toader object specified';
292 0           $self->warn;
293 0           return $self;
294             }
295 0 0         if ( ref( $args{toader} ) ne "Toader" ){
296 0           $self->{perror}=1;
297 0           $self->{error}=24;
298 0           $self->{errorString}='The object specified is a "'.ref($args{toader}).'"';
299 0           $self->warn;
300 0           return $self;
301             }
302 0           $self->{toader}=$args{toader};
303              
304             #gets the Toader::VCS object
305 0           $self->{vcs}=$self->{toader}->getVCS;
306 0 0         if ( $self->{toader}->error ){
307 0           $self->{perror}=1;
308 0           $self->{error}=20;
309 0           $self->{errorString}='Toader->getVCS errored. error="'.
310             $self->{toader}->error.'" errorString="'.$self->{toader}->errorString.'"';
311 0           $self->warn;
312 0           return $self;
313             }
314            
315             #checks if VCS is usable
316 0           $self->{VCSusable}=$self->{vcs}->usable;
317 0 0         if ( $self->{vcs}->error ){
318 0           $self->{perror}=1;
319 0           $self->{error}=21;
320 0           $self->{errorString}='Toader::VCS->usable errored. error="'.
321             $self->{toader}->error.'" errorString="'.$self->{toader}->errorString.'"';
322 0           $self->warn;
323 0           return $self;
324             }
325              
326 0           return $self;
327             }
328              
329             =head2 newFromString
330              
331             This creates a new entry from a string.
332              
333             Two argument are accepted. The first is the entry string and the second
334             is a L object.
335              
336             my $foo=Toader::Entry->newFromString($entryString, $toader);
337             if($foo->error){
338             warn('Error:'.$foo->error.': '.$foo->errorString);
339             }
340              
341             =cut
342              
343             sub newFromString{
344 0     0 1   my $string=$_[1];
345 0           my $toader=$_[2];
346              
347 0           my $self={
348             error=>undef,
349             errorString=>'',
350             module=>'Toader-Entry',
351             perror=>undef,
352             dir=>undef,
353             entryName=>undef,
354             toader=>undef,
355             errorExtra=>{
356             flags=>{
357             1=>'noNameSpecified',
358             2=>'emailMIMEerror',
359             3=>'notAnArray',
360             4=>'fileDoesNotExist',
361             5=>'MIMEinfoError',
362             6=>'unableToOpenFile',
363             7=>'emailMIMEerror',
364             8=>'noBody',
365             9=>'invalidEntryName',
366             10=>'notAtoaderDir',
367             11=>'noDirSpecified',
368             12=>'noDirSet',
369             13=>'noLongerAtoaderDir',
370             14=>'noEntryDir',
371             15=>'noSummarySpecified',
372             16=>'noEntryNameSet',
373             17=>'dirDNEorNAD',
374             18=>'noFileSpecified',
375             19=>'publishValError',
376             20=>'getVCSfailed',
377             21=>'VCSusableFailed',
378             22=>'underVCSerrored',
379             23=>'VCSaddErrored',
380             24=>'notAtoaderObj',
381             25=>'noToaderObj',
382             },
383             },
384             VCSusable=>0,
385             };
386 0           bless $self;
387              
388             #Email::MIME will exit if we pass it a null value
389 0 0         if (!defined($string)) {
390 0           $self->{error}=8;
391 0           $self->{perror}=1;
392 0           $self->{errorString}='The string is null';
393 0           $self->warn;
394 0           return $self;
395             }
396              
397             #creates the MIME object
398 0           my $mime=Email::MIME->new($string);
399 0 0         if (!defined($mime)) {
400 0           $self->{error}=2;
401 0           $self->{perror}=1;
402 0           $self->{errorString}='Unable to create Email::MIME object';
403 0           $self->warn;
404 0           return $self;
405             }
406              
407             #make sure we have a title
408 0 0         if (!defined( $mime->header( "title" ) )) {
409 0           $self->{error}=1;
410 0           $self->{perror}=1;
411 0           $self->{errorString}='No title specified';
412 0           $self->warn;
413 0           return $self;
414             }
415              
416             #make sure we have a from
417 0 0         if (!defined( $mime->header( "from" ) )) {
418 0           $self->{error}=9;
419 0           $self->{perror}=1;
420 0           $self->{errorString}='No from specified';
421 0           $self->warn;
422 0           return $self;
423             }
424              
425             #set the summary to blank if one is not specified
426 0 0         if (!defined( $mime->header( "summary" ) )) {
427 0           $mime->header_set(summary=>'');
428             }
429              
430             #if there are no tags, make sure it is blank
431 0 0         if (!defined( $mime->header( "tags" ) )) {
432 0           $mime->header_set(tags=>'');
433             }
434             #clean the tags
435 0           my @tags=Text::Tags::Parser->new->parse_tags( $mime->header("tags") );
436 0           $mime->header_set( tags=>Text::Tags::Parser->new->join_tags( @tags ) );
437              
438             #make sure we have a renderer type
439 0 0         if (!defined( $mime->header( "renderer" ) )) {
440 0           $mime->header_set(renderer=>'html')
441             }
442              
443             #make sure we have publish set
444 0 0         if (!defined( $mime->header( "publish" ) )) {
445 0           $mime->header_set(publish=>'1');
446             }
447              
448             #makes sure it is a recognized boolean value
449 0 0 0       if (
450             ( $mime->header( "publish" ) ne "0" ) &&
451             ( $mime->header( "publish" ) ne "1" )
452             ){
453 0           $self->{perror}=1;
454 0           $self->{error}=19;
455 0           $self->{errorstring}='"'.$mime->header( "publish" ).
456             '" is not a recognized boolean value';
457 0           $self->warn;
458 0           return $self;
459             }
460            
461 0           $self->{mime}=$mime;
462              
463             #if we have a Toader object, reel it in
464 0 0         if ( ! defined( $toader ) ){
465 0           $self->{perror}=1;
466 0           $self->{error}=25;
467 0           $self->{errorString}='No Toader object specified';
468 0           $self->warn;
469 0           return $self;
470             }
471 0 0         if ( ref( $toader ) ne "Toader" ){
472 0           $self->{perror}=1;
473 0           $self->{error}=24;
474 0           $self->{errorString}='The object specified is a "'.ref($toader).'"';
475 0           $self->warn;
476 0           return $self;
477             }
478 0           $self->{toader}=$toader;
479              
480             #gets the Toader::VCS object
481 0           $self->{vcs}=$self->{toader}->getVCS;
482 0 0         if ( $toader->error ){
483 0           $self->{perror}=1;
484 0           $self->{error}=20;
485 0           $self->{errorString}='Toader->getVCS errored. error="'.
486             $self->{toader}->error.'" errorString="'.$self->{toader}->errorString.'"';
487 0           $self->warn;
488 0           return $self;
489             }
490            
491             #checks if VCS is usable
492 0           $self->{VCSusable}=$self->{vcs}->usable;
493 0 0         if ( $self->{vcs}->error ){
494 0           $self->{perror}=1;
495 0           $self->{error}=21;
496 0           $self->{errorString}='Toader::VCS->usable errored. error="'.
497             $self->{toader}->error.'" errorString="'.$self->{toader}->errorString.'"';
498 0           $self->warn;
499 0           return $self;
500             }
501              
502 0           return $self;
503             }
504              
505             =head1 GENERAL METHODS
506              
507             =head2 as_string
508              
509             This returns the entry as a string.
510              
511             my $mimeString=$foo->as_string;
512             if($foo->error)
513             warn('Error:'.$foo->error.': '.$foo->errorString);
514             }
515              
516             =cut
517              
518             sub as_string{
519 0     0 1   my $self=$_[0];
520              
521 0 0         if (!$self->errorblank){
522 0           return undef;
523             }
524              
525 0           return $self->{mime}->as_string;
526             }
527              
528             =head2 bodyGet
529              
530             This gets body.
531              
532             my $body=$foo->bodyGet;
533             if($foo->error){
534             warn('Error:'.$foo->error.': '.$foo->errorString);
535             }
536              
537             =cut
538              
539             sub bodyGet{
540 0     0 1   my $self=$_[0];
541              
542 0 0         if (!$self->errorblank){
543 0           return undef;
544             }
545              
546 0           my @parts=$self->{mime}->subparts;
547            
548 0           my $int=0;
549 0           while ( defined( $parts[$int] ) ){
550 0 0         if ( ! defined( $parts[$int]->filename ) ){
551 0           return $parts[$int]->body;
552             }
553              
554 0           $int++;
555             }
556              
557 0           return $self->{mime}->body;
558             }
559              
560             =head2 bodySet
561              
562             This sets the body.
563              
564             One argument is required and it is the body.
565              
566             $foo->bodySet($body);
567             if($foo->error){
568             warn('Error:'.$foo->error.': '.$foo->errorString);
569             }
570              
571             =cut
572              
573             sub bodySet{
574 0     0 1   my $self=$_[0];
575 0           my $body=$_[1];
576              
577 0 0         if (!$self->errorblank){
578 0           return undef;
579             }
580              
581 0 0         if (!defined($body)) {
582 0           $self->{error}=8;
583 0           $self->{errorString}='No body defined';
584 0           $self->warn;
585 0           return undef;
586             }
587              
588              
589 0           my @parts=$self->{mime}->subparts;
590            
591 0 0         if ( defined( $parts[1] ) ){
592 0           my $int=0;
593 0           while ( defined( $parts[$int] ) ){
594 0 0         if ( ! defined( $parts[$int]->filename ) ){
595 0           $parts[$int]->body_set($body);
596             }
597              
598 0           $int++;
599             }
600              
601 0           $self->{mime}->parts_set( \@parts );
602              
603 0           return 1;
604             }
605              
606 0           $self->{mime}->body_set($body);
607              
608 0           return 1;
609             }
610              
611             =head2 dirGet
612              
613             This gets L directory this entry is associated with.
614              
615             This will only error if a permanent error is set.
616              
617             This will return undef if no directory has been set.
618              
619             my $dir=$foo->dirGet;
620             if($foo->error){
621             warn('Error:'.$foo->error.': '.$foo->errorString);
622             }
623              
624             =cut
625              
626             sub dirGet{
627 0     0 1   my $self=$_[0];
628              
629 0 0         if (!$self->errorblank){
630 0           return undef;
631             }
632              
633 0           return $self->{dir};
634             }
635              
636             =head2 dirSet
637              
638             This sets L directory this entry is associated with.
639              
640             One argument is taken and it is the L directory to set it to.
641              
642             my $dir=$foo->dirSet($toaderDirectory);
643             if($foo->error){
644             warn('Error:'.$foo->error.': '.$foo->errorString);
645             }
646              
647             =cut
648              
649             sub dirSet{
650 0     0 1   my $self=$_[0];
651 0           my $dir=$_[1];
652              
653 0 0         if (!$self->errorblank){
654 0           return undef;
655             }
656              
657             #make sure a directory has been specified
658 0 0         if (!defined($dir)) {
659 0           $self->{error}=11;
660 0           $self->{errorString}='No directory specified.';
661 0           $self->warn;
662 0           return undef;
663             }
664              
665             #cleans up the naming
666 0           my $pathHelper=Toader::pathHelper->new($dir);
667 0           $dir=$pathHelper->cleanup($dir);
668              
669             #checks if the directory is Toader directory or not
670 0           my $isatd=Toader::isaToaderDir->new;
671 0           my $returned=$isatd->isaToaderDir($dir);
672 0 0         if (! $returned ) {
673 0           $self->{error}=10;
674 0           $self->{errorString}='"'.$dir.'" is not a Toader directory.';
675 0           $self->warn;
676 0           return undef;
677             }
678              
679 0           $self->{dir}=$dir;
680              
681 0           return 1;
682             }
683              
684             =head2 entryNameGet
685              
686             This gets L directory this entry is associated with.
687              
688             This will only error if a permanent error is set.
689              
690             This will return undef if no entry name has been set.
691              
692             my $entryName=$foo->entryNameGet;
693             if($foo->error){
694             warn('Error:'.$foo->error.': '.$foo->errorString);
695             }
696              
697             =cut
698              
699             sub entryNameGet{
700 0     0 1   my $self=$_[0];
701              
702 0 0         if (!$self->errorblank){
703 0           $self->warn;
704 0           return undef;
705             }
706              
707 0           return $self->{entryName};
708             }
709              
710             =head2 entryNameSet
711              
712             This sets L directory this entry is associated with.
713              
714             One argument is taken and it is the Toader directory to set it to.
715             If none is specified it will be generated.
716              
717             $foo->entryNameSet($entryName);
718             if($foo->error){
719             warn('Error:'.$foo->error.': '.$foo->errorString);
720             }
721              
722             =cut
723              
724             sub entryNameSet{
725 0     0 1   my $self=$_[0];
726 0           my $entryName=$_[1];
727              
728 0 0         if (!$self->errorblank){
729 0           return undef;
730             }
731              
732             #makes sure the entry name is valid
733 0           my $ehelper=Toader::Entry::Helper->new( $self->{toader} ) ;
734 0           my $returned=$ehelper->validEntryName($entryName);
735 0 0         if ( ! $returned ) {
736 0           $self->{error}=9;
737 0           $self->{errorString}='Not a valid entry name';
738 0           $self->warn;
739 0           return undef;
740             }
741              
742             #generate a entry name if one has not been
743 0 0         if (!defined($entryName)) {
744 0           $entryName=$ehelper->generateEntryName;
745             }
746              
747 0           $self->{entryName}=$entryName;
748              
749 0           return 1;
750             }
751              
752             =head2 fromGet
753              
754             This returns the from.
755              
756             my $from=$foo->fromGet;
757             if($foo->error){
758             warn('error: '.$foo->error.":".$foo->errorString);
759             }
760              
761             =cut
762              
763             sub fromGet{
764 0     0 1   my $self=$_[0];
765              
766 0 0         if (!$self->errorblank){
767 0           return undef;
768             }
769              
770 0           return $self->{mime}->header('From');
771             }
772              
773             =head2 fromSet
774              
775             This sets the from.
776              
777             One argument is taken and it is the name.
778              
779             $foo->fromSet($name);
780             if($foo->error){
781             warn('error: '.$foo->error.":".$foo->errorString);
782             }
783              
784             =cut
785              
786             sub fromSet{
787 0     0 1   my $self=$_[0];
788 0           my $from=$_[1];
789              
790 0 0         if (!$self->errorblank){
791 0           return undef;
792             }
793              
794 0 0         if (!defined( $from )) {
795 0           $self->{error}=9;
796 0           $self->{errorString}='No short name specified';
797 0           $self->warn;
798 0           return $self;
799             }
800              
801 0           $self->{mime}->header_set('From'=>$from);
802              
803 0           return 1;
804             }
805              
806             =head2 publishGet
807              
808             This returns the publish value.
809              
810             my $publish=$foo->publishGet;
811             if($foo->error){
812             warn('error: '.$foo->error.":".$foo->errorString);
813             }
814              
815             =cut
816              
817             sub publishGet{
818 0     0 1   my $self=$_[0];
819              
820 0 0         if (!$self->errorblank){
821 0           return undef;
822             }
823              
824 0           my $publish=$self->{mime}->header('publish');
825            
826             #return the default if none is specified
827 0 0         if ( ! defined( $publish ) ){
828 0           return "1";
829             }
830              
831 0 0 0       if (
832             ( $publish ne "0" ) &&
833             ( $publish ne "1" )
834             ){
835 0           $self->{error}=19;
836 0           $self->{errorString}='"'.$publish.'" is not a recognized boolean value';
837 0           $self->warn;
838 0           return undef;
839             }
840              
841 0           return $publish;
842             }
843              
844             =head2 publishSet
845              
846             This sets the publish value.
847              
848             One argument is taken and it is the publish value.
849              
850             $foo->publishSet($publish);
851             if($foo->error){
852             warn('error: '.$foo->error.":".$foo->errorString);
853             }
854              
855             =cut
856              
857             sub publishSet{
858 0     0 1   my $self=$_[0];
859 0           my $publish=$_[1];
860              
861 0 0         if (!$self->errorblank){
862 0           return undef;
863             }
864              
865 0 0         if (!defined( $publish )) {
866 0           $publish='0';
867             }
868              
869 0 0 0       if (
870             ( $publish ne '0' ) &&
871             ( $publish ne '1' )
872             ){
873 0           $self->error=19;
874 0           $self->errorString='The publish value is not "0" or "1", but "'.$publish.'"';
875 0           $self->warn;
876 0           return undef;
877             }
878            
879              
880 0           $self->{mime}->header_set('publish'=>$publish);
881              
882 0           return 1;
883             }
884              
885             =head2 summaryGet
886              
887             This returns the summary.
888              
889             my $summary=$foo->summaryGet;
890             if($foo->error){
891             warn('error: '.$foo->error.":".$foo->errorString);
892             }
893              
894             =cut
895              
896             sub summaryGet{
897 0     0 1   my $self=$_[0];
898              
899 0 0         if (!$self->errorblank){
900 0           return undef;
901             }
902              
903 0           my $summary=$self->{mime}->header('summary');
904              
905 0 0         if ( ! defined( $summary ) ){
906 0           $summary='';
907             }
908              
909 0           return $summary;
910             }
911              
912             =head2 summarySet
913              
914             This sets the summary.
915              
916             One argument is taken and it is the summary.
917              
918             $foo->summarySet($summary);
919             if($foo->error){
920             warn('error: '.$foo->error.":".$foo->errorString);
921             }
922              
923             =cut
924              
925             sub summarySet{
926 0     0 1   my $self=$_[0];
927 0           my $summary=$_[1];
928              
929 0 0         if (!$self->errorblank){
930 0           return undef;
931             }
932              
933 0 0         if (!defined( $summary )) {
934 0           $self->{error}=15;
935 0           $self->{errorString}='No summary specified';
936 0           $self->warn;
937 0           return $self;
938             }
939              
940 0           $self->{mime}->header_set('summary'=>$summary);
941              
942 0           return 1;
943             }
944              
945             =head2 titleGet
946              
947             This returns the title.
948              
949             my $name=$foo->titleGet;
950             if($foo->error){
951             warn('error: '.$foo->error.":".$foo->errorString);
952             }
953              
954             =cut
955              
956             sub titleGet{
957 0     0 1   my $self=$_[0];
958              
959 0 0         if (!$self->errorblank){
960 0           return undef;
961             }
962              
963 0           return $self->{mime}->header('title');
964             }
965              
966             =head2 titleSet
967              
968             This sets the title.
969              
970             One argument is taken and it is the title.
971              
972             $foo->titleSet($title);
973             if($foo->error){
974             warn('error: '.$foo->error.":".$foo->errorString);
975             }
976              
977             =cut
978              
979             sub titleSet{
980 0     0 1   my $self=$_[0];
981 0           my $title=$_[1];
982              
983 0 0         if (!$self->errorblank){
984 0           return undef;
985             }
986              
987 0 0         if (!defined( $title )) {
988 0           $self->{error}=1;
989 0           $self->{errorString}='No title specified';
990 0           $self->warn;
991 0           return $self;
992             }
993              
994 0           $self->{mime}->header_set('title'=>$title);
995              
996 0           return 1;
997             }
998              
999             =head2 rendererGet
1000              
1001             This returns the renderer type.
1002              
1003             my $renderer=$foo->rendererGet;
1004             if($foo->error){
1005             warn('error: '.$foo->error.":".$foo->errorString);
1006             }
1007              
1008             =cut
1009              
1010             sub rendererGet{
1011 0     0 1   my $self=$_[0];
1012              
1013 0 0         if (!$self->errorblank){
1014 0           return undef;
1015             }
1016              
1017 0           return $self->{mime}->header('renderer');
1018             }
1019              
1020             =head2 rendererSet
1021              
1022             This sets the renderer type.
1023              
1024             One argument is taken and it is the render type.
1025              
1026             A value of undef sets it to the default, 'html'.
1027              
1028             my $renderer=$foo->rendererGet;
1029             if($foo->error){
1030             warn('error: '.$foo->error.":".$foo->errorString);
1031             }
1032              
1033             =cut
1034              
1035             sub rendererSet{
1036 0     0 1   my $self=$_[0];
1037 0           my $renderer=$_[1];
1038              
1039 0 0         if (!$self->errorblank){
1040 0           return undef;
1041             }
1042              
1043 0 0         if (!defined( $renderer )) {
1044 0           $renderer='html';
1045             }
1046              
1047 0           $self->{mime}->header_set('renderer'=>$renderer);
1048              
1049 0           return 1;
1050             }
1051              
1052             =head2 subpartsAdd
1053              
1054             This adds a new file as a subpart.
1055              
1056             One argument is required and it is the path to the file.
1057              
1058             $foo->subpartsAdd( $file );
1059             if ( $foo->error ){
1060             warn('Error:'.$foo->error.': '.$foo->errorString);
1061             }
1062              
1063             =cut
1064              
1065             sub subpartsAdd{
1066 0     0 1   my $self=$_[0];
1067 0           my $file=$_[1];
1068              
1069 0 0         if (!$self->errorblank){
1070 0           return undef;
1071             }
1072              
1073             #makes sure a file is specified
1074 0 0         if ( ! defined( $file ) ){
1075 0           $self->{error}=18;
1076 0           $self->{errorstring}='No file specified';
1077 0           $self->warn;
1078 0           return undef;
1079             }
1080              
1081             #makes sure the file exists and is a file
1082 0 0         if ( ! -f $file ){
1083 0           $self->{error}=4;
1084 0           $self->{errorString}='The file, "'.$file.'", does not exist or is not a file';
1085 0           $self->warn;
1086 0           return undef;
1087             }
1088              
1089             #gets the MIME type
1090 0           my $mimetype=mimetype( $file );
1091            
1092             #makes sure it is a mimetype
1093 0 0         if ( !defined( $mimetype ) ) {
1094 0           $self->{error}=5;
1095 0           $self->{errorString}="'".$file."' could not be read or does not exist";
1096 0           $self->warn;
1097 0           return $self;
1098             }
1099              
1100             #create a short name for it... removing the path
1101 0           my $filename=$file;
1102 0           $filename=~s/.*\///g;
1103              
1104             #open and read the file
1105 0           my $fh;
1106 0 0         if ( ! open( $fh, '<', $file ) ) {
1107 0           $self->{error}=6;
1108 0           $self->{errorString}="Unable to open '".$file."'";
1109 0           $self->warn;
1110 0           return undef;
1111             }
1112 0           my $body=join('',<$fh>);
1113 0           close $fh;
1114              
1115              
1116             #creates the part
1117 0           my $part=Email::MIME->create(attributes=>{
1118             filename=>$filename,
1119             content_type=>$mimetype,
1120             encode=>"base64",
1121             },
1122             body=>$body,
1123             );
1124 0           my @parts;
1125 0           push( @parts, $part );
1126 0           $self->{mime}->parts_add( \@parts );
1127              
1128 0           return 1;
1129             }
1130              
1131             =head2 subpartsExtract
1132              
1133             This extracts the subparts of a entry.
1134              
1135             One argument is extracted, it is the directory
1136             to extract the files to.
1137              
1138             $foo->subpartsExtract( $dir );
1139             if ( $foo->error ){
1140             warn('Error:'.$foo->error.': '.$foo->errorString);
1141             }
1142              
1143             =cut
1144              
1145             sub subpartsExtract{
1146 0     0 1   my $self=$_[0];
1147 0           my $dir=$_[1];
1148              
1149 0 0         if (!$self->errorblank){
1150 0           return undef;
1151             }
1152              
1153 0 0         if ( ! defined( $dir ) ){
1154 0           $self->{error}=11;
1155 0           $self->{errorString}='No directory specified';
1156 0           $self->warn;
1157 0           return undef;
1158             }
1159              
1160             #make sure it exists and is a directory
1161 0 0         if ( ! -d $dir ){
1162 0           $self->{error}=17;
1163 0           $self->{errorString}='"'.$dir.'" is not a directory or does not exist';
1164 0           $self->warn;
1165 0           return undef;
1166             }
1167              
1168 0           my @subparts=$self->subpartsGet;
1169 0 0         if ( $self->error ){
1170 0           $self->warnString('Failed to get the subparts');
1171 0           return undef;
1172             }
1173              
1174             # no subparts to write to the FS
1175 0 0         if ( ! defined( $subparts[0] ) ){
1176 0           return 1;
1177             }
1178              
1179 0           my $int=0;
1180 0           while ( defined( $subparts[$int] ) ){
1181 0           my $file=$subparts[$int]->filename;
1182 0 0         if( defined( $file ) ){
1183 0           my $file=$dir.'/'.$file;
1184            
1185 0           my $fh;
1186 0 0         if ( ! open( $fh, '>', $file ) ){
1187 0           $self->{error}=18;
1188 0           $self->{errorString}='"Failed to open "'.$file.
1189             '" for writing the body of a subpart out to';
1190 0           $self->warn;
1191 0           return undef;
1192             }
1193 0           print $fh $subparts[$int]->body;
1194 0           close( $fh );
1195             }
1196              
1197 0           $int++;
1198             }
1199              
1200 0           return 1;
1201             }
1202              
1203             =head2 subpartsGet
1204              
1205             This returns the results from the subparts
1206             methods from the internal L object.
1207              
1208             my @parts=$foo->subpartsGet;
1209             if ( $foo->error ){
1210             warn('Error:'.$foo->error.': '.$foo->errorString);
1211             }
1212              
1213             =cut
1214              
1215             sub subpartsGet{
1216 0     0 1   my $self=$_[0];
1217              
1218 0 0         if (!$self->errorblank){
1219 0           return undef;
1220             }
1221              
1222 0           return $self->{mime}->subparts;
1223             }
1224              
1225             =head2 subpartsList
1226              
1227             This returns a list filenames for the subparts.
1228              
1229             my @files=$foo->subpartsList;
1230             if ( $foo->error ){
1231             warn('Error:'.$foo->error.': '.$foo->errorString);
1232             }
1233              
1234             =cut
1235              
1236             sub subpartsList{
1237 0     0 1   my $self=$_[0];
1238              
1239 0 0         if (!$self->errorblank){
1240 0           return undef;
1241             }
1242              
1243 0           my @subparts=$self->subpartsGet;
1244 0 0         if ( $self->error ){
1245 0           $self->warnString('Failed to get the subparts');
1246 0           return undef;
1247             }
1248              
1249 0           my @files;
1250 0           my $int=0;
1251 0           while( defined( $subparts[$int] ) ){
1252 0 0         if ( defined( $subparts[$int]->filename ) ){
1253 0           push( @files, $subparts[$int]->filename );
1254             }
1255              
1256 0           $int++;
1257             }
1258              
1259 0           return @files;
1260             }
1261              
1262             =head2 subpartsRemove
1263              
1264             This removes the specified subpart.
1265              
1266             One argument is required and it is the name of the
1267             file to remove.
1268              
1269             $foo->subpartsRemove( $filename );
1270             if ( $foo->error ){
1271             warn('Error:'.$foo->error.': '.$foo->errorString);
1272             }
1273              
1274             =cut
1275              
1276             sub subpartsRemove{
1277 0     0 1   my $self=$_[0];
1278 0           my $file=$_[1];
1279              
1280 0 0         if (!$self->errorblank){
1281 0           return undef;
1282             }
1283              
1284             #makes sure a file is specified
1285 0 0         if ( ! defined( $file ) ){
1286 0           $self->{error}=18;
1287 0           $self->{errorstring}='No file specified';
1288 0           $self->warn;
1289 0           return undef;
1290             }
1291              
1292 0           my @parts=$self->{mime}->parts;
1293 0           my @newparts;
1294 0           my $int=0;
1295 0           while ( defined( $parts[$int] ) ){
1296 0           my $partFilename=$parts[$int]->filename;
1297 0 0 0       if ( ( ! defined( $partFilename ) ) ||
1298             ( $file ne $partFilename ) ){
1299 0           push( @newparts, $parts[$int] );
1300             }
1301              
1302 0           $int++;
1303             }
1304              
1305 0           $self->{mime}->parts_set( \@newparts );
1306              
1307 0           return 1;
1308             }
1309              
1310             =head2 tagsGet
1311              
1312             Returns a array of tags tags.
1313              
1314             The returned value is an array.
1315              
1316             my @tags=$foo->tagsGet;
1317             if ( $foo->error ){
1318             warn('Error:'.$foo->error.': '.$foo->errorString);
1319             }
1320              
1321             =cut
1322              
1323             sub tagsGet{
1324 0     0 1   my $self=$_[0];
1325              
1326 0 0         if (!$self->errorblank){
1327 0           return undef;
1328             }
1329            
1330             #if there are no tags, make sure it is blank
1331 0 0         if (!defined( $self->{mime}->header( "tags" ) )) {
1332 0           $self->{mime}->header_set(tags=>'');
1333             }
1334             #clean the tags
1335 0           my @tags=Text::Tags::Parser->new->parse_tags( $self->{mime}->header("tags") );
1336              
1337 0           return @tags;
1338             }
1339              
1340             =head2 tagsGetAsString
1341              
1342             This returns the tags as a string.
1343              
1344             As long as this object has initiated with
1345             out issue, then there is no need to do error
1346             checking for this method.
1347              
1348             my $tagsString=$foo->tagsGetAsString;
1349              
1350             =cut
1351              
1352             sub tagsGetAsString{
1353 0     0 1   my $self=$_[0];
1354              
1355 0 0         if (!$self->errorblank){
1356 0           return undef;
1357             }
1358              
1359 0           my $tags=$self->{mime}->header( "tags" );
1360              
1361 0 0         if ( ! defined( $tags ) ){
1362 0           $tags='';
1363             }
1364              
1365 0           return $tags;
1366             }
1367              
1368             =head2 tagsSet
1369              
1370             This sets the tags.
1371              
1372             One value is taken and that is the a array reference.
1373              
1374             $foo->tagsSet( \@tags );
1375             if ( $foo->error ){
1376             warn('Error:'.$foo->error.': '.$foo->errorString);
1377             }
1378              
1379             =cut
1380              
1381             sub tagsSet{
1382 0     0 1   my $self=$_[0];
1383 0           my @tags;
1384 0 0         if ( defined( $_[1] ) ){
1385 0           @tags=@{ $_[1] };
  0            
1386             }
1387              
1388 0 0         if (!$self->errorblank){
1389 0           return undef;
1390             }
1391              
1392 0           $self->{mime}->header_set( Text::Tags::Parser->new->join_tags( @tags ) );
1393            
1394 0           return @tags;
1395             }
1396              
1397             =head2 tagsSetFromString
1398              
1399             This sets the tags.
1400              
1401             One value is taken and that is a L parsable
1402             string. A value of undef will blank the tags.
1403              
1404             $foo->tagsSetFromString( $tagsString );
1405             if ( $foo->error ){
1406             warn('Error:'.$foo->error.': '.$foo->errorString);
1407             }
1408              
1409             =cut
1410              
1411             sub tagsSetFromString{
1412 0     0 1   my $self=$_[0];
1413 0           my $tagsString=$_[1];
1414              
1415 0 0         if (!$self->errorblank){
1416 0           return undef;
1417             }
1418              
1419 0 0         if ( ! defined( $tagsString ) ){
1420 0           $tagsString='';
1421             }
1422              
1423 0           my @tags=Text::Tags::Parser->new->parse_tags( $tagsString );
1424 0           $self->{mime}->header_set( tags=>Text::Tags::Parser->new->join_tags( @tags ) );
1425            
1426 0           return @tags;
1427             }
1428              
1429             =head2 write
1430              
1431             This writes the entry out to a file.
1432              
1433             This requires a L directory to have been specified.
1434              
1435             $foo->write;
1436             if($foo->error){
1437             warn('error: '.$foo->error.":".$foo->errorString);
1438             }
1439              
1440             =cut
1441              
1442             sub write{
1443 0     0 1   my $self=$_[0];
1444              
1445 0 0         if (!$self->errorblank){
1446 0           return undef;
1447             }
1448              
1449             #makes so a directory has been specified
1450 0 0         if (!defined( $self->{dir} )) {
1451 0           $self->{error}=12;
1452 0           $self->{errorString}='No directory has been specified yet';
1453 0           $self->warn;
1454 0           return undef;
1455             }
1456              
1457             #makes sure it is still a toader directory...
1458 0 0         if (! -d $self->{dir}.'/.toader/' ) {
1459 0           $self->{error}=13;
1460 0           $self->{errorString}='No directory has been specified yet';
1461 0           $self->warn;
1462 0           return undef;
1463             }
1464              
1465             #if we don't have a entry title, generate one
1466 0 0         if (!defined( $self->{entryName} )) {
1467 0           $self->entryNameSet;
1468             }
1469              
1470             #if there is no entry directory, generate one...
1471 0 0         if (! -d $self->{dir}.'/.toader/entries/' ) {
1472 0 0         if (! make_path( $self->{dir}.'/.toader/entries/' ) ) {
1473 0           $self->{error}=14;
1474 0           $self->{errorString}='The entries directory did not exist and was not able to create it';
1475 0           $self->warn;
1476 0           return undef;
1477             }
1478             }
1479              
1480             #the file that will be writen
1481 0           my $file=$self->{dir}.'/.toader/entries/'.$self->{entryName};
1482              
1483             #dump the entry to a string
1484 0           my $entry=$self->as_string;
1485              
1486             #writes the file
1487 0           my $fh;
1488 0 0         if ( ! open($fh, '>', $file) ){
1489 0           $self->{error}=15;
1490 0           $self->{errorString}='Unable to open "'.$file.'" for writing';
1491 0           $self->warn;
1492 0           return undef;
1493             }
1494 0           print $fh $entry;
1495 0           close($fh);
1496              
1497             #if VCS is not usable, stop here
1498 0 0         if ( ! $self->{VCSusable} ){
1499 0           return 1;
1500             }
1501              
1502             #if it is under VCS, we have nothing to do
1503 0           my $underVCS=$self->{vcs}->underVCS($file);
1504 0 0         if ( $self->{vcs}->error ){
1505 0           $self->{error}=22;
1506 0           $self->{errorString}='Toader::VCS->underVCS errored. error="'.
1507             $self->{vcs}->error.'" errorString="'.$self->{vcs}->errorString.'"';
1508 0           $self->warn;
1509 0           return undef;
1510             }
1511 0 0         if ( $underVCS ){
1512 0           return 1;
1513             }
1514              
1515             #add it as if we reach here it is not under VCS and VCS is being used
1516 0           $self->{vcs}->add( $file );
1517 0 0         if ( $self->{vcs}->error ){
1518 0           $self->{error}=23;
1519 0           $self->{errorString}='Toader::VCS->add errored. error="'.
1520             $self->{vcs}->error.'" errorString="'.$self->{vcs}->errorString.'"';
1521 0           $self->warn;
1522 0           return undef;
1523             }
1524              
1525 0           return 1;
1526             }
1527              
1528             =head1 REQUIRED RENDERING METHODS
1529              
1530             =head2 filesDir
1531              
1532             This returns the file directory for the object.
1533              
1534             This is not a full path, but a partial path that should
1535             be appended the directory current directory being outputted to.
1536              
1537             =cut
1538              
1539             sub filesDir{
1540 0     0 1   my $self=$_[0];
1541              
1542 0 0         if (!$self->errorblank){
1543 0           return undef;
1544             }
1545              
1546 0 0         if ( ! defined( $self->{entryName} ) ){
1547 0           $self->{error}=16;
1548 0           $self->{errorString}='No entry name has been set';
1549 0           $self->warn;
1550 0           return undef;
1551             }
1552              
1553 0           return $self->renderDir.'/'.$self->{entryName}.'/.files';
1554             }
1555              
1556             =head2 locationID
1557              
1558             This returns the location ID.
1559              
1560             This one requires the object to be initialized.
1561              
1562             =cut
1563              
1564             sub locationID{
1565 0     0 1   my $self=$_[0];
1566              
1567 0 0         if (!$self->errorblank){
1568 0           return undef;
1569             }
1570              
1571 0           return 'Entry='.$self->entryNameGet;
1572             }
1573              
1574             =head2 renderDir
1575              
1576             This is the directory that it will be rendered to.
1577              
1578             The base directory that will be used for rendering.
1579              
1580             =cut
1581              
1582             sub renderDir{
1583 0     0 1   return '.entries';
1584             }
1585              
1586             =head2 renderUsing
1587              
1588             This returns the module to use for rendering.
1589              
1590             my $module=$foo->renderUsing;
1591              
1592             =cut
1593              
1594             sub renderUsing{
1595 0     0 1   return 'Toader::Render::Entry';
1596             }
1597              
1598             =head2 toaderRenderable
1599              
1600             This method returns true and marks it as being L
1601             renderable.
1602              
1603             =cut
1604              
1605             sub toaderRenderable{
1606 0     0 1   return 1;
1607             }
1608              
1609             =head2 toDir
1610              
1611             This returns the directory that will return the directory
1612             that contains where this object should be rendered to.
1613              
1614             This is not a full path, but a partial path that should
1615             be appended the directory current directory being outputted to.
1616              
1617             =cut
1618              
1619             sub toDir{
1620 0     0 1   my $self=$_[0];
1621              
1622 0 0         if (!$self->errorblank){
1623 0           return undef;
1624             }
1625              
1626 0 0         if ( ! defined( $self->{entryName} ) ){
1627 0           $self->{error}=16;
1628 0           $self->{errorString}='No entry name has been set';
1629 0           $self->warn;
1630 0           return undef;
1631             }
1632              
1633 0           return $self->renderDir.'/'.$self->{entryName};
1634             }
1635              
1636              
1637             =head1 ERROR CODES
1638              
1639             =head2 1, noNameSpecified
1640              
1641             No name specified.
1642              
1643             =head2 2, emailMIMEerror
1644              
1645             Unable to create L object.
1646              
1647             =head2 3, notAnArray
1648              
1649             Has files specified, but the passed object is not a array.
1650              
1651             =head2 4, fileDoesNotExist
1652              
1653             The file does not exist or is not a file.
1654              
1655             =head2 5, MIMEinfoError
1656              
1657             File::MimeInfo->mimetype returned undef, meaning the file does not exist or is not readable.
1658              
1659             =head2 6, unableToOpenFile
1660              
1661             Unable to open the file.
1662              
1663             =head2 7, emailMIMEerror
1664              
1665             Unable to create a L object for one of the parts/files.
1666              
1667             =head2 8, noBody
1668              
1669             No body defined.
1670              
1671             =head2 9, invalidEntryName
1672              
1673             Not a valid entry name.
1674              
1675             =head2 10. notAtoaderDir
1676              
1677             The specified directory is not a Toader directory.
1678              
1679             =head2 11, noDirSpecified
1680              
1681             No directory specified.
1682              
1683             =head2 12, noDirSet
1684              
1685             No directory has been set yet.
1686              
1687             =head2 13, noLongerAtoaderDir
1688              
1689             The directory is no longer a L directory. It looks like
1690             it has been removed.
1691              
1692             =head2 14, noEntryDir
1693              
1694             The entries directory did not exist and was not able to create it.
1695              
1696             =head2 15, noSummarySpecified
1697              
1698             No summary specified.
1699              
1700             =head2 16, noEntryNameSet
1701              
1702             No entry name has been set.
1703              
1704             =head2 17, dirDNEorNAD
1705              
1706             The directory does not exist or is a not a directory.
1707              
1708             =head2 18, noFileSpecified
1709              
1710             No file specified.
1711              
1712             =head2 19, publishValError
1713              
1714             Invalid publish value. It is not a recognized boolean value of
1715             either "0" or "1".
1716              
1717             =head2 20, getVCSerrored
1718              
1719             L->getVCS errored.
1720              
1721             =head2 21, VCSusableErrored
1722              
1723             L->usable errored.
1724              
1725             =head2 22, underVCSerrored
1726              
1727             L->underVCS errored.
1728              
1729             =head2 23, VCSaddErrored
1730              
1731             L->add errored.
1732              
1733             =head2 24, notAtoaderObj
1734              
1735             The specified object is not a L object.
1736              
1737             =head2 25, noToaderObj
1738              
1739             Nothing passed for a L object.
1740              
1741             =head1 AUTHOR
1742              
1743             Zane C. Bowers-Hadley, C<< >>
1744              
1745              
1746             =head1 BUGS
1747              
1748             Please report any bugs or feature requests to C, or through
1749             the web interface at L. I will be notified, and then you'll
1750             automatically be notified of progress on your bug as I make changes.
1751              
1752             =head1 SUPPORT
1753              
1754             You can find documentation for this module with the perldoc command.
1755              
1756             perldoc Toader::Entry
1757              
1758              
1759             You can also look for information at:
1760              
1761             =over 4
1762              
1763             =item * RT: CPAN's request tracker
1764              
1765             L
1766              
1767             =item * AnnoCPAN: Annotated CPAN documentation
1768              
1769             L
1770              
1771             =item * CPAN Ratings
1772              
1773             L
1774              
1775             =item * Search CPAN
1776              
1777             L
1778              
1779             =back
1780              
1781              
1782             =head1 ACKNOWLEDGEMENTS
1783              
1784              
1785             =head1 LICENSE AND COPYRIGHT
1786              
1787             Copyright 2013 Zane C. Bowers-Hadley.
1788              
1789             This program is free software; you can redistribute it and/or modify it
1790             under the terms of either: the GNU General Public License as published
1791             by the Free Software Foundation; or the Artistic License.
1792              
1793             See http://dev.perl.org/licenses/ for more information.
1794              
1795              
1796             =cut
1797              
1798             1; # End of Toader