line  
 stmt  
 bran  
 cond  
 sub  
 pod  
 time  
 code  
 
1 
 
 
 
 
 
 
 
 
 
 
 
 
 
 package WWW::eiNetwork;  
 
2 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
3 
 
1
 
 
 
 
 
  
1
   
 
 
 
592
 
 use strict;  
 
  
 
1
 
 
 
 
 
 
 
 
 
2
 
    
 
  
 
1
 
 
 
 
 
 
 
 
 
29
 
    
 
4 
 
1
 
 
 
 
 
  
1
   
 
 
 
5
 
 use warnings;  
 
  
 
1
 
 
 
 
 
 
 
 
 
2
 
    
 
  
 
1
 
 
 
 
 
 
 
 
 
22
 
    
 
5 
 
1
 
 
 
 
 
  
1
   
 
 
 
5
 
 use Carp;  
 
  
 
1
 
 
 
 
 
 
 
 
 
5
 
    
 
  
 
1
 
 
 
 
 
 
 
 
 
89
 
    
 
6 
 
1
 
 
 
 
 
  
1
   
 
 
 
1696
 
 use HTML::TableContentParser;  
 
  
 
0
 
 
 
 
 
 
 
 
 
 
 
    
 
  
 
0
 
 
 
 
 
 
 
 
 
 
 
    
 
7 
 
 
 
 
 
 
 
 
 
 
 
 
 
 use WWW::Mechanize;  
 
8 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
9 
 
 
 
 
 
 
 
 
 
 
 
 
 
 our $VERSION = '0.02';  
 
10 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
11 
 
 
 
 
 
 
 
 
 
 
 
 
 
 sub new  
 
12 
 
 
 
 
 
 
 
 
 
 
 
 
 
 {  
 
13 
 
 
 
 
 
 
 
 
 
 
 
 
 
     my ($class, %args) = @_;  
 
14 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
15 
 
 
 
 
 
 
 
 
 
 
 
 
 
     croak "You must specify your library card number" unless $args{card_number};  
 
16 
 
 
 
 
 
 
 
 
 
 
 
 
 
     croak "You must specify your PIN number"          unless $args{pin_number};  
 
17 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
18 
 
 
 
 
 
 
 
 
 
 
 
 
 
     # Strip trailing slash from URL prefix  
 
19 
 
 
 
 
 
 
 
 
 
 
 
 
 
     my $prefix = $args{url_prefix} || '';  
 
20 
 
 
 
 
 
 
 
 
 
 
 
 
 
     $prefix =~ s/\/$//;  
 
21 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
22 
 
 
 
 
 
 
 
 
 
 
 
 
 
     my $self =  
 
23 
 
 
 
 
 
 
 
 
 
 
 
 
 
     {  
 
24 
 
 
 
 
 
 
 
 
 
 
 
 
 
         card_number => $args{card_number},  
 
25 
 
 
 
 
 
 
 
 
 
 
 
 
 
         pin_number  => $args{pin_number},  
 
26 
 
 
 
 
 
 
 
 
 
 
 
 
 
         url_prefix  => $prefix || 'https://iiisy1.einetwork.net/patroninfo~S1',  
 
27 
 
 
 
 
 
 
 
 
 
 
 
 
 
     };  
 
28 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
29 
 
 
 
 
 
 
 
 
 
 
 
 
 
     bless $self, $class;  
 
30 
 
 
 
 
 
 
 
 
 
 
 
 
 
     return $self;  
 
31 
 
 
 
 
 
 
 
 
 
 
 
 
 
 };  
 
32 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
33 
 
 
 
 
 
 
 
 
 
 
 
 
 
 sub _login  
 
