| line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
|
1
|
|
|
|
|
|
|
package DateTime::Locale; |
|
2
|
|
|
|
|
|
|
|
|
3
|
16
|
|
|
16
|
|
10103804
|
use 5.008004; |
|
|
16
|
|
|
|
|
155
|
|
|
4
|
|
|
|
|
|
|
|
|
5
|
16
|
|
|
16
|
|
86
|
use strict; |
|
|
16
|
|
|
|
|
39
|
|
|
|
16
|
|
|
|
|
360
|
|
|
6
|
16
|
|
|
16
|
|
76
|
use warnings; |
|
|
16
|
|
|
|
|
31
|
|
|
|
16
|
|
|
|
|
451
|
|
|
7
|
16
|
|
|
16
|
|
6207
|
use namespace::autoclean; |
|
|
16
|
|
|
|
|
234377
|
|
|
|
16
|
|
|
|
|
61
|
|
|
8
|
|
|
|
|
|
|
|
|
9
|
|
|
|
|
|
|
our $VERSION = '1.38'; |
|
10
|
|
|
|
|
|
|
|
|
11
|
16
|
|
|
16
|
|
17349
|
use DateTime::Locale::Data; |
|
|
16
|
|
|
|
|
526
|
|
|
|
16
|
|
|
|
|
1488
|
|
|
12
|
16
|
|
|
16
|
|
6868
|
use DateTime::Locale::FromData; |
|
|
16
|
|
|
|
|
63
|
|
|
|
16
|
|
|
|
|
568
|
|
|
13
|
16
|
|
|
16
|
|
118
|
use DateTime::Locale::Util qw( parse_locale_code ); |
|
|
16
|
|
|
|
|
35
|
|
|
|
16
|
|
|
|
|
781
|
|
|
14
|
16
|
|
|
16
|
|
94
|
use Params::ValidationCompiler 0.13 qw( validation_for ); |
|
|
16
|
|
|
|
|
348
|
|
|
|
16
|
|
|
|
|
623
|
|
|
15
|
16
|
|
|
16
|
|
6487
|
use Specio::Library::String; |
|
|
16
|
|
|
|
|
143294
|
|
|
|
16
|
|
|
|
|
136
|
|
|
16
|
|
|
|
|
|
|
|
|
17
|
|
|
|
|
|
|
my %Class; |
|
18
|
|
|
|
|
|
|
my %DataForCode; |
|
19
|
|
|
|
|
|
|
my %NameToCode; |
|
20
|
|
|
|
|
|
|
my %NativeNameToCode; |
|
21
|
|
|
|
|
|
|
my %UserDefinedAlias; |
|
22
|
|
|
|
|
|
|
|
|
23
|
|
|
|
|
|
|
my %LoadCache; |
|
24
|
|
|
|
|
|
|
|
|
25
|
|
|
|
|
|
|
sub register { |
|
26
|
8
|
|
|
8
|
0
|
9292
|
my $class = shift; |
|
27
|
|
|
|
|
|
|
|
|
28
|
8
|
|
|
|
|
54
|
%LoadCache = (); |
|
29
|
|
|
|
|
|
|
|
|
30
|
8
|
100
|
|
|
|
27
|
if ( ref $_[0] ) { |
|
31
|
2
|
|
|
|
|
11
|
$class->_register(%$_) foreach @_; |
|
32
|
|
|
|
|
|
|
} |
|
33
|
|
|
|
|
|
|
else { |
|
34
|
6
|
|
|
|
|
19
|
$class->_register(@_); |
|
35
|
|
|
|
|
|
|
} |
|
36
|
|
|
|
|
|
|
} |
|
37
|
|
|
|
|
|
|
|
|
38
|
|
|
|
|
|
|
sub _register { |
|
39
|
9
|
|
|
9
|
|
15
|
shift; |
|
40
|
9
|
|
|
|
|
36
|
my %p = @_; |
|
41
|
|
|
|
|
|
|
|
|
42
|
9
|
|
|
|
|
18
|
my $id = $p{id}; |
|
43
|
|
|
|
|
|
|
|
|
44
|
9
|
100
|
|
|
|
51
|
die q{'\@' or '=' are not allowed in locale ids} |
|
45
|
|
|
|
|
|
|
if $id =~ /[\@=]/; |
|
46
|
|
|
|
|
|
|
|
|
47
|
|
|
|
|
|
|
die |
|
48
|
|
|
|
|
|
|
"You cannot replace an existing locale ('$id') unless you also specify the 'replace' parameter as true\n" |
|
49
|
7
|
50
|
33
|
|
|
39
|
if !delete $p{replace} && exists $DataForCode{$id}; |
|
50
|
|
|
|
|
|
|
|
|
51
|
|
|
|
|
|
|
$p{native_language} = $p{en_language} |
|
52
|
7
|
50
|
|
|
|
24
|
unless exists $p{native_language}; |
|
53
|
|
|
|
|
|
|
|
|
54
|
7
|
|
|
|
|
10
|
my @en_pieces; |
|
55
|
|
|
|
|
|
|
my @native_pieces; |
|
56
|
7
|
|
|
|
|
15
|
foreach my $p (qw( language script territory variant )) { |
|
57
|
28
|
100
|
|
|
|
75
|
push @en_pieces, $p{"en_$p"} if exists $p{"en_$p"}; |
|
58
|
28
|
100
|
|
|
|
65
|
push @native_pieces, $p{"native_$p"} if exists $p{"native_$p"}; |
|
59
|
|
|
|
|
|
|
} |
|
60
|
|
|
|
|
|
|
|
|
61
|
7
|
|
|
|
|
23
|
$p{en_complete_name} = join q{ }, @en_pieces; |
|
62
|
7
|
|
|
|
|
18
|
$p{native_complete_name} = join q{ }, @native_pieces; |
|
63
|
|
|
|
|
|
|
|
|
64
|
7
|
|
|
|
|
28
|
$id =~ s/_/-/g; |
|
65
|
|
|
|
|
|
|
|
|
66
|
7
|
|
|
|
|
17
|
$DataForCode{$id} = \%p; |
|
67
|
|
|
|
|
|
|
|
|
68
|
7
|
|
|
|
|
18
|
$NameToCode{ $p{en_complete_name} } = $id; |
|
69
|
7
|
|
|
|
|
16
|
$NativeNameToCode{ $p{native_complete_name} } = $id; |
|
70
|
|
|
|
|
|
|
|
|
71
|
7
|
50
|
|
|
|
36
|
$Class{$id} = $p{class} if defined exists $p{class}; |
|
72
|
|
|
|
|
|
|
} |
|
73
|
|
|
|
|
|
|
|
|
74
|
|
|
|
|
|
|
sub register_from_data { |
|
75
|
1
|
|
|
1
|
1
|
14
|
shift; |
|
76
|
|
|
|
|
|
|
|
|
77
|
1
|
|
|
|
|
2
|
%LoadCache = (); |
|
78
|
|
|
|
|
|
|
|
|
79
|
1
|
50
|
|
|
|
11
|
my %p = ref $_[0] ? %{ $_[0] } : @_; |
|
|
0
|
|
|
|
|
0
|
|
|
80
|
|
|
|
|
|
|
|
|
81
|
1
|
|
|
|
|
2
|
my $code = $p{code}; |
|
82
|
|
|
|
|
|
|
|
|
83
|
1
|
50
|
|
|
|
5
|
die q{'\@' or '=' are not allowed in locale codes} |
|
84
|
|
|
|
|
|
|
if $code =~ /[\@=]/; |
|
85
|
|
|
|
|
|
|
|
|
86
|
1
|
|
|
|
|
2
|
$code =~ s/_/-/g; |
|
87
|
|
|
|
|
|
|
|
|
88
|
1
|
|
|
|
|
5
|
DateTime::Locale::Data::add_locale( $code, \%p ); |
|
89
|
1
|
|
|
|
|
5
|
return $LoadCache{$code} = DateTime::Locale::FromData->new( \%p ); |
|
90
|
|
|
|
|
|
|
} |
|
91
|
|
|
|
|
|
|
|
|
92
|
|
|
|
|
|
|
sub add_aliases { |
|
93
|
5
|
|
|
5
|
0
|
4947
|
shift; |
|
94
|
|
|
|
|
|
|
|
|
95
|
5
|
|
|
|
|
8
|
%LoadCache = (); |
|
96
|
|
|
|
|
|
|
|
|
97
|
5
|
50
|
|
|
|
17
|
my $aliases = ref $_[0] ? $_[0] : {@_}; |
|
98
|
|
|
|
|
|
|
|
|
99
|
5
|
|
|
|
|
7
|
for my $alias ( keys %{$aliases} ) { |
|
|
5
|
|
|
|
|
12
|
|
|
100
|
5
|
|
|
|
|
7
|
my $code = $aliases->{$alias}; |
|
101
|
|
|
|
|
|
|
|
|
102
|
5
|
100
|
|
|
|
17
|
die q{Can't alias an id to itself} |
|
103
|
|
|
|
|
|
|
if $alias eq $code; |
|
104
|
|
|
|
|
|
|
|
|
105
|
|
|
|
|
|
|
# check for overwrite? |
|
106
|
|
|
|
|
|
|
|
|
107
|
4
|
|
|
|
|
9
|
my %seen = ( $alias => 1, $code => 1 ); |
|
108
|
4
|
|
|
|
|
4
|
my $copy = $code; |
|
109
|
4
|
|
|
|
|
10
|
while ( $copy = $UserDefinedAlias{$copy} ) { |
|
110
|
|
|
|
|
|
|
die |
|
111
|
|
|
|
|
|
|
"Creating an alias from $alias to $code would create a loop.\n" |
|
112
|
4
|
100
|
|
|
|
13
|
if $seen{$copy}; |
|
113
|
|
|
|
|
|
|
|
|
114
|
3
|
|
|
|
|
7
|
$seen{$copy} = 1; |
|
115
|
|
|
|
|
|
|
} |
|
116
|
|
|
|
|
|
|
|
|
117
|
3
|
|
|
|
|
8
|
$UserDefinedAlias{$alias} = $code; |
|
118
|
|
|
|
|
|
|
} |
|
119
|
|
|
|
|
|
|
} |
|
120
|
|
|
|
|
|
|
|
|
121
|
|
|
|
|
|
|
sub remove_alias { |
|
122
|
1
|
|
|
1
|
0
|
2
|
shift; |
|
123
|
|
|
|
|
|
|
|
|
124
|
1
|
|
|
|
|
2
|
%LoadCache = (); |
|
125
|
|
|
|
|
|
|
|
|
126
|
1
|
|
|
|
|
13
|
my $alias = shift; |
|
127
|
|
|
|
|
|
|
|
|
128
|
1
|
|
|
|
|
6
|
return delete $UserDefinedAlias{$alias}; |
|
129
|
|
|
|
|
|
|
} |
|
130
|
|
|
|
|
|
|
|
|
131
|
|
|
|
|
|
|
# deprecated |
|
132
|
|
|
|
|
|
|
sub ids { |
|
133
|
0
|
|
|
0
|
0
|
0
|
shift->codes; |
|
134
|
|
|
|
|
|
|
} |
|
135
|
|
|
|
|
|
|
|
|
136
|
|
|
|
|
|
|
## no critic (Variables::ProhibitPackageVars) |
|
137
|
|
|
|
|
|
|
sub codes { |
|
138
|
|
|
|
|
|
|
wantarray |
|
139
|
2
|
50
|
|
2
|
1
|
1657
|
? keys %DateTime::Locale::Data::Codes |
|
140
|
|
|
|
|
|
|
: [ keys %DateTime::Locale::Data::Codes ]; |
|
141
|
|
|
|
|
|
|
} |
|
142
|
|
|
|
|
|
|
|
|
143
|
|
|
|
|
|
|
sub names { |
|
144
|
|
|
|
|
|
|
wantarray |
|
145
|
1
|
50
|
|
1
|
1
|
221
|
? keys %DateTime::Locale::Data::Names |
|
146
|
|
|
|
|
|
|
: [ keys %DateTime::Locale::Data::Names ]; |
|
147
|
|
|
|
|
|
|
} |
|
148
|
|
|
|
|
|
|
|
|
149
|
|
|
|
|
|
|
sub native_names { |
|
150
|
|
|
|
|
|
|
wantarray |
|
151
|
0
|
0
|
|
0
|
1
|
0
|
? keys %DateTime::Locale::Data::NativeNames |
|
152
|
|
|
|
|
|
|
: [ keys %DateTime::Locale::Data::NativeNames ]; |
|
153
|
|
|
|
|
|
|
} |
|
154
|
|
|
|
|
|
|
|
|
155
|
|
|
|
|
|
|
# These are hard-coded for backwards comaptibility with the DateTime::Language |
|
156
|
|
|
|
|
|
|
# code. |
|
157
|
|
|
|
|
|
|
my %DateTimeLanguageAliases = ( |
|
158
|
|
|
|
|
|
|
|
|
159
|
|
|
|
|
|
|
# 'Afar' => 'aa', |
|
160
|
|
|
|
|
|
|
'Amharic' => 'am-ET', |
|
161
|
|
|
|
|
|
|
'Austrian' => 'de-AT', |
|
162
|
|
|
|
|
|
|
'Brazilian' => 'pt-BR', |
|
163
|
|
|
|
|
|
|
'Czech' => 'cs-CZ', |
|
164
|
|
|
|
|
|
|
'Danish' => 'da-DK', |
|
165
|
|
|
|
|
|
|
'Dutch' => 'nl-NL', |
|
166
|
|
|
|
|
|
|
'English' => 'en-US', |
|
167
|
|
|
|
|
|
|
'French' => 'fr-FR', |
|
168
|
|
|
|
|
|
|
|
|
169
|
|
|
|
|
|
|
# 'Gedeo' => undef, # XXX |
|
170
|
|
|
|
|
|
|
'German' => 'de-DE', |
|
171
|
|
|
|
|
|
|
'Italian' => 'it-IT', |
|
172
|
|
|
|
|
|
|
'Norwegian' => 'no-NO', |
|
173
|
|
|
|
|
|
|
'Oromo' => 'om-ET', # Maybe om-KE or plain om ? |
|
174
|
|
|
|
|
|
|
'Portugese' => 'pt-PT', |
|
175
|
|
|
|
|
|
|
|
|
176
|
|
|
|
|
|
|
# 'Sidama' => 'sid', |
|
177
|
|
|
|
|
|
|
'Somali' => 'so-SO', |
|
178
|
|
|
|
|
|
|
'Spanish' => 'es-ES', |
|
179
|
|
|
|
|
|
|
'Swedish' => 'sv-SE', |
|
180
|
|
|
|
|
|
|
|
|
181
|
|
|
|
|
|
|
# 'Tigre' => 'tig', |
|
182
|
|
|
|
|
|
|
'TigrinyaEthiopian' => 'ti-ET', |
|
183
|
|
|
|
|
|
|
'TigrinyaEritrean' => 'ti-ER', |
|
184
|
|
|
|
|
|
|
); |
|
185
|
|
|
|
|
|
|
|
|
186
|
|
|
|
|
|
|
my %POSIXAliases = ( |
|
187
|
|
|
|
|
|
|
C => 'en-US', |
|
188
|
|
|
|
|
|
|
POSIX => 'en-US', |
|
189
|
|
|
|
|
|
|
); |
|
190
|
|
|
|
|
|
|
|
|
191
|
|
|
|
|
|
|
{ |
|
192
|
|
|
|
|
|
|
my $validator = validation_for( |
|
193
|
|
|
|
|
|
|
name => '_check_load_params', |
|
194
|
|
|
|
|
|
|
name_is_optional => 1, |
|
195
|
|
|
|
|
|
|
params => [ |
|
196
|
|
|
|
|
|
|
{ type => t('NonEmptyStr') }, |
|
197
|
|
|
|
|
|
|
], |
|
198
|
|
|
|
|
|
|
); |
|
199
|
|
|
|
|
|
|
|
|
200
|
|
|
|
|
|
|
sub load { |
|
201
|
1070
|
|
|
1070
|
1
|
4080602
|
my $class = shift; |
|
202
|
1070
|
|
|
|
|
24234
|
my ($code) = $validator->(@_); |
|
203
|
|
|
|
|
|
|
|
|
204
|
|
|
|
|
|
|
# We used to use underscores in codes instead of dashes. We want to |
|
205
|
|
|
|
|
|
|
# support both indefinitely. |
|
206
|
1070
|
|
|
|
|
11823
|
$code =~ tr/_/-/; |
|
207
|
|
|
|
|
|
|
|
|
208
|
|
|
|
|
|
|
# Strip off charset for LC_* codes : en_GB.UTF-8 etc |
|
209
|
1070
|
|
|
|
|
2135
|
$code =~ s/\..*$//; |
|
210
|
|
|
|
|
|
|
|
|
211
|
1070
|
100
|
|
|
|
2984
|
return $LoadCache{$code} if exists $LoadCache{$code}; |
|
212
|
|
|
|
|
|
|
|
|
213
|
1059
|
|
|
|
|
2297
|
while ( exists $UserDefinedAlias{$code} ) { |
|
214
|
3
|
|
|
|
|
7
|
$code = $UserDefinedAlias{$code}; |
|
215
|
|
|
|
|
|
|
} |
|
216
|
|
|
|
|
|
|
|
|
217
|
|
|
|
|
|
|
$code = $DateTimeLanguageAliases{$code} |
|
218
|
1059
|
100
|
|
|
|
2222
|
if exists $DateTimeLanguageAliases{$code}; |
|
219
|
1059
|
100
|
|
|
|
1864
|
$code = $POSIXAliases{$code} if exists $POSIXAliases{$code}; |
|
220
|
|
|
|
|
|
|
$code = $DateTime::Locale::Data::ISO639Aliases{$code} |
|
221
|
1059
|
100
|
|
|
|
2489
|
if exists $DateTime::Locale::Data::ISO639Aliases{$code}; |
|
222
|
|
|
|
|
|
|
|
|
223
|
1059
|
100
|
|
|
|
2488
|
if ( exists $DateTime::Locale::Data::Codes{$code} ) { |
|
224
|
1040
|
|
|
|
|
2590
|
return $class->_locale_object_for($code); |
|
225
|
|
|
|
|
|
|
} |
|
226
|
|
|
|
|
|
|
|
|
227
|
19
|
100
|
|
|
|
60
|
if ( exists $DateTime::Locale::Data::Names{$code} ) { |
|
228
|
|
|
|
|
|
|
return $class->_locale_object_for( |
|
229
|
4
|
|
|
|
|
24
|
$DateTime::Locale::Data::Names{$code} ); |
|
230
|
|
|
|
|
|
|
} |
|
231
|
|
|
|
|
|
|
|
|
232
|
15
|
100
|
|
|
|
56
|
if ( exists $DateTime::Locale::Data::NativeNames{$code} ) { |
|
233
|
|
|
|
|
|
|
return $class->_locale_object_for( |
|
234
|
1
|
|
|
|
|
38
|
$DateTime::Locale::Data::NativeNames{$code} ); |
|
235
|
|
|
|
|
|
|
} |
|
236
|
|
|
|
|
|
|
|
|
237
|
14
|
100
|
|
|
|
41
|
if ( my $locale = $class->_registered_locale_for($code) ) { |
|
238
|
7
|
|
|
|
|
19
|
return $locale; |
|
239
|
|
|
|
|
|
|
} |
|
240
|
|
|
|
|
|
|
|
|
241
|
7
|
100
|
|
|
|
17
|
if ( my $guessed = $class->_guess_code($code) ) { |
|
242
|
5
|
|
|
|
|
10
|
return $class->_locale_object_for($guessed); |
|
243
|
|
|
|
|
|
|
} |
|
244
|
|
|
|
|
|
|
|
|
245
|
2
|
|
|
|
|
13
|
die "Invalid locale code or name: $code\n"; |
|
246
|
|
|
|
|
|
|
} |
|
247
|
|
|
|
|
|
|
} |
|
248
|
|
|
|
|
|
|
|
|
249
|
|
|
|
|
|
|
sub _guess_code { |
|
250
|
7
|
|
|
7
|
|
7
|
shift; |
|
251
|
7
|
|
|
|
|
11
|
my $code = shift; |
|
252
|
|
|
|
|
|
|
|
|
253
|
7
|
|
|
|
|
27
|
my %codes = parse_locale_code($code); |
|
254
|
|
|
|
|
|
|
|
|
255
|
7
|
|
|
|
|
12
|
my @guesses; |
|
256
|
|
|
|
|
|
|
|
|
257
|
7
|
100
|
|
|
|
28
|
if ( $codes{script} ) { |
|
258
|
1
|
|
|
|
|
3
|
my $guess = join q{-}, $codes{language}, $codes{script}; |
|
259
|
|
|
|
|
|
|
|
|
260
|
1
|
|
|
|
|
3
|
push @guesses, $guess; |
|
261
|
|
|
|
|
|
|
|
|
262
|
1
|
50
|
|
|
|
3
|
$guess .= q{-} . $codes{territory} if defined $codes{territory}; |
|
263
|
|
|
|
|
|
|
|
|
264
|
|
|
|
|
|
|
# version with script comes first |
|
265
|
1
|
|
|
|
|
2
|
unshift @guesses, $guess; |
|
266
|
|
|
|
|
|
|
} |
|
267
|
|
|
|
|
|
|
|
|
268
|
7
|
50
|
|
|
|
43
|
if ( $codes{variant} ) { |
|
269
|
|
|
|
|
|
|
push @guesses, join q{-}, $codes{language}, $codes{territory}, |
|
270
|
0
|
|
|
|
|
0
|
$codes{variant}; |
|
271
|
|
|
|
|
|
|
} |
|
272
|
|
|
|
|
|
|
|
|
273
|
7
|
100
|
|
|
|
16
|
if ( $codes{territory} ) { |
|
274
|
4
|
|
|
|
|
28
|
push @guesses, join q{-}, $codes{language}, $codes{territory}; |
|
275
|
|
|
|
|
|
|
} |
|
276
|
|
|
|
|
|
|
|
|
277
|
7
|
|
|
|
|
15
|
push @guesses, $codes{language}; |
|
278
|
|
|
|
|
|
|
|
|
279
|
7
|
|
|
|
|
15
|
for my $code (@guesses) { |
|
280
|
|
|
|
|
|
|
return $code |
|
281
|
|
|
|
|
|
|
if exists $DateTime::Locale::Data::Codes{$code} |
|
282
|
7
|
100
|
66
|
|
|
45
|
|| exists $DateTime::Locale::Data::Names{$code}; |
|
283
|
|
|
|
|
|
|
} |
|
284
|
|
|
|
|
|
|
} |
|
285
|
|
|
|
|
|
|
|
|
286
|
|
|
|
|
|
|
sub _locale_object_for { |
|
287
|
1050
|
|
|
1050
|
|
1409
|
shift; |
|
288
|
1050
|
|
|
|
|
1581
|
my $code = shift; |
|
289
|
|
|
|
|
|
|
|
|
290
|
1050
|
50
|
|
|
|
2896
|
my $data = DateTime::Locale::Data::locale_data($code) |
|
291
|
|
|
|
|
|
|
or return; |
|
292
|
|
|
|
|
|
|
|
|
293
|
|
|
|
|
|
|
# We want to make a copy of the data just in case ... |
|
294
|
1050
|
|
|
|
|
1593
|
return $LoadCache{$code} = DateTime::Locale::FromData->new( \%{$data} ); |
|
|
1050
|
|
|
|
|
6044
|
|
|
295
|
|
|
|
|
|
|
} |
|
296
|
|
|
|
|
|
|
|
|
297
|
|
|
|
|
|
|
sub _registered_locale_for { |
|
298
|
14
|
|
|
14
|
|
25
|
my $class = shift; |
|
299
|
14
|
|
|
|
|
23
|
my $code = shift; |
|
300
|
|
|
|
|
|
|
|
|
301
|
|
|
|
|
|
|
# Custom locale registered by user |
|
302
|
14
|
100
|
|
|
|
33
|
if ( $Class{$code} ) { |
|
303
|
|
|
|
|
|
|
return $LoadCache{$code} |
|
304
|
2
|
|
|
|
|
7
|
= $class->_load_class_from_code( $code, $Class{$code} ); |
|
305
|
|
|
|
|
|
|
} |
|
306
|
|
|
|
|
|
|
|
|
307
|
12
|
100
|
|
|
|
25
|
if ( $DataForCode{$code} ) { |
|
308
|
5
|
|
|
|
|
12
|
return $LoadCache{$code} = $class->_load_class_from_code($code); |
|
309
|
|
|
|
|
|
|
} |
|
310
|
|
|
|
|
|
|
|
|
311
|
7
|
50
|
|
|
|
13
|
if ( $NameToCode{$code} ) { |
|
312
|
|
|
|
|
|
|
return $LoadCache{$code} |
|
313
|
0
|
|
|
|
|
0
|
= $class->_load_class_from_code( $NameToCode{$code} ); |
|
314
|
|
|
|
|
|
|
} |
|
315
|
|
|
|
|
|
|
|
|
316
|
7
|
50
|
|
|
|
23
|
if ( $NativeNameToCode{$code} ) { |
|
317
|
|
|
|
|
|
|
return $LoadCache{$code} |
|
318
|
0
|
|
|
|
|
0
|
= $class->_load_class_from_code( $NativeNameToCode{$code} ); |
|
319
|
|
|
|
|
|
|
} |
|
320
|
|
|
|
|
|
|
} |
|
321
|
|
|
|
|
|
|
|
|
322
|
|
|
|
|
|
|
sub _load_class_from_code { |
|
323
|
7
|
|
|
7
|
|
11
|
my $class = shift; |
|
324
|
7
|
|
|
|
|
11
|
my $code = shift; |
|
325
|
7
|
|
|
|
|
9
|
my $real_class = shift; |
|
326
|
|
|
|
|
|
|
|
|
327
|
|
|
|
|
|
|
# We want the first alias for which there is data, even if it has |
|
328
|
|
|
|
|
|
|
# no corresponding .pm file. There may be multiple levels of |
|
329
|
|
|
|
|
|
|
# alias to go through. |
|
330
|
7
|
|
|
|
|
11
|
my $data_code = $code; |
|
331
|
7
|
|
33
|
|
|
18
|
while ( exists $UserDefinedAlias{$data_code} |
|
332
|
|
|
|
|
|
|
&& !exists $DataForCode{$data_code} ) { |
|
333
|
|
|
|
|
|
|
|
|
334
|
0
|
|
|
|
|
0
|
$data_code = $UserDefinedAlias{$data_code}; |
|
335
|
|
|
|
|
|
|
} |
|
336
|
|
|
|
|
|
|
|
|
337
|
7
|
|
|
|
|
26
|
( my $underscore_code = $data_code ) =~ s/-/_/g; |
|
338
|
7
|
|
66
|
|
|
32
|
$real_class ||= "DateTime::Locale::$underscore_code"; |
|
339
|
|
|
|
|
|
|
|
|
340
|
7
|
50
|
|
|
|
92
|
unless ( $real_class->can('new') ) { |
|
341
|
|
|
|
|
|
|
## no critic (BuiltinFunctions::ProhibitStringyEval, ErrorHandling::RequireCheckingReturnValueOfEval) |
|
342
|
0
|
|
|
|
|
0
|
eval "require $real_class"; |
|
343
|
0
|
0
|
|
|
|
0
|
die $@ if $@; |
|
344
|
|
|
|
|
|
|
## use critic |
|
345
|
|
|
|
|
|
|
} |
|
346
|
|
|
|
|
|
|
|
|
347
|
|
|
|
|
|
|
my $locale = $real_class->new( |
|
348
|
7
|
|
|
|
|
10
|
%{ $DataForCode{$data_code} }, |
|
|
7
|
|
|
|
|
39
|
|
|
349
|
|
|
|
|
|
|
code => $code, |
|
350
|
|
|
|
|
|
|
); |
|
351
|
|
|
|
|
|
|
|
|
352
|
7
|
100
|
|
|
|
49
|
if ( $locale->can('cldr_version') ) { |
|
353
|
1
|
|
|
|
|
3
|
my $object_version = $locale->cldr_version; |
|
354
|
|
|
|
|
|
|
|
|
355
|
1
|
50
|
|
|
|
8
|
if ( $object_version ne $DateTime::Locale::Data::CLDRVersion ) { |
|
356
|
1
|
|
|
|
|
12
|
warn |
|
357
|
|
|
|
|
|
|
"Loaded $real_class, which is from an older version ($object_version)" |
|
358
|
|
|
|
|
|
|
. ' of the CLDR database than this installation of' |
|
359
|
|
|
|
|
|
|
. " DateTime::Locale ($DateTime::Locale::Data::CLDRVersion).\n"; |
|
360
|
|
|
|
|
|
|
} |
|
361
|
|
|
|
|
|
|
} |
|
362
|
|
|
|
|
|
|
|
|
363
|
7
|
|
|
|
|
60
|
return $locale; |
|
364
|
|
|
|
|
|
|
} |
|
365
|
|
|
|
|
|
|
## use critic |
|
366
|
|
|
|
|
|
|
|
|
367
|
|
|
|
|
|
|
1; |
|
368
|
|
|
|
|
|
|
|
|
369
|
|
|
|
|
|
|
# ABSTRACT: Localization support for DateTime.pm |
|
370
|
|
|
|
|
|
|
|
|
371
|
|
|
|
|
|
|
__END__ |
|
372
|
|
|
|
|
|
|
|
|
373
|
|
|
|
|
|
|
=pod |
|
374
|
|
|
|
|
|
|
|
|
375
|
|
|
|
|
|
|
=encoding UTF-8 |
|
376
|
|
|
|
|
|
|
|
|
377
|
|
|
|
|
|
|
=head1 NAME |
|
378
|
|
|
|
|
|
|
|
|
379
|
|
|
|
|
|
|
DateTime::Locale - Localization support for DateTime.pm |
|
380
|
|
|
|
|
|
|
|
|
381
|
|
|
|
|
|
|
=head1 VERSION |
|
382
|
|
|
|
|
|
|
|
|
383
|
|
|
|
|
|
|
version 1.38 |
|
384
|
|
|
|
|
|
|
|
|
385
|
|
|
|
|
|
|
=head1 SYNOPSIS |
|
386
|
|
|
|
|
|
|
|
|
387
|
|
|
|
|
|
|
use DateTime::Locale; |
|
388
|
|
|
|
|
|
|
|
|
389
|
|
|
|
|
|
|
my $loc = DateTime::Locale->load('en-GB'); |
|
390
|
|
|
|
|
|
|
|
|
391
|
|
|
|
|
|
|
print $loc->native_name, "\n", $loc->datetime_format_long, "\n"; |
|
392
|
|
|
|
|
|
|
|
|
393
|
|
|
|
|
|
|
# but mostly just things like ... |
|
394
|
|
|
|
|
|
|
|
|
395
|
|
|
|
|
|
|
my $dt = DateTime->now( locale => 'fr' ); |
|
396
|
|
|
|
|
|
|
print "Aujourd'hui le mois est " . $dt->month_name, "\n"; |
|
397
|
|
|
|
|
|
|
|
|
398
|
|
|
|
|
|
|
=head1 DESCRIPTION |
|
399
|
|
|
|
|
|
|
|
|
400
|
|
|
|
|
|
|
DateTime::Locale is primarily a factory for the various locale subclasses. It |
|
401
|
|
|
|
|
|
|
also provides some functions for getting information on all the available |
|
402
|
|
|
|
|
|
|
locales. |
|
403
|
|
|
|
|
|
|
|
|
404
|
|
|
|
|
|
|
If you want to know what methods are available for locale objects, then please |
|
405
|
|
|
|
|
|
|
read the L<DateTime::Locale::FromData> documentation. |
|
406
|
|
|
|
|
|
|
|
|
407
|
|
|
|
|
|
|
=head1 USAGE |
|
408
|
|
|
|
|
|
|
|
|
409
|
|
|
|
|
|
|
This module provides the following class methods: |
|
410
|
|
|
|
|
|
|
|
|
411
|
|
|
|
|
|
|
=head2 DateTime::Locale->load( $locale_code | $locale_name ) |
|
412
|
|
|
|
|
|
|
|
|
413
|
|
|
|
|
|
|
Returns the locale object for the specified locale code or name - see the |
|
414
|
|
|
|
|
|
|
L<DateTime::Locale::Catalog> documentation for the list of available codes and |
|
415
|
|
|
|
|
|
|
names. The name provided may be either the English or native name. |
|
416
|
|
|
|
|
|
|
|
|
417
|
|
|
|
|
|
|
If the requested locale is not found, a fallback search takes place to find a |
|
418
|
|
|
|
|
|
|
suitable replacement. |
|
419
|
|
|
|
|
|
|
|
|
420
|
|
|
|
|
|
|
The fallback search order is: |
|
421
|
|
|
|
|
|
|
|
|
422
|
|
|
|
|
|
|
{language}-{script}-{territory} |
|
423
|
|
|
|
|
|
|
{language}-{script} |
|
424
|
|
|
|
|
|
|
{language}-{territory}-{variant} |
|
425
|
|
|
|
|
|
|
{language}-{territory} |
|
426
|
|
|
|
|
|
|
{language} |
|
427
|
|
|
|
|
|
|
|
|
428
|
|
|
|
|
|
|
Eg. For the locale code C<es-XX-UNKNOWN> the fallback search would be: |
|
429
|
|
|
|
|
|
|
|
|
430
|
|
|
|
|
|
|
es-XX-UNKNOWN # Fails - no such locale |
|
431
|
|
|
|
|
|
|
es-XX # Fails - no such locale |
|
432
|
|
|
|
|
|
|
es # Found - the es locale is returned as the |
|
433
|
|
|
|
|
|
|
# closest match to the requested id |
|
434
|
|
|
|
|
|
|
|
|
435
|
|
|
|
|
|
|
Eg. For the locale code C<es-Latn-XX> the fallback search would be: |
|
436
|
|
|
|
|
|
|
|
|
437
|
|
|
|
|
|
|
es-Latn-XX # Fails - no such locale |
|
438
|
|
|
|
|
|
|
es-Latn # Fails - no such locale |
|
439
|
|
|
|
|
|
|
es-XX # Fails - no such locale |
|
440
|
|
|
|
|
|
|
es # Found - the es locale is returned as the |
|
441
|
|
|
|
|
|
|
# closest match to the requested id |
|
442
|
|
|
|
|
|
|
|
|
443
|
|
|
|
|
|
|
If no suitable replacement is found, then an exception is thrown. |
|
444
|
|
|
|
|
|
|
|
|
445
|
|
|
|
|
|
|
The loaded locale is cached, so that B<locale objects may be singletons>. |
|
446
|
|
|
|
|
|
|
Calling C<< DateTime::Locale->register_from_data >>, C<< |
|
447
|
|
|
|
|
|
|
DateTime::Locale->add_aliases >>, or C<< DateTime::Locale->remove_alias >> |
|
448
|
|
|
|
|
|
|
clears the cache. |
|
449
|
|
|
|
|
|
|
|
|
450
|
|
|
|
|
|
|
=head2 DateTime::Locale->codes |
|
451
|
|
|
|
|
|
|
|
|
452
|
|
|
|
|
|
|
my @codes = DateTime::Locale->codes; |
|
453
|
|
|
|
|
|
|
my $codes = DateTime::Locale->codes; |
|
454
|
|
|
|
|
|
|
|
|
455
|
|
|
|
|
|
|
Returns an unsorted list of the available locale codes, or an array reference |
|
456
|
|
|
|
|
|
|
if called in a scalar context. This list does not include aliases. |
|
457
|
|
|
|
|
|
|
|
|
458
|
|
|
|
|
|
|
=head2 DateTime::Locale->names |
|
459
|
|
|
|
|
|
|
|
|
460
|
|
|
|
|
|
|
my @names = DateTime::Locale->names; |
|
461
|
|
|
|
|
|
|
my $names = DateTime::Locale->names; |
|
462
|
|
|
|
|
|
|
|
|
463
|
|
|
|
|
|
|
Returns an unsorted list of the available locale names in English, or an array |
|
464
|
|
|
|
|
|
|
reference if called in a scalar context. |
|
465
|
|
|
|
|
|
|
|
|
466
|
|
|
|
|
|
|
=head2 DateTime::Locale->native_names |
|
467
|
|
|
|
|
|
|
|
|
468
|
|
|
|
|
|
|
my @names = DateTime::Locale->native_names; |
|
469
|
|
|
|
|
|
|
my $names = DateTime::Locale->native_names; |
|
470
|
|
|
|
|
|
|
|
|
471
|
|
|
|
|
|
|
Returns an unsorted list of the available locale names in their native |
|
472
|
|
|
|
|
|
|
language, or an array reference if called in a scalar context. All native names |
|
473
|
|
|
|
|
|
|
use UTF-8 as appropriate. |
|
474
|
|
|
|
|
|
|
|
|
475
|
|
|
|
|
|
|
=head2 DateTime::Locale->register_from_data( $locale_data ) |
|
476
|
|
|
|
|
|
|
|
|
477
|
|
|
|
|
|
|
This method allows you to register a custom locale. The data for the locale is |
|
478
|
|
|
|
|
|
|
specified as a hash (or hashref) where the keys match the method names given in |
|
479
|
|
|
|
|
|
|
L<DateTime::Locale::FromData>. |
|
480
|
|
|
|
|
|
|
|
|
481
|
|
|
|
|
|
|
If you just want to make some small changes on top of an existing locale you |
|
482
|
|
|
|
|
|
|
can get that locale's data by calling C<< $locale->locale_data >>. |
|
483
|
|
|
|
|
|
|
|
|
484
|
|
|
|
|
|
|
Here is an example of making a custom locale based off of C<en-US>: |
|
485
|
|
|
|
|
|
|
|
|
486
|
|
|
|
|
|
|
my $locale = DateTime::Locale->load('en-US'); |
|
487
|
|
|
|
|
|
|
my %data = $locale->locale_data; |
|
488
|
|
|
|
|
|
|
$data{code} = 'en-US-CUSTOM'; |
|
489
|
|
|
|
|
|
|
$data{time_format_medium} = 'HH:mm:ss'; |
|
490
|
|
|
|
|
|
|
|
|
491
|
|
|
|
|
|
|
DateTime::Locale->register_from_data(%data); |
|
492
|
|
|
|
|
|
|
|
|
493
|
|
|
|
|
|
|
# Prints 18:24:38 |
|
494
|
|
|
|
|
|
|
say DateTime->now( locale => 'en-US-CUSTOM' )->strftime('%X'); |
|
495
|
|
|
|
|
|
|
|
|
496
|
|
|
|
|
|
|
# Prints 6:24:38 PM |
|
497
|
|
|
|
|
|
|
say DateTime->now( locale => 'en-US' )->strftime('%X'); |
|
498
|
|
|
|
|
|
|
|
|
499
|
|
|
|
|
|
|
The keys that should be present in the hash are the same as the accessor |
|
500
|
|
|
|
|
|
|
methods provided by L<DateTime::Locale::FromData>, except for the following: |
|
501
|
|
|
|
|
|
|
|
|
502
|
|
|
|
|
|
|
=over 4 |
|
503
|
|
|
|
|
|
|
|
|
504
|
|
|
|
|
|
|
=item The C<*_code> methods |
|
505
|
|
|
|
|
|
|
|
|
506
|
|
|
|
|
|
|
While you should provide a C<code> key, the other methods like C<language_code> |
|
507
|
|
|
|
|
|
|
and C<script_code> are determined by parsing the code. |
|
508
|
|
|
|
|
|
|
|
|
509
|
|
|
|
|
|
|
=item All C<id> returning methods |
|
510
|
|
|
|
|
|
|
|
|
511
|
|
|
|
|
|
|
These are aliases for the corresponding C<*code> methods. |
|
512
|
|
|
|
|
|
|
|
|
513
|
|
|
|
|
|
|
=item C<prefers_24_hour_time> |
|
514
|
|
|
|
|
|
|
|
|
515
|
|
|
|
|
|
|
This is determined by looking at the short time format to see how it formats |
|
516
|
|
|
|
|
|
|
hours, |
|
517
|
|
|
|
|
|
|
|
|
518
|
|
|
|
|
|
|
=item C<date_format_default> and C<time_format_default> |
|
519
|
|
|
|
|
|
|
|
|
520
|
|
|
|
|
|
|
These are the corresponding medium formats. |
|
521
|
|
|
|
|
|
|
|
|
522
|
|
|
|
|
|
|
=item C<datetime_format> and C<datetime_format_default> |
|
523
|
|
|
|
|
|
|
|
|
524
|
|
|
|
|
|
|
This is the same as the medium format. |
|
525
|
|
|
|
|
|
|
|
|
526
|
|
|
|
|
|
|
=item C<date_formats> and C<time_formats> |
|
527
|
|
|
|
|
|
|
|
|
528
|
|
|
|
|
|
|
These are calculated as needed. |
|
529
|
|
|
|
|
|
|
|
|
530
|
|
|
|
|
|
|
=item C<available_formats> |
|
531
|
|
|
|
|
|
|
|
|
532
|
|
|
|
|
|
|
This should be provided as a hashref where the keys are things like C<Gy> or |
|
533
|
|
|
|
|
|
|
C<MMMEd> and the values are an actual format like C<"y G"> or C<"E, MMM d">. |
|
534
|
|
|
|
|
|
|
|
|
535
|
|
|
|
|
|
|
=item C<locale_data> |
|
536
|
|
|
|
|
|
|
|
|
537
|
|
|
|
|
|
|
This is everything you pass in. |
|
538
|
|
|
|
|
|
|
|
|
539
|
|
|
|
|
|
|
=back |
|
540
|
|
|
|
|
|
|
|
|
541
|
|
|
|
|
|
|
=head1 LOADING LOCALES IN A PRE-FORKING SYSTEM |
|
542
|
|
|
|
|
|
|
|
|
543
|
|
|
|
|
|
|
If you are running an application that does pre-forking (for example with |
|
544
|
|
|
|
|
|
|
Starman), then you should try to load all the locales that you'll need in the |
|
545
|
|
|
|
|
|
|
parent process. Locales are loaded on-demand, so loading them once in each |
|
546
|
|
|
|
|
|
|
child will waste memory that could otherwise be shared. |
|
547
|
|
|
|
|
|
|
|
|
548
|
|
|
|
|
|
|
=head1 CLDR DATA BUGS |
|
549
|
|
|
|
|
|
|
|
|
550
|
|
|
|
|
|
|
Please be aware that all locale data has been generated from the CLDR (Common |
|
551
|
|
|
|
|
|
|
Locale Data Repository) project locales data). The data is incomplete, and may |
|
552
|
|
|
|
|
|
|
contain errors in some locales. |
|
553
|
|
|
|
|
|
|
|
|
554
|
|
|
|
|
|
|
When reporting errors in data, please check the primary data sources first, |
|
555
|
|
|
|
|
|
|
then where necessary report errors directly to the primary source via the CLDR |
|
556
|
|
|
|
|
|
|
bug report system. See L<http://unicode.org/cldr/filing_bug_reports.html> for |
|
557
|
|
|
|
|
|
|
details. |
|
558
|
|
|
|
|
|
|
|
|
559
|
|
|
|
|
|
|
Once these errors have been confirmed, please forward the error report and |
|
560
|
|
|
|
|
|
|
corrections to the DateTime mailing list, datetime@perl.org. |
|
561
|
|
|
|
|
|
|
|
|
562
|
|
|
|
|
|
|
=head1 AUTHOR EMERITUS |
|
563
|
|
|
|
|
|
|
|
|
564
|
|
|
|
|
|
|
Richard Evans wrote the first version of DateTime::Locale, including the tools |
|
565
|
|
|
|
|
|
|
to extract the CLDR data. |
|
566
|
|
|
|
|
|
|
|
|
567
|
|
|
|
|
|
|
=head1 SEE ALSO |
|
568
|
|
|
|
|
|
|
|
|
569
|
|
|
|
|
|
|
datetime@perl.org mailing list |
|
570
|
|
|
|
|
|
|
|
|
571
|
|
|
|
|
|
|
=head1 SUPPORT |
|
572
|
|
|
|
|
|
|
|
|
573
|
|
|
|
|
|
|
Bugs may be submitted at L<https://github.com/houseabsolute/DateTime-Locale/issues>. |
|
574
|
|
|
|
|
|
|
|
|
575
|
|
|
|
|
|
|
There is a mailing list available for users of this distribution, |
|
576
|
|
|
|
|
|
|
L<mailto:datetime@perl.org>. |
|
577
|
|
|
|
|
|
|
|
|
578
|
|
|
|
|
|
|
=head1 SOURCE |
|
579
|
|
|
|
|
|
|
|
|
580
|
|
|
|
|
|
|
The source code repository for DateTime-Locale can be found at L<https://github.com/houseabsolute/DateTime-Locale>. |
|
581
|
|
|
|
|
|
|
|
|
582
|
|
|
|
|
|
|
=head1 DONATIONS |
|
583
|
|
|
|
|
|
|
|
|
584
|
|
|
|
|
|
|
If you'd like to thank me for the work I've done on this module, please |
|
585
|
|
|
|
|
|
|
consider making a "donation" to me via PayPal. I spend a lot of free time |
|
586
|
|
|
|
|
|
|
creating free software, and would appreciate any support you'd care to offer. |
|
587
|
|
|
|
|
|
|
|
|
588
|
|
|
|
|
|
|
Please note that B<I am not suggesting that you must do this> in order for me |
|
589
|
|
|
|
|
|
|
to continue working on this particular software. I will continue to do so, |
|
590
|
|
|
|
|
|
|
inasmuch as I have in the past, for as long as it interests me. |
|
591
|
|
|
|
|
|
|
|
|
592
|
|
|
|
|
|
|
Similarly, a donation made in this way will probably not make me work on this |
|
593
|
|
|
|
|
|
|
software much more, unless I get so many donations that I can consider working |
|
594
|
|
|
|
|
|
|
on free software full time (let's all have a chuckle at that together). |
|
595
|
|
|
|
|
|
|
|
|
596
|
|
|
|
|
|
|
To donate, log into PayPal and send money to autarch@urth.org, or use the |
|
597
|
|
|
|
|
|
|
button at L<https://houseabsolute.com/foss-donations/>. |
|
598
|
|
|
|
|
|
|
|
|
599
|
|
|
|
|
|
|
=head1 AUTHOR |
|
600
|
|
|
|
|
|
|
|
|
601
|
|
|
|
|
|
|
Dave Rolsky <autarch@urth.org> |
|
602
|
|
|
|
|
|
|
|
|
603
|
|
|
|
|
|
|
=head1 CONTRIBUTORS |
|
604
|
|
|
|
|
|
|
|
|
605
|
|
|
|
|
|
|
=for stopwords Alexander Pankoff James Raspass Karen Etheridge Mohammad S Anwar Ryley Breiddal Sergey Leschenko yasu47b |
|
606
|
|
|
|
|
|
|
|
|
607
|
|
|
|
|
|
|
=over 4 |
|
608
|
|
|
|
|
|
|
|
|
609
|
|
|
|
|
|
|
=item * |
|
610
|
|
|
|
|
|
|
|
|
611
|
|
|
|
|
|
|
Alexander Pankoff <ccntrq@screenri.de> |
|
612
|
|
|
|
|
|
|
|
|
613
|
|
|
|
|
|
|
=item * |
|
614
|
|
|
|
|
|
|
|
|
615
|
|
|
|
|
|
|
James Raspass <jraspass@gmail.com> |
|
616
|
|
|
|
|
|
|
|
|
617
|
|
|
|
|
|
|
=item * |
|
618
|
|
|
|
|
|
|
|
|
619
|
|
|
|
|
|
|
Karen Etheridge <ether@cpan.org> |
|
620
|
|
|
|
|
|
|
|
|
621
|
|
|
|
|
|
|
=item * |
|
622
|
|
|
|
|
|
|
|
|
623
|
|
|
|
|
|
|
Mohammad S Anwar <mohammad.anwar@yahoo.com> |
|
624
|
|
|
|
|
|
|
|
|
625
|
|
|
|
|
|
|
=item * |
|
626
|
|
|
|
|
|
|
|
|
627
|
|
|
|
|
|
|
Ryley Breiddal <rbreiddal@presinet.com> |
|
628
|
|
|
|
|
|
|
|
|
629
|
|
|
|
|
|
|
=item * |
|
630
|
|
|
|
|
|
|
|
|
631
|
|
|
|
|
|
|
Sergey Leschenko <Sergey.Leschenko@portaone.com> |
|
632
|
|
|
|
|
|
|
|
|
633
|
|
|
|
|
|
|
=item * |
|
634
|
|
|
|
|
|
|
|
|
635
|
|
|
|
|
|
|
yasu47b <nakayamayasuhiro1986@gmail.com> |
|
636
|
|
|
|
|
|
|
|
|
637
|
|
|
|
|
|
|
=back |
|
638
|
|
|
|
|
|
|
|
|
639
|
|
|
|
|
|
|
=head1 COPYRIGHT AND LICENSE |
|
640
|
|
|
|
|
|
|
|
|
641
|
|
|
|
|
|
|
This software is copyright (c) 2003 - 2023 by Dave Rolsky. |
|
642
|
|
|
|
|
|
|
|
|
643
|
|
|
|
|
|
|
This is free software; you can redistribute it and/or modify it under |
|
644
|
|
|
|
|
|
|
the same terms as the Perl 5 programming language system itself. |
|
645
|
|
|
|
|
|
|
|
|
646
|
|
|
|
|
|
|
The full text of the license can be found in the |
|
647
|
|
|
|
|
|
|
F<LICENSE> file included with this distribution. |
|
648
|
|
|
|
|
|
|
|
|
649
|
|
|
|
|
|
|
=cut |