File Coverage

blib/lib/App/MonM/Util.pm
Criterion Covered Total %
statement 169 303 55.7
branch 51 142 35.9
condition 31 96 32.2
subroutine 29 53 54.7
pod 26 26 100.0
total 306 620 49.3


line stmt bran cond sub pod time code
1             package App::MonM::Util; # $Id: Util.pm 134 2022-09-09 10:33:00Z abalama $
2 5     5   158213 use strict;
  5         30  
  5         116  
3 5     5   1361 use utf8;
  5         37  
  5         21  
4              
5             =encoding utf-8
6              
7             =head1 NAME
8              
9             App::MonM::Util - Internal utilities
10              
11             =head1 VERSION
12              
13             Version 1.02
14              
15             =head1 SYNOPSIS
16              
17             use App::MonM::Util qw/
18             explain expire_calc
19             /;
20              
21             print explain( $object );
22              
23             =head1 DESCRIPTION
24              
25             Internal utilities
26              
27             =head1 FUNCTIONS
28              
29             =over 4
30              
31             =item B
32              
33             print explain( $object );
34              
35             Returns Data::Dumper dump
36              
37             =item B, B, B, B, B, B, B
38              
39             print cyan("Format %s", "text");
40              
41             Returns colored string
42              
43             =item B, B, B, B
44              
45             my $status = nope("Format %s", "text");
46              
47             Prints status message and returns status.
48              
49             For nope returns - 0; for skip, wow, yep - 1
50              
51             =item B
52              
53             my $checkits = getCheckitByName($app->config("checkit"), "foo", "bar");
54              
55             Returns list of normalized the "checkit" config sections by name
56              
57             =item B
58              
59             print getExpireOffset("+1d"); # 86400
60             print getExpireOffset("-1d"); # -86400
61              
62             Returns offset of expires time (in secs).
63              
64             Original this function is the part of CGI::Util::expire_calc!
65              
66             This internal routine creates an expires time exactly some number of hours from the current time.
67             It incorporates modifications from Mark Fisher.
68              
69             format for time can be in any of the forms:
70              
71             now -- expire immediately
72             +180s -- in 180 seconds
73             +2m -- in 2 minutes
74             +12h -- in 12 hours
75             +1d -- in 1 day
76             +3M -- in 3 months
77             +2y -- in 2 years
78             -3m -- 3 minutes ago(!)
79              
80             If you don't supply one of these forms, we assume you are specifying the date yourself
81              
82             =item B
83              
84             my $off = getTimeOffset("1h2m24s"); # 4344
85             my $off = getTimeOffset("1h 2m 24s"); # 4344
86              
87             Returns offset of time (in secs)
88              
89             =item B
90              
91             print getBit(123, 3) ? "SET" : "UNSET"; # UNSET
92              
93             Getting specified Bit
94              
95             =item B
96              
97             print header_field_normalize("content-type"); # Content-Type
98              
99             Returns normalized header field
100              
101             =item B
102              
103             my $a = {a => 1, c => 3, d => { i => 2 }, r => {}};
104             my $b = {b => 2, a => 100, d => { l => 4 }};
105             my $c = merge($a, $b);
106             # $c is {a => 100, b => 2, c => 3, d => { i => 2, l => 4 }, r => {}}
107              
108             Recursively merge two or more hashes, simply
109              
110             This code was taken from L (Thanks, Robert Krimen)
111              
112             =item B
113              
114             my $anode = node2anode({});
115              
116             Returns array of nodes
117              
118             =item B
119              
120             my @b = parsewords("foo,bar baz"); # qw/foo bar baz/
121              
122             Parses string and split it by words. See L
123              
124             =item B
125              
126             my $hash = run_cmd($command, $timeout, $stdin);
127              
128             Wrapped L function
129              
130             This function returns hash:
131              
132             {
133             'cmd' => 'perl -w',
134             'code' => 0, # Exit code (errorlevel)
135             'message' => 'OK', # OK/ERROR
136             'pgid' => 176294, # Pid of child process
137             'status' => 1, # 1/0
138             'stderr' => '', # STDERR
139             'stdout' => '', # STDOUT
140             }
141              
142             =item B
143              
144             my $hash = set2attr({set => ["AttrName Value"]}); # {"AttrName" => "Value"}
145              
146             Converts attributes from the "set" format to regular hash
147              
148             =item B
149              
150             printf("%08b", setBit(123, 3)); # 01111111
151              
152             Setting specified Bit. Returns new value.
153              
154             =item B
155              
156             my $content = slurp($file);
157              
158             Read all data at once from the file (utf8)
159              
160             my $content = slurp($file, 1);
161              
162             Read all data at once from the file (binary)
163              
164             =item B, B
165              
166             my $error = spurt($file, qw/foo bar baz/);
167              
168             Write all data at once to the file
169              
170             =back
171              
172             =head1 HISTORY
173              
174             See C file
175              
176             =head1 AUTHOR
177              
178             Serż Minus (Sergey Lepenkov) L Eabalama@cpan.orgE
179              
180             =head1 COPYRIGHT
181              
182             Copyright (C) 1998-2022 D&D Corporation. All Rights Reserved
183              
184             =head1 LICENSE
185              
186             This program is free software; you can redistribute it and/or
187             modify it under the same terms as Perl itself.
188              
189             See C file and L
190              
191             =cut
192              
193 5     5   223 use vars qw/ $VERSION @EXPORT @EXPORT_OK /;
  5         6  
  5         242  