34 
 
 
 
 
 
 
 
 
 
 
 
 
 
 {  
 
35 
 
 
 
 
 
 
 
 
 
 
 
 
 
     my ($self, $name, $card) = @_;  
 
36 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
37 
 
 
 
 
 
 
 
 
 
 
 
 
 
     my $mech = WWW::Mechanize->new;  
 
38 
 
 
 
 
 
 
 
 
 
 
 
 
 
     $mech->get($self->{url_prefix});  
 
39 
 
 
 
 
 
 
 
 
 
 
 
 
 
     $mech->form_with_fields(qw(code pin));  
 
40 
 
 
 
 
 
 
 
 
 
 
 
 
 
     $mech->field('code', $self->{card_number});  
 
41 
 
 
 
 
 
 
 
 
 
 
 
 
 
     $mech->field('pin', $self->{pin_number});  
 
42 
 
 
 
 
 
 
 
 
 
 
 
 
 
     $mech->click('submit');  
 
43 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
44 
 
 
 
 
 
 
 
 
 
 
 
 
 
     my $uri = $mech->uri;  
 
45 
 
 
 
 
 
 
 
 
 
 
 
 
 
     if ($uri =~ /patroninfo~S1\/(\d+)\//)  
 
46 
 
 
 
 
 
 
 
 
 
 
 
 
 
     {  
 
47 
 
 
 
 
 
 
 
 
 
 
 
 
 
         $self->{patron_id} = $1;  
 
48 
 
 
 
 
 
 
 
 
 
 
 
 
 
         $self->{mech}      = $mech;  
 
49 
 
 
 
 
 
 
 
 
 
 
 
 
 
         return $self->{mech};  
 
50 
 
 
 
 
 
 
 
 
 
 
 
 
 
     }  
 
51 
 
 
 
 
 
 
 
 
 
 
 
 
 
     else  
 
52 
 
 
 
 
 
 
 
 
 
 
 
 
 
     {  
 
53 
 
 
 
 
 
 
 
 
 
 
 
 
 
         croak "Couldn't log in to eiNetwork!";  
 
54 
 
 
 
 
 
 
 
 
 
 
 
 
 
         return;  
 
55 
 
 
 
 
 
 
 
 
 
 
 
 
 
     }  
 
56 
 
 
 
 
 
 
 
 
 
 
 
 
 
 }  
 
57 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
58 
 
 
 
 
 
 
 
 
 
 
 
 
 
 sub holds  
 
59 
 
 
 
 
 
 
 
 
 
 
 
 
 
 {  
 
60 
 
 
 
 
 
 
 
 
 
 
 
 
 
     my ($self, %args) = @_;  
 
61 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
62 
 
 
 
 
 
 
 
 
 
 
 
 
 
     my @classes = ('Title', 'Status', 'Pickup', 'Cancel');  
 
63 
 
 
 
 
 
 
 
 
 
 
 
 
 
     my @items = $self->_get_content(  
 
64 
 
 
 
 
 
 
 
 
 
 
 
 
 
         page    => 'holds',  
 
65 
 
 
 
 
 
 
 
 
 
 
 
 
 
         classes => \@classes,  
 
66 
 
 
 
 
 
 
 
 
 
 
 
 
 
         html    => $args{html},  
 
67 
 
 
 
 
 
 
 
 
 
 
 
 
 
     );  
 
68 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
69 
 
 
 
 
 
 
 
 
 
 
 
 
 
     return wantarray ? @items : \@items;  
 
70 
 
 
 
 
 
 
 
 
 
 
 
 
 
 }  
 
71 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
72 
 
 
 
 
 
 
 
 
 
 
 
 
 
 sub items  
 
73 
 
 
 
 
 
 
 
 
 
 
 
 
 
 {  
 
74 
 
 
 
 
 
 
 
 
 
 
 
 
 
     my ($self, %args) = @_;  
 
75 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
76 
 
 
 
 
 
 
 
 
 
 
 
 
 
     my @classes = ('Title', 'Barcode', 'Status', 'CallNo');  
 
77 
 
 
 
 
 
 
 
 
 
 
 
 
 
     my @items = $self->_get_content(  
 
78 
 
 
 
 
 
 
 
 
 
 
 
 
 
         page    => 'items',  
 
79 
 
 
 
 
 
 
 
 
 
 
 
 
 
         classes => \@classes,  
 
80 
 
 
 
 
 
 
 
 
 
 
 
 
 
         html    => $args{html},  
 
81 
 
 
 
 
 
 
 
 
 
 
 
 
 
     );  
 
82 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
83 
 
 
 
 
 
 
 
 
 
 
 
 
 
     return wantarray ? @items : \@items;  
 
84 
 
 
 
 
 
 
 
 
 
 
 
 
 
 }  
 
85 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
86 
 
 
 
 
 
 
 
 
 
 
 
 
 
 sub _get_content  
 
87 
 
 
 
 
 
 
 
 
 
 
 
 
 
 {  
 
88 
 
 
 
 
 
 
 
 
 
 
 
 
 
     my ($self, %args) = @_;  
 
89 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
90 
 
 
 
 
 
 
 
 
 
 
 
 
 
     my $page    = $args{page};  
 
91 
 
 
 
 
 
 
 
 
 
 
 
 
 
     my $classes = $args{classes};  
 
92 
 
 
 
 
 
 
 
 
 
 
 
 
 
     my $html    = $args{html};  
 
93 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
94 
 
 
 
 
 
 
 
 
 
 
 
 
 
     # Hack to facilitate unit tests  
 
95 
 
 
 
 
 
 
 
 
 
 
 
 
 
     $html ||= $self->_get_html($page);  
 
96 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
97 
 
 
 
 
 
 
 
 
 
 
 
 
 
     my $tables = $self->_get_tables($html);  
 
98 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
99 
 
 
 
 
 
 
 
 
 
 
 
 
 
     my @items;  
 
100 
 
 
 
 
 
 
 
 
 
 
 
 
 
     for my $table (@$tables)  
 
101 
 
 
 
 
 
 
 
 
 
 
 
 
 
     {  
 
102 
 
 
 
 
 
 
 
 
 
 
 
 
 
         next unless ($table->{class} and $table->{class} eq 'patFunc');  
 
103 
 
 
 
 
 
 
 
 
 
 
 
 
 
         for my $row (@{$table->{rows}})  
 
104 
 
 
 
 
 
 
 
 
 
 
 
 
 
         {  
 
105 
 
 
 
 
 
 
 
 
 
 
 
 
 
             next unless ($row->{class} and $row->{class} eq 'patFuncEntry');  
 
106 
 
 
 
 
 
 
 
 
 
 
 
 
 
             my %record;  
 
107 
 
 
 
 
 
 
 
 
 
 
 
 
 
             for my $cell (@{$row->{cells}})  
 
108 
 
 
 
 
 
 
 
 
 
 
 
 
 
             {  
 
109 
 
 
 
 
 
 
 
 
 
 
 
 
 
                 for my $class (@$classes)  
 
110 
 
 
 
 
 
 
 
 
 
 
 
 
 
                 {  
 
111 
 
 
 
 
 
 
 
 
 
 
 
 
 
                     if ($cell->{class} and $cell->{class} eq "patFunc$class")  
 
112 
 
 
 
 
 
 
 
 
 
 
 
 
 
                     {  
 
113 
 
 
 
 
 
 
 
 
 
 
 
 
 
                         my $data = $self->_cleanup_data($cell->{data});  
 
114 
 
 
 
 
 
 
 
 
 
 
 
 
 
                         $record{lc($class)} = $data;  
 
115 
 
 
 
 
 
 
 
 
 
 
 
 
 
                         next;  
 
116 
 
 
 
 
 
 
 
 
 
 
 
 
 
                     }  
 
117 
 
 
 
 
 
 
 
 
 
 
 
 
 
                 }  
 
118 
 
 
 
 
 
 
 
 
 
 
 
 
 
             }  
 
119 
 
 
 
 
 
 
 
 
 
 
 
 
 
           
 
120 
 
 
 
 
 
 
 
 
 
 
 
 
 
             push @items, \%record;  
 
121 
 
 
 
 
 
 
 
 
 
 
 
 
 
         }  
 
122 
 
 
 
 
 
 
 
 
 
 
 
 
 
     }  
 
123 
 
 
 
 
 
 
 
 
 
 
 
 
 
       
 
124 
 
 
 
 
 
 
 
 
 
 
 
 
 
     return wantarray ? @items : \@items;  
 
125 
 
 
 
 
 
 
 
 
 
 
 
 
 
 }  
 
126 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
127 
 
 
 
 
 
 
 
 
 
 
 
 
 
 sub _get_html  
 
128 
 
 
 
 
 
 
 
 
 
 
 
 
 
 {  
 
129 
 
 
 
 
 
 
 
 
 
 
 
 
 
     my ($self, $page) = @_;  
 
130 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
131 
 
 
 
 
 
 
 
 
 
 
 
 
 
     $self->_login or croak "Couldn't log in!";  
 
132 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
133 
 
 
 
 
 
 
 
 
 
 
 
 
 
     my $mech = $self->{mech};  
 
134 
 
 
 
 
 
 
 
 
 
 
 
 
 
     return unless $mech;  
 
135 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
136 
 
 
 
 
 
 
 
 
 
 
 
 
 
     my $patron_id = $self->{patron_id};  
 
137 
 
 
 
 
 
 
 
 
 
 
 
 
 
     return unless $patron_id;  
 
138 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
139 
 
 
 
 
 
 
 
 
 
 
 
 
 
     my $prefix = $self->{url_prefix};  
 
140 
 
 
 
 
 
 
 
 
 
 
 
 
 
     return unless $prefix;  
 
141 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
142 
 
 
 
 
 
 
 
 
 
 
 
 
 
     $mech->get("$prefix/$patron_id/$page");  
 
143 
 
 
 
 
 
 
 
 
 
 
 
 
 
     return $mech->content;  
 
144 
 
 
 
 
 
 
 
 
 
 
 
 
 
 }  
 
145 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
146 
 
 
 
 
 
 
 
 
 
 
 
 
 
 sub _get_tables  
 
147 
 
 
 
 
 
 
 
 
 
 
 
 
 
 {  
 
148 
 
 
 
 
 
 
 
 
 
 
 
 
 
     my ($self, $html) = @_;  
 
149 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
150 
 
 
 
 
 
 
 
 
 
 
 
 
 
     my $tp     = HTML::TableContentParser->new();  
 
151 
 
 
 
 
 
 
 
 
 
 
 
 
 
     my $tables = $tp->parse($html);  
 
152 
 
 
 
 
 
 
 
 
 
 
 
 
 
     return $tables;  
 
153 
 
 
 
 
 
 
 
 
 
 
 
 
 
 }  
 
154 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
155 
 
 
 
 
 
 
 
 
 
 
 
 
 
 sub _cleanup_data  
 
156 
 
 
 
 
 
 
 
 
 
 
 
 
 
 {  
 
157 
 
 
 
 
 
 
 
 
 
 
 
 
 
     my ($self, $data) = @_;  
 
158 
 
 
 
 
 
 
 
 
 
 
 
 
 
       
 
159 
 
 
 
 
 
 
 
 
 
 
 
 
 
     # If the result is a link, strip the link tags and use the title.  
 
160 
 
 
 
 
 
 
 
 
 
 
 
 
 
     # Not the greatest regex, but works for these simple cases.  
 
161 
 
 
 
 
 
 
 
 
 
 
 
 
 
     if ($data =~ /"\>\s*(.*)\s*<\/a>/m)  
 
162 
 
 
 
 
 
 
 
 
 
 
 
 
 
     {  
 
163 
 
 
 
 
 
 
 
 
 
 
 
 
 
         $data = $1;  
 
164 
 
 
 
 
 
 
 
 
 
 
 
 
 
     }  
 
165 
 
 
 
 
 
 
 
 
 
 
 
 
 
           
 
166 
 
 
 
 
 
 
 
 
 
 
 
 
 
     # If the data is a select and there's something selected, use the  
 
167 
 
 
 
 
 
 
 
 
 
 
 
 
 
     # title of the selected option.  
 
168 
 
 
 
 
 
 
 
 
 
 
 
 
 
     if ($data =~ /\
   
169 
 
 
 
 
 
 
 
 
 
 
 
 
 
     {  
 
170 
 
 
 
 
 
 
 
 
 
 
 
 
 
         $data =~ /selected="selected">\s*(.*)\s*<\/option>/m;  
 
171 
 
 
 
 
 
 
 
 
 
 
 
 
 
         $data = $1;  
 
172 
 
 
 
 
 
 
 
 
 
 
 
 
 
     }  
 
173 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
174 
 
 
 
 
 
 
 
 
 
 
 
 
 
     # Remove leading and trailing whitespace.  
 
175 
 
 
 
 
 
 
 
 
 
 
 
 
 
     $data =~ s/^\s*//;  
 
176 
 
 
 
 
 
 
 
 
 
 
 
 
 
     $data =~ s/\s*$//;  
 
177 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
178 
 
 
 
 
 
 
 
 
 
 
 
 
 
     return $data;  
 
179 
 
 
 
 
 
 
 
 
 
 
 
 
 
 }  
 
180 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
181 
 
 
 
 
 
 
 
 
 
 
 
 
 
 1;  
 
182 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
183 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
184 
 
 
 
 
 
 
 
 
 
 
 
 
 
 =head1 NAME  
 
185 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
186 
 
 
 
 
 
 
 
 
 
 
 
 
 
 WWW::eiNetwork - Perl interface to Allegheny County, PA libraries  
 
187 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
188 
 
 
 
 
 
 
 
 
 
 
 
 
 
 =head1 SYNOPSIS  
 
189 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
190 
 
 
 
 
 
 
 
 
 
 
 
 
 
   use WWW::eiNetwork;  
 
191 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
192 
 
 
 
 
 
 
 
 
 
 
 
 
 
   my $ein = WWW::eiNetwork->new(  
 
193 
 
 
 
 
 
 
 
 
 
 
 
 
 
       card_number => '23456000000000',  
 
194 
 
 
 
 
 
 
 
 
 
 
 
 
 
       pin_number  => '1234',  
 
195 
 
 
 
 
 
 
 
 
 
 
 
 
 
       url_prefix  => 'https://iiisy1.einetwork.net/patroninfo~S1', #optional  
 
196 
 
 
 
 
 
 
 
 
 
 
 
 
 
   );  
 
197 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
198 
 
 
 
 
 
 
 
 
 
 
 
 
 
   my @holds = $ein->holds;  
 
199 
 
 
 
 
 
 
 
 
 
 
 
 
 
   my @items = $ein->items;  
 
200 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
201 
 
 
 
 
 
 
 
 
 
 
 
 
 
   for my $hold (@holds)  
 
202 
 
 
 
 
 
 
 
 
 
 
 
 
 
   {  
 
203 
 
 
 
 
 
 
 
 
 
 
 
 
 
       print qq(  
 
204 
 
 
 
 
 
 
 
 
 
 
 
 
 
           Title:                      $hold->{title}  
 
205 
 
 
 
 
 
 
 
 
 
 
 
 
 
           Status:                     $hold->{status}  
 
206 
 
 
 
 
 
 
 
 
 
 
 
 
 
           Pickup at:                  $hold->{pickup}  
 
207 
 
 
 
 
 
 
 
 
 
 
 
 
 
           Cancel if not picked up by: $hold->{cancel}\n\n  
 
208 
 
 
 
 
 
 
 
 
 
 
 
 
 
       );  
 
209 
 
 
 
 
 
 
 
 
 
 
 
 
 
   }  
 
210 
 
 
 
 
 
 
 
 
 
 
 
 
 
     
 
211 
 
 
 
 
 
 
 
 
 
 
 
 
 
   for my $item (@items)  
 
212 
 
 
 
 
 
 
 
 
 
 
 
 
 
   {  
 
213 
 
 
 
 
 
 
 
 
 
 
 
 
 
       print qq(  
 
214 
 
 
 
 
 
 
 
 
 
 
 
 
 
           Title:   $item->{title}  
 
215 
 
 
 
 
 
 
 
 
 
 
 
 
 
           Barcode: $item->{barcode}  
 
216 
 
 
 
 
 
 
 
 
 
 
 
 
 
           Status:  $item->{status}  
 
217 
 
 
 
 
 
 
 
 
 
 
 
 
 
           CallNo:  $item->{callno}\n\n  
 
218 
 
 
 
 
 
 
 
 
 
 
 
 
 
       );  
 
219 
 
 
 
 
 
 
 
 
 
 
 
 
 
   }  
 
220 
 
 
 
 
 
 
 
 
 
 
 
 
 
     
 
221 
 
 
 
 
 
 
 
 
 
 
 
 
 
 =head1 DESCRIPTION  
 
222 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
223 
 
 
 
 
 
 
 
 
 
 
 
 
 
 This module provides an object-oriented Perl interface to eiNetwork libraries in Allegheny County, Pennsylvania.  
 
224 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
225 
 
 
 
 
 
 
 
 
 
 
 
 
 
 =head1 DEPENDENCIES  
 
226 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
227 
 
 
 
 
 
 
 
 
 
 
 
 
 
 WWW::Mechanize, HTML::TableContentParser, Crypt::SSLeay or IO::Socket::SSL  
 
228 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
229 
 
 
 
 
 
 
 
 
 
 
 
 
 
 =head1 BUGS  
 
230 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
231 
 
 
 
 
 
 
 
 
 
 
 
 
 
 The eiNetwork doesn't provide a public API - this module uses screen scraping to pull data directly from the HTML on their site. While I made an effort to code this module in such a way that small changes to the site layout and table arrangement won't break the module, any number of changes to the EIN's site could break this module.  
 
232 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
233 
 
 
 
 
 
 
 
 
 
 
 
 
 
 =head1 DISCLAIMER  
 
234 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
235 
 
 
 
 
 
 
 
 
 
 
 
 
 
 The author of this module is not affiliated in any way with the EINetwork or any Allegheny County library.  
 
236 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
237 
 
 
 
 
 
 
 
 
 
 
 
 
 
 =head1 ACKNOWLEDGMENTS  
 
238 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
239 
 
 
 
 
 
 
 
 
 
 
 
 
 
 Thanks to:  
 
240 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
241 
 
 
 
 
 
 
 
 
 
 
 
 
 
 Adam Foxson (L) for the great newbie's tutorial to contributing to CPAN at the Pittsburgh Perl Workshop (L  
 
242 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
243 
 
 
 
 
 
 
 
 
 
 
 
 
 
 Bob O'Neill (L) for sharing his CPAN know-how.   
 
244 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
245 
 
 
 
 
 
 
 
 
 
 
 
 
 
 =head1 COPYRIGHT AND LICENSE  
 
246 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
247 
 
 
 
 
 
 
 
 
 
 
 
 
 
 Copyright (C) 2008 Michael Aquilina. All rights reserved.  
 
248 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
249 
 
 
 
 
 
 
 
 
 
 
 
 
 
 This code is free software; you can redistribute it and/or modify it under the same terms as Perl itself.  
 
250 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
251 
 
 
 
 
 
 
 
 
 
 
 
 
 
 =head1 AUTHOR  
 
252 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
253 
 
 
 
 
 
 
 
 
 
 
 
 
 
 Michael Aquilina, aquilina@cpan.org  
 
254 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
255 
 
 
 
 
 
 
 
 
 
 
 
 
 
 =cut