line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
package PPI::Find; |
2
|
|
|
|
|
|
|
|
3
|
|
|
|
|
|
|
=pod |
4
|
|
|
|
|
|
|
|
5
|
|
|
|
|
|
|
=head1 NAME |
6
|
|
|
|
|
|
|
|
7
|
|
|
|
|
|
|
PPI::Find - Object version of the Element->find method |
8
|
|
|
|
|
|
|
|
9
|
|
|
|
|
|
|
=head1 SYNOPSIS |
10
|
|
|
|
|
|
|
|
11
|
|
|
|
|
|
|
# Create the Find object |
12
|
|
|
|
|
|
|
my $Find = PPI::Find->new( \&wanted ); |
13
|
|
|
|
|
|
|
|
14
|
|
|
|
|
|
|
# Return all matching Elements as a list |
15
|
|
|
|
|
|
|
my @found = $Find->in( $Document ); |
16
|
|
|
|
|
|
|
|
17
|
|
|
|
|
|
|
# Can we find any matching Elements |
18
|
|
|
|
|
|
|
if ( $Find->any_matches($Document) ) { |
19
|
|
|
|
|
|
|
print "Found at least one matching Element"; |
20
|
|
|
|
|
|
|
} |
21
|
|
|
|
|
|
|
|
22
|
|
|
|
|
|
|
# Use the object as an iterator |
23
|
|
|
|
|
|
|
$Find->start($Document) or die "Failed to execute search"; |
24
|
|
|
|
|
|
|
while ( my $token = $Find->match ) { |
25
|
|
|
|
|
|
|
... |
26
|
|
|
|
|
|
|
} |
27
|
|
|
|
|
|
|
|
28
|
|
|
|
|
|
|
=head1 DESCRIPTION |
29
|
|
|
|
|
|
|
|
30
|
|
|
|
|
|
|
PPI::Find is the primary PDOM searching class in the core PPI package. |
31
|
|
|
|
|
|
|
|
32
|
|
|
|
|
|
|
=head2 History |
33
|
|
|
|
|
|
|
|
34
|
|
|
|
|
|
|
It became quite obvious during the development of PPI that many of the |
35
|
|
|
|
|
|
|
modules that would be built on top of it were going to need large numbers |
36
|
|
|
|
|
|
|
of saved, storable or easily creatable search objects that could be |
37
|
|
|
|
|
|
|
reused a number of times. |
38
|
|
|
|
|
|
|
|
39
|
|
|
|
|
|
|
Although the internal ->find method provides a basic ability to search, |
40
|
|
|
|
|
|
|
it is by no means thorough. PPI::Find attempts to resolve this problem. |
41
|
|
|
|
|
|
|
|
42
|
|
|
|
|
|
|
=head2 Structure and Style |
43
|
|
|
|
|
|
|
|
44
|
|
|
|
|
|
|
PPI::Find provides a similar API to the popular L |
45
|
|
|
|
|
|
|
module for file searching, but without the ability to assemble queries. |
46
|
|
|
|
|
|
|
|
47
|
|
|
|
|
|
|
The implementation of a separate PPI::Find::Rule sub-class that does |
48
|
|
|
|
|
|
|
provide this ability is left as an exercise for the reader. |
49
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
=head2 The &wanted function |
51
|
|
|
|
|
|
|
|
52
|
|
|
|
|
|
|
At the core of each PPI::Find object is a "wanted" function that is |
53
|
|
|
|
|
|
|
passed a number of arguments and returns a value which controls the |
54
|
|
|
|
|
|
|
flow of the search. |
55
|
|
|
|
|
|
|
|
56
|
|
|
|
|
|
|
As the search executes, each Element will be passed to the wanted function |
57
|
|
|
|
|
|
|
in depth-first order. |
58
|
|
|
|
|
|
|
|
59
|
|
|
|
|
|
|
It will be provided with two arguments. The current Element to test as $_[0], |
60
|
|
|
|
|
|
|
and the top-level Element of the search as $_[1]. |
61
|
|
|
|
|
|
|
|
62
|
|
|
|
|
|
|
The &wanted function is expected to return 1 (positive) if the Element |
63
|
|
|
|
|
|
|
matches the condition, 0 (false) if it does not, and undef (undefined) if |
64
|
|
|
|
|
|
|
the condition does not match, and the Find search should not descend to |
65
|
|
|
|
|
|
|
any of the current Element's children. |
66
|
|
|
|
|
|
|
|
67
|
|
|
|
|
|
|
Errors should be reported from the &wanted function via die, which will be |
68
|
|
|
|
|
|
|
caught by the Find object and returned as an error. |
69
|
|
|
|
|
|
|
|
70
|
|
|
|
|
|
|
=head1 METHODS |
71
|
|
|
|
|
|
|
|
72
|
|
|
|
|
|
|
=cut |
73
|
|
|
|
|
|
|
|
74
|
1
|
|
|
1
|
|
1008
|
use strict; |
|
1
|
|
|
|
|
3
|
|
|
1
|
|
|
|
|
33
|
|
75
|
1
|
|
|
1
|
|
4
|
use Params::Util qw{_INSTANCE}; |
|
1
|
|
|
|
|
3
|
|
|
1
|
|
|
|
|
927
|
|
76
|
|
|
|
|
|
|
|
77
|
|
|
|
|
|
|
our $VERSION = '1.277'; |
78
|
|
|
|
|
|
|
|
79
|
|
|
|
|
|
|
|
80
|
|
|
|
|
|
|
|
81
|
|
|
|
|
|
|
|
82
|
|
|
|
|
|
|
|
83
|
|
|
|
|
|
|
##################################################################### |
84
|
|
|
|
|
|
|
# Constructor |
85
|
|
|
|
|
|
|
|
86
|
|
|
|
|
|
|
=pod |
87
|
|
|
|
|
|
|
|
88
|
|
|
|
|
|
|
=head2 new &wanted |
89
|
|
|
|
|
|
|
|
90
|
|
|
|
|
|
|
The C constructor takes a single argument of the &wanted function, |
91
|
|
|
|
|
|
|
as described above and creates a new search. |
92
|
|
|
|
|
|
|
|
93
|
|
|
|
|
|
|
Returns a new PPI::Find object, or C if not passed a CODE reference. |
94
|
|
|
|
|
|
|
|
95
|
|
|
|
|
|
|
=cut |
96
|
|
|
|
|
|
|
|
97
|
|
|
|
|
|
|
sub new { |
98
|
0
|
0
|
|
0
|
1
|
|
my $class = ref $_[0] ? ref shift : shift; |
99
|
0
|
0
|
|
|
|
|
my $wanted = ref $_[0] eq 'CODE' ? shift : return undef; |
100
|
|
|
|
|
|
|
|
101
|
|
|
|
|
|
|
# Create the object |
102
|
0
|
|
|
|
|
|
my $self = bless { |
103
|
|
|
|
|
|
|
wanted => $wanted, |
104
|
|
|
|
|
|
|
}, $class; |
105
|
|
|
|
|
|
|
|
106
|
0
|
|
|
|
|
|
$self; |
107
|
|
|
|
|
|
|
} |
108
|
|
|
|
|
|
|
|
109
|
|
|
|
|
|
|
=pod |
110
|
|
|
|
|
|
|
|
111
|
|
|
|
|
|
|
=head2 clone |
112
|
|
|
|
|
|
|
|
113
|
|
|
|
|
|
|
The C method creates another instance of the same Find object. |
114
|
|
|
|
|
|
|
|
115
|
|
|
|
|
|
|
The cloning is done safely, so if your existing Find object is in the |
116
|
|
|
|
|
|
|
middle of an iteration, the cloned Find object will not also be in the |
117
|
|
|
|
|
|
|
iteration and can be safely used independently. |
118
|
|
|
|
|
|
|
|
119
|
|
|
|
|
|
|
Returns a duplicate PPI::Find object. |
120
|
|
|
|
|
|
|
|
121
|
|
|
|
|
|
|
=cut |
122
|
|
|
|
|
|
|
|
123
|
|
|
|
|
|
|
sub clone { |
124
|
0
|
0
|
|
0
|
1
|
|
my $self = ref $_[0] ? shift |
125
|
|
|
|
|
|
|
: die "->clone can only be called as an object method"; |
126
|
0
|
|
|
|
|
|
my $class = ref $self; |
127
|
|
|
|
|
|
|
|
128
|
|
|
|
|
|
|
# Create the object |
129
|
|
|
|
|
|
|
my $clone = bless { |
130
|
|
|
|
|
|
|
wanted => $self->{wanted}, |
131
|
0
|
|
|
|
|
|
}, $class; |
132
|
|
|
|
|
|
|
|
133
|
0
|
|
|
|
|
|
$clone; |
134
|
|
|
|
|
|
|
} |
135
|
|
|
|
|
|
|
|
136
|
|
|
|
|
|
|
|
137
|
|
|
|
|
|
|
|
138
|
|
|
|
|
|
|
|
139
|
|
|
|
|
|
|
|
140
|
|
|
|
|
|
|
#################################################################### |
141
|
|
|
|
|
|
|
# Search Execution Methods |
142
|
|
|
|
|
|
|
|
143
|
|
|
|
|
|
|
=pod |
144
|
|
|
|
|
|
|
|
145
|
|
|
|
|
|
|
=head2 in $Document [, array_ref => 1 ] |
146
|
|
|
|
|
|
|
|
147
|
|
|
|
|
|
|
The C method starts and completes a full run of the search. |
148
|
|
|
|
|
|
|
|
149
|
|
|
|
|
|
|
It takes as argument a single L object which will |
150
|
|
|
|
|
|
|
serve as the top of the search process. |
151
|
|
|
|
|
|
|
|
152
|
|
|
|
|
|
|
Returns a list of PPI::Element objects that match the condition |
153
|
|
|
|
|
|
|
described by the &wanted function, or the null list on error. |
154
|
|
|
|
|
|
|
|
155
|
|
|
|
|
|
|
You should check the ->errstr method for any errors if you are |
156
|
|
|
|
|
|
|
returned the null list, which may also mean simply that no Elements |
157
|
|
|
|
|
|
|
were found that matched the condition. |
158
|
|
|
|
|
|
|
|
159
|
|
|
|
|
|
|
Because of this need to explicitly check for errors, an alternative |
160
|
|
|
|
|
|
|
return value mechanism is provide. If you pass the C<< array_ref => 1 >> |
161
|
|
|
|
|
|
|
parameter to the method, it will return the list of matched Elements |
162
|
|
|
|
|
|
|
as a reference to an ARRAY. The method will return false if no elements |
163
|
|
|
|
|
|
|
were matched, or C on error. |
164
|
|
|
|
|
|
|
|
165
|
|
|
|
|
|
|
The ->errstr method can still be used to get the error message as normal. |
166
|
|
|
|
|
|
|
|
167
|
|
|
|
|
|
|
=cut |
168
|
|
|
|
|
|
|
|
169
|
|
|
|
|
|
|
sub in { |
170
|
0
|
|
|
0
|
1
|
|
my $self = shift; |
171
|
0
|
|
|
|
|
|
my $Element = shift; |
172
|
0
|
|
|
|
|
|
my %params = @_; |
173
|
0
|
|
|
|
|
|
delete $self->{errstr}; |
174
|
|
|
|
|
|
|
|
175
|
|
|
|
|
|
|
# Are we already acting as an iterator |
176
|
0
|
0
|
|
|
|
|
if ( $self->{in} ) { |
177
|
0
|
|
|
|
|
|
return $self->_error('->in called while another search is in progress', %params); |
178
|
|
|
|
|
|
|
} |
179
|
|
|
|
|
|
|
|
180
|
|
|
|
|
|
|
# Get the root element for the search |
181
|
0
|
0
|
|
|
|
|
unless ( _INSTANCE($Element, 'PPI::Element') ) { |
182
|
0
|
|
|
|
|
|
return $self->_error('->in was not passed a PPI::Element object', %params); |
183
|
|
|
|
|
|
|
} |
184
|
|
|
|
|
|
|
|
185
|
|
|
|
|
|
|
# Prepare the search |
186
|
0
|
|
|
|
|
|
$self->{in} = $Element; |
187
|
0
|
|
|
|
|
|
$self->{matches} = []; |
188
|
|
|
|
|
|
|
|
189
|
|
|
|
|
|
|
# Execute the search |
190
|
0
|
0
|
|
|
|
|
if ( !eval { $self->_execute; 1 } ) { |
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
191
|
0
|
|
|
|
|
|
my $errstr = $@; |
192
|
0
|
|
|
|
|
|
$errstr =~ s/\s+at\s+line\s+.+$//; |
193
|
0
|
|
|
|
|
|
return $self->_error("Error while searching: $errstr", %params); |
194
|
|
|
|
|
|
|
} |
195
|
|
|
|
|
|
|
|
196
|
|
|
|
|
|
|
# Clean up and return |
197
|
0
|
|
|
|
|
|
delete $self->{in}; |
198
|
0
|
0
|
|
|
|
|
if ( $params{array_ref} ) { |
199
|
0
|
0
|
|
|
|
|
if ( @{$self->{matches}} ) { |
|
0
|
|
|
|
|
|
|
200
|
0
|
|
|
|
|
|
return delete $self->{matches}; |
201
|
|
|
|
|
|
|
} |
202
|
0
|
|
|
|
|
|
delete $self->{matches}; |
203
|
0
|
|
|
|
|
|
return ''; |
204
|
|
|
|
|
|
|
} |
205
|
|
|
|
|
|
|
|
206
|
|
|
|
|
|
|
# Return as a list |
207
|
0
|
|
|
|
|
|
my $matches = delete $self->{matches}; |
208
|
0
|
|
|
|
|
|
@$matches; |
209
|
|
|
|
|
|
|
} |
210
|
|
|
|
|
|
|
|
211
|
|
|
|
|
|
|
=pod |
212
|
|
|
|
|
|
|
|
213
|
|
|
|
|
|
|
=head2 start $Element |
214
|
|
|
|
|
|
|
|
215
|
|
|
|
|
|
|
The C method lets the Find object act as an iterator. The method |
216
|
|
|
|
|
|
|
is passed the parent PPI::Element object as for the C method, but does |
217
|
|
|
|
|
|
|
not accept any parameters. |
218
|
|
|
|
|
|
|
|
219
|
|
|
|
|
|
|
To simplify error handling, the entire search is done at once, with the |
220
|
|
|
|
|
|
|
results cached and provided as-requested. |
221
|
|
|
|
|
|
|
|
222
|
|
|
|
|
|
|
Returns true if the search completes, and false on error. |
223
|
|
|
|
|
|
|
|
224
|
|
|
|
|
|
|
=cut |
225
|
|
|
|
|
|
|
|
226
|
|
|
|
|
|
|
sub start { |
227
|
0
|
|
|
0
|
1
|
|
my $self = shift; |
228
|
0
|
|
|
|
|
|
my $Element = shift; |
229
|
0
|
|
|
|
|
|
delete $self->{errstr}; |
230
|
|
|
|
|
|
|
|
231
|
|
|
|
|
|
|
# Are we already acting as an iterator |
232
|
0
|
0
|
|
|
|
|
if ( $self->{in} ) { |
233
|
0
|
|
|
|
|
|
return $self->_error('->in called while another search is in progress'); |
234
|
|
|
|
|
|
|
} |
235
|
|
|
|
|
|
|
|
236
|
|
|
|
|
|
|
# Get the root element for the search |
237
|
0
|
0
|
|
|
|
|
unless ( _INSTANCE($Element, 'PPI::Element') ) { |
238
|
0
|
|
|
|
|
|
return $self->_error('->in was not passed a PPI::Element object'); |
239
|
|
|
|
|
|
|
} |
240
|
|
|
|
|
|
|
|
241
|
|
|
|
|
|
|
# Prepare the search |
242
|
0
|
|
|
|
|
|
$self->{in} = $Element; |
243
|
0
|
|
|
|
|
|
$self->{matches} = []; |
244
|
|
|
|
|
|
|
|
245
|
|
|
|
|
|
|
# Execute the search |
246
|
0
|
0
|
|
|
|
|
if ( !eval { $self->_execute; 1 } ) { |
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
247
|
0
|
|
|
|
|
|
my $errstr = $@; |
248
|
0
|
|
|
|
|
|
$errstr =~ s/\s+at\s+line\s+.+$//; |
249
|
0
|
|
|
|
|
|
$self->_error("Error while searching: $errstr"); |
250
|
0
|
|
|
|
|
|
return undef; |
251
|
|
|
|
|
|
|
} |
252
|
|
|
|
|
|
|
|
253
|
0
|
|
|
|
|
|
1; |
254
|
|
|
|
|
|
|
} |
255
|
|
|
|
|
|
|
|
256
|
|
|
|
|
|
|
=pod |
257
|
|
|
|
|
|
|
|
258
|
|
|
|
|
|
|
=head2 match |
259
|
|
|
|
|
|
|
|
260
|
|
|
|
|
|
|
The C method returns the next matching Element in the iteration. |
261
|
|
|
|
|
|
|
|
262
|
|
|
|
|
|
|
Returns a PPI::Element object, or C if there are no remaining |
263
|
|
|
|
|
|
|
Elements to be returned. |
264
|
|
|
|
|
|
|
|
265
|
|
|
|
|
|
|
=cut |
266
|
|
|
|
|
|
|
|
267
|
|
|
|
|
|
|
sub match { |
268
|
0
|
|
|
0
|
1
|
|
my $self = shift; |
269
|
0
|
0
|
|
|
|
|
return undef unless $self->{matches}; |
270
|
|
|
|
|
|
|
|
271
|
|
|
|
|
|
|
# Fetch and return the next match |
272
|
0
|
|
|
|
|
|
my $match = shift @{$self->{matches}}; |
|
0
|
|
|
|
|
|
|
273
|
0
|
0
|
|
|
|
|
return $match if $match; |
274
|
|
|
|
|
|
|
|
275
|
0
|
|
|
|
|
|
$self->finish; |
276
|
0
|
|
|
|
|
|
undef; |
277
|
|
|
|
|
|
|
} |
278
|
|
|
|
|
|
|
|
279
|
|
|
|
|
|
|
=pod |
280
|
|
|
|
|
|
|
|
281
|
|
|
|
|
|
|
=head2 finish |
282
|
|
|
|
|
|
|
|
283
|
|
|
|
|
|
|
The C method provides a mechanism to end iteration if you wish to |
284
|
|
|
|
|
|
|
stop the iteration prematurely. It resets the Find object and allows it to |
285
|
|
|
|
|
|
|
be safely reused. |
286
|
|
|
|
|
|
|
|
287
|
|
|
|
|
|
|
A Find object will be automatically finished when C returns false. |
288
|
|
|
|
|
|
|
This means you should only need to call C when you stop |
289
|
|
|
|
|
|
|
iterating early. |
290
|
|
|
|
|
|
|
|
291
|
|
|
|
|
|
|
You may safely call this method even when not iterating and it will return |
292
|
|
|
|
|
|
|
without failure. |
293
|
|
|
|
|
|
|
|
294
|
|
|
|
|
|
|
Always returns true |
295
|
|
|
|
|
|
|
|
296
|
|
|
|
|
|
|
=cut |
297
|
|
|
|
|
|
|
|
298
|
|
|
|
|
|
|
sub finish { |
299
|
0
|
|
|
0
|
1
|
|
my $self = shift; |
300
|
0
|
|
|
|
|
|
delete $self->{in}; |
301
|
0
|
|
|
|
|
|
delete $self->{matches}; |
302
|
0
|
|
|
|
|
|
delete $self->{errstr}; |
303
|
0
|
|
|
|
|
|
1; |
304
|
|
|
|
|
|
|
} |
305
|
|
|
|
|
|
|
|
306
|
|
|
|
|
|
|
|
307
|
|
|
|
|
|
|
|
308
|
|
|
|
|
|
|
|
309
|
|
|
|
|
|
|
|
310
|
|
|
|
|
|
|
##################################################################### |
311
|
|
|
|
|
|
|
# Support Methods and Error Handling |
312
|
|
|
|
|
|
|
|
313
|
|
|
|
|
|
|
sub _execute { |
314
|
0
|
|
|
0
|
|
|
my $self = shift; |
315
|
0
|
|
|
|
|
|
my $wanted = $self->{wanted}; |
316
|
0
|
|
|
|
|
|
my @queue = ( $self->{in} ); |
317
|
|
|
|
|
|
|
|
318
|
|
|
|
|
|
|
# Pull entries off the queue and hand them off to the wanted function |
319
|
0
|
|
|
|
|
|
while ( my $Element = shift @queue ) { |
320
|
0
|
|
|
|
|
|
my $rv = &$wanted( $Element, $self->{in} ); |
321
|
|
|
|
|
|
|
|
322
|
|
|
|
|
|
|
# Add to the matches if returns true |
323
|
0
|
0
|
|
|
|
|
push @{$self->{matches}}, $Element if $rv; |
|
0
|
|
|
|
|
|
|
324
|
|
|
|
|
|
|
|
325
|
|
|
|
|
|
|
# Continue and don't descend if it returned undef |
326
|
|
|
|
|
|
|
# or if it doesn't have children |
327
|
0
|
0
|
|
|
|
|
next unless defined $rv; |
328
|
0
|
0
|
|
|
|
|
next unless $Element->isa('PPI::Node'); |
329
|
|
|
|
|
|
|
|
330
|
|
|
|
|
|
|
# Add the children to the head of the queue |
331
|
0
|
0
|
|
|
|
|
if ( $Element->isa('PPI::Structure') ) { |
332
|
0
|
0
|
|
|
|
|
unshift @queue, $Element->finish if $Element->finish; |
333
|
0
|
|
|
|
|
|
unshift @queue, $Element->children; |
334
|
0
|
0
|
|
|
|
|
unshift @queue, $Element->start if $Element->start; |
335
|
|
|
|
|
|
|
} else { |
336
|
0
|
|
|
|
|
|
unshift @queue, $Element->children; |
337
|
|
|
|
|
|
|
} |
338
|
|
|
|
|
|
|
} |
339
|
|
|
|
|
|
|
|
340
|
0
|
|
|
|
|
|
1; |
341
|
|
|
|
|
|
|
} |
342
|
|
|
|
|
|
|
|
343
|
|
|
|
|
|
|
=pod |
344
|
|
|
|
|
|
|
|
345
|
|
|
|
|
|
|
=head2 errstr |
346
|
|
|
|
|
|
|
|
347
|
|
|
|
|
|
|
The C method returns the error messages when a given PPI::Find |
348
|
|
|
|
|
|
|
object fails any action. |
349
|
|
|
|
|
|
|
|
350
|
|
|
|
|
|
|
Returns a string, or C if there is no error. |
351
|
|
|
|
|
|
|
|
352
|
|
|
|
|
|
|
=cut |
353
|
|
|
|
|
|
|
|
354
|
|
|
|
|
|
|
sub errstr { |
355
|
0
|
|
|
0
|
1
|
|
shift->{errstr}; |
356
|
|
|
|
|
|
|
} |
357
|
|
|
|
|
|
|
|
358
|
|
|
|
|
|
|
sub _error { |
359
|
0
|
|
|
0
|
|
|
my $self = shift; |
360
|
0
|
|
|
|
|
|
$self->{errstr} = shift; |
361
|
0
|
|
|
|
|
|
my %params = @_; |
362
|
0
|
0
|
|
|
|
|
$params{array_ref} ? undef : (); |
363
|
|
|
|
|
|
|
} |
364
|
|
|
|
|
|
|
|
365
|
|
|
|
|
|
|
1; |
366
|
|
|
|
|
|
|
|
367
|
|
|
|
|
|
|
=pod |
368
|
|
|
|
|
|
|
|
369
|
|
|
|
|
|
|
=head1 TO DO |
370
|
|
|
|
|
|
|
|
371
|
|
|
|
|
|
|
- Implement the L class |
372
|
|
|
|
|
|
|
|
373
|
|
|
|
|
|
|
=head1 SUPPORT |
374
|
|
|
|
|
|
|
|
375
|
|
|
|
|
|
|
See the L in the main module. |
376
|
|
|
|
|
|
|
|
377
|
|
|
|
|
|
|
=head1 AUTHOR |
378
|
|
|
|
|
|
|
|
379
|
|
|
|
|
|
|
Adam Kennedy Eadamk@cpan.orgE |
380
|
|
|
|
|
|
|
|
381
|
|
|
|
|
|
|
=head1 COPYRIGHT |
382
|
|
|
|
|
|
|
|
383
|
|
|
|
|
|
|
Copyright 2001 - 2011 Adam Kennedy. |
384
|
|
|
|
|
|
|
|
385
|
|
|
|
|
|
|
This program is free software; you can redistribute |
386
|
|
|
|
|
|
|
it and/or modify it under the same terms as Perl itself. |
387
|
|
|
|
|
|
|
|
388
|
|
|
|
|
|
|
The full text of the license can be found in the |
389
|
|
|
|
|
|
|
LICENSE file included with this module. |
390
|
|
|
|
|
|
|
|
391
|
|
|
|
|
|
|
=cut |