File Coverage

blib/lib/Business/Edifact/Message.pm
Criterion Covered Total %
statement 222 248 89.5
branch 88 112 78.5
condition 7 12 58.3
subroutine 35 37 94.5
pod 31 31 100.0
total 383 440 87.0


line stmt bran cond sub pod time code
1             package Business::Edifact::Message;
2              
3 6     6   38 use warnings;
  6         14  
  6         269  
4 6     6   35 use strict;
  6         12  
  6         180  
5 6     6   169 use 5.010;
  6         24  
  6         223  
6 6     6   39 use Carp;
  6         9  
  6         571  
7 6     6   5227 use Business::Edifact::Message::LineItem;
  6         18  
  6         26731  
8              
9             =head1 NAME
10              
11             Business::Edifact::Message - Class that models Edifact Messages
12              
13             =head1 VERSION
14              
15             Version 0.07
16              
17             =cut
18              
19             our $VERSION = '0.07';
20              
21             =head1 SYNOPSIS
22              
23             Parses an individual Edifact message
24             Message objects are instantiated by Business::Edifact::Interchange and an array
25             of them is returned in its messages function
26             $interchange->parse($incoming);
27             my $m_array = $interchange->messages();
28             for my $msg (@{$m_array}) {
29             ...retrieve message data
30             }
31              
32             =cut
33              
34             =head1 SUBROUTINES/METHODS
35              
36             =head2 new
37              
38             Called by Business::Edifact::Interchange to instantiate a new Message
39             object. The caller passes the header fields with the
40             reference number identifier and message type
41              
42             =cut
43              
44             sub new {
45 8     8 1 15 my $class = shift;
46 8         19 my $hdr_fields = shift;
47              
48 8         48 my $self = {
49             ref_num => $hdr_fields->[0]->[0],
50             message_identifier => $hdr_fields->[1],
51             reference => [],
52             addresses => [],
53             lines => [],
54             free_text => [],
55             segment_group => 0,
56             type => $hdr_fields->[1]->[0],
57             segment_handler => _init_sh(),
58             };
59              
60 8         30 bless $self, $class;
61 8         27 return $self;
62             }
63              
64             sub _init_sh {
65             return {
66 8     8   317 BGM => \&handle_bgm,
67             DTM => \&handle_dtm,
68             PAT => \&handle_pat,
69             RFF => \&handle_rff,
70             CUX => \&handle_cux,
71             NAD => \&handle_nad,
72             LIN => \&handle_lin,
73             PIA => \&handle_pia,
74             IMD => \&handle_imd,
75             QTY => \&handle_qty,
76             GIR => \&handle_gir,
77             MOA => \&handle_moa,
78             TAX => \&handle_tax,
79             ALC => \&handle_alc,
80             RTE => \&handle_rte,
81             LOC => \&handle_loc,
82             PRI => \&handle_pri,
83             UNS => \&handle_uns,
84             CNT => \&handle_cnt,
85             FTX => \&handle_ftx,
86             PCD => \&handle_pcd,
87             };
88             }
89              
90             =head2 add_segment
91              
92             Process the next data segment
93              
94             =cut
95              
96             sub add_segment {
97 1340     1340 1 1570 my $self = shift;
98 1340         1498 my $tag = shift;
99 1340         1379 my $data_arr = shift;
100              
101 1340         2116 my $handler = $self->{segment_handler}->{$tag};
102 1340 50       2389 if ($handler) {
103 1340         2110 $self->$handler($data_arr);
104             }
105 1340         2809 return;
106             }
107              
108             =head2 type
109              
110             return the message's type
111             e.g. 'QUOTES' or 'ORDERS'
112              
113             =cut
114              
115             sub type {
116 104     104 1 13778 my $self = shift;
117 104         349 return $self->{type}; # e.g. 'QUOTES'
118             }
119              
120             =head2 function
121              
122             Returns the message's function field
123             May be 'original' or 'retransmission'
124              
125             =cut
126              
127             sub function {
128 4     4 1 9 my $self = shift;
129 4         16 my $f = $self->{bgm_data}->[2]->[0];
130 4 100       28 if ( $f == 9 ) {
    50          
    50          
    0          
131 2         11 return 'original';
132             }
133             elsif ( $f == 7 ) {
134 0         0 return 'retransmission';
135             }
136             elsif ( $f == 43 ) {
137 2         10 return 'additional transmission';
138             }
139             elsif ( $f == 46 ) {
140 0         0 return 'provisional';
141             }
142             else {
143 0         0 return $f;
144             }
145             }
146              
147             =head2 message_code
148              
149             Returns 3 character message code from the BGM message
150              
151             =cut
152              
153             sub message_code {
154 2     2 1 5 my $self = shift;
155 2         12 return $self->{bgm_data}->[0]->[0];
156             }
157              
158             =head2 currency_code
159              
160             =cut
161              
162             sub currency_code {
163 0     0 1 0 my $self = shift;
164 0 0       0 if ( exists $self->{currency} ) {
165 0         0 return $self->{currency}->[1];
166             }
167 0         0 return;
168             }
169              
170             =head2 reference_number
171              
172             =cut
173              
174             sub reference_number {
175 0     0 1 0 my $self = shift;
176 0         0 return $self->{ref_num};
177             }
178              
179             =head2 date_of_message
180              
181             =cut
182              
183             sub date_of_message {
184 5     5 1 15 my $self = shift;
185 5         27 return $self->{message_date};
186             }
187              
188             =head2 items
189              
190             return the list of lineitems
191              
192             =cut
193              
194             sub items {
195 6     6 1 21 my $self = shift;
196 6         24 return $self->{lines};
197             }
198              
199             =head2 handle_bgm
200              
201             =cut
202              
203             sub handle_bgm {
204 8     8 1 14 my ( $self, $data_arr ) = @_;
205 8         42 $self->{bgm_data} = $data_arr;
206 8         20 return;
207             }
208              
209             =head2 handle_dtm
210              
211             NB DTM can occur in different segment groups
212              
213             =cut
214              
215             sub handle_dtm {
216 16     16 1 33 my ( $self, $data_arr ) = @_;
217 16         22 my ( $qualifier, $date, $format ) = @{ $data_arr->[0] };
  16         40  
218 16 100       80 if ( length $date == 6 ) { # century missing
219 2         6 $date = "20$date";
220             }
221 16 100       62 if ( $self->{segment_group} == 0 ) { # message header
    50          
    100          
222             #TBD standard allows 35 repeats
223 12 100       52 if ( $qualifier == 137 ) {
    50          
    100          
224 8         20 $self->{message_date} = $date;
225             }
226             elsif ( $qualifier == 36 ) {
227 0         0 $self->{expiry_date} = $date;
228             }
229             elsif ( $qualifier == 131 ) {
230 3         16 $self->{tax_point_date} = $date;
231             }
232             }
233             elsif ( $self->{segment_group} == 27 ) {
234 0         0 $self->{lines}->[-1]->addsegment( 'datetimeperiod', $data_arr );
235             }
236             elsif ( $self->{segment_group} == 11 ) {
237 2         6 $self->{payment_terms}->{payment_date} = $date;
238             }
239 16         39 return;
240             }
241              
242             =head2 handle_pat
243              
244             =cut
245              
246             sub handle_pat { # invoices only
247 4     4 1 7 my ( $self, $data_arr ) = @_;
248 4 100       16 if ( $data_arr->[0]->[0] == 1 ) {
    50          
249 2         10 $self->{payment_terms} = {
250             type => 'basic',
251             terms => $data_arr->[2],
252              
253             # terms time_reference_code|Time relation|Type of period[D = days]
254             # number of periods
255             };
256             }
257             elsif ( $data_arr->[0]->[0] == 3 ) {
258 2         10 $self->{payment_terms} = { type => 'fixed_date', };
259             }
260 4         6 return;
261             }
262              
263             =head2 handle_rff
264              
265             =cut
266              
267             sub handle_rff {
268 150     150 1 197 my ( $self, $data_arr ) = @_;
269 150         246 my $ref_qualifier = $data_arr->[0]->[0];
270 150 100       703 if ( $ref_qualifier eq 'VA' ) {
    100          
    100          
    100          
    50          
271 5         14 $self->{supplier_vat_number} = $data_arr->[0]->[1];
272             }
273             elsif ( $ref_qualifier eq 'API' ) {
274 2         6 $self->{additional_party_id} = $data_arr->[0]->[1];
275             }
276             elsif ( $ref_qualifier eq 'FC' ) {
277 1         5 $self->{fiscal_number} = $data_arr->[0]->[1];
278             }
279             elsif ( $ref_qualifier eq 'IA' ) {
280 44         82 $self->{internal_vendor_number} = $data_arr->[0]->[1];
281             }
282             elsif ( $ref_qualifier eq 'TL' ) {
283 0         0 $self->{tax_exemption_licence} = $data_arr->[0]->[1];
284             }
285 150 100       525 if ( $self->{segment_group} == 0 ) {
    100          
    100          
    100          
286 3         7 $self->{segment_group} = 1; # 1 mandatory occurence
287 3         13 $self->{message_reference} = {
288             qualifier => $data_arr->[0]->[0],
289             number => $data_arr->[0]->[1],
290             };
291             }
292             elsif ( $self->{segment_group} == 11 ) { # ref to an address (SG12)
293 8         39 $self->{addresses}->[-1]->{RFF} = {
294             qualifier => $data_arr->[0]->[0],
295             number => $data_arr->[0]->[1],
296             };
297              
298             }
299             elsif ( $self->{segment_group} == 27 ) { # ref to an address (SG12)
300 124         558 $self->{lines}->[-1]->addsegment( 'item_reference', $data_arr );
301             }
302             elsif ( $self->{segment_group} == 25 ) { # Buyer's orderline number
303 13 100       30 if ( $ref_qualifier eq 'LI' ) {
304 9         25 $self->{lines}->[-1]->{buyers_refnumber} = $data_arr->[0]->[1];
305 9 50       25 if ( $data_arr->[0]->[2] ) {
306 0         0 $self->{lines}->[-1]->{buyers_ref_lineno} = $data_arr->[0]->[2];
307             }
308             }
309             else {
310 4         17 $self->{lines}->[-1]->addsegment( 'item_reference', $data_arr );
311             }
312             }
313             else {
314 2         4 push @{ $self->{reference} },
  2         11  
315             {
316             qualifier => $data_arr->[0]->[0],
317             number => $data_arr->[0]->[1],
318             };
319             }
320 150         235 return;
321             }
322              
323             =head2 handle_cux
324              
325             =cut
326              
327             sub handle_cux {
328 6     6 1 15 my ( $self, $data_arr ) = @_;
329 6 50       29 if ( $self->{segment_group} == 1 ) {
    100          
330              
331 0         0 $self->{currency} = $data_arr->[0];
332 0         0 $self->{segment_group} = 4;
333             }
334             elsif ( $self->{segment_group} == 11 ) {
335 4         11 $self->{currency} = $data_arr->[0];
336             }
337 6         12 return;
338             }
339              
340             =head2 handle_nad
341              
342             =cut
343              
344             sub handle_nad {
345 19     19 1 28 my ( $self, $data_arr ) = @_;
346 19         22 push @{ $self->{addresses} }, { NAD => $data_arr, };
  19         62  
347 19         32 $self->{segment_group} = 11;
348 19         33 return;
349             }
350              
351             =head2 handle_lin
352              
353             =cut
354              
355             sub handle_lin {
356 91     91 1 123 my ( $self, $data_arr ) = @_;
357 91         225 $self->clear_item_flags();
358 91 100       224 if ( $self->{type} eq 'INVOIC' ) {
359 11         24 $self->{segment_group} = 25;
360             }
361             else {
362 80         118 $self->{segment_group} = 27;
363             }
364 91         678 my $line = {
365             line_number => $data_arr->[0]->[0],
366             action_req => $data_arr->[1]->[0],
367             item_number => $data_arr->[2]->[0],
368             item_number_type => $data_arr->[2]->[1],
369             additional_product_ids => [],
370             item_description => [],
371             monetary_amount => [],
372             };
373 91 100       268 if ( $data_arr->[3]->[0] ) {
374 1         3 $line->{sub_line_info} = $data_arr->[3];
375             }
376 91         373 my $lineitem = Business::Edifact::Message::LineItem->new($line);
377              
378 91         131 push @{ $self->{lines} }, $lineitem;
  91         181  
379 91         155 return;
380             }
381              
382             =head2 handle_pia
383              
384             =cut
385              
386             sub handle_pia {
387 51     51 1 65 my ( $self, $data_arr ) = @_;
388 51         171 $self->{lines}->[-1]->addsegment( 'additional_product_ids', $data_arr );
389 51 100       113 if ( $self->{segment_group} == 25 ) {
390              
391             # For invoice may well be the item identifier
392 7 100       26 if ( $data_arr->[0]->[0] eq '5' ) { #alphanum as 5V is valid
393 6         36 my %id_type = (
394             IB => 'ISBN',
395             IM => 'ISMN',
396             IN => 'Purchasers_ID',
397             IS => 'ISSN',
398             MF => 'Manufacturers_Number',
399             SA => 'Suppliers_Number',
400             );
401 6         10 my $t = $data_arr->[1]->[1];
402 6 50       15 if ( exists $id_type{$t} ) {
403 6         17 $t = $id_type{$t};
404             }
405 6         139 $self->{lines}->[-1]->{item_ID_number} = {
406             number => $data_arr->[1]->[0],
407             type => $t,
408             };
409             }
410             }
411 51         76 return;
412             }
413              
414             =head2 handle_imd
415              
416             =cut
417              
418             sub handle_imd {
419 543     543 1 663 my ( $self, $data_arr ) = @_;
420 543 100       1188 if ( $data_arr->[0]->[0] eq 'L' ) { # only handle text at the moment
421 540 100       991 if ( $data_arr->[2]->[4] ) {
422 21         58 $data_arr->[2]->[3] .= $data_arr->[2]->[4];
423             }
424 540         3085 $self->{lines}->[-1]->addsegment(
425             'item_description',
426             {
427             code => $data_arr->[1]->[0],
428             text => $data_arr->[2]->[3],
429             }
430             );
431             }
432 543         857 return;
433             }
434              
435             =head2 handle_qty
436              
437             =cut
438              
439             sub handle_qty {
440 99     99 1 128 my ( $self, $data_arr ) = @_;
441 99 100       170 if ( $self->type eq 'INVOIC' ) {
442 19         34 my $code = $data_arr->[0]->[0];
443 19 100       45 if ( $code == 47 ) {
444 13 50       29 if ( $self->{segment_group} == 25 ) { # item level
445 13         37 $self->{lines}->[-1]->{quantity_invoiced} = $data_arr->[0]->[1];
446             }
447             else {
448 0         0 $self->{quantity_invoiced} = $data_arr->[0]->[1];
449             }
450             }
451             }
452             else {
453 80 50       165 if ( !$self->{item_locqty_flag} ) {
454 80         303 $self->{lines}->[-1]->{quantity} = $data_arr->[0]->[1];
455             }
456             else {
457 0         0 $self->{lines}->[-1]->{place_of_delivery}->[-1]->{quantity} =
458             $data_arr->[0]->[1];
459 0         0 delete $self->{item_locqty_flag};
460             }
461             }
462 99         168 return;
463             }
464              
465             =head2 handle_gir
466              
467             =cut
468              
469             sub handle_gir {
470 107     107 1 150 my ( $self, $data_arr ) = @_;
471 107         105 my $id = shift @{$data_arr};
  107         151  
472 107         314 my $relnum = { id => $id->[0], };
473 107         115 for my $d ( @{$data_arr} ) {
  107         206  
474 438         400 push @{ $relnum->{ $d->[1] } }, $d->[0];
  438         1428  
475             }
476              
477 107         136 push @{ $self->{lines}->[-1]->{related_numbers} }, $relnum;
  107         334  
478 107         234 return;
479             }
480              
481             =head2 handle_moa
482              
483             =cut
484              
485             sub handle_moa {
486 66     66 1 93 my ( $self, $data_arr ) = @_;
487 66 100 66     356 if ( $self->{segment_group} == 27 || $self->{segment_group} == 25 ) {
488 35 100       155 if ( $data_arr->[0]->[0] == 203 ) {
    100          
    100          
    50          
    100          
489 10         34 $self->{lines}->[-1]->{lineitem_amount} = $data_arr->[0]->[1];
490             }
491             elsif ( $data_arr->[0]->[0] == 128 ) {
492 4         12 $self->{lines}->[-1]->{lineitem_total_amount} =
493             $data_arr->[0]->[1];
494             }
495             elsif ( $data_arr->[0]->[0] == 52 ) {
496 7         19 $self->{lines}->[-1]->{lineitem_discount_amount} =
497             $data_arr->[0]->[1];
498             }
499             elsif ( $data_arr->[0]->[0] == 146 ) {
500 0         0 $self->{lines}->[-1]->{lineitem_unit_price} =
501             $data_arr->[0]->[1];
502             }
503             elsif ( $self->{item_alc_flag} ) {
504 8         25 $self->{lines}->[-1]->{item_allowance_or_charge}->[-1]->{amount} =
505             $data_arr->[0]->[1];
506             }
507             else {
508 6         8 my $data = shift @{$data_arr};
  6         10  
509 6         21 my $ma = {
510             qualifier => $data->[0],
511             value => $data->[1],
512             };
513              
514 6         7 push @{ $self->{lines}->[-1]->{monetary_amount} }, $ma;
  6         20  
515             }
516             }
517             else {
518 31 100       51 if ( !$self->{item_alc_flag} ) {
519 30         29 my $data = shift @{$data_arr};
  30         39  
520 30         110 my $ma = {
521             qualifier => $data->[0],
522             value => $data->[1],
523             };
524 30         33 push @{ $self->{monetary_amount} }, $ma;
  30         74  
525             }
526             else {
527 1         2 my $data = shift @{$data_arr};
  1         2  
528 1         4 my $ma = {
529             qualifier => $data->[0],
530             value => $data->[1],
531             };
532 1         2 push @{ $self->{allowance_or_charge}->[-1]->{amount} }, $ma;
  1         3  
533 1         3 delete $self->{item_alc_flag};
534             }
535             }
536 66         102 return;
537             }
538              
539             =head2 handle_tax
540              
541             =cut
542              
543             sub handle_tax {
544 25     25 1 31 my ( $self, $data_arr ) = @_;
545              
546 25         126 my $tax = {
547             function_code => $data_arr->[0]->[0],
548             type_code => $data_arr->[1]->[0],
549             rate => $data_arr->[4]->[3],
550             category_code => $data_arr->[5]->[0],
551             };
552 25 100 66     118 if ( $self->{segment_group} == 27 || $self->{segment_group} == 25 ) {
553 18 100       43 if ( !$self->{item_alc_flag} ) {
554 11         11 push @{ $self->{lines}->[-1]->{tax} }, $tax;
  11         39  
555             }
556             else {
557 7         22 push
558 7         7 @{ $self->{lines}->[-1]->{item_allowance_or_charge}->[-1]->{tax}
559             }, $tax;
560 7         14 delete $self->{item_alc_flag};
561             }
562             }
563             else {
564 7         8 push @{ $self->{tax} }, $tax;
  7         16  
565             }
566 25         43 return;
567             }
568              
569             =head2 handle_alc
570              
571             =cut
572              
573             sub handle_alc {
574 17     17 1 27 my ( $self, $data_arr ) = @_;
575 17 100 66     119 if ( $self->{segment_group} == 27 || $self->{segment_group} == 25 ) {
576 16         76 my $alc = {
577             type => $data_arr->[0]->[0],
578             sequence => $data_arr->[3]->[0],
579             service_code => $data_arr->[4]->[0],
580             };
581 16         20 push @{ $self->{lines}->[-1]->{item_allowance_or_charge} }, $alc;
  16         47  
582 16         31 $self->{item_alc_flag} = 1;
583             }
584             else {
585 1         10 my $alc = {
586             type => $data_arr->[0]->[0],
587             sequence => $data_arr->[3]->[0],
588             service_code => $data_arr->[4]->[0],
589             };
590 1         2 push @{ $self->{allowance_or_charge} }, $alc;
  1         2  
591 1         2 $self->{item_alc_flag} = 1;
592             }
593 17         23 return;
594             }
595              
596             =head2 handle_rte
597              
598             =cut
599              
600             sub handle_rte {
601 8     8 1 14 my ( $self, $data_arr ) = @_;
602 8 50       21 if ( $self->{type} ne 'INVOIC' ) {
603 0 0       0 if ( $self->{item_alc_flag} == 1 ) {
604 0         0 $self->{lines}->[-1]->{item_allowance_or_charge}->[-1]->{rate} =
605             $data_arr->[0]->[1];
606 0         0 delete $self->{item_alc_flag};
607             }
608             }
609 8         13 return;
610             }
611              
612             =head2 handle_loc
613              
614             =cut
615              
616             sub handle_loc {
617 5     5 1 8 my ( $self, $data_arr ) = @_;
618 5 50 33     15 if ( $self->{segment_group} == 27 && $data_arr->[0]->[0] == 7 ) {
619 0         0 my $loc = {
620             place => $data_arr->[1]->[0],
621             type_code => $data_arr->[1]->[2],
622             };
623 0         0 push @{ $self->{lines}->[-1]->{place_of_delivery} }, $loc;
  0         0  
624 0         0 $self->{item_locqty_flag} = 1;
625             }
626 5         8 return;
627             }
628              
629             =head2 handle_pri
630              
631             =cut
632              
633             sub handle_pri {
634 93     93 1 137 my ( $self, $data_arr ) = @_;
635 93         99 push @{ $self->{lines}->[-1]->{price} }, {
  93         623  
636              
637             # qualifier: AAA = net AAB = gross AAE/F = info
638             qualifier => $data_arr->[0]->[0],
639             price => $data_arr->[0]->[1],
640             price_type => $data_arr->[0]->[2],
641             price_type_qualifier => $data_arr->[0]->[3],
642             };
643 93         165 return;
644             }
645              
646             =head2 handle_uns
647              
648             =cut
649              
650             sub handle_uns {
651 8     8 1 16 my ( $self, $data_arr ) = @_;
652 8         17 $self->{segment_group} = -1; # summary does not have a seg group
653 8         28 $self->clear_item_flags();
654 8         12 return;
655             }
656              
657             =head2 handle_cnt
658              
659             =cut
660              
661             sub handle_cnt {
662 6     6 1 12 my ( $self, $data_arr ) = @_;
663 6 50       33 if ( $data_arr->[0]->[0] == 2 ) {
664 6         24 $self->{summary_count} = $data_arr->[0]->[1];
665             }
666 6         25 return;
667             }
668              
669             =head2 handle_ftx
670              
671             =cut
672              
673             sub handle_ftx {
674 14     14 1 21 my ( $self, $data_arr ) = @_;
675 14         81 my $text_field = {
676             qualifier => $data_arr->[0]->[0],
677             function => $data_arr->[1]->[0],
678             reference => $data_arr->[2],
679             };
680 14 50       37 if ( $data_arr->[3] ) {
681 14         17 $text_field->{text} = join q{ }, @{ $data_arr->[3] };
  14         45  
682             }
683 14 100       27 if ( @{ $self->{lines} } ) { # at the lineitem level
  14         55  
684 12         33 $self->{lines}->[-1]->{free_text} = $text_field;
685             }
686             else {
687 2         1 push @{ $self->{free_text} }, $text_field;
  2         5  
688             }
689 14         24 return;
690             }
691              
692             =head2 handle_pcd
693              
694             =cut
695              
696             sub handle_pcd {
697 4     4 1 9 my ( $self, $data_arr ) = @_;
698 4 50       16 if ( $self->{item_alc_flag} ) {
699 4         16 $self->{lines}->[-1]->{item_allowance_or_charge}->[-1]->{percentage} =
700             $data_arr->[0]->[1];
701 4         8 delete $self->{item_alc_flag};
702             }
703 4         6 return;
704              
705             }
706              
707             =head2 clear_item_flags
708              
709             clear flags at start of new item or summary
710              
711             =cut
712              
713             sub clear_item_flags {
714 99     99 1 114 my $self = shift;
715 99         144 delete $self->{item_locqty_flag};
716 99         115 delete $self->{item_alc_flag};
717 99         135 return;
718             }
719              
720             =head1 AUTHOR
721              
722             Colin Campbell, C<< >>
723              
724             =head1 BUGS
725              
726             Please report any bugs or feature requests to C, or through
727             the web interface at L. I will be notified, and then you'll
728             automatically be notified of progress on your bug as I make changes.
729              
730              
731              
732              
733             =head1 SUPPORT
734              
735             You can find documentation for this module with the perldoc command.
736              
737             perldoc Business::Edifact::Message
738              
739              
740             =head1 ACKNOWLEDGEMENTS
741              
742              
743             =head1 LICENSE AND COPYRIGHT
744              
745             Copyright 2011-2014 Colin Campbell.
746              
747             This program is free software; you can redistribute it and/or modify it
748             under the terms of either: the GNU General Public License as published
749             by the Free Software Foundation; or the Artistic License.
750              
751             See http://dev.perl.org/licenses/ for more information.
752              
753              
754             =cut
755              
756             1;