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   182418 use strict;
  5         33  
  5         150  
3 5     5   1458 use utf8;
  5         41  
  5         25  
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   264 use vars qw/ $VERSION @EXPORT @EXPORT_OK /;
  5         8  
  5         387  
194             $VERSION = '1.02';
195              
196 5     5   2663 use Data::Dumper; #$Data::Dumper::Deparse = 1;
  5         28653  
  5         275  
197 5     5   2095 use Term::ANSIColor qw/ colored /;
  5         28010  
  5         2486  
198 5     5   1728 use Text::ParseWords qw/quotewords/;
  5         4998  
  5         242  
199 5     5   1782 use Clone qw/clone/;
  5         7091  
  5         227  
200 5     5   1213 use IO::File;
  5         21545  
  5         618  
201 5     5   2932 use IPC::Cmd qw/run_forked/;
  5         184948  
  5         254  
202              
203 5     5   1193 use CTK::ConfGenUtil;
  5         3110  
  5         346  
204 5     5   1173 use CTK::TFVals qw/ :ALL /;
  5         5231  
  5         970  
205 5     5   1651 use CTK::Util qw/ trim /;
  5         357264  
  5         373  
206 5     5   1076 use App::MonM::Const qw/IS_TTY/;
  5         10  
  5         271  
207              
208             use constant {
209 5         313 BIT_SET => 1,
210             BIT_UNSET => 0,
211 5     5   27 };
  5         19  