194             $VERSION = '1.02';
195              
196 5     5   2315 use Data::Dumper; #$Data::Dumper::Deparse = 1;
  5         25596  
  5         303  
197 5     5   1885 use Term::ANSIColor qw/ colored /;
  5         24935  
  5         2479  
198 5     5   1690 use Text::ParseWords qw/quotewords/;
  5         4270  
  5         228  
199 5     5   1682 use Clone qw/clone/;
  5         6569  
  5         231  
200 5     5   1162 use IO::File;
  5         19943  
  5         468  
201 5     5   3187 use IPC::Cmd qw/run_forked/;
  5         170388  
  5         243  
202              
203 5     5   1233 use CTK::ConfGenUtil;
  5         2907  
  5         323  
204 5     5   1211 use CTK::TFVals qw/ :ALL /;
  5         4986  
  5         922  
205 5     5   1573 use CTK::Util qw/ trim /;
  5         324988  
  5         372  
206 5     5   1037 use App::MonM::Const qw/IS_TTY/;
  5         9  
  5         278  
207              
208             use constant {
209 5         236 BIT_SET => 1,
210             BIT_UNSET => 0,
211 5     5   27 };
  5         21  
212              
213 5     5   22 use base qw/Exporter/;
  5         6  
  5         9593  
214             @EXPORT = qw/
215             blue green red yellow cyan magenta gray
216             yep nope skip wow
217             /;
218             @EXPORT_OK = qw/
219             explain
220             parsewords
221             getCheckitByName getExpireOffset getTimeOffset
222             node2anode set2attr
223             getBit setBit
224             merge
225             header_field_normalize
226             slurp spurt spew
227             run_cmd
228             /;
229              
230             sub explain {
231 0     0 1 0 my $dumper = Data::Dumper->new( [shift] );
232 0         0 $dumper->Indent(1)->Terse(1);
233 0 0       0 $dumper->Sortkeys(1) if $dumper->can("Sortkeys");
234 0         0 return $dumper->Dump;
235             }
236             sub parsewords {
237 0     0 1 0 my $s = shift;
238 0 0       0 my @words = grep { defined && length } quotewords(qr/\s+|[\,\;]+/, 0, $s);
  0         0  
239 0         0 return @words;
240             }
241             sub getExpireOffset {
242 11   50 11 1 21 my $time = trim(shift // 0);
243 11         110 my %mult = (
244             's' => 1,
245             'm' => 60,
246             'h' => 60*60,
247             'd' => 60*60*24,
248             'M' => 60*60*24*30,
249             'y' => 60*60*24*365
250             );
251 11 50 33     56 if (!$time || (lc($time) eq 'now')) {
    50          
    50          
252 0         0 return 0;
253             } elsif ($time =~ /^\d+$/) {
254 0         0 return $time; # secs
255             } elsif ($time=~/^([+-]?(?:\d+|\d*\.\d*))([smhdMy])/) {
256 11   50     40 return ($mult{$2} || 1) * $1;
257             }
258 0         0 return $time;
259             }
260             sub getTimeOffset {
261 5   50 5 1 85 my $s = trim(shift // 0);
262 5 50       51 return $s if $s =~ /^\d+$/;
263 5         7 my $r = 0;
264 5         4 my $c = 0;
265 5         20 while ($s =~ s/([+-]?(?:\d+|\d*\.\d*)[smhdMy])//) {
266 11         25 my $i = getExpireOffset("$1");
267 11 100       20 $c++ if $i < 0;
268             #print ">> $1 ($i)\n";
269 11 100       31 $r += $i < 0 ? $i*-1 : $i;
270             }
271 5 100       16 return $c ? $r*-1 : $r;
272             }
273              
274             sub getCheckitByName {
275 0     0 1 0 my $sects = shift; # $app->config("checkit");
276 0         0 my @names = @_; # names
277              
278 0         0 my $i = 0;
279 0         0 my @j = ();
280 0 0 0     0 if (ref($sects) eq 'ARRAY') { # Array
    0          
    0          
281 0         0 foreach my $r (@$sects) {
282 0 0 0     0 if ((ref($r) eq 'HASH') && exists $r->{enable}) { # Anonymous
    0          
283 0         0 $r->{name} = sprintf("virtual%d", ++$i);
284 0 0 0     0 next unless (!@names || grep {$r->{name} eq lc($_)} @names);
  0         0  
285 0         0 push @j, $r;
286             } elsif (ref($r) eq 'HASH') { # Named
287 0         0 foreach my $k (keys %$r) {
288 0         0 my $v = $r->{$k};
289 0 0       0 next unless ref($v) eq 'HASH';
290 0         0 $v->{name} = lc($k);
291 0 0 0     0 next unless (!@names || grep {$v->{name} eq lc($_)} @names);
  0         0  
292 0         0 push @j, $v;
293             }
294             }
295             }
296             } elsif ((ref($sects) eq 'HASH') && !exists $sects->{enable}) { # Hash {name => {...}}
297 0         0 foreach my $k (keys %$sects) {
298 0         0 my $v = $sects->{$k};
299 0 0       0 next unless ref($v) eq 'HASH';
300 0         0 $v->{name} = lc($k);
301 0 0 0     0 next unless (!@names || grep {$v->{name} eq lc($_)} @names);
  0         0  
302 0         0 push @j, $v;
303             }
304             } elsif (ref($sects) eq 'HASH') { # Hash {...}
305 0         0 $sects->{name} = sprintf("virtual%d", ++$i);
306 0 0 0     0 push @j, $sects if (!@names || grep {$sects->{name} eq lc($_)} @names);
  0         0  
307             }
308 0         0 return grep {$_->{enable}} @j;
  0         0  
309             }
310             sub node2anode {
311 0     0 1 0 my $n = shift;
312 0 0 0     0 return [] unless $n && ref($n) =~ /ARRAY|HASH/;
313 0 0       0 return [$n] if ref($n) eq 'HASH';
314 0         0 return $n;
315             }
316             sub set2attr {
317 1     1 1 2 my $in = shift;
318 1 50       4 my $attr = is_array($in) ? $in : array($in => "set");
319 1         16 my %attrs;
320 1         3 foreach (@$attr) {
321 3 50       16 $attrs{$1} = $2 if $_ =~ /^\s*(\S+)\s+(.+)$/;
322             }
323 1         12 return {%attrs};
324             }
325             sub setBit {
326 0     0 1 0 my $v = fv2zero(shift);
327 0         0 my $n = fv2zero(shift);
328 0         0 return $v | (2**$n);
329             }
330             sub getBit {
331 0     0 1 0 my $v = fv2zero(shift);
332 0         0 my $n = fv2zero(shift);
333 0 0       0 return ($v & (1 << $n)) ? BIT_SET : BIT_UNSET;
334             }
335             sub merge {
336 0     0 1 0 my ($left, @right) = @_;
337 0 0       0 return clone($left) unless @right; # Nothing to do
338 0 0       0 return merge($left, merge(@right)) if @right > 1; # More than 2
339 0         0 my ($r) = @right; # Get worked right
340 0         0 my $l = clone($left);
341 0         0 my %m = %$l;
342 0         0 for my $key (keys %$r) {
343 0         0 my ($hr, $hl) = map { ref $_->{$key} eq 'HASH' } $r, $l;
  0         0  
344 0 0 0     0 if ($hr and $hl){
345 0         0 $m{$key} = merge($l->{$key}, $r->{$key});
346             } else {
347 0         0 $m{$key} = $r->{$key};
348             }
349             }
350 0         0 return {%m};
351             }
352             sub header_field_normalize {
353 0   0 0 1 0 my $s = shift // "";
354 0         0 $s =~ s/\b(\w)/\u$1/g;
355 0         0 return $s;
356             }
357             sub slurp {
358 0     0 1 0 my $file = shift;
359 0   0     0 my $isbin = shift || 0;
360 0 0       0 return "" unless $file;
361 0         0 my $fh = IO::File->new($file, "r");
362 0 0       0 return unless defined $fh; # "Can't load file $file: $!"
363 0 0       0 $isbin ? $fh->binmode : $fh->binmode(':raw:utf8');
364              
365 0         0 my $ret;
366 0         0 my $content = "";
367 0         0 my $buf;
368 0         0 while ($ret = read($fh, $buf, 131072)) {
369 0         0 $content .= $buf;
370             }
371 0         0 undef $fh;
372 0 0       0 return unless defined $ret;
373 0         0 return $content;
374             }
375             sub spurt {
376 0     0 1 0 my $file = shift;
377 0         0 my @arr = @_;
378 0         0 my $fh = IO::File->new($file, "w");
379 0 0       0 return "Can't write file $file: $!" unless defined $fh;
380 0         0 $fh->binmode(':raw:utf8');
381 0         0 $fh->print(join("\n", @arr));
382 0         0 undef $fh;
383 0         0 return "";
384             }
385 0     0 1 0 sub spew {goto &spurt}
386             sub run_cmd {
387 0     0 1 0 my $cmd = shift;
388 0   0     0 my $timeout = shift || 0;
389 0         0 my $exe_in = shift;
390              
391 0         0 my %args = ();
392 0 0       0 $args{timeout} = $timeout if $timeout;
393 0 0       0 $args{child_stdin} = $exe_in if $exe_in;
394              
395 0         0 my $r = {};
396 0 0       0 $r = run_forked( $cmd, \%args) if $cmd;
397              
398              
399             my %ret = (
400             cmd => $r->{cmd} // $cmd,
401             pgid => $r->{child_pgid} || 0,
402             code => $r->{exit_code} || 0,
403             stderr => $r->{stderr} // '',
404             stdout => $r->{stdout} // '',
405             status => $r->{exit_code} ? 0 : 1,
406 0 0 0     0 message => $r->{exit_code} ? 'ERROR' : 'OK',
    0 0        
      0        
      0        
      0        
407             );
408 0         0 chomp($ret{stderr});
409 0         0 chomp($ret{stdout});
410              
411             # Time outed
412 0 0       0 if ($r->{killed_by_signal}) {
413 0         0 $ret{status} = 0;
414 0         0 $ret{message} = 'ERROR';
415 0         0 $ret{code} = -1;
416 0         0 $ret{stderr} = sprintf("Timeouted: killed by signal [%s]", $r->{killed_by_signal});
417             }
418              
419             # Exitval
420 0 0 0     0 if ($ret{code} && !length($ret{stderr})) {
421 0         0 $ret{stderr} = sprintf("Exitval=%d", $ret{code});
422             }
423              
424 0         0 return {%ret};
425             }
426              
427             ####################
428             # Colored functions
429             ####################
430             sub yep {
431 0     0 1 0 print(green(sprintf(shift, @_)), "\n");
432 0         0 return 1;
433             }
434             sub nope {
435 0     0 1 0 print(red(sprintf(shift, @_)), "\n");
436 0         0 return 0;
437             }
438             sub skip {
439 0     0 1 0 print(gray(sprintf(shift, @_)), "\n");
440 0         0 return 1;
441             }
442             sub wow {
443 0     0 1 0 print(yellow(sprintf(shift, @_)), "\n");
444 0         0 return 1;
445             }
446              
447             # Colored helper functions
448 0     0 1 0 sub green { IS_TTY ? colored(['bright_green'], sprintf(shift, @_)) : sprintf(shift, @_) }
449 0     0 1 0 sub red { IS_TTY ? colored(['bright_red'], sprintf(shift, @_)) : sprintf(shift, @_) }
450 0     0 1 0 sub yellow { IS_TTY ? colored(['bright_yellow'], sprintf(shift, @_)) : sprintf(shift, @_) }
451 0     0 1 0 sub cyan { IS_TTY ? colored(['bright_cyan'], sprintf(shift, @_)) : sprintf(shift, @_) }
452 0     0 1 0 sub blue { IS_TTY ? colored(['bright_blue'], sprintf(shift, @_)) : sprintf(shift, @_) }
453 0     0 1 0 sub magenta {IS_TTY ? colored(['bright_magenta'],sprintf(shift, @_)) : sprintf(shift, @_) }
454 0     0 1 0 sub gray { IS_TTY ? colored(['white'], sprintf(shift, @_)) : sprintf(shift, @_) }
455              
456             1;
457              
458             package # hide me from PAUSE
459             App::MonM::Util::Scheduler;
460 5     5   41 use strict;
  5         10  
  5         107  
461              
462 5     5   20 use Carp; # carp - warn; croak - die;
  5         8  
  5         311  
463 5     5   27 use CTK::TFVals qw/ is_void /;
  5         7  
  5         214  
464 5     5   33 use CTK::ConfGenUtil qw/ array is_array is_hash /;
  5         7  
  5         562  
465              
466             our $VERSION = '1.00';
467              
468             use constant {
469 5         6094 DAYS_OF_WEEK => [qw/sunday monday tuesday wednesday thursday friday saturday/],
470             DAYS_OF_WEEK_S => [qw/sun mon tue wed thu fri sat/],
471             DAYS_ALIASES => {
472             "sunday" => "sun",
473             "monday" => "mon",
474             "tuesday" => "tue",
475             "wednesday" => "wed",
476             "thursday" => "thu",
477             "friday" => "fri",
478             "saturday" => "sat",
479             },
480             AT_DEFAULT => 'Sun-Sat',
481             SFT_DEFAULT => '[00:00-23:59]',
482             OFFSET_START => 0, # 00:00
483             OFFSET_FINISH => 60*60*24-1, # 23:59
484 5     5   38 };
  5         10  
485              
486             sub new {
487 1     1   952 my $class = shift;
488 1         2 my %args = @_;
489              
490 1         3 my $self = bless {
491             calendar => {}, # { channel_name => [ { weekday_index => [start, finish] } ] }
492             added => {}, # { channel_name => at }
493             }, $class;
494              
495 1         3 return $self;
496             }
497              
498             sub getAtString {
499 0     0   0 my $self = shift;
500 0         0 my $chname = shift;
501 0 0       0 croak("The channel name missing") unless $chname;
502 0         0 my $added = $self->{added};
503 0 0       0 return exists $added->{$chname} ? $added->{$chname} : '';
504             }
505             sub add {
506 4     4   12 my $self = shift;
507 4         5 my $chname = shift;
508 4   50     10 my $at = lc(shift || AT_DEFAULT);
509 4 50       8 croak("The channel name missing") unless $chname;
510 4         6 $at =~ s/\s+//g; # remove spaces
511              
512             # Maybe already exists? - return
513 4         7 my $added = $self->{added};
514 4 50 33     7 return $self if $added->{$chname} && $added->{$chname} eq $at;
515 4         8 $added->{$chname} = $at;
516              
517             # Split by days & times
518 4         4 my @wdt_blocks = ();
519 4         17 while ($at =~ /([a-z\-]{3,18}(\[([0-9\-:,;]+|none|no|off)\])?)/ig) {
520 8         12 push @wdt_blocks, _parse_wdt($1);
521             }
522 4         10 $self->{calendar}{$chname} = [@wdt_blocks];
523              
524 4         8 return $self;
525             }
526             sub check {
527 4     4   79 my $self = shift;
528 4   50     8 my $chname = shift || "default";
529 4   33     9 my $test = shift || time();
530              
531             # Exists
532 4 50       7 return 1 unless exists $self->{calendar}{$chname}; # No calendar - no limits
533 4         12 my $calendar = array($self->{calendar}, $chname);
534 4 100       135 return 0 if is_void($calendar); # No allow intervals in the calendar - denied
535              
536             # Get test values
537 3         240 my ($sec, $min, $hour, $mday, $mon, $year, $wday, $yday, $isdst) = localtime($test);
538 3         11 my $t = $hour*60*60 + $min*60 + $sec;
539              
540             # Check
541 3         3 my $allow = 0; # denied by default
542 3         6 foreach my $int (@$calendar) {
543 17 50       25 next unless is_hash($int);
544 17         83 my $sec = $int->{$wday};
545 17 100 66     38 next unless $sec && is_array($sec);
546 4   100     27 my ($s, $f) = (($sec->[0] || 0), ($sec->[1] || 0));
      50        
547 4 50       7 next unless $s+$f;
548 4 100 100     14 if (($t >= $s and $t <= $f) || ($t >= $f and $t <= $s)) {
      66        
      66        
549 2         3 $allow++;
550 2         2 next;
551             }
552             }
553 3         17 return $allow;
554             }
555              
556             sub _parse_wdt { # parse week day blocks
557 8     8   13 my $wdtin = shift;
558 8         18 $wdtin =~ /([a-z\-]{3,18})(\[([0-9\-:,;]+|none|no|off)\])?/;
559 8         8 my $wd = $1;
560 8   100     19 my $t = $2 || SFT_DEFAULT;
561 8 50       16 $t = '[off]' if $t =~ /\[\-+\]/;
562              
563             # Resolve week days (wd)
564 8         8 my %dw_aliases = %{DAYS_ALIASES()};
  8         24  
565 8         10 my %dw_map; my $i = 0;
  8         9  
566 8         8 for (@{DAYS_OF_WEEK_S()}) {
  8         11  
567 56         61 $dw_map{$_} = $i++;
568             }
569              
570             #print App::MonM::Util::explain(\%dw_map);
571 8         8 my @wdts;
572 8         13 my @pt = _parse_t($t);
573 8 100       26 if ($wd =~ /^[a-z]{3,9}$/) {
    50          
574 4 50       6 $wd = $dw_aliases{$wd} if $dw_aliases{$wd};
575 4 50       6 return () unless exists $dw_map{$wd};
576 4         5 for (@pt) {
577 6         30 push @wdts, {$dw_map{$wd} => $_};
578             }
579             } elsif ($wd =~ /([a-z]{3,9})[\-]+([a-z]{3,9})/) {
580 4         9 my ($sd, $fd) = ($1, $2);
581 4 100       7 $sd = $dw_aliases{$sd} if $dw_aliases{$sd};
582 4 50       6 $fd = $dw_aliases{$fd} if $dw_aliases{$fd};
583 4 50 33     12 return () unless exists $dw_map{$sd} and exists $dw_map{$fd};
584             #print ">>$dw_map{$sd} -- $dw_map{$fd}\n";
585 4         2 my $mx = 7; # Max days per wd-interval
586 4         4 my $start_flag = 0;
587 4         16 foreach my $wdi (0..6,0..6) { # 2 weeks!!
588             # Start def
589 27 100 100     46 $start_flag = 1 if !$start_flag && ($dw_map{$sd} == $wdi);
590 27 100       32 next unless $start_flag;
591             # only 7 days!
592 18 50       27 next if $mx-- <= 0;
593             # Proc
594             #print ">>cnt=$mx; wdi=$wdi\n";
595 18         19 for (@pt) {
596 11         18 push @wdts, {$wdi => $_};
597             }
598             # Finish def
599 18 100       29 last if $dw_map{$fd} == $wdi;
600             }
601             }
602 8         53 return (@wdts);
603             }
604             sub _parse_t { # parse time sections
605 8     8   8 my $tin = shift;
606 8         8 my @ret = ();
607 8         22 while ($tin =~ /([0-9\-:]+|none|no|off)/g) {
608 10         12 my ($s,$f) = (_parse_p($1));
609 10 100 100     42 push @ret, [$s, $f] if $s || $f;
610             }
611 8         13 return @ret;
612             }
613             sub _parse_p { # parse time intervals (periods)
614 10     10   14 my $period = shift;
615 10 50       13 return (0,0) unless defined $period;
616 10         8 my $start = OFFSET_START; # 00:00
617 10         10 my $finish = OFFSET_FINISH; # 23:59
618 10 50       45 if ($period =~ /^\-+$/) { # -
    100          
    100          
    50          
    0          
619 0         0 return (0,0);
620             } elsif ($period =~ /none|no|off/i) {
621 1         3 return (0,0);
622             } elsif ($period =~ /(\d{1,2})\s*\:\s*(\d{1,2})\s*\-+\s*(\d{1,2})\s*\:\s*(\d{1,2})/) { # 00:00-23:59
623 8         19 my ($sh,$sm,$fh,$fm) = ($1,$2,$3,$4);
624 8         12 $start = $sh*60*60 + $sm*60;
625 8         11 $finish = $fh*60*60 + $fm*60;
626             } elsif ($period =~ /(\d{1,2})\s*\-+\s*(\d{1,2})\s*\:\s*(\d{1,2})/) { # 00-23:59
627 1         3 my ($sh,$fh,$fm) = ($1,$2,$3);
628 1         2 $start = $sh*60*60;
629 1         1 $finish = $fh*60*60 + $fm*60;
630             } elsif ($period =~ /(\d{1,2})\s*\-+\s*(\d{1,2})/) { # 00-23
631 0         0 my ($sh,$fh) = ($1,$2);
632 0         0 $start = $sh*60*60;
633 0         0 $finish = $fh*60*60;
634             } else { # Errors
635 0         0 return (0,0);
636             }
637              
638 9 50 33     22 $start = OFFSET_START if $start < OFFSET_START or $start > OFFSET_FINISH;
639 9 50 33     17 $finish = OFFSET_FINISH if $finish < OFFSET_START or $finish > OFFSET_FINISH;
640 9         21 return ($start, $finish);
641             }
642              
643             1;
644              
645             __END__