line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
package XML::GSA; |
2
|
|
|
|
|
|
|
|
3
|
1
|
|
|
1
|
|
62789
|
use strict; |
|
1
|
|
|
|
|
5
|
|
|
1
|
|
|
|
|
95
|
|
4
|
1
|
|
|
1
|
|
7
|
use warnings; |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
46
|
|
5
|
|
|
|
|
|
|
|
6
|
1
|
|
|
1
|
|
2355
|
use XML::Writer; |
|
1
|
|
|
|
|
25375
|
|
|
1
|
|
|
|
|
224
|
|
7
|
1
|
|
|
1
|
|
1444
|
use Data::Dumper; |
|
1
|
|
|
|
|
10576
|
|
|
1
|
|
|
|
|
93
|
|
8
|
1
|
|
|
1
|
|
10
|
use Carp; |
|
1
|
|
|
|
|
3
|
|
|
1
|
|
|
|
|
63
|
|
9
|
1
|
|
|
1
|
|
1534
|
use DateTime (); |
|
1
|
|
|
|
|
232889
|
|
|
1
|
|
|
|
|
56
|
|
10
|
1
|
|
|
1
|
|
996
|
use Date::Parse (); |
|
1
|
|
|
|
|
9983
|
|
|
1
|
|
|
|
|
33
|
|
11
|
1
|
|
|
1
|
|
809
|
use XML::GSA::Group; |
|
1
|
|
|
|
|
4
|
|
|
1
|
|
|
|
|
879
|
|
12
|
|
|
|
|
|
|
|
13
|
|
|
|
|
|
|
sub new { |
14
|
0
|
|
|
0
|
1
|
|
my $class = shift; |
15
|
|
|
|
|
|
|
|
16
|
0
|
|
0
|
|
|
|
return bless { |
17
|
|
|
|
|
|
|
'type' => 'incremental', |
18
|
|
|
|
|
|
|
'datasource' => 'web', |
19
|
|
|
|
|
|
|
@_, |
20
|
|
|
|
|
|
|
'groups' => [], |
21
|
|
|
|
|
|
|
'encoding' => 'UTF-8', #read-only |
22
|
|
|
|
|
|
|
}, |
23
|
|
|
|
|
|
|
ref $class || $class; |
24
|
|
|
|
|
|
|
} |
25
|
|
|
|
|
|
|
|
26
|
|
|
|
|
|
|
#encoding is read-only |
27
|
|
|
|
|
|
|
sub encoding { |
28
|
0
|
|
|
0
|
1
|
|
my $self = shift; |
29
|
|
|
|
|
|
|
|
30
|
0
|
|
|
|
|
|
return $self->{'encoding'}; |
31
|
|
|
|
|
|
|
} |
32
|
|
|
|
|
|
|
|
33
|
|
|
|
|
|
|
#getters |
34
|
|
|
|
|
|
|
sub xml { |
35
|
0
|
|
|
0
|
1
|
|
my $self = shift; |
36
|
|
|
|
|
|
|
|
37
|
0
|
|
|
|
|
|
return $self->{'xml'}; |
38
|
|
|
|
|
|
|
} |
39
|
|
|
|
|
|
|
|
40
|
|
|
|
|
|
|
sub to_string { |
41
|
0
|
|
|
0
|
1
|
|
my $self = shift; |
42
|
|
|
|
|
|
|
|
43
|
0
|
|
|
|
|
|
return $self->{'xml'}; |
44
|
|
|
|
|
|
|
} |
45
|
|
|
|
|
|
|
|
46
|
|
|
|
|
|
|
sub writer { |
47
|
0
|
|
|
0
|
1
|
|
my $self = shift; |
48
|
|
|
|
|
|
|
|
49
|
0
|
|
|
|
|
|
return $self->{'writer'}; |
50
|
|
|
|
|
|
|
} |
51
|
|
|
|
|
|
|
|
52
|
|
|
|
|
|
|
#getters and setters |
53
|
|
|
|
|
|
|
sub type { |
54
|
0
|
|
|
0
|
1
|
|
my ( $self, $value ) = @_; |
55
|
|
|
|
|
|
|
|
56
|
0
|
0
|
0
|
|
|
|
$self->{'type'} = $value |
57
|
|
|
|
|
|
|
if $value && $value =~ /(incremental|full|metadata-and-url)/; |
58
|
|
|
|
|
|
|
|
59
|
0
|
|
|
|
|
|
return $self->{'type'}; |
60
|
|
|
|
|
|
|
} |
61
|
|
|
|
|
|
|
|
62
|
|
|
|
|
|
|
sub datasource { |
63
|
0
|
|
|
0
|
1
|
|
my ( $self, $value ) = @_; |
64
|
|
|
|
|
|
|
|
65
|
0
|
0
|
|
|
|
|
$self->{'datasource'} = $value |
66
|
|
|
|
|
|
|
if $value; |
67
|
|
|
|
|
|
|
|
68
|
0
|
|
|
|
|
|
return $self->{'datasource'}; |
69
|
|
|
|
|
|
|
} |
70
|
|
|
|
|
|
|
|
71
|
|
|
|
|
|
|
sub base_url { |
72
|
0
|
|
|
0
|
1
|
|
my ( $self, $value ) = @_; |
73
|
|
|
|
|
|
|
|
74
|
0
|
0
|
|
|
|
|
$self->{'base_url'} = $value |
75
|
|
|
|
|
|
|
if $value; |
76
|
|
|
|
|
|
|
|
77
|
0
|
|
|
|
|
|
return $self->{'base_url'}; |
78
|
|
|
|
|
|
|
} |
79
|
|
|
|
|
|
|
|
80
|
|
|
|
|
|
|
sub groups { |
81
|
0
|
|
|
0
|
1
|
|
my $self = shift; |
82
|
|
|
|
|
|
|
|
83
|
0
|
|
0
|
|
|
|
return $self->{'groups'} || []; |
84
|
|
|
|
|
|
|
} |
85
|
|
|
|
|
|
|
|
86
|
|
|
|
|
|
|
sub add_group { |
87
|
0
|
|
|
0
|
1
|
|
my ( $self, $value ) = @_; |
88
|
|
|
|
|
|
|
|
89
|
0
|
0
|
0
|
|
|
|
unless ( ref $value eq 'HASH' || ref $value eq 'XML::GSA::Group' ) { |
90
|
0
|
|
|
|
|
|
carp("Must receive an HASH ref or an XML::GSA::Group object"); |
91
|
0
|
|
|
|
|
|
return; |
92
|
|
|
|
|
|
|
} |
93
|
|
|
|
|
|
|
|
94
|
0
|
0
|
|
|
|
|
my $group |
95
|
|
|
|
|
|
|
= ref $value eq 'HASH' |
96
|
|
|
|
|
|
|
? XML::GSA::Group->new( |
97
|
|
|
|
|
|
|
'action' => $value->{'action'}, |
98
|
|
|
|
|
|
|
'records' => $value->{'records'} |
99
|
|
|
|
|
|
|
) |
100
|
|
|
|
|
|
|
: $value; |
101
|
|
|
|
|
|
|
|
102
|
0
|
|
|
|
|
|
push @{ $self->groups }, $group; |
|
0
|
|
|
|
|
|
|
103
|
|
|
|
|
|
|
} |
104
|
|
|
|
|
|
|
|
105
|
|
|
|
|
|
|
#empties the group arrayref |
106
|
|
|
|
|
|
|
sub clear_groups { |
107
|
0
|
|
|
0
|
1
|
|
my $self = shift; |
108
|
|
|
|
|
|
|
|
109
|
0
|
|
|
|
|
|
$self->{'groups'} = []; |
110
|
|
|
|
|
|
|
} |
111
|
|
|
|
|
|
|
|
112
|
|
|
|
|
|
|
sub create { |
113
|
0
|
|
|
0
|
1
|
|
my ( $self, $data ) = @_; |
114
|
|
|
|
|
|
|
|
115
|
|
|
|
|
|
|
#use $self->groups |
116
|
0
|
0
|
|
|
|
|
if ( !defined $data ) { |
117
|
0
|
|
|
|
|
|
$data = $self->groups(); |
118
|
|
|
|
|
|
|
} |
119
|
|
|
|
|
|
|
else { #add each structure as new group, emptying the existing groups |
120
|
0
|
0
|
|
|
|
|
unless ( ref $data eq 'ARRAY' ) { |
121
|
0
|
|
|
|
|
|
carp("An array data structure must be passed as parameter"); |
122
|
0
|
|
|
|
|
|
return; |
123
|
|
|
|
|
|
|
} |
124
|
|
|
|
|
|
|
|
125
|
0
|
|
|
|
|
|
$self->clear_groups(); |
126
|
|
|
|
|
|
|
} |
127
|
|
|
|
|
|
|
|
128
|
0
|
|
|
|
|
|
my $writer = XML::Writer->new( OUTPUT => 'self', 'UNSAFE' => 1 ); |
129
|
0
|
|
|
|
|
|
$self->{'writer'} = $writer; |
130
|
|
|
|
|
|
|
|
131
|
0
|
|
|
|
|
|
$self->writer->xmlDecl( $self->encoding ); |
132
|
0
|
|
|
|
|
|
$self->writer->doctype( "gsafeed", '-//Google//DTD GSA Feeds//EN', "" ); |
133
|
|
|
|
|
|
|
|
134
|
0
|
|
|
|
|
|
$self->writer->startTag('gsafeed'); |
135
|
0
|
|
|
|
|
|
$self->writer->startTag('header'); |
136
|
0
|
|
|
|
|
|
$self->writer->dataElement( 'datasource', $self->datasource() ); |
137
|
0
|
|
|
|
|
|
$self->writer->dataElement( 'feedtype', $self->type() ); |
138
|
0
|
|
|
|
|
|
$self->writer->endTag('header'); |
139
|
|
|
|
|
|
|
|
140
|
0
|
0
|
|
|
|
|
for my $group ( @{ $data || [] } ) { |
|
0
|
|
|
|
|
|
|
141
|
|
|
|
|
|
|
|
142
|
|
|
|
|
|
|
#if not group, add it as one |
143
|
0
|
0
|
|
|
|
|
unless ( ref $group eq 'XML::GSA::Group' ) { |
144
|
|
|
|
|
|
|
|
145
|
0
|
|
|
|
|
|
$group = XML::GSA::Group->new( |
146
|
|
|
|
|
|
|
'action' => $group->{'action'}, |
147
|
|
|
|
|
|
|
'records' => $group->{'records'} |
148
|
|
|
|
|
|
|
); |
149
|
|
|
|
|
|
|
} |
150
|
0
|
|
|
|
|
|
$group->create($self); |
151
|
|
|
|
|
|
|
|
152
|
0
|
|
|
|
|
|
$self->writer->raw( $group->to_string ); |
153
|
|
|
|
|
|
|
} |
154
|
|
|
|
|
|
|
|
155
|
0
|
|
|
|
|
|
$self->writer->endTag('gsafeed'); |
156
|
|
|
|
|
|
|
|
157
|
0
|
|
|
|
|
|
my $xml = $self->writer->to_string; |
158
|
|
|
|
|
|
|
|
159
|
|
|
|
|
|
|
#gsa needs utf8 encoding |
160
|
0
|
|
|
|
|
|
utf8::encode($xml); |
161
|
|
|
|
|
|
|
|
162
|
0
|
|
|
|
|
|
$self->{'xml'} = $xml; |
163
|
0
|
|
|
|
|
|
return $xml; |
164
|
|
|
|
|
|
|
} |
165
|
|
|
|
|
|
|
|
166
|
|
|
|
|
|
|
1; |
167
|
|
|
|
|
|
|
|
168
|
|
|
|
|
|
|
=head1 NAME |
169
|
|
|
|
|
|
|
|
170
|
|
|
|
|
|
|
XML::GSA - Creates xml in google search appliance (GSA) format |
171
|
|
|
|
|
|
|
|
172
|
|
|
|
|
|
|
=head1 VERSION |
173
|
|
|
|
|
|
|
|
174
|
|
|
|
|
|
|
Version 0.07 |
175
|
|
|
|
|
|
|
|
176
|
|
|
|
|
|
|
=cut |
177
|
|
|
|
|
|
|
|
178
|
|
|
|
|
|
|
our $VERSION = '0.07'; |
179
|
|
|
|
|
|
|
|
180
|
|
|
|
|
|
|
=head1 SYNOPSIS |
181
|
|
|
|
|
|
|
|
182
|
|
|
|
|
|
|
This is a lib that allows one to create xml in Google Search Appliance (GSA) format. |
183
|
|
|
|
|
|
|
|
184
|
|
|
|
|
|
|
You can use this lib in the following way: |
185
|
|
|
|
|
|
|
|
186
|
|
|
|
|
|
|
use XML::GSA; |
187
|
|
|
|
|
|
|
|
188
|
|
|
|
|
|
|
my $gsa = XML::GSA->new('base_url' => 'http://foo.bar'); |
189
|
|
|
|
|
|
|
my $xml = $gsa->create( |
190
|
|
|
|
|
|
|
[ { 'action' => 'add', |
191
|
|
|
|
|
|
|
'records' => [ |
192
|
|
|
|
|
|
|
{ 'url' => '/aaa', |
193
|
|
|
|
|
|
|
'mimetype' => 'text/plain', |
194
|
|
|
|
|
|
|
'action' => 'delete', |
195
|
|
|
|
|
|
|
}, |
196
|
|
|
|
|
|
|
{ 'url' => '/bbb', |
197
|
|
|
|
|
|
|
'mimetype' => 'text/plain', |
198
|
|
|
|
|
|
|
'metadata' => [ |
199
|
|
|
|
|
|
|
{ 'name' => 'og:title', 'content' => 'BBB' }, |
200
|
|
|
|
|
|
|
], |
201
|
|
|
|
|
|
|
} |
202
|
|
|
|
|
|
|
], |
203
|
|
|
|
|
|
|
}, |
204
|
|
|
|
|
|
|
] |
205
|
|
|
|
|
|
|
); |
206
|
|
|
|
|
|
|
print $xml; |
207
|
|
|
|
|
|
|
|
208
|
|
|
|
|
|
|
Which will output: |
209
|
|
|
|
|
|
|
|
210
|
|
|
|
|
|
|
|
211
|
|
|
|
|
|
|
|
212
|
|
|
|
|
|
|
|
213
|
|
|
|
|
|
|
|
214
|
|
|
|
|
|
|
Source |
215
|
|
|
|
|
|
|
incremental |
216
|
|
|
|
|
|
|
|
217
|
|
|
|
|
|
|
|
218
|
|
|
|
|
|
|
|
219
|
|
|
|
|
|
|
|
220
|
|
|
|
|
|
|
|
221
|
|
|
|
|
|
|
|
222
|
|
|
|
|
|
|
|
223
|
|
|
|
|
|
|
|
224
|
|
|
|
|
|
|
|
225
|
|
|
|
|
|
|
|
226
|
|
|
|
|
|
|
|
227
|
|
|
|
|
|
|
=head1 METHODS |
228
|
|
|
|
|
|
|
|
229
|
|
|
|
|
|
|
=head2 new( C<$params> ) |
230
|
|
|
|
|
|
|
|
231
|
|
|
|
|
|
|
Create a new XML::GSA object: |
232
|
|
|
|
|
|
|
|
233
|
|
|
|
|
|
|
my $gsa = XML::GSA->new('base_url' => 'http://foo.bar'); |
234
|
|
|
|
|
|
|
|
235
|
|
|
|
|
|
|
Arguments of this method are an anonymous hash of parameters: |
236
|
|
|
|
|
|
|
|
237
|
|
|
|
|
|
|
=head3 datasource |
238
|
|
|
|
|
|
|
|
239
|
|
|
|
|
|
|
Defines the datasource to be included in the header of the xml. |
240
|
|
|
|
|
|
|
|
241
|
|
|
|
|
|
|
=head3 type |
242
|
|
|
|
|
|
|
|
243
|
|
|
|
|
|
|
Defines the type of the feed. This attribute tells the feed what kind of attributes the records are able to receive. |
244
|
|
|
|
|
|
|
|
245
|
|
|
|
|
|
|
=head3 base_url |
246
|
|
|
|
|
|
|
|
247
|
|
|
|
|
|
|
Defines a base url to be preppended to all records' urls. |
248
|
|
|
|
|
|
|
|
249
|
|
|
|
|
|
|
=cut |
250
|
|
|
|
|
|
|
|
251
|
|
|
|
|
|
|
=head2 type( C<$value> ) |
252
|
|
|
|
|
|
|
|
253
|
|
|
|
|
|
|
Getter/setter for the type attribute of GSA feed. By default it is 'incremental'. |
254
|
|
|
|
|
|
|
Possible values are 'incremental', 'full' or 'metadata-and-url' |
255
|
|
|
|
|
|
|
|
256
|
|
|
|
|
|
|
=cut |
257
|
|
|
|
|
|
|
|
258
|
|
|
|
|
|
|
=head2 datasource( C<$value> ) |
259
|
|
|
|
|
|
|
|
260
|
|
|
|
|
|
|
Getter/setter for the datasource attribute of GSA feed. By default it is 'web'. |
261
|
|
|
|
|
|
|
|
262
|
|
|
|
|
|
|
=cut |
263
|
|
|
|
|
|
|
|
264
|
|
|
|
|
|
|
=head2 base_url( C<$value> ) |
265
|
|
|
|
|
|
|
|
266
|
|
|
|
|
|
|
Getter/setter for the base_url attribute of GSA feed. This is an url that will be preppended to all record urls. If a base_url is not defined, one must pass full urls in the records data structure. |
267
|
|
|
|
|
|
|
|
268
|
|
|
|
|
|
|
=cut |
269
|
|
|
|
|
|
|
|
270
|
|
|
|
|
|
|
=head2 create( C<$data> ) |
271
|
|
|
|
|
|
|
|
272
|
|
|
|
|
|
|
Receives an arrayref data structure where each entry represents a group in the xml, generates an xml in GSA format and returns it as a string. |
273
|
|
|
|
|
|
|
Important note: All data passed to create must be in unicode! This class will utf-8 encode it making it compatible with GSA. |
274
|
|
|
|
|
|
|
|
275
|
|
|
|
|
|
|
One can have has many group has one wants, and a group is an hashref with an optional key 'action' and a mandatory key 'records'. The key 'action' can have the values of 'add' or 'delete' and the 'records' key is an array of hashrefs. |
276
|
|
|
|
|
|
|
|
277
|
|
|
|
|
|
|
Each hashref in the array corresponding to 'records' can have the following keys: |
278
|
|
|
|
|
|
|
|
279
|
|
|
|
|
|
|
* Mandatory |
280
|
|
|
|
|
|
|
* url |
281
|
|
|
|
|
|
|
* mimetype => (text/plain|text/html) - in the future it will also support other mimetype |
282
|
|
|
|
|
|
|
* Optional |
283
|
|
|
|
|
|
|
* action => (add|delete) |
284
|
|
|
|
|
|
|
* lock => (true|false) |
285
|
|
|
|
|
|
|
* displayurl => an url |
286
|
|
|
|
|
|
|
* last-modified => a well formatted date as string |
287
|
|
|
|
|
|
|
* authmethod => (none|httpbasic|ntlm|httpsso) |
288
|
|
|
|
|
|
|
* pagerank => an int number |
289
|
|
|
|
|
|
|
* crawl-immediately => (true|false) |
290
|
|
|
|
|
|
|
* crawl-once => (true|false) |
291
|
|
|
|
|
|
|
|
292
|
|
|
|
|
|
|
=cut |
293
|
|
|
|
|
|
|
|
294
|
|
|
|
|
|
|
=head2 create |
295
|
|
|
|
|
|
|
|
296
|
|
|
|
|
|
|
Creates the xml using the groups already added to the object. |
297
|
|
|
|
|
|
|
|
298
|
|
|
|
|
|
|
=head2 add_group( C<$group> ) |
299
|
|
|
|
|
|
|
|
300
|
|
|
|
|
|
|
Receives an hashref data structure representing a group and adds it to the current feed - you must call the `create` method with no arguments to have the xml updated. A group is an hashref with an optional key 'action' and a mandatory key 'records'. The key 'action' can have the values of 'add' or 'delete' and the 'records' key is an array of hashrefs. |
301
|
|
|
|
|
|
|
|
302
|
|
|
|
|
|
|
Each hashref in the array corresponding to 'records' can have the following keys: |
303
|
|
|
|
|
|
|
|
304
|
|
|
|
|
|
|
* Mandatory |
305
|
|
|
|
|
|
|
* url |
306
|
|
|
|
|
|
|
* mimetype => (text/plain|text/html) - in the future it will also support other mimetype |
307
|
|
|
|
|
|
|
* Optional |
308
|
|
|
|
|
|
|
* action => (add|delete) |
309
|
|
|
|
|
|
|
* lock => (true|false) |
310
|
|
|
|
|
|
|
* displayurl => an url |
311
|
|
|
|
|
|
|
* last-modified => a well formatted date as string |
312
|
|
|
|
|
|
|
* authmethod => (none|httpbasic|ntlm|httpsso) |
313
|
|
|
|
|
|
|
* pagerank => an int number |
314
|
|
|
|
|
|
|
* crawl-immediately => (true|false) |
315
|
|
|
|
|
|
|
* crawl-once => (true|false) |
316
|
|
|
|
|
|
|
|
317
|
|
|
|
|
|
|
Important note: All data passed must be in unicode! This class will utf-8 encode it making it compatible with GSA. |
318
|
|
|
|
|
|
|
|
319
|
|
|
|
|
|
|
=head2 add_group( C<$group> ) |
320
|
|
|
|
|
|
|
|
321
|
|
|
|
|
|
|
Receives an instance of the class XML::GSA::Group and adds it to the current feed - you must call the `create` method with no arguments to have the xml updated. |
322
|
|
|
|
|
|
|
|
323
|
|
|
|
|
|
|
=head2 clear_groups |
324
|
|
|
|
|
|
|
|
325
|
|
|
|
|
|
|
Empties the property `groups` of this class. |
326
|
|
|
|
|
|
|
|
327
|
|
|
|
|
|
|
=head2 xml |
328
|
|
|
|
|
|
|
|
329
|
|
|
|
|
|
|
Getter for the xml generated by the `create` method. |
330
|
|
|
|
|
|
|
|
331
|
|
|
|
|
|
|
=head2 to_string |
332
|
|
|
|
|
|
|
|
333
|
|
|
|
|
|
|
Getter for the xml generated by the `create` method. |
334
|
|
|
|
|
|
|
|
335
|
|
|
|
|
|
|
=head2 encoding |
336
|
|
|
|
|
|
|
|
337
|
|
|
|
|
|
|
Getter for the encoding used in this class |
338
|
|
|
|
|
|
|
|
339
|
|
|
|
|
|
|
=head2 groups |
340
|
|
|
|
|
|
|
|
341
|
|
|
|
|
|
|
Getter for the array of groups added to this class |
342
|
|
|
|
|
|
|
|
343
|
|
|
|
|
|
|
=head2 writer |
344
|
|
|
|
|
|
|
|
345
|
|
|
|
|
|
|
Getter for the XML::Writer object used in this class to create the xml |
346
|
|
|
|
|
|
|
|
347
|
|
|
|
|
|
|
=cut |
348
|
|
|
|
|
|
|
|
349
|
|
|
|
|
|
|
=head1 AUTHOR |
350
|
|
|
|
|
|
|
|
351
|
|
|
|
|
|
|
Shemahmforash, C<< >> |
352
|
|
|
|
|
|
|
|
353
|
|
|
|
|
|
|
=head1 BUGS |
354
|
|
|
|
|
|
|
|
355
|
|
|
|
|
|
|
Please report any bugs or feature requests to C, or through |
356
|
|
|
|
|
|
|
the web interface at L. I will be notified, and then you'll |
357
|
|
|
|
|
|
|
automatically be notified of progress on your bug as I make changes. |
358
|
|
|
|
|
|
|
|
359
|
|
|
|
|
|
|
|
360
|
|
|
|
|
|
|
|
361
|
|
|
|
|
|
|
|
362
|
|
|
|
|
|
|
=head1 SUPPORT |
363
|
|
|
|
|
|
|
|
364
|
|
|
|
|
|
|
You can find documentation for this module with the perldoc command. |
365
|
|
|
|
|
|
|
|
366
|
|
|
|
|
|
|
perldoc XML::GSA |
367
|
|
|
|
|
|
|
|
368
|
|
|
|
|
|
|
|
369
|
|
|
|
|
|
|
You can also look for information at: |
370
|
|
|
|
|
|
|
|
371
|
|
|
|
|
|
|
=over 4 |
372
|
|
|
|
|
|
|
|
373
|
|
|
|
|
|
|
=item * RT: CPAN's request tracker (report bugs here) |
374
|
|
|
|
|
|
|
|
375
|
|
|
|
|
|
|
L |
376
|
|
|
|
|
|
|
|
377
|
|
|
|
|
|
|
=item * AnnoCPAN: Annotated CPAN documentation |
378
|
|
|
|
|
|
|
|
379
|
|
|
|
|
|
|
L |
380
|
|
|
|
|
|
|
|
381
|
|
|
|
|
|
|
=item * CPAN Ratings |
382
|
|
|
|
|
|
|
|
383
|
|
|
|
|
|
|
L |
384
|
|
|
|
|
|
|
|
385
|
|
|
|
|
|
|
=item * Search CPAN |
386
|
|
|
|
|
|
|
|
387
|
|
|
|
|
|
|
L |
388
|
|
|
|
|
|
|
|
389
|
|
|
|
|
|
|
=item * Github Repository |
390
|
|
|
|
|
|
|
|
391
|
|
|
|
|
|
|
L |
392
|
|
|
|
|
|
|
|
393
|
|
|
|
|
|
|
=back |
394
|
|
|
|
|
|
|
|
395
|
|
|
|
|
|
|
=head1 LICENSE AND COPYRIGHT |
396
|
|
|
|
|
|
|
|
397
|
|
|
|
|
|
|
Copyright 2013-2014 Shemahmforash. |
398
|
|
|
|
|
|
|
|
399
|
|
|
|
|
|
|
This program is free software: you can redistribute it and/or modify |
400
|
|
|
|
|
|
|
it under the terms of the GNU General Public License as published by |
401
|
|
|
|
|
|
|
the Free Software Foundation, either version 3 of the License, or |
402
|
|
|
|
|
|
|
(at your option) any later version. |
403
|
|
|
|
|
|
|
|
404
|
|
|
|
|
|
|
This program is distributed in the hope that it will be useful, |
405
|
|
|
|
|
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of |
406
|
|
|
|
|
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
407
|
|
|
|
|
|
|
GNU General Public License for more details. |
408
|
|
|
|
|
|
|
|
409
|
|
|
|
|
|
|
You should have received a copy of the GNU General Public License |
410
|
|
|
|
|
|
|
along with this program. If not, see L. |
411
|
|
|
|
|
|
|
|
412
|
|
|
|
|
|
|
|
413
|
|
|
|
|
|
|
=cut |