212              
213 5     5   24 use base qw/Exporter/;
  5         9  
  5         10799  
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 26 my $time = trim(shift // 0);
243 11         100 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     70 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     51 return ($mult{$2} || 1) * $1;
257             }
258 0         0 return $time;
259             }
260             sub getTimeOffset {
261 5   50 5 1 96 my $s = trim(shift // 0);
262 5 50       62 return $s if $s =~ /^\d+$/;
263 5         7 my $r = 0;
264 5         5 my $c = 0;
265 5         22 while ($s =~ s/([+-]?(?:\d+|\d*\.\d*)[smhdMy])//) {
266 11         29 my $i = getExpireOffset("$1");
267 11 100       22 $c++ if $i < 0;
268             #print ">> $1 ($i)\n";
269 11 100       40 $r += $i < 0 ? $i*-1 : $i;
270             }
271 5 100       20 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 1 my $in = shift;
318 1 50       5 my $attr = is_array($in) ? $in : array($in => "set");
319 1         20 my %attrs;
320 1         3 foreach (@$attr) {
321 3 50       17 $attrs{$1} = $2 if $_ =~ /^\s*(\S+)\s+(.+)$/;
322             }
323 1         14 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   35 use strict;
  5         10  
  5         118  
461              
462 5     5   23 use Carp; # carp - warn; croak - die;
  5         7  
  5         307  
463 5     5   27 use CTK::TFVals qw/ is_void /;
  5         11  
  5         240  
464 5     5   26 use CTK::ConfGenUtil qw/ array is_array is_hash /;
  5         10  
  5         656  
465              
466             our $VERSION = '1.00';
467              
468             use constant {
469 5         7093 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   31 };
  5         9  
485              
486             sub new {
487 1     1   860 my $class = shift;
488 1         2 my %args = @_;
489              
490 1         4 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   20 my $self = shift;
507 4         6 my $chname = shift;
508 4   50     22 my $at = lc(shift || AT_DEFAULT);
509 4 50       9 croak("The channel name missing") unless $chname;
510 4         9 $at =~ s/\s+//g; # remove spaces
511              
512             # Maybe already exists? - return
513 4         8 my $added = $self->{added};
514 4 50 33     8 return $self if $added->{$chname} && $added->{$chname} eq $at;
515 4         9 $added->{$chname} = $at;
516              
517             # Split by days & times
518 4         5 my @wdt_blocks = ();
519 4         21 while ($at =~ /([a-z\-]{3,18}(\[([0-9\-:,;]+|none|no|off)\])?)/ig) {
520 8         15 push @wdt_blocks, _parse_wdt($1);
521             }
522 4         12 $self->{calendar}{$chname} = [@wdt_blocks];
523              
524 4         11 return $self;
525             }
526             sub check {
527 4     4   106 my $self = shift;
528 4   50     9 my $chname = shift || "default";
529 4   33     9 my $test = shift || time();
530              
531             # Exists
532 4 50       9 return 1 unless exists $self->{calendar}{$chname}; # No calendar - no limits
533 4         11 my $calendar = array($self->{calendar}, $chname);
534 4 100       171 return 0 if is_void($calendar); # No allow intervals in the calendar - denied
535              
536             # Get test values
537 3         254 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         4 my $allow = 0; # denied by default
542 3         5 foreach my $int (@$calendar) {
543 17 50       30 next unless is_hash($int);
544 17         94 my $sec = $int->{$wday};
545 17 100 66     46 next unless $sec && is_array($sec);
546 4   100     34 my ($s, $f) = (($sec->[0] || 0), ($sec->[1] || 0));
      50        
547 4 50       8 next unless $s+$f;
548 4 100 100     17 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         20 return $allow;
554             }
555              
556             sub _parse_wdt { # parse week day blocks
557 8     8   17 my $wdtin = shift;
558 8         19 $wdtin =~ /([a-z\-]{3,18})(\[([0-9\-:,;]+|none|no|off)\])?/;
559 8         16 my $wd = $1;
560 8   100     20 my $t = $2 || SFT_DEFAULT;
561 8 50       20 $t = '[off]' if $t =~ /\[\-+\]/;
562              
563             # Resolve week days (wd)
564 8         9 my %dw_aliases = %{DAYS_ALIASES()};
  8         28  
565 8         13 my %dw_map; my $i = 0;
  8         9  
566 8         9 for (@{DAYS_OF_WEEK_S()}) {
  8         10  
567 56         76 $dw_map{$_} = $i++;
568             }
569              
570             #print App::MonM::Util::explain(\%dw_map);
571 8         9 my @wdts;
572 8         14 my @pt = _parse_t($t);
573 8 100       31 if ($wd =~ /^[a-z]{3,9}$/) {
    50          
574 4 50       8 $wd = $dw_aliases{$wd} if $dw_aliases{$wd};
575 4 50       8 return () unless exists $dw_map{$wd};
576 4         7 for (@pt) {
577 6         34 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       10 $sd = $dw_aliases{$sd} if $dw_aliases{$sd};
582 4 50       8 $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         6 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     50 $start_flag = 1 if !$start_flag && ($dw_map{$sd} == $wdi);
590 27 100       36 next unless $start_flag;
591             # only 7 days!
592 18 50       22 next if $mx-- <= 0;
593             # Proc
594             #print ">>cnt=$mx; wdi=$wdi\n";
595 18         24 for (@pt) {
596 11         31 push @wdts, {$wdi => $_};
597             }
598             # Finish def
599 18 100       34 last if $dw_map{$fd} == $wdi;
600             }
601             }
602 8         85 return (@wdts);
603             }
604             sub _parse_t { # parse time sections
605 8     8   11 my $tin = shift;
606 8         10 my @ret = ();
607 8         26 while ($tin =~ /([0-9\-:]+|none|no|off)/g) {
608 10         17 my ($s,$f) = (_parse_p($1));
609 10 100 100     56 push @ret, [$s, $f] if $s || $f;
610             }
611 8         36 return @ret;
612             }
613             sub _parse_p { # parse time intervals (periods)
614 10     10   17 my $period = shift;
615 10 50       15 return (0,0) unless defined $period;
616 10         11 my $start = OFFSET_START; # 00:00
617 10         11 my $finish = OFFSET_FINISH; # 23:59
618 10 50       61 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         22 my ($sh,$sm,$fh,$fm) = ($1,$2,$3,$4);
624 8         19 $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         3 $start = $sh*60*60;
629 1         3 $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     27 $start = OFFSET_START if $start < OFFSET_START or $start > OFFSET_FINISH;
639 9 50 33     22 $finish = OFFSET_FINISH if $finish < OFFSET_START or $finish > OFFSET_FINISH;
640 9         17 return ($start, $finish);
641             }
642              
643             1;
644              
645             __END__