line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
package Elive::Util; |
2
|
36
|
|
|
36
|
|
20750
|
use warnings; use strict; |
|
36
|
|
|
36
|
|
46
|
|
|
36
|
|
|
|
|
1086
|
|
|
36
|
|
|
|
|
137
|
|
|
36
|
|
|
|
|
52
|
|
|
36
|
|
|
|
|
896
|
|
3
|
|
|
|
|
|
|
|
4
|
36
|
|
|
36
|
|
20398
|
use Term::ReadKey; |
|
36
|
|
|
|
|
124210
|
|
|
36
|
|
|
|
|
2749
|
|
5
|
36
|
|
|
36
|
|
19553
|
use Term::ReadLine; |
|
36
|
|
|
|
|
134271
|
|
|
36
|
|
|
|
|
1165
|
|
6
|
36
|
|
|
36
|
|
17025
|
use IO::Interactive; |
|
36
|
|
|
|
|
306790
|
|
|
36
|
|
|
|
|
189
|
|
7
|
36
|
|
|
36
|
|
1468
|
use Scalar::Util; |
|
36
|
|
|
|
|
62
|
|
|
36
|
|
|
|
|
1226
|
|
8
|
36
|
|
|
36
|
|
17384
|
use Clone; |
|
36
|
|
|
|
|
18502
|
|
|
36
|
|
|
|
|
1496
|
|
9
|
36
|
|
|
36
|
|
1162
|
use YAML::Syck; |
|
36
|
|
|
|
|
3453
|
|
|
36
|
|
|
|
|
1952
|
|
10
|
36
|
|
|
36
|
|
1250
|
use Try::Tiny; |
|
36
|
|
|
|
|
2632
|
|
|
36
|
|
|
|
|
2054
|
|
11
|
|
|
|
|
|
|
|
12
|
|
|
|
|
|
|
our $VERSION = '0.03'; |
13
|
|
|
|
|
|
|
|
14
|
36
|
|
|
36
|
|
13728
|
use Elive::Util::Type; |
|
36
|
|
|
|
|
84
|
|
|
36
|
|
|
|
|
48641
|
|
15
|
|
|
|
|
|
|
|
16
|
|
|
|
|
|
|
=head1 NAME |
17
|
|
|
|
|
|
|
|
18
|
|
|
|
|
|
|
Elive::Util - Utility functions for Elive |
19
|
|
|
|
|
|
|
|
20
|
|
|
|
|
|
|
=cut |
21
|
|
|
|
|
|
|
|
22
|
|
|
|
|
|
|
=head1 METHODS |
23
|
|
|
|
|
|
|
|
24
|
|
|
|
|
|
|
=cut |
25
|
|
|
|
|
|
|
|
26
|
|
|
|
|
|
|
=head2 inspect_type |
27
|
|
|
|
|
|
|
|
28
|
|
|
|
|
|
|
$type = Elive::Util::inspect_type('Elive::Entity::Participants'); |
29
|
|
|
|
|
|
|
if ($type->is_array) { |
30
|
|
|
|
|
|
|
# ... |
31
|
|
|
|
|
|
|
} |
32
|
|
|
|
|
|
|
|
33
|
|
|
|
|
|
|
Returns an object of type L. |
34
|
|
|
|
|
|
|
|
35
|
|
|
|
|
|
|
=cut |
36
|
|
|
|
|
|
|
|
37
|
|
|
|
|
|
|
sub inspect_type { |
38
|
58
|
|
|
58
|
1
|
100
|
my $type_union = shift; |
39
|
|
|
|
|
|
|
|
40
|
58
|
|
|
|
|
198
|
my @types = split(/\|/, $type_union); |
41
|
|
|
|
|
|
|
|
42
|
58
|
|
|
|
|
406
|
return Elive::Util::Type->new($types[0]) |
43
|
|
|
|
|
|
|
} |
44
|
|
|
|
|
|
|
|
45
|
|
|
|
|
|
|
sub _freeze { |
46
|
254
|
|
|
254
|
|
350
|
my ($val, $type) = @_; |
47
|
|
|
|
|
|
|
|
48
|
254
|
|
|
|
|
396
|
for ($val) { |
49
|
|
|
|
|
|
|
|
50
|
254
|
50
|
|
|
|
412
|
if (!defined) { |
51
|
0
|
|
|
|
|
0
|
warn "undefined value of type $type\n" |
52
|
|
|
|
|
|
|
} |
53
|
|
|
|
|
|
|
else { |
54
|
254
|
|
|
|
|
424
|
$_ = string($_, $type); |
55
|
254
|
|
|
|
|
254
|
my $raw_val = $_; |
56
|
|
|
|
|
|
|
|
57
|
254
|
50
|
|
|
|
740
|
if ($type =~ m{^Bool}ix) { |
|
|
100
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
58
|
|
|
|
|
|
|
|
59
|
|
|
|
|
|
|
# |
60
|
|
|
|
|
|
|
# DBize boolean flags.. |
61
|
|
|
|
|
|
|
# |
62
|
0
|
0
|
|
|
|
0
|
$_ = $_ ? 'true' : 'false'; |
63
|
|
|
|
|
|
|
} |
64
|
|
|
|
|
|
|
elsif ($type =~ m{^(Str|enum)}ix) { |
65
|
|
|
|
|
|
|
|
66
|
|
|
|
|
|
|
# |
67
|
|
|
|
|
|
|
# low level check for taintness. Only applicible when |
68
|
|
|
|
|
|
|
# perl program is running in taint mode |
69
|
|
|
|
|
|
|
# |
70
|
126
|
50
|
|
|
|
984
|
die "attempt to freeze tainted data (type $type): $_" |
71
|
|
|
|
|
|
|
if _tainted($_); |
72
|
|
|
|
|
|
|
# |
73
|
|
|
|
|
|
|
# l-r trim |
74
|
|
|
|
|
|
|
# |
75
|
126
|
50
|
|
|
|
680
|
$_ = $1 |
76
|
|
|
|
|
|
|
if m{^ \s* (.*?) \s* $}x; |
77
|
126
|
100
|
|
|
|
301
|
$_ = lc if $type =~ m{^enum}; |
78
|
|
|
|
|
|
|
} |
79
|
|
|
|
|
|
|
elsif ($type =~ m{^(Int|HiResDate)}ix) { |
80
|
128
|
|
|
|
|
1533
|
$_ = _tidy_decimal("$_"); |
81
|
|
|
|
|
|
|
} |
82
|
|
|
|
|
|
|
elsif ($type =~ m{^Ref|Any}ix) { |
83
|
0
|
|
|
|
|
0
|
$_ = undef; |
84
|
|
|
|
|
|
|
} |
85
|
|
|
|
|
|
|
else { |
86
|
0
|
0
|
|
|
|
0
|
die "unable to convert $raw_val to $type\n" |
87
|
|
|
|
|
|
|
unless defined; |
88
|
|
|
|
|
|
|
} |
89
|
|
|
|
|
|
|
} |
90
|
|
|
|
|
|
|
}; |
91
|
|
|
|
|
|
|
|
92
|
254
|
|
|
|
|
1290
|
return $val; |
93
|
|
|
|
|
|
|
} |
94
|
|
|
|
|
|
|
|
95
|
|
|
|
|
|
|
# |
96
|
|
|
|
|
|
|
# thawing of elementry datatypes |
97
|
|
|
|
|
|
|
# |
98
|
|
|
|
|
|
|
|
99
|
|
|
|
|
|
|
sub _thaw { |
100
|
0
|
|
|
0
|
|
0
|
my ($val, $type) = @_; |
101
|
|
|
|
|
|
|
|
102
|
0
|
0
|
0
|
|
|
0
|
return $val if $type =~ m{Ref}i |
103
|
|
|
|
|
|
|
|| ref( $val); |
104
|
|
|
|
|
|
|
|
105
|
0
|
0
|
|
|
|
0
|
return unless defined $val; |
106
|
|
|
|
|
|
|
|
107
|
0
|
|
|
|
|
0
|
for ($val) { |
108
|
|
|
|
|
|
|
|
109
|
0
|
0
|
|
|
|
0
|
if ($type =~ m{^Bool}i) { |
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
110
|
|
|
|
|
|
|
# |
111
|
|
|
|
|
|
|
# Perlise boolean flags.. |
112
|
|
|
|
|
|
|
# |
113
|
0
|
0
|
|
|
|
0
|
$_ = m{^(true|1)$}i ? 1 : 0; |
114
|
|
|
|
|
|
|
} |
115
|
|
|
|
|
|
|
elsif ($type =~ m{^(Str|enum)}i) { |
116
|
|
|
|
|
|
|
# |
117
|
|
|
|
|
|
|
# l-r trim |
118
|
|
|
|
|
|
|
# |
119
|
0
|
0
|
|
|
|
0
|
$_ = $1 |
120
|
|
|
|
|
|
|
if m{^ \s* (.*?) \s* $}x; |
121
|
0
|
0
|
|
|
|
0
|
$_ = lc if $type =~ m{^enum}i; |
122
|
|
|
|
|
|
|
} |
123
|
|
|
|
|
|
|
elsif ($type =~ m{^Int|HiResDate}i) { |
124
|
|
|
|
|
|
|
|
125
|
0
|
|
|
|
|
0
|
$_ = _tidy_decimal("$_"); |
126
|
|
|
|
|
|
|
|
127
|
|
|
|
|
|
|
} |
128
|
|
|
|
|
|
|
elsif ($type eq 'Any') { |
129
|
|
|
|
|
|
|
# more or less a placeholder type |
130
|
0
|
|
|
|
|
0
|
$_ = string($_); |
131
|
|
|
|
|
|
|
} |
132
|
|
|
|
|
|
|
else { |
133
|
0
|
|
|
|
|
0
|
die "unknown type: $type"; |
134
|
|
|
|
|
|
|
} |
135
|
|
|
|
|
|
|
}; |
136
|
|
|
|
|
|
|
|
137
|
0
|
|
|
|
|
0
|
return $val; |
138
|
|
|
|
|
|
|
} |
139
|
|
|
|
|
|
|
|
140
|
|
|
|
|
|
|
# |
141
|
|
|
|
|
|
|
# _tidy_decimal(): general cleanup and normalisation of an integer. |
142
|
|
|
|
|
|
|
# used to clean up numbers for data storage or comparison |
143
|
|
|
|
|
|
|
|
144
|
|
|
|
|
|
|
sub _tidy_decimal { |
145
|
128
|
|
|
128
|
|
172
|
my ($i) = @_; |
146
|
|
|
|
|
|
|
# |
147
|
|
|
|
|
|
|
# well a number really. don't convert or sprintf etc |
148
|
|
|
|
|
|
|
# to avoid overflow. Just normalise it for potential |
149
|
|
|
|
|
|
|
# string comparisons |
150
|
|
|
|
|
|
|
# |
151
|
|
|
|
|
|
|
# l-r trim, also untaint |
152
|
|
|
|
|
|
|
# |
153
|
128
|
50
|
|
|
|
525
|
if ($i =~ m{^ [\s\+]* (-?\d+) \s* $}x) { |
154
|
128
|
|
|
|
|
267
|
$i = $1; |
155
|
|
|
|
|
|
|
} |
156
|
|
|
|
|
|
|
else { |
157
|
0
|
|
|
|
|
0
|
return; |
158
|
|
|
|
|
|
|
} |
159
|
|
|
|
|
|
|
|
160
|
|
|
|
|
|
|
# |
161
|
|
|
|
|
|
|
# remove any leading zeros: |
162
|
|
|
|
|
|
|
# 000123 => 123 |
163
|
|
|
|
|
|
|
# -00045 => -45 |
164
|
|
|
|
|
|
|
# -000 => 0 |
165
|
|
|
|
|
|
|
# |
166
|
|
|
|
|
|
|
|
167
|
128
|
|
|
|
|
719
|
$i =~ s{^ |
168
|
|
|
|
|
|
|
(-?) # leading minus retained (for now) |
169
|
|
|
|
|
|
|
0* # leading zeros discarded |
170
|
|
|
|
|
|
|
(\d+?) # number - retained |
171
|
|
|
|
|
|
|
$} |
172
|
|
|
|
|
|
|
{$1$2}x; |
173
|
|
|
|
|
|
|
|
174
|
|
|
|
|
|
|
# |
175
|
|
|
|
|
|
|
# reduce -0 => 0 |
176
|
128
|
50
|
|
|
|
320
|
$i = 0 if ($i eq '-0'); |
177
|
|
|
|
|
|
|
|
178
|
|
|
|
|
|
|
# |
179
|
|
|
|
|
|
|
# sanity check. |
180
|
|
|
|
|
|
|
# |
181
|
128
|
50
|
|
|
|
388
|
die "bad integer: $_[0]" |
182
|
|
|
|
|
|
|
unless $i =~ m{^[+-]?\d+$}; |
183
|
|
|
|
|
|
|
|
184
|
128
|
|
|
|
|
467
|
return $i; |
185
|
|
|
|
|
|
|
} |
186
|
|
|
|
|
|
|
|
187
|
|
|
|
|
|
|
=head2 prompt |
188
|
|
|
|
|
|
|
|
189
|
|
|
|
|
|
|
my $password = Elive::Util::prompt('Password: ', password => 1) |
190
|
|
|
|
|
|
|
|
191
|
|
|
|
|
|
|
Prompt for user input |
192
|
|
|
|
|
|
|
|
193
|
|
|
|
|
|
|
=cut |
194
|
|
|
|
|
|
|
|
195
|
|
|
|
|
|
|
sub prompt { |
196
|
0
|
|
|
0
|
1
|
0
|
my ($prompt,%opt) = @_; |
197
|
|
|
|
|
|
|
|
198
|
0
|
|
0
|
|
|
0
|
chomp($prompt ||= 'input:'); |
199
|
|
|
|
|
|
|
|
200
|
0
|
0
|
|
|
|
0
|
ReadMode $opt{password}? 2: 1; # Turn off controls keys |
201
|
|
|
|
|
|
|
|
202
|
0
|
|
|
|
|
0
|
my $input; |
203
|
0
|
|
|
|
|
0
|
my $n = 0; |
204
|
|
|
|
|
|
|
|
205
|
0
|
|
0
|
|
|
0
|
do { |
206
|
0
|
0
|
|
|
|
0
|
die "giving up on input of $prompt" if ++$n > 100; |
207
|
0
|
0
|
|
|
|
0
|
print $prompt if IO::Interactive::is_interactive(); |
208
|
0
|
|
|
|
|
0
|
$input = ReadLine(0); |
209
|
|
|
|
|
|
|
return |
210
|
0
|
0
|
|
|
|
0
|
unless (defined $input); |
211
|
0
|
|
|
|
|
0
|
chomp($input); |
212
|
|
|
|
|
|
|
} until (defined($input) && length($input)); |
213
|
|
|
|
|
|
|
|
214
|
0
|
|
|
|
|
0
|
ReadMode 0; # Reset tty mode before exiting |
215
|
|
|
|
|
|
|
|
216
|
0
|
|
|
|
|
0
|
return $input; |
217
|
|
|
|
|
|
|
} |
218
|
|
|
|
|
|
|
|
219
|
|
|
|
|
|
|
sub _reftype { |
220
|
1013
|
|
100
|
1013
|
|
4235
|
return Scalar::Util::reftype( shift() ) || ''; |
221
|
|
|
|
|
|
|
} |
222
|
|
|
|
|
|
|
|
223
|
|
|
|
|
|
|
sub _clone { |
224
|
5
|
|
|
5
|
|
4528
|
return Clone::clone(shift); |
225
|
|
|
|
|
|
|
} |
226
|
|
|
|
|
|
|
|
227
|
|
|
|
|
|
|
sub _tainted { |
228
|
126
|
|
|
126
|
|
152
|
return grep { Scalar::Util::tainted($_) } @_; |
|
126
|
|
|
|
|
403
|
|
229
|
|
|
|
|
|
|
} |
230
|
|
|
|
|
|
|
|
231
|
|
|
|
|
|
|
# |
232
|
|
|
|
|
|
|
# Hex encoding/decoding. Use for data streaming. E.g. upload & download |
233
|
|
|
|
|
|
|
# of preload data. |
234
|
|
|
|
|
|
|
# |
235
|
|
|
|
|
|
|
|
236
|
|
|
|
|
|
|
sub _hex_decode { |
237
|
0
|
|
|
0
|
|
0
|
my $data = shift; |
238
|
|
|
|
|
|
|
|
239
|
|
|
|
|
|
|
return |
240
|
0
|
0
|
|
|
|
0
|
unless defined $data; |
241
|
|
|
|
|
|
|
|
242
|
0
|
0
|
|
|
|
0
|
$data = '0'.$data |
243
|
|
|
|
|
|
|
unless length($data) % 2 == 0; |
244
|
|
|
|
|
|
|
|
245
|
0
|
|
|
|
|
0
|
my ($non_hex_char) = ($data =~ m{([^0-9a-f])}ix); |
246
|
|
|
|
|
|
|
|
247
|
0
|
0
|
|
|
|
0
|
die "non hex character in data: ".$non_hex_char |
248
|
|
|
|
|
|
|
if (defined $non_hex_char); |
249
|
|
|
|
|
|
|
# |
250
|
|
|
|
|
|
|
# Works for simple ascii |
251
|
0
|
|
|
|
|
0
|
$data =~ s{(..)}{chr(hex($1))}gex; |
|
0
|
|
|
|
|
0
|
|
252
|
|
|
|
|
|
|
|
253
|
0
|
|
|
|
|
0
|
return $data; |
254
|
|
|
|
|
|
|
} |
255
|
|
|
|
|
|
|
|
256
|
|
|
|
|
|
|
sub _hex_encode { |
257
|
0
|
|
|
0
|
|
0
|
my $data = shift; |
258
|
|
|
|
|
|
|
|
259
|
0
|
|
|
|
|
0
|
$data =~ s{(.)}{sprintf("%02x", ord($1))}gesx; |
|
0
|
|
|
|
|
0
|
|
260
|
|
|
|
|
|
|
|
261
|
0
|
|
|
|
|
0
|
return $data; |
262
|
|
|
|
|
|
|
} |
263
|
|
|
|
|
|
|
|
264
|
|
|
|
|
|
|
=head2 string |
265
|
|
|
|
|
|
|
|
266
|
|
|
|
|
|
|
print Elive::Util::string($myscalar); |
267
|
|
|
|
|
|
|
print Elive::Util::string($myobj); |
268
|
|
|
|
|
|
|
print Elive::Util::string($myref, $datatype); |
269
|
|
|
|
|
|
|
|
270
|
|
|
|
|
|
|
Return a string for an object. This method is widely used for casting |
271
|
|
|
|
|
|
|
objects to ids. |
272
|
|
|
|
|
|
|
|
273
|
|
|
|
|
|
|
=over 4 |
274
|
|
|
|
|
|
|
|
275
|
|
|
|
|
|
|
=item |
276
|
|
|
|
|
|
|
|
277
|
|
|
|
|
|
|
If it's a simple scalar, just pass the value back. |
278
|
|
|
|
|
|
|
|
279
|
|
|
|
|
|
|
=item |
280
|
|
|
|
|
|
|
|
281
|
|
|
|
|
|
|
If it's an object use the C method. |
282
|
|
|
|
|
|
|
|
283
|
|
|
|
|
|
|
=item |
284
|
|
|
|
|
|
|
|
285
|
|
|
|
|
|
|
If it's a reference, resolve datatype to a class, and use its |
286
|
|
|
|
|
|
|
C method. |
287
|
|
|
|
|
|
|
|
288
|
|
|
|
|
|
|
=back |
289
|
|
|
|
|
|
|
|
290
|
|
|
|
|
|
|
=cut |
291
|
|
|
|
|
|
|
|
292
|
|
|
|
|
|
|
sub string { |
293
|
418
|
|
|
418
|
1
|
529
|
my $obj = shift; |
294
|
418
|
|
|
|
|
404
|
my $data_type = shift; |
295
|
|
|
|
|
|
|
|
296
|
418
|
|
|
|
|
464
|
for ($obj) { |
297
|
|
|
|
|
|
|
|
298
|
418
|
100
|
|
|
|
1139
|
if ($data_type) { |
299
|
360
|
|
|
|
|
978
|
my ($dt) = ($data_type =~ m{(.*)}); |
300
|
|
|
|
|
|
|
|
301
|
360
|
|
|
360
|
|
10821
|
return $dt->stringify($_) |
302
|
360
|
100
|
|
|
|
2914
|
if try {$dt->can('stringify')}; |
303
|
|
|
|
|
|
|
} |
304
|
|
|
|
|
|
|
|
305
|
312
|
|
|
|
|
3006
|
my $reftype = _reftype($_); |
306
|
|
|
|
|
|
|
|
307
|
312
|
50
|
|
|
|
976
|
return $_ |
308
|
|
|
|
|
|
|
unless $reftype; |
309
|
|
|
|
|
|
|
|
310
|
0
|
0
|
0
|
|
|
|
return $_->stringify |
311
|
|
|
|
|
|
|
if (Scalar::Util::blessed($_) && $_->can('stringify')); |
312
|
|
|
|
|
|
|
|
313
|
0
|
0
|
|
|
|
|
if ($reftype eq 'ARRAY') { |
314
|
0
|
|
|
|
|
|
return join(',', map {string($_ => $data_type)} @$_) |
|
0
|
|
|
|
|
|
|
315
|
|
|
|
|
|
|
} |
316
|
|
|
|
|
|
|
} |
317
|
|
|
|
|
|
|
|
318
|
|
|
|
|
|
|
# |
319
|
|
|
|
|
|
|
# Nothing else worked; dump it. |
320
|
|
|
|
|
|
|
# |
321
|
0
|
|
|
|
|
|
return YAML::Syck::Dump($obj); |
322
|
|
|
|
|
|
|
} |
323
|
|
|
|
|
|
|
|
324
|
|
|
|
|
|
|
=head2 next_quarter_hour |
325
|
|
|
|
|
|
|
|
326
|
|
|
|
|
|
|
Quarter hour advancement for the Time Module impoverished. |
327
|
|
|
|
|
|
|
|
328
|
|
|
|
|
|
|
my $start = Elive::Util::next_quarter_hour(); |
329
|
|
|
|
|
|
|
my $end = Elive::Util::next_quarter_hour($start); |
330
|
|
|
|
|
|
|
|
331
|
|
|
|
|
|
|
Advance to the next quarter hour without the use of any supporting |
332
|
|
|
|
|
|
|
time modules. We just simply increment in seconds until C |
333
|
|
|
|
|
|
|
indicates that we're exactly on a quarter hour and ahead of the start time. |
334
|
|
|
|
|
|
|
|
335
|
|
|
|
|
|
|
A small initial increment is added to ensure that the date remains |
336
|
|
|
|
|
|
|
in the future, allowing for minor gotchas such as leap seconds, general |
337
|
|
|
|
|
|
|
latency and smallish time drifts between the client and server. |
338
|
|
|
|
|
|
|
|
339
|
|
|
|
|
|
|
=cut |
340
|
|
|
|
|
|
|
|
341
|
|
|
|
|
|
|
sub next_quarter_hour { |
342
|
0
|
|
0
|
0
|
1
|
|
my $time = shift || time(); |
343
|
|
|
|
|
|
|
|
344
|
0
|
|
|
|
|
|
$time += 30; |
345
|
|
|
|
|
|
|
|
346
|
0
|
|
|
|
|
|
for (;;) { |
347
|
0
|
|
|
|
|
|
my @t = localtime(++$time); |
348
|
0
|
|
|
|
|
|
my $sec = $t[0]; |
349
|
0
|
|
|
|
|
|
my $min = $t[1]; |
350
|
|
|
|
|
|
|
|
351
|
0
|
0
|
0
|
|
|
|
last unless $min % 15 || $sec; |
352
|
|
|
|
|
|
|
} |
353
|
|
|
|
|
|
|
|
354
|
0
|
|
|
|
|
|
return $time; |
355
|
|
|
|
|
|
|
} |
356
|
|
|
|
|
|
|
|
357
|
|
|
|
|
|
|
1; |