line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
# |
2
|
|
|
|
|
|
|
# This file is part of Software-Copyright |
3
|
|
|
|
|
|
|
# |
4
|
|
|
|
|
|
|
# This software is Copyright (c) 2022 by Dominique Dumont <dod@debian.org>. |
5
|
|
|
|
|
|
|
# |
6
|
|
|
|
|
|
|
# This is free software, licensed under: |
7
|
|
|
|
|
|
|
# |
8
|
|
|
|
|
|
|
# The GNU General Public License, Version 3, June 2007 |
9
|
|
|
|
|
|
|
# |
10
|
|
|
|
|
|
|
package Software::Copyright::Statement; |
11
|
|
|
|
|
|
|
$Software::Copyright::Statement::VERSION = '0.010'; |
12
|
3
|
|
|
3
|
|
1531
|
use 5.20.0; |
|
3
|
|
|
|
|
14
|
|
13
|
3
|
|
|
3
|
|
27
|
use warnings; |
|
3
|
|
|
|
|
6
|
|
|
3
|
|
|
|
|
82
|
|
14
|
|
|
|
|
|
|
|
15
|
3
|
|
|
3
|
|
930
|
use Mouse; |
|
3
|
|
|
|
|
58372
|
|
|
3
|
|
|
|
|
45
|
|
16
|
3
|
|
|
3
|
|
2943
|
use Array::IntSpan; |
|
3
|
|
|
|
|
8886
|
|
|
3
|
|
|
|
|
92
|
|
17
|
3
|
|
|
3
|
|
28
|
use Carp; |
|
3
|
|
|
|
|
8
|
|
|
3
|
|
|
|
|
189
|
|
18
|
3
|
|
|
3
|
|
1582
|
use Software::Copyright::Owner; |
|
3
|
|
|
|
|
19
|
|
|
3
|
|
|
|
|
93
|
|
19
|
3
|
|
|
3
|
|
1542
|
use Date::Parse; |
|
3
|
|
|
|
|
22498
|
|
|
3
|
|
|
|
|
400
|
|
20
|
3
|
|
|
3
|
|
967
|
use Time::localtime; |
|
3
|
|
|
|
|
10211
|
|
|
3
|
|
|
|
|
181
|
|
21
|
|
|
|
|
|
|
|
22
|
3
|
|
|
3
|
|
20
|
use feature qw/postderef signatures/; |
|
3
|
|
|
|
|
7
|
|
|
3
|
|
|
|
|
234
|
|
23
|
3
|
|
|
3
|
|
17
|
no warnings qw/experimental::postderef experimental::signatures/; |
|
3
|
|
|
|
|
6
|
|
|
3
|
|
|
|
|
127
|
|
24
|
|
|
|
|
|
|
|
25
|
3
|
|
|
3
|
|
16
|
use overload '""' => \&stringify; |
|
3
|
|
|
|
|
7
|
|
|
3
|
|
|
|
|
25
|
|
26
|
3
|
|
|
3
|
|
214
|
use overload 'cmp' => \&compare; |
|
3
|
|
|
|
|
6
|
|
|
3
|
|
|
|
|
14
|
|
27
|
3
|
|
|
3
|
|
165
|
use overload '==' => \&_equal; |
|
3
|
|
|
|
|
7
|
|
|
3
|
|
|
|
|
14
|
|
28
|
3
|
|
|
3
|
|
191
|
use overload 'eq' => \&_equal; |
|
3
|
|
|
|
|
6
|
|
|
3
|
|
|
|
|
13
|
|
29
|
|
|
|
|
|
|
|
30
|
|
|
|
|
|
|
has span => ( |
31
|
|
|
|
|
|
|
is => 'ro', |
32
|
|
|
|
|
|
|
isa => 'Array::IntSpan', |
33
|
|
|
|
|
|
|
required => 1 , # may be an empty span |
34
|
|
|
|
|
|
|
); |
35
|
|
|
|
|
|
|
|
36
|
11
|
|
|
11
|
0
|
298
|
sub range ($self) { |
|
11
|
|
|
|
|
20
|
|
|
11
|
|
|
|
|
18
|
|
37
|
11
|
|
|
|
|
36
|
return scalar $self->span->get_range_list; |
38
|
|
|
|
|
|
|
} |
39
|
|
|
|
|
|
|
|
40
|
|
|
|
|
|
|
has owner => ( |
41
|
|
|
|
|
|
|
is => 'rw', |
42
|
|
|
|
|
|
|
isa => 'Software::Copyright::Owner', |
43
|
|
|
|
|
|
|
required => 1, |
44
|
|
|
|
|
|
|
handles => { |
45
|
|
|
|
|
|
|
map { $_ => $_ } qw/name email record identifier/ |
46
|
|
|
|
|
|
|
}, |
47
|
|
|
|
|
|
|
); |
48
|
|
|
|
|
|
|
|
49
|
124
|
|
|
124
|
|
179
|
sub __clean_copyright ($c) { |
|
124
|
|
|
|
|
184
|
|
|
124
|
|
|
|
|
160
|
|
50
|
124
|
|
|
|
|
259
|
$c =~ s/^©\s*//g; |
51
|
1
|
|
|
1
|
|
10
|
$c =~ s/\(c\)\s*//gi; |
|
1
|
|
|
|
|
3
|
|
|
1
|
|
|
|
|
16
|
|
|
124
|
|
|
|
|
371
|
|
52
|
|
|
|
|
|
|
# remove space around dash between number (eg. 2003 - 2004 => 2003-2004) |
53
|
124
|
|
|
|
|
28693
|
$c =~ s/(\d+)\s*-\s*(?=\d+)/$1-/g; |
54
|
|
|
|
|
|
|
# extract year from YY-MM-DD:hh:mm:ss format |
55
|
124
|
|
|
|
|
316
|
$c =~ s/(\d{2,4}-\d\d-\d{2,4})[:\d]*/my @r = strptime($1); $r[5]+1900/gex; |
|
3
|
|
|
|
|
70
|
|
|
3
|
|
|
|
|
427
|
|
56
|
|
|
|
|
|
|
# remove extra years inside range, e,g 2003- 2004- 2008 -> 2003- 2008 |
57
|
124
|
|
|
|
|
286
|
$c =~ s/(?<=\b\d{4})\s*-\s*\d{4}(?=\s*-\s*(\d{4})\b)//g; |
58
|
|
|
|
|
|
|
# add space after a comma between years |
59
|
124
|
|
|
|
|
1010
|
$c =~ s/\b(\d{4}),?\s+([\S^\d])/$1, $2/g; |
60
|
124
|
|
|
|
|
268
|
$c =~ s/\s+by\s+//g; |
61
|
124
|
|
|
|
|
257
|
$c =~ s/(\\n)*all\s+rights?\s+reserved\.?(\\n)*\s*//gi; # yes there are literal \n |
62
|
124
|
100
|
|
|
|
351
|
$c = '' if $c =~ /^\*No copyright/i; |
63
|
124
|
|
|
|
|
217
|
$c =~ s/\(r\)//g; |
64
|
124
|
|
|
|
|
701
|
$c =~ s!^[\s,/*]|[\s,#/*-]+$!!g; |
65
|
124
|
|
|
|
|
196
|
$c =~ s/--/-/g; |
66
|
124
|
|
|
|
|
185
|
$c =~ s!\s+\*/\s+! !; |
67
|
|
|
|
|
|
|
# libuv1 has copyright like "2000, -present" |
68
|
124
|
|
|
|
|
192
|
$c =~ s![,\s]*-present!'-'.(localtime->year() + 1900)!e; |
|
1
|
|
|
|
|
5
|
|
69
|
|
|
|
|
|
|
# cleanup markdown copyright |
70
|
124
|
|
|
|
|
323
|
$c =~ s/\[([\w\s]+)\]\(mailto:([\w@.+-]+)\)/$1 <$2>/; |
71
|
124
|
|
|
|
|
318
|
return $c; |
72
|
|
|
|
|
|
|
} |
73
|
|
|
|
|
|
|
|
74
|
135
|
|
|
135
|
|
9776
|
sub __split_copyright ($c) { |
|
135
|
|
|
|
|
219
|
|
|
135
|
|
|
|
|
171
|
|
75
|
135
|
|
|
|
|
530
|
my ($years,$owner) = $c =~ /^(\d\d[\s,\d-]+)(.*)/; |
76
|
|
|
|
|
|
|
# say "undef year in $c" unless defined $years; |
77
|
135
|
100
|
|
|
|
346
|
if (not defined $years) { |
78
|
|
|
|
|
|
|
# try owner and years in reversed order (works also without year) |
79
|
24
|
|
|
|
|
191
|
($owner,$years) = $c =~ m/(.*?)(\d\d[\s,\d-]+)?$/; |
80
|
|
|
|
|
|
|
} |
81
|
|
|
|
|
|
|
|
82
|
135
|
|
50
|
|
|
280
|
$owner //=''; |
83
|
|
|
|
|
|
|
|
84
|
135
|
100
|
|
|
|
530
|
my @data = defined $years ? split /(?<=\d)[,\s]+/, $years : (); |
85
|
135
|
|
|
|
|
643
|
$owner =~ s/^[\s.,-]+|[\s,*-]+$//g; |
86
|
135
|
|
|
|
|
429
|
return ($owner,@data); |
87
|
|
|
|
|
|
|
} |
88
|
|
|
|
|
|
|
|
89
|
|
|
|
|
|
|
around BUILDARGS => sub ($orig, $class, @args) { |
90
|
|
|
|
|
|
|
my $c = __clean_copyright($args[0]); |
91
|
|
|
|
|
|
|
my ($owner_str, @data) = __split_copyright($c); |
92
|
|
|
|
|
|
|
|
93
|
|
|
|
|
|
|
my $span = Array::IntSpan->new(); |
94
|
|
|
|
|
|
|
my $owner = Software::Copyright::Owner->new($owner_str); |
95
|
|
|
|
|
|
|
|
96
|
|
|
|
|
|
|
foreach my $year (@data) { |
97
|
|
|
|
|
|
|
last if $year =~ /[^\d-]/; # bail-out |
98
|
|
|
|
|
|
|
# take care of ranges written like 2002-3 |
99
|
|
|
|
|
|
|
$year =~ s/^(\d\d\d)(\d)-(\d)$/$1$2-$1$3/; |
100
|
|
|
|
|
|
|
# take care of ranges written like 2014-15 |
101
|
|
|
|
|
|
|
$year =~ s/^(\d\d)(\d\d)-(\d\d)$/$1$2-$1$3/; |
102
|
|
|
|
|
|
|
eval { |
103
|
|
|
|
|
|
|
# the value stored in range is not used. |
104
|
|
|
|
|
|
|
$span->set_range_as_string($year, $owner->identifier // 'unknown'); |
105
|
|
|
|
|
|
|
}; |
106
|
|
|
|
|
|
|
if ($@) { |
107
|
|
|
|
|
|
|
warn "Invalid year span: '$year' found in statement '$c'\n"; |
108
|
|
|
|
|
|
|
} |
109
|
|
|
|
|
|
|
} |
110
|
|
|
|
|
|
|
$span->consolidate(); |
111
|
|
|
|
|
|
|
|
112
|
|
|
|
|
|
|
return $class->$orig({ |
113
|
|
|
|
|
|
|
span => $span, |
114
|
|
|
|
|
|
|
owner => $owner, |
115
|
|
|
|
|
|
|
}) ; |
116
|
|
|
|
|
|
|
}; |
117
|
|
|
|
|
|
|
|
118
|
216
|
|
|
216
|
1
|
990
|
sub stringify ($self,$=1,$=1) { |
|
216
|
|
|
|
|
299
|
|
|
216
|
|
|
|
|
297
|
|
|
216
|
|
|
|
|
284
|
|
|
216
|
|
|
|
|
269
|
|
119
|
216
|
|
|
|
|
573
|
my $range = $self->span->get_range_list; |
120
|
216
|
|
|
|
|
2557
|
return join (', ', grep { $_ } ($range, $self->owner)); |
|
432
|
|
|
|
|
1326
|
|
121
|
|
|
|
|
|
|
} |
122
|
|
|
|
|
|
|
|
123
|
42
|
|
|
42
|
0
|
193
|
sub compare ($self, $other, $swap) { |
|
42
|
|
|
|
|
78
|
|
|
42
|
|
|
|
|
76
|
|
|
42
|
|
|
|
|
61
|
|
|
42
|
|
|
|
|
55
|
|
124
|
|
|
|
|
|
|
# we must force stringify before calling cmp |
125
|
42
|
|
|
|
|
83
|
return "$self" cmp "$other"; |
126
|
|
|
|
|
|
|
} |
127
|
|
|
|
|
|
|
|
128
|
6
|
|
|
6
|
|
1443
|
sub _equal ($self, $other, $swap) { |
|
6
|
|
|
|
|
14
|
|
|
6
|
|
|
|
|
9
|
|
|
6
|
|
|
|
|
12
|
|
|
6
|
|
|
|
|
10
|
|
129
|
|
|
|
|
|
|
# we must force stringify before calling eq |
130
|
6
|
|
|
|
|
13
|
return "$self" eq "$other"; |
131
|
|
|
|
|
|
|
} |
132
|
|
|
|
|
|
|
|
133
|
22
|
|
|
22
|
1
|
34
|
sub merge ($self, $other) { |
|
22
|
|
|
|
|
37
|
|
|
22
|
|
|
|
|
36
|
|
|
22
|
|
|
|
|
28
|
|
134
|
22
|
50
|
|
|
|
64
|
if ($self->identifier eq $other->identifier ) { |
135
|
22
|
100
|
|
|
|
70
|
$self->email($other->email) if $other->email; |
136
|
22
|
|
|
|
|
428
|
$self->span->set_range_as_string(scalar $other->span->get_range_list, $other->identifier); |
137
|
22
|
|
|
|
|
1052
|
$self->span->consolidate(); |
138
|
|
|
|
|
|
|
} |
139
|
|
|
|
|
|
|
else { |
140
|
0
|
|
|
|
|
0
|
croak "Cannot merge statement with mismatching owners"; |
141
|
|
|
|
|
|
|
} |
142
|
22
|
|
|
|
|
568
|
return $self; |
143
|
|
|
|
|
|
|
} |
144
|
|
|
|
|
|
|
|
145
|
5
|
|
|
5
|
1
|
11
|
sub add_years ($self, $range) { |
|
5
|
|
|
|
|
40
|
|
|
5
|
|
|
|
|
13
|
|
|
5
|
|
|
|
|
7
|
|
146
|
5
|
|
|
|
|
23
|
$self->span->set_range_as_string($range, $self->owner->identifier); |
147
|
5
|
|
|
|
|
492
|
$self->span->consolidate; |
148
|
5
|
|
|
|
|
118
|
return $self; |
149
|
|
|
|
|
|
|
} |
150
|
|
|
|
|
|
|
|
151
|
13
|
|
|
13
|
1
|
34
|
sub contains($self, $other) { |
|
13
|
|
|
|
|
22
|
|
|
13
|
|
|
|
|
22
|
|
|
13
|
|
|
|
|
21
|
|
152
|
13
|
100
|
|
|
|
36
|
return 0 unless $self->identifier eq $other->identifier; |
153
|
|
|
|
|
|
|
|
154
|
12
|
|
|
|
|
36
|
my $span = Array::IntSpan->new; |
155
|
12
|
|
|
|
|
164
|
$span->set_range_as_string(scalar $self->span->get_range_list, $self->identifier); |
156
|
|
|
|
|
|
|
# now $span is a copy of $self->span. Merge $other-span. |
157
|
12
|
|
|
|
|
450
|
$span->set_range_as_string(scalar $other->span->get_range_list, $self->identifier); |
158
|
12
|
|
|
|
|
784
|
$span->consolidate; |
159
|
|
|
|
|
|
|
|
160
|
|
|
|
|
|
|
# if other span is contained in self->span, the merged result is not changed. |
161
|
12
|
100
|
|
|
|
180
|
return scalar $span->get_range_list eq scalar $self->span->get_range_list ? 1 : 0; |
162
|
|
|
|
|
|
|
} |
163
|
|
|
|
|
|
|
|
164
|
|
|
|
|
|
|
1; |
165
|
|
|
|
|
|
|
|
166
|
|
|
|
|
|
|
# ABSTRACT: a copyright statement for one owner |
167
|
|
|
|
|
|
|
|
168
|
|
|
|
|
|
|
__END__ |
169
|
|
|
|
|
|
|
|
170
|
|
|
|
|
|
|
=pod |
171
|
|
|
|
|
|
|
|
172
|
|
|
|
|
|
|
=encoding UTF-8 |
173
|
|
|
|
|
|
|
|
174
|
|
|
|
|
|
|
=head1 NAME |
175
|
|
|
|
|
|
|
|
176
|
|
|
|
|
|
|
Software::Copyright::Statement - a copyright statement for one owner |
177
|
|
|
|
|
|
|
|
178
|
|
|
|
|
|
|
=head1 VERSION |
179
|
|
|
|
|
|
|
|
180
|
|
|
|
|
|
|
version 0.010 |
181
|
|
|
|
|
|
|
|
182
|
|
|
|
|
|
|
=head1 SYNOPSIS |
183
|
|
|
|
|
|
|
|
184
|
|
|
|
|
|
|
use Software::Copyright::Statement; |
185
|
|
|
|
|
|
|
|
186
|
|
|
|
|
|
|
my $statement = Software::Copyright::Statement->new('2020,2021, Joe <joe@example.com>'); |
187
|
|
|
|
|
|
|
|
188
|
|
|
|
|
|
|
$statement->name; # => is "Joe" |
189
|
|
|
|
|
|
|
$statement->email; # => is 'joe@example.com' |
190
|
|
|
|
|
|
|
$statement->range; # => is '2020, 2021' |
191
|
|
|
|
|
|
|
|
192
|
|
|
|
|
|
|
# merge records |
193
|
|
|
|
|
|
|
$statement->merge(Software::Copyright::Statement->new('2022, Joe <joe@example.com>')); |
194
|
|
|
|
|
|
|
$statement->range; # => is '2020-2022' |
195
|
|
|
|
|
|
|
|
196
|
|
|
|
|
|
|
# update the year range |
197
|
|
|
|
|
|
|
$statement->add_years('2015, 2016-2019')->stringify; # => is '2015-2022, Joe <joe@example.com>' |
198
|
|
|
|
|
|
|
|
199
|
|
|
|
|
|
|
# stringification |
200
|
|
|
|
|
|
|
my $string = "$statement"; # => is '2015-2022, Joe <joe@example.com>' |
201
|
|
|
|
|
|
|
|
202
|
|
|
|
|
|
|
# test if a statement "contains" another one |
203
|
|
|
|
|
|
|
my $st_2020 = Software::Copyright::Statement->new('2020, Joe <joe@example.com>'); |
204
|
|
|
|
|
|
|
$statement->contains($st_2020); # => is '1' |
205
|
|
|
|
|
|
|
|
206
|
|
|
|
|
|
|
=head1 DESCRIPTION |
207
|
|
|
|
|
|
|
|
208
|
|
|
|
|
|
|
This class holds one copyright statement, i.e. year range, name |
209
|
|
|
|
|
|
|
and email of one copyright contributor. |
210
|
|
|
|
|
|
|
|
211
|
|
|
|
|
|
|
On construction, a cleanup is done to make the statement more |
212
|
|
|
|
|
|
|
standard. Here are some cleanup example: |
213
|
|
|
|
|
|
|
|
214
|
|
|
|
|
|
|
2002-6 Joe => 2002-2006, Joe |
215
|
|
|
|
|
|
|
2001,2002,2003,2004 Joe => 2001-2004, Joe |
216
|
|
|
|
|
|
|
# found in markdown documents |
217
|
|
|
|
|
|
|
2002 Joe mailto:joe@example.com => 2002, Joe <joe@example.com> |
218
|
|
|
|
|
|
|
|
219
|
|
|
|
|
|
|
=head1 CONSTRUCTOR |
220
|
|
|
|
|
|
|
|
221
|
|
|
|
|
|
|
The constructor can be called without argument or with a string |
222
|
|
|
|
|
|
|
containing: |
223
|
|
|
|
|
|
|
|
224
|
|
|
|
|
|
|
=over |
225
|
|
|
|
|
|
|
|
226
|
|
|
|
|
|
|
=item * |
227
|
|
|
|
|
|
|
|
228
|
|
|
|
|
|
|
a year range (optional) |
229
|
|
|
|
|
|
|
|
230
|
|
|
|
|
|
|
=item * |
231
|
|
|
|
|
|
|
|
232
|
|
|
|
|
|
|
a name (mandatory) |
233
|
|
|
|
|
|
|
|
234
|
|
|
|
|
|
|
=item * |
235
|
|
|
|
|
|
|
|
236
|
|
|
|
|
|
|
an email address (optional) |
237
|
|
|
|
|
|
|
|
238
|
|
|
|
|
|
|
=back |
239
|
|
|
|
|
|
|
|
240
|
|
|
|
|
|
|
E.g: |
241
|
|
|
|
|
|
|
|
242
|
|
|
|
|
|
|
my $st = Software::Copyright::Statement->new(); |
243
|
|
|
|
|
|
|
my $st = Software::Copyright::Statement->new('2002, Joe <joe@example.com>'); |
244
|
|
|
|
|
|
|
|
245
|
|
|
|
|
|
|
=head1 Methods |
246
|
|
|
|
|
|
|
|
247
|
|
|
|
|
|
|
=head2 name |
248
|
|
|
|
|
|
|
|
249
|
|
|
|
|
|
|
Set or get owner's name |
250
|
|
|
|
|
|
|
|
251
|
|
|
|
|
|
|
=head2 email |
252
|
|
|
|
|
|
|
|
253
|
|
|
|
|
|
|
Set or get owner's name |
254
|
|
|
|
|
|
|
|
255
|
|
|
|
|
|
|
=head2 owner |
256
|
|
|
|
|
|
|
|
257
|
|
|
|
|
|
|
Returns a L<Software::Copyright::Owner> object. This object can be |
258
|
|
|
|
|
|
|
used as a string. |
259
|
|
|
|
|
|
|
|
260
|
|
|
|
|
|
|
=head2 merge |
261
|
|
|
|
|
|
|
|
262
|
|
|
|
|
|
|
Merge 2 statements. Note that the 2 statements must belong to the same |
263
|
|
|
|
|
|
|
owner (the name attributes must be identical). |
264
|
|
|
|
|
|
|
|
265
|
|
|
|
|
|
|
See the Synopsis for an example. |
266
|
|
|
|
|
|
|
|
267
|
|
|
|
|
|
|
This method returns C<$self> |
268
|
|
|
|
|
|
|
|
269
|
|
|
|
|
|
|
=head2 add_years |
270
|
|
|
|
|
|
|
|
271
|
|
|
|
|
|
|
Add a year range to the copyright owner. This method accepts year |
272
|
|
|
|
|
|
|
ranges like "2020", "2018, 2020", "2016-2020,2022". White spaces are |
273
|
|
|
|
|
|
|
ignored. |
274
|
|
|
|
|
|
|
|
275
|
|
|
|
|
|
|
This method returns C<$self> |
276
|
|
|
|
|
|
|
|
277
|
|
|
|
|
|
|
=head2 stringify |
278
|
|
|
|
|
|
|
|
279
|
|
|
|
|
|
|
Returns a string containing a year range (if any), a name and email |
280
|
|
|
|
|
|
|
(if any) of the copyright owner. |
281
|
|
|
|
|
|
|
|
282
|
|
|
|
|
|
|
=head2 contains |
283
|
|
|
|
|
|
|
|
284
|
|
|
|
|
|
|
Return 1 if the other statement is contained in current statement, |
285
|
|
|
|
|
|
|
i.e. owner or record are identical and other year range is contained |
286
|
|
|
|
|
|
|
in current year range. |
287
|
|
|
|
|
|
|
|
288
|
|
|
|
|
|
|
For instance: |
289
|
|
|
|
|
|
|
|
290
|
|
|
|
|
|
|
=over |
291
|
|
|
|
|
|
|
|
292
|
|
|
|
|
|
|
=item * |
293
|
|
|
|
|
|
|
|
294
|
|
|
|
|
|
|
C<2016, Joe> is contained in C<2014-2020, Joe> |
295
|
|
|
|
|
|
|
|
296
|
|
|
|
|
|
|
=item * |
297
|
|
|
|
|
|
|
|
298
|
|
|
|
|
|
|
C<2010, Joe> is B<not> contained in C<2014-2020, Joe> |
299
|
|
|
|
|
|
|
|
300
|
|
|
|
|
|
|
=back |
301
|
|
|
|
|
|
|
|
302
|
|
|
|
|
|
|
=head2 Operator overload |
303
|
|
|
|
|
|
|
|
304
|
|
|
|
|
|
|
Operator C<""> is overloaded to call C<stringify>. |
305
|
|
|
|
|
|
|
|
306
|
|
|
|
|
|
|
=head1 AUTHOR |
307
|
|
|
|
|
|
|
|
308
|
|
|
|
|
|
|
Dominique Dumont |
309
|
|
|
|
|
|
|
|
310
|
|
|
|
|
|
|
=head1 COPYRIGHT AND LICENSE |
311
|
|
|
|
|
|
|
|
312
|
|
|
|
|
|
|
This software is Copyright (c) 2022 by Dominique Dumont <dod@debian.org>. |
313
|
|
|
|
|
|
|
|
314
|
|
|
|
|
|
|
This is free software, licensed under: |
315
|
|
|
|
|
|
|
|
316
|
|
|
|
|
|
|
The GNU General Public License, Version 3, June 2007 |
317
|
|
|
|
|
|
|
|
318
|
|
|
|
|
|
|
=cut |