|  line  | 
 stmt  | 
 bran  | 
 cond  | 
 sub  | 
 pod  | 
 time  | 
 code  | 
| 
1
 | 
14
 | 
 
 | 
 
 | 
  
14
  
 | 
 
 | 
3798964
 | 
 use strict;  | 
| 
 
 | 
14
 | 
 
 | 
 
 | 
 
 | 
 
 | 
34
 | 
    | 
| 
 
 | 
14
 | 
 
 | 
 
 | 
 
 | 
 
 | 
872
 | 
    | 
| 
2
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
3
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 package DateTime::Set::ICal;  | 
| 
4
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
5
 | 
14
 | 
 
 | 
 
 | 
  
14
  
 | 
 
 | 
87
 | 
 use vars qw(@ISA);  | 
| 
 
 | 
14
 | 
 
 | 
 
 | 
 
 | 
 
 | 
28
 | 
    | 
| 
 
 | 
14
 | 
 
 | 
 
 | 
 
 | 
 
 | 
8484
 | 
    | 
| 
6
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 # use Carp;  | 
| 
7
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
8
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 # a "dt::set" with a symbolic string representation   | 
| 
9
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 @ISA = qw( DateTime::Set );  | 
| 
10
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
11
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 sub set_ical { # include list, exclude list  | 
| 
12
 | 
106
 | 
 
 | 
 
 | 
  
106
  
 | 
 
 | 
180
 | 
     my $self = shift;  | 
| 
13
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     # carp "set_ical $_[0] => @{$_[1]}" if @_;  | 
| 
14
 | 
106
 | 
 
 | 
 
 | 
 
 | 
 
 | 
410
 | 
     $self->{as_ical} = [ @_ ];  | 
| 
15
 | 
106
 | 
 
 | 
 
 | 
 
 | 
 
 | 
259
 | 
     $self;   | 
| 
16
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 }  | 
| 
17
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
18
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 sub get_ical {   | 
| 
19
 | 
59
 | 
 
 | 
 
 | 
  
59
  
 | 
 
 | 
151
 | 
     my $self = shift;  | 
| 
20
 | 
59
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
210
 | 
     return unless $self->{as_ical};  | 
| 
21
 | 
38
 | 
 
 | 
 
 | 
 
 | 
 
 | 
64
 | 
     return @{ $self->{as_ical} };    | 
| 
 
 | 
38
 | 
 
 | 
 
 | 
 
 | 
 
 | 
230
 | 
    | 
| 
22
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 }  | 
| 
23
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
24
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 sub clone {  | 
| 
25
 | 
31
 | 
 
 | 
 
 | 
  
31
  
 | 
 
 | 
13721
 | 
     my $self = shift;  | 
| 
26
 | 
31
 | 
 
 | 
 
 | 
 
 | 
 
 | 
187
 | 
     my $new = $self->SUPER::clone( @_ );  | 
| 
27
 | 
31
 | 
 
 | 
 
 | 
 
 | 
 
 | 
2089
 | 
     $new->set_ical( $self->get_ical );  | 
| 
28
 | 
31
 | 
 
 | 
 
 | 
 
 | 
 
 | 
106
 | 
     $new;  | 
| 
29
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 }  | 
| 
30
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
31
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 sub union {  | 
| 
32
 | 
14
 | 
 
 | 
 
 | 
  
14
  
 | 
 
 | 
1328
 | 
     my $self = shift;  | 
| 
33
 | 
14
 | 
 
 | 
 
 | 
 
 | 
 
 | 
83
 | 
     my $new = $self->SUPER::union( @_ );  | 
| 
34
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
35
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     # RFC2445 - op1, op2 must have no 'exclude'  | 
| 
36
 | 
14
 | 
 
 | 
 
 | 
 
 | 
 
 | 
2504
 | 
     my (%op1, %op2);  | 
| 
37
 | 
14
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
90
 | 
     %op1 = ( $self->get_ical ) if ( UNIVERSAL::can( $self, 'get_ical' ) );  | 
| 
38
 | 
14
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
83
 | 
     %op2 = ( $_[0]->get_ical ) if ( UNIVERSAL::can( $_[0], 'get_ical' ) );  | 
| 
39
 | 
14
 | 
  
 50
  
 | 
  
 33
  
 | 
 
 | 
 
 | 
84
 | 
     return $new if ( ( exists $op1{exclude} ) ||  | 
| 
40
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                      ( exists $op2{exclude} ) );  | 
| 
41
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
42
 | 
14
 | 
 
 | 
 
 | 
 
 | 
 
 | 
36
 | 
     bless $new, 'DateTime::Set::ICal';  | 
| 
43
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     # warn " -- 1 isa @{[%op1]} -- 2 isa @{[%op2]} -- ";  | 
| 
44
 | 
14
 | 
 
 | 
 
 | 
 
 | 
 
 | 
21
 | 
     my @ical;  | 
| 
45
 | 
7
 | 
 
 | 
 
 | 
 
 | 
 
 | 
19
 | 
     @ical = exists $op1{include} ?   | 
| 
46
 | 
14
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
71
 | 
             @{$op1{include}} :   | 
| 
47
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
             $self;  | 
| 
48
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
49
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     # push @ical, @{$op2{include}}, @_;  | 
| 
50
 | 
14
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
37
 | 
     if ( exists $op2{include} )  | 
| 
51
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     {  | 
| 
52
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
         push @ical, @{$op2{include}};  | 
| 
 
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
    | 
| 
53
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     }  | 
| 
54
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     else  | 
| 
55
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     {  | 
| 
56
 | 
14
 | 
 
 | 
 
 | 
 
 | 
 
 | 
50
 | 
         push @ical, @_;  # whatever...  | 
| 
57
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     }  | 
| 
58
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     # warn "union: @ical";  | 
| 
59
 | 
14
 | 
 
 | 
 
 | 
 
 | 
 
 | 
56
 | 
     $new->set_ical( include => [ @ical ] );   | 
| 
60
 | 
14
 | 
 
 | 
 
 | 
 
 | 
 
 | 
84
 | 
     $new;  | 
| 
61
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 }  | 
| 
62
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
63
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 sub complement {  | 
| 
64
 | 
1
 | 
 
 | 
 
 | 
  
1
  
 | 
 
 | 
4988
 | 
     my $self = shift;  | 
| 
65
 | 
1
 | 
 
 | 
 
 | 
 
 | 
 
 | 
14
 | 
     my $new = $self->SUPER::complement( @_ );  | 
| 
66
 | 
1
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
948
 | 
     return $new unless @_;  | 
| 
67
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
68
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     # RFC2445 - op2 must have no 'exclude'  | 
| 
69
 | 
1
 | 
 
 | 
 
 | 
 
 | 
 
 | 
3
 | 
     my (%op1, %op2);  | 
| 
70
 | 
1
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
12
 | 
     %op1 = ( $self->get_ical ) if ( UNIVERSAL::can( $self, 'get_ical' ) );  | 
| 
71
 | 
1
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
8
 | 
     %op2 = ( $_[0]->get_ical ) if ( UNIVERSAL::can( $_[0], 'get_ical' ) );  | 
| 
72
 | 
1
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
5
 | 
     return $new if ( exists $op2{exclude} );  | 
| 
73
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
74
 | 
1
 | 
 
 | 
 
 | 
 
 | 
 
 | 
4
 | 
     bless $new, 'DateTime::Set::ICal';  | 
| 
75
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     # warn " -- 1 isa @{[%op1]} -- 2 isa @{[%op2]} -- ";  | 
| 
76
 | 
1
 | 
 
 | 
 
 | 
 
 | 
 
 | 
2
 | 
     my ( @include, @exclude );  | 
| 
77
 | 
1
 | 
 
 | 
 
 | 
 
 | 
 
 | 
4
 | 
     @include = exists $op1{include} ?  | 
| 
78
 | 
1
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
7
 | 
                @{$op1{include}} :  | 
| 
79
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                $self;  | 
| 
80
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
81
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
     @exclude = exists $op1{exclude} ?  | 
| 
82
 | 
1
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
6
 | 
                @{$op1{exclude}} :  | 
| 
83
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                ();  | 
| 
84
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
85
 | 
1
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
4
 | 
     if ( exists $op2{include} )  | 
| 
86
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     {  | 
| 
87
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
         push @exclude, @{$op2{include}};  | 
| 
 
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
    | 
| 
88
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     }  | 
| 
89
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     else  | 
| 
90
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     {  | 
| 
91
 | 
1
 | 
 
 | 
 
 | 
 
 | 
 
 | 
3
 | 
         push @exclude, @_;  # whatever...  | 
| 
92
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     }  | 
| 
93
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
94
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     # warn "complement: include @include exclude @exclude";  | 
| 
95
 | 
1
 | 
 
 | 
 
 | 
 
 | 
 
 | 
9
 | 
     $new->set_ical( include => [ @include ], exclude => [ @exclude ] );   | 
| 
96
 | 
1
 | 
 
 | 
 
 | 
 
 | 
 
 | 
4
 | 
     $new;  | 
| 
97
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 }  | 
| 
98
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
99
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 package DateTime::Event::Recurrence;  | 
| 
100
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
101
 | 
14
 | 
 
 | 
 
 | 
  
14
  
 | 
 
 | 
103
 | 
 use strict;  | 
| 
 
 | 
14
 | 
 
 | 
 
 | 
 
 | 
 
 | 
43
 | 
    | 
| 
 
 | 
14
 | 
 
 | 
 
 | 
 
 | 
 
 | 
458
 | 
    | 
| 
102
 | 
14
 | 
 
 | 
 
 | 
  
14
  
 | 
 
 | 
3993
 | 
 use DateTime;  | 
| 
 
 | 
14
 | 
 
 | 
 
 | 
 
 | 
 
 | 
2981677
 | 
    | 
| 
 
 | 
14
 | 
 
 | 
 
 | 
 
 | 
 
 | 
306
 | 
    | 
| 
103
 | 
14
 | 
 
 | 
 
 | 
  
14
  
 | 
 
 | 
13639
 | 
 use DateTime::Set;  | 
| 
 
 | 
14
 | 
 
 | 
 
 | 
 
 | 
 
 | 
703235
 | 
    | 
| 
 
 | 
14
 | 
 
 | 
 
 | 
 
 | 
 
 | 
437
 | 
    | 
| 
104
 | 
14
 | 
 
 | 
 
 | 
  
14
  
 | 
 
 | 
168
 | 
 use DateTime::Span;  | 
| 
 
 | 
14
 | 
 
 | 
 
 | 
 
 | 
 
 | 
31
 | 
    | 
| 
 
 | 
14
 | 
 
 | 
 
 | 
 
 | 
 
 | 
348
 | 
    | 
| 
105
 | 
14
 | 
 
 | 
 
 | 
  
14
  
 | 
 
 | 
87
 | 
 use Params::Validate qw(:all);  | 
| 
 
 | 
14
 | 
 
 | 
 
 | 
 
 | 
 
 | 
32
 | 
    | 
| 
 
 | 
14
 | 
 
 | 
 
 | 
 
 | 
 
 | 
3809
 | 
    | 
| 
106
 | 
14
 | 
 
 | 
 
 | 
  
14
  
 | 
 
 | 
86
 | 
 use vars qw( $VERSION );  | 
| 
 
 | 
14
 | 
 
 | 
 
 | 
 
 | 
 
 | 
29
 | 
    | 
| 
 
 | 
14
 | 
 
 | 
 
 | 
 
 | 
 
 | 
1013
 | 
    | 
| 
107
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 $VERSION = '0.16';  | 
| 
108
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
109
 | 
14
 | 
 
 | 
 
 | 
  
14
  
 | 
 
 | 
81
 | 
 use constant INFINITY     =>       100 ** 100 ** 100 ;  | 
| 
 
 | 
14
 | 
 
 | 
 
 | 
 
 | 
 
 | 
32
 | 
    | 
| 
 
 | 
14
 | 
 
 | 
 
 | 
 
 | 
 
 | 
1063
 | 
    | 
| 
110
 | 
14
 | 
 
 | 
 
 | 
  
14
  
 | 
 
 | 
259
 | 
 use constant NEG_INFINITY => -1 * (100 ** 100 ** 100);  | 
| 
 
 | 
14
 | 
 
 | 
 
 | 
 
 | 
 
 | 
27
 | 
    | 
| 
 
 | 
14
 | 
 
 | 
 
 | 
 
 | 
 
 | 
892
 | 
    | 
| 
111
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
112
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 # -------- BASE OPERATIONS  | 
| 
113
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
114
 | 
14
 | 
 
 | 
 
 | 
 
 | 
 
 | 
3986
 | 
 use vars qw(   | 
| 
115
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     %as_number  | 
| 
116
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
117
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     %truncate   | 
| 
118
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     %next_unit   | 
| 
119
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     %previous_unit   | 
| 
120
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
       | 
| 
121
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     %truncate_interval   | 
| 
122
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     %next_unit_interval   | 
| 
123
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     %previous_unit_interval   | 
| 
124
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
125
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     %weekdays   | 
| 
126
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     %weekdays_1   | 
| 
127
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     %weekdays_any  | 
| 
128
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
       | 
| 
129
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     %memoized_duration  | 
| 
130
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
       | 
| 
131
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     %ical_name  | 
| 
132
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     %ical_days  | 
| 
133
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     %limits  | 
| 
134
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     @units  | 
| 
135
 | 
14
 | 
 
 | 
 
 | 
  
14
  
 | 
 
 | 
64
 | 
 );  | 
| 
 
 | 
14
 | 
 
 | 
 
 | 
 
 | 
 
 | 
25
 | 
    | 
| 
136
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
137
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 BEGIN {  | 
| 
138
 | 
14
 | 
 
 | 
 
 | 
  
14
  
 | 
 
 | 
191
 | 
     %weekdays =   qw(  mo 1   tu 2   we 3   th 4   fr 5   sa 6   su 7 );  | 
| 
139
 | 
14
 | 
 
 | 
 
 | 
 
 | 
 
 | 
127
 | 
     %weekdays_1 = qw( 1mo 1  1tu 2  1we 3  1th 4  1fr 5  1sa 6  1su 7 );  | 
| 
140
 | 
14
 | 
 
 | 
 
 | 
 
 | 
 
 | 
200
 | 
     %weekdays_any = ( %weekdays, %weekdays_1 );  | 
| 
141
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
       | 
| 
142
 | 
14
 | 
 
 | 
 
 | 
 
 | 
 
 | 
93
 | 
     %ical_name =  qw(   | 
| 
143
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         months  BYMONTH     | 
| 
144
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         weeks   BYWEEKNO   | 
| 
145
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         days    BYMONTHDAY    | 
| 
146
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         hours   BYHOUR  | 
| 
147
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         minutes BYMINUTE   | 
| 
148
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         seconds BYSECOND   | 
| 
149
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     );  | 
| 
150
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
       | 
| 
151
 | 
14
 | 
 
 | 
 
 | 
 
 | 
 
 | 
199
 | 
     %ical_days =  qw(   | 
| 
152
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
          1 MO  2 TU  3 WE  4 TH  5 FR  6 SA  7 SU   | 
| 
153
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         -7 MO -6 TU -5 WE -4 TH -3 FR -2 SA -1 SU   | 
| 
154
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     );  | 
| 
155
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                         | 
| 
156
 | 
14
 | 
 
 | 
 
 | 
 
 | 
 
 | 
42
 | 
     @units = qw( years months weeks days hours minutes seconds nanoseconds );  | 
| 
157
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
       | 
| 
158
 | 
14
 | 
 
 | 
 
 | 
 
 | 
 
 | 
3104
 | 
     %limits = qw(  | 
| 
159
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         nanoseconds 1000000000  | 
| 
160
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         seconds     61  | 
| 
161
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         minutes     60  | 
| 
162
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         hours       24  | 
| 
163
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         months      12  | 
| 
164
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         weeks       53  | 
| 
165
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         days        366  | 
| 
166
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     );  | 
| 
167
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
168
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 } # BEGIN  | 
| 
169
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
170
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
171
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 # memoization reduces 'duration' creation from >10000 to about 30 per run,  | 
| 
172
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 # in DT::E::ICal  | 
| 
173
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
174
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 sub _add {  | 
| 
175
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     # datetime, unit, value  | 
| 
176
 | 
17721
 | 
 
 | 
 
 | 
  
17721
  
 | 
 
 | 
47035
 | 
     my $dur = \$memoized_duration{$_[1]}{$_[2]};  | 
| 
177
 | 
17721
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
56396
 | 
     $$dur = new DateTime::Duration( $_[1] => $_[2] )  | 
| 
178
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         unless defined $$dur;  | 
| 
179
 | 
17721
 | 
 
 | 
 
 | 
 
 | 
 
 | 
72937
 | 
     $_[0]->add_duration( $$dur );  | 
| 
180
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 }  | 
| 
181
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
182
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 # TODO: %as_number should use the "subtract" routines from DateTime  | 
| 
183
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
184
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 %as_number = (  | 
| 
185
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     years => sub {   | 
| 
186
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         $_[0]->year   | 
| 
187
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     },  | 
| 
188
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     months => sub {  | 
| 
189
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         12 * $_[0]->year + $_[0]->month - 1  | 
| 
190
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     },  | 
| 
191
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     days => sub {   | 
| 
192
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         ( $_[0]->local_rd_values() )[0]  | 
| 
193
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     },  | 
| 
194
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     weeks => sub {  | 
| 
195
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         # $_[1] is the "week start day", such as "1mo"  | 
| 
196
 | 
14
 | 
 
 | 
 
 | 
  
14
  
 | 
 
 | 
88
 | 
         use integer;  | 
| 
 
 | 
14
 | 
 
 | 
 
 | 
 
 | 
 
 | 
29
 | 
    | 
| 
 
 | 
14
 | 
 
 | 
 
 | 
 
 | 
 
 | 
127
 | 
    | 
| 
197
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         return ( $as_number{days}->( $_[0] ) - $weekdays_any{ $_[1] } ) / 7;  | 
| 
198
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     },  | 
| 
199
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     hours => sub {   | 
| 
200
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         $as_number{days}->($_[0]) * 24 + $_[0]->hour   | 
| 
201
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     },  | 
| 
202
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     minutes => sub {   | 
| 
203
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         $as_number{hours}->($_[0]) * 60 + $_[0]->minute   | 
| 
204
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     },  | 
| 
205
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     seconds => sub {   | 
| 
206
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         $_[0]->local_rd_as_seconds  | 
| 
207
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     },  | 
| 
208
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     years_weekly => sub {  | 
| 
209
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         # get the internal year number, in 'week' mode  | 
| 
210
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         # $_[1] is the "week start day", such as "1mo"  | 
| 
211
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         my $base = $_[0]->clone;  | 
| 
212
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         $base = $truncate{years_weekly}->( $base, $_[1] )  | 
| 
213
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
             if $base->month > 11 || $base->month < 2;  | 
| 
214
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         _add( $base, weeks => 1 );  | 
| 
215
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         return $as_number{years}->( $base );  | 
| 
216
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     },  | 
| 
217
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     months_weekly => sub {  | 
| 
218
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         # get the internal month number, in 'week' mode  | 
| 
219
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         # $_[1] is the "week start day", such as "1mo"  | 
| 
220
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         my $base = $_[0]->clone;  | 
| 
221
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         $base = $truncate{months_weekly}->( $base, $_[1] )  | 
| 
222
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
             if $base->day > 20 || $base->day < 7;  | 
| 
223
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         _add( $base, weeks => 1 );  | 
| 
224
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         return $as_number{months}->( $base );  | 
| 
225
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     },  | 
| 
226
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 );  | 
| 
227
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
228
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
229
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 %truncate = (  | 
| 
230
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     # @_ = ( $datetime, $week_start_day )  | 
| 
231
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
232
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     (  | 
| 
233
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         map {  | 
| 
234
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
               my $name = $_;   | 
| 
235
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
               $name =~ s/s$//;  | 
| 
236
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
               $_ => sub {   | 
| 
237
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                            my $tmp = $_[0]->clone;   | 
| 
238
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                            $tmp->truncate( to => $name )   | 
| 
239
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                         }   | 
| 
240
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
             } qw( years months days hours minutes seconds )  | 
| 
241
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     ),  | 
| 
242
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
243
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     weeks   => sub {   | 
| 
244
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         my $base = $_[0]->clone->truncate( to => 'day' );  | 
| 
245
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         _add( $base, days => - $_[0]->day_of_week   | 
| 
246
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                              + $weekdays_any{ $_[1] } );  | 
| 
247
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         while(1) {  | 
| 
248
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
             return $base if $base <= $_[0];  | 
| 
249
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
             _add( $base, weeks => -1 );  | 
| 
250
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         }  | 
| 
251
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     },  | 
| 
252
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
253
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     months_weekly => sub {  | 
| 
254
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         my $tmp;  | 
| 
255
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         my $base = $_[0]->clone;  | 
| 
256
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         _add( $base, days => 7 );  | 
| 
257
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         $base->truncate( to => 'month' );  | 
| 
258
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         my $val;  | 
| 
259
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         my $diff;  | 
| 
260
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         while(1) {  | 
| 
261
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
             $tmp = $base->clone;  | 
| 
262
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
             $val = $weekdays_1{ $_[1] };  | 
| 
263
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
             if ( $val )   | 
| 
264
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
             {  | 
| 
265
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                 $diff = $val - $base->day_of_week;  | 
| 
266
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                 $diff += 7 if $diff < 0;  | 
| 
267
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
             }  | 
| 
268
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
             else   | 
| 
269
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
             {  | 
| 
270
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                 $diff = ( $weekdays{ $_[1] } -   | 
| 
271
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                           $base->day_of_week ) % 7;  | 
| 
272
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                 $diff -= 7 if $diff > 3;  | 
| 
273
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
             }  | 
| 
274
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
             _add( $tmp, days =>  $diff );  | 
| 
275
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
             return $tmp if $tmp <= $_[0];  | 
| 
276
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
             _add( $base, months => -1 );  | 
| 
277
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         }  | 
| 
278
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     },  | 
| 
279
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
280
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     years_weekly => sub {  | 
| 
281
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         my $tmp;  | 
| 
282
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         my $base = $_[0]->clone;  | 
| 
283
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         _add( $base, months => 1 );  | 
| 
284
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         $base->truncate( to => 'year' );  | 
| 
285
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         my $val;  | 
| 
286
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         my $diff;  | 
| 
287
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         # warn "wsd $_[1]\n";  | 
| 
288
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         while(1) {  | 
| 
289
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
             $tmp = $base->clone;  | 
| 
290
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
             $val = $weekdays_1{ $_[1] };  | 
| 
291
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
             if ( $val )   | 
| 
292
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
             {  | 
| 
293
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                 $diff = $val - $base->day_of_week;  | 
| 
294
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                 $diff += 7 if $diff < 0;  | 
| 
295
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
             }  | 
| 
296
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
             else   | 
| 
297
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
             {  | 
| 
298
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                 $diff = ( $weekdays{ $_[1] } -   | 
| 
299
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                           $base->day_of_week ) % 7;  | 
| 
300
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                 $diff -= 7 if $diff > 3;  | 
| 
301
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
             }  | 
| 
302
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
             _add( $tmp, days =>  $diff );  | 
| 
303
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
             return $tmp if $tmp <= $_[0];  | 
| 
304
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
             _add( $base, years => -1 );  | 
| 
305
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         }  | 
| 
306
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     },  | 
| 
307
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 );  | 
| 
308
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
309
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 %next_unit = (  | 
| 
310
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     # @_ = ( $datetime, $week_start_day )  | 
| 
311
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
312
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     (  | 
| 
313
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         map {   | 
| 
314
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
               my $names = $_;  | 
| 
315
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
               $_ => sub {   | 
| 
316
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                            _add( $_[0], $names => 1 )   | 
| 
317
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                         }   | 
| 
318
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
             } qw( years months weeks days hours minutes seconds )  | 
| 
319
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     ),  | 
| 
320
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
321
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     months_weekly => sub {  | 
| 
322
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         my $base = $_[0]->clone;  | 
| 
323
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         my $return;  | 
| 
324
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         while(1) {  | 
| 
325
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
             _add( $base, days => 21 );  | 
| 
326
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
             $return = $truncate{months_weekly}->( $base, $_[1] );  | 
| 
327
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
             return $_[0] = $return if $return > $_[0];  | 
| 
328
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         }  | 
| 
329
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     },  | 
| 
330
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
331
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     years_weekly => sub {  | 
| 
332
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         my $base = $_[0]->clone;  | 
| 
333
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         my $return;  | 
| 
334
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         while(1) {  | 
| 
335
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
             _add( $base, months => 11 );  | 
| 
336
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
             $return = $truncate{years_weekly}->( $base, $_[1] );  | 
| 
337
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
             return $_[0] = $return if $return > $_[0];  | 
| 
338
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         }  | 
| 
339
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     },  | 
| 
340
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 );  | 
| 
341
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
342
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 %previous_unit = (  | 
| 
343
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     # @_ = ( $datetime, $week_start_day )  | 
| 
344
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
345
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     months_weekly => sub {  | 
| 
346
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         my $base = $_[0]->clone;  | 
| 
347
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         my $return;  | 
| 
348
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         while(1) {  | 
| 
349
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
             $return = $truncate{months_weekly}->( $base, $_[1] );  | 
| 
350
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
             return $_[0] = $return if $return < $_[0];  | 
| 
351
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
             _add( $base, days => -21 );  | 
| 
352
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         }  | 
| 
353
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     },  | 
| 
354
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
355
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     years_weekly => sub {  | 
| 
356
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         my $base = $_[0]->clone;  | 
| 
357
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         my $return;  | 
| 
358
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         while(1) {  | 
| 
359
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
             $return = $truncate{years_weekly}->( $base, $_[1] );  | 
| 
360
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
             return $_[0] = $return if $return < $_[0];  | 
| 
361
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
             _add( $base, months => -11 );  | 
| 
362
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         }  | 
| 
363
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     },  | 
| 
364
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 );  | 
| 
365
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
366
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 # -------- "INTERVAL" OPERATIONS  | 
| 
367
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
368
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 %truncate_interval = (  | 
| 
369
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     # @_ = ( $datetime, $args )  | 
| 
370
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
371
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     (  | 
| 
372
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         map {   | 
| 
373
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
               my $names = $_;  | 
| 
374
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
               my $name = $_;   | 
| 
375
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
               $name =~ s/s$//;  | 
| 
376
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
               $_ => sub {   | 
| 
377
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                            my $tmp = $_[0]->clone;  | 
| 
378
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                            $tmp->truncate( to => $name );  | 
| 
379
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                            _add( $tmp, $names =>   | 
| 
380
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                                      $_[1]{offset} -   | 
| 
381
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                                      ( $as_number{$names}->($_[0]) %  | 
| 
382
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                                        $_[1]{interval}   | 
| 
383
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                                      )   | 
| 
384
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                                );  | 
| 
385
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                         }   | 
| 
386
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
             } qw( years months days hours minutes seconds )  | 
| 
387
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     ),  | 
| 
388
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
389
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     weeks   => sub {   | 
| 
390
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         my $tmp = $truncate{weeks}->( $_[0], $_[1]{week_start_day} );  | 
| 
391
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         while ( $_[1]{offset} !=   | 
| 
392
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                 ( $as_number{weeks}->(   | 
| 
393
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                     $tmp, $_[1]{week_start_day} ) %   | 
| 
394
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                   $_[1]{interval}   | 
| 
395
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                 )   | 
| 
396
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
               )  | 
| 
397
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         {  | 
| 
398
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
             _add( $tmp, weeks => -1 );  | 
| 
399
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         }  | 
| 
400
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         return $tmp;  | 
| 
401
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     },  | 
| 
402
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
403
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     months_weekly => sub {  | 
| 
404
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         my $tmp = $truncate{months_weekly}->( $_[0], $_[1]{week_start_day} );  | 
| 
405
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         while ( $_[1]{offset} !=   | 
| 
406
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                 ( $as_number{months_weekly}->(   | 
| 
407
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                     $tmp, $_[1]{week_start_day} ) %   | 
| 
408
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                   $_[1]{interval}   | 
| 
409
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                 )  | 
| 
410
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
               )  | 
| 
411
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         {  | 
| 
412
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
             $previous_unit{months_weekly}->( $tmp, $_[1]{week_start_day} );  | 
| 
413
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         }  | 
| 
414
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         return $tmp;  | 
| 
415
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     },  | 
| 
416
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
417
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     years_weekly => sub {  | 
| 
418
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         my $tmp = $truncate{years_weekly}->( $_[0], $_[1]{week_start_day} );  | 
| 
419
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         while ( $_[1]{offset} !=   | 
| 
420
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                 ( $as_number{years_weekly}->( $tmp, $_[1]{week_start_day} ) %   | 
| 
421
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                     $_[1]{interval}   | 
| 
422
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                 )   | 
| 
423
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
               )   | 
| 
424
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         {  | 
| 
425
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
             $previous_unit{years_weekly}->( $tmp, $_[1]{week_start_day} );  | 
| 
426
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         }  | 
| 
427
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         return $tmp;  | 
| 
428
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     },  | 
| 
429
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 );  | 
| 
430
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
431
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 %next_unit_interval = (  | 
| 
432
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     (  | 
| 
433
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         map {  | 
| 
434
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
               my $names = $_;  | 
| 
435
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
               $_ => sub {   | 
| 
436
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                            _add( $_[0], $names => $_[1]{interval} )   | 
| 
437
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                         }   | 
| 
438
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
             } qw( years months weeks days hours minutes seconds )  | 
| 
439
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     ),  | 
| 
440
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
441
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     months_weekly => sub {  | 
| 
442
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         for ( 1 .. $_[1]{interval} )  | 
| 
443
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         {  | 
| 
444
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
             $next_unit{months_weekly}->( $_[0], $_[1]{week_start_day} );  | 
| 
445
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         }  | 
| 
446
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     },  | 
| 
447
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
448
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     years_weekly => sub {  | 
| 
449
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         for ( 1 .. $_[1]{interval} )   | 
| 
450
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         {  | 
| 
451
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
             $next_unit{years_weekly}->( $_[0], $_[1]{week_start_day} );  | 
| 
452
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         }  | 
| 
453
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     },  | 
| 
454
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 );  | 
| 
455
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
456
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 %previous_unit_interval = (  | 
| 
457
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     (   | 
| 
458
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         map {   | 
| 
459
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
               my $names = $_;  | 
| 
460
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
               $_ => sub {   | 
| 
461
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                            _add( $_[0], $names => - $_[1]{interval} )  | 
| 
462
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                         }   | 
| 
463
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
             } qw( years months weeks days hours minutes seconds )    | 
| 
464
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     ),  | 
| 
465
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
466
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     months_weekly => sub {  | 
| 
467
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         for ( 1 .. $_[1]{interval} )  | 
| 
468
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         {  | 
| 
469
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
             $previous_unit{months_weekly}->( $_[0], $_[1]{week_start_day} );  | 
| 
470
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         }  | 
| 
471
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     },  | 
| 
472
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
473
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     years_weekly => sub {  | 
| 
474
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         for ( 1 .. $_[1]{interval} )  | 
| 
475
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         {  | 
| 
476
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
             $previous_unit{years_weekly}->( $_[0], $_[1]{week_start_day} );  | 
| 
477
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         }  | 
| 
478
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     },  | 
| 
479
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 );  | 
| 
480
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
481
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 # -------- CONSTRUCTORS  | 
| 
482
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
483
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 BEGIN {  | 
| 
484
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     # setup all constructors: daily, ...  | 
| 
485
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
486
 | 
14
 | 
 
 | 
 
 | 
  
14
  
 | 
 
 | 
88
 | 
     for ( @units[ 0 .. $#units-1 ] )   | 
| 
487
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     {  | 
| 
488
 | 
98
 | 
 
 | 
 
 | 
 
 | 
 
 | 
140
 | 
         my $name = $_;  | 
| 
489
 | 
98
 | 
 
 | 
 
 | 
 
 | 
 
 | 
123
 | 
         my $namely = $_;  | 
| 
490
 | 
98
 | 
 
 | 
 
 | 
 
 | 
 
 | 
156
 | 
         $namely =~ s/ys$/ily/;  | 
| 
491
 | 
98
 | 
 
 | 
 
 | 
 
 | 
 
 | 
313
 | 
         $namely =~ s/s$/ly/;  | 
| 
492
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
           | 
| 
493
 | 
14
 | 
 
 | 
 
 | 
  
14
  
 | 
 
 | 
37927
 | 
         no strict 'refs';  | 
| 
 
 | 
14
 | 
 
 | 
 
 | 
 
 | 
 
 | 
33
 | 
    | 
| 
 
 | 
14
 | 
 
 | 
 
 | 
 
 | 
 
 | 
912
 | 
    | 
| 
494
 | 
98
 | 
 
 | 
 
 | 
 
 | 
 
 | 
42275
 | 
         *{__PACKAGE__ . "::$namely"} =  | 
| 
495
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
             sub {   | 
| 
496
 | 
14
 | 
 
 | 
 
 | 
  
14
  
 | 
 
 | 
89
 | 
                     use strict 'refs';  | 
| 
 
 | 
14
 | 
 
 | 
 
 | 
 
 | 
 
 | 
40
 | 
    | 
| 
 
 | 
14
 | 
 
 | 
 
 | 
 
 | 
 
 | 
1018
 | 
    | 
| 
497
 | 
62
 | 
 
 | 
 
 | 
  
62
  
 | 
 
 | 
72881
 | 
                     my $class = shift;  | 
| 
498
 | 
62
 | 
 
 | 
 
 | 
 
 | 
 
 | 
280
 | 
                     return _create_recurrence( base => $name, @_ );  | 
| 
499
 | 
98
 | 
 
 | 
 
 | 
 
 | 
 
 | 
315
 | 
                 };  | 
| 
500
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     }  | 
| 
501
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 } # BEGIN  | 
| 
502
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
503
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
504
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 sub _create_recurrence {  | 
| 
505
 | 
62
 | 
 
 | 
 
 | 
  
62
  
 | 
 
 | 
347
 | 
     my %args = @_;  | 
| 
506
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
507
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     # print "ARGS: ";   | 
| 
508
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     # for(@_){ print (( ref($_) eq "ARRAY" ) ? "[ @$_ ] " : "$_ ") }  | 
| 
509
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     # print " \n";  | 
| 
510
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
       | 
| 
511
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     # --- FREQUENCY  | 
| 
512
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
       | 
| 
513
 | 
62
 | 
 
 | 
 
 | 
 
 | 
 
 | 
203
 | 
     my $base = delete $args{base};  | 
| 
514
 | 
62
 | 
 
 | 
 
 | 
 
 | 
 
 | 
143
 | 
     my $namely = $base;  | 
| 
515
 | 
62
 | 
 
 | 
 
 | 
 
 | 
 
 | 
213
 | 
     $namely =~ s/ys$/ily/;  | 
| 
516
 | 
62
 | 
 
 | 
 
 | 
 
 | 
 
 | 
292
 | 
     $namely =~ s/s$/ly/;  | 
| 
517
 | 
62
 | 
 
 | 
 
 | 
 
 | 
 
 | 
216
 | 
     my $ical_string = uc( "RRULE:FREQ=$namely" );  | 
| 
518
 | 
62
 | 
 
 | 
 
 | 
 
 | 
 
 | 
130
 | 
     my $base_unit = $base;  | 
| 
519
 | 
62
 | 
  
100
  
 | 
  
100
  
 | 
 
 | 
 
 | 
435
 | 
     $base_unit = 'years_weekly'   | 
| 
520
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
          if $base_unit eq 'years' &&  | 
| 
521
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
             exists $args{weeks} ;  | 
| 
522
 | 
62
 | 
  
100
  
 | 
  
100
  
 | 
 
 | 
 
 | 
351
 | 
     $base_unit = 'months_weekly'  | 
| 
523
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
          if $base_unit eq 'months' &&  | 
| 
524
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
             exists $args{weeks} ;  | 
| 
525
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
526
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     # --- WEEK-START-DAY  | 
| 
527
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
       | 
| 
528
 | 
62
 | 
 
 | 
 
 | 
 
 | 
 
 | 
141
 | 
     my $week_start_day = delete $args{week_start_day};  | 
| 
529
 | 
62
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
198
 | 
     $ical_string .= ";WKST=". uc($week_start_day)  | 
| 
530
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         if $week_start_day;  | 
| 
531
 | 
62
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
290
 | 
     $week_start_day = ( $base eq 'years' ) ? 'mo' : '1mo'  | 
| 
 
 | 
 
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
532
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         unless defined $week_start_day;  | 
| 
533
 | 
62
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
465
 | 
     die "$base: invalid week start day ($week_start_day)"  | 
| 
534
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         unless $weekdays_any{ $week_start_day };  | 
| 
535
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                      | 
| 
536
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     # --- INTERVAL, START, and OFFSET  | 
| 
537
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
               | 
| 
538
 | 
62
 | 
 
 | 
  
 50
  
 | 
 
 | 
 
 | 
355
 | 
     my $interval = delete $args{interval} || 1;  | 
| 
539
 | 
62
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
196
 | 
     die "invalid 'interval' specification ($interval)"  | 
| 
540
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         if $interval < 1;  | 
| 
541
 | 
62
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
265
 | 
     $ical_string .= ";INTERVAL=$interval"   | 
| 
542
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         if $interval > 1;  | 
| 
543
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
544
 | 
62
 | 
 
 | 
 
 | 
 
 | 
 
 | 
126
 | 
     my $start = delete $args{start};  | 
| 
545
 | 
62
 | 
  
 50
  
 | 
  
 33
  
 | 
 
 | 
 
 | 
216
 | 
     undef $start   | 
| 
546
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         if defined $start && $start->is_infinite;  | 
| 
547
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
           | 
| 
548
 | 
62
 | 
 
 | 
 
 | 
 
 | 
 
 | 
119
 | 
     my $offset = 0;  | 
| 
549
 | 
62
 | 
  
 50
  
 | 
  
 33
  
 | 
 
 | 
 
 | 
248
 | 
     $offset = $as_number{$base_unit}->( $start, $week_start_day ) % $interval  | 
| 
550
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         if $start && $interval > 1;  | 
| 
551
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
552
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     # --- DURATION LIST  | 
| 
553
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
       | 
| 
554
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     # check for invalid "units" arguments, such as "daily( years=> )"  | 
| 
555
 | 
62
 | 
 
 | 
 
 | 
 
 | 
 
 | 
114
 | 
     my @valid_units;  | 
| 
556
 | 
62
 | 
 
 | 
 
 | 
 
 | 
 
 | 
246
 | 
     for ( 0 .. $#units )  | 
| 
557
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     {  | 
| 
558
 | 
131
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
412
 | 
         if ( $base eq $units[$_] )  | 
| 
559
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         {  | 
| 
560
 | 
62
 | 
 
 | 
 
 | 
 
 | 
 
 | 
369
 | 
             @valid_units = @units[ $_+1 .. $#units ];  | 
| 
561
 | 
62
 | 
 
 | 
 
 | 
 
 | 
 
 | 
156
 | 
             last;  | 
| 
562
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         }  | 
| 
563
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     }  | 
| 
564
 | 
62
 | 
  
 50
  
 | 
  
 66
  
 | 
 
 | 
 
 | 
319
 | 
     die "can't have both 'months' and 'weeks' arguments"   | 
| 
565
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         if exists $args{weeks} &&   | 
| 
566
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
            exists $args{months};  | 
| 
567
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
       | 
| 
568
 | 
62
 | 
 
 | 
 
 | 
 
 | 
 
 | 
115
 | 
     my $level = 1;  | 
| 
569
 | 
62
 | 
 
 | 
 
 | 
 
 | 
 
 | 
155
 | 
     my @duration =   ( [] );    | 
| 
570
 | 
62
 | 
 
 | 
 
 | 
 
 | 
 
 | 
166
 | 
     my @level_unit = ( $base_unit );  | 
| 
571
 | 
62
 | 
 
 | 
 
 | 
 
 | 
 
 | 
147
 | 
     for my $unit ( @valid_units )  | 
| 
572
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     {  | 
| 
573
 | 
361
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
939
 | 
             next unless exists $args{$unit};  | 
| 
574
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
575
 | 
100
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
291
 | 
             if ( ref( $args{$unit} ) eq 'ARRAY' )  | 
| 
576
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
             {  | 
| 
577
 | 
61
 | 
 
 | 
 
 | 
 
 | 
 
 | 
78
 | 
                 $args{$unit} = [ @{ $args{$unit} } ]   | 
| 
 
 | 
61
 | 
 
 | 
 
 | 
 
 | 
 
 | 
212
 | 
    | 
| 
578
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
             }  | 
| 
579
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
             else      | 
| 
580
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
             {  | 
| 
581
 | 
39
 | 
 
 | 
 
 | 
 
 | 
 
 | 
114
 | 
                 $args{$unit} = [ $args{$unit} ]   | 
| 
582
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
             }  | 
| 
583
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                   | 
| 
584
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
             # TODO: sort _after_ normalization  | 
| 
585
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
586
 | 
100
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
378
 | 
             if ( $unit eq 'days' )  | 
| 
587
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
             {  | 
| 
588
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                 # map rfc2445 weekdays to numbers  | 
| 
589
 | 
27
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
149
 | 
                 @{$args{$unit}} =   | 
| 
 
 | 
149
 | 
 
 | 
 
 | 
 
 | 
 
 | 
443
 | 
    | 
| 
590
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                     map {  | 
| 
591
 | 
27
 | 
 
 | 
 
 | 
 
 | 
 
 | 
63
 | 
                           $_ =~ /[a-z]/ ? $weekdays{$_} : $_  | 
| 
592
 | 
27
 | 
 
 | 
 
 | 
 
 | 
 
 | 
54
 | 
                         } @{$args{$unit}};  | 
| 
593
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
             }  | 
| 
594
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
595
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
             # sort positive values first  | 
| 
596
 | 
100
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
308
 | 
             @{$args{$unit}} =   | 
| 
 
 | 
381
 | 
 
 | 
 
 | 
 
 | 
 
 | 
693
 | 
    | 
| 
597
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                 sort {  | 
| 
598
 | 
100
 | 
 
 | 
 
 | 
 
 | 
 
 | 
373
 | 
                        ( $a < 0 ) <=> ( $b < 0 ) || $a <=> $b  | 
| 
599
 | 
100
 | 
 
 | 
 
 | 
 
 | 
 
 | 
175
 | 
                      } @{$args{$unit}};  | 
| 
600
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
601
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
602
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
             # make the "ical" string  | 
| 
603
 | 
100
 | 
  
100
  
 | 
  
 66
  
 | 
 
 | 
 
 | 
497
 | 
             if ( $unit eq 'nanoseconds' )  | 
| 
 
 | 
 
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
604
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
             {  | 
| 
605
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                 # there are no nanoseconds in ICal  | 
| 
606
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
             }  | 
| 
607
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
             elsif ( $base eq 'weeks' &&  | 
| 
608
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                     $unit eq 'days' )  | 
| 
609
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
             {  | 
| 
610
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                 # weekdays have names  | 
| 
611
 | 
6
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
48
 | 
                 $ical_string .= uc( ';' . 'BYDAY' . '=' .   | 
| 
612
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                     join(",",   | 
| 
613
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                         map {   | 
| 
614
 | 
6
 | 
 
 | 
 
 | 
 
 | 
 
 | 
18
 | 
                               exists( $ical_days{$_} ) ? $ical_days{$_} : $_   | 
| 
615
 | 
6
 | 
 
 | 
 
 | 
 
 | 
 
 | 
18
 | 
                             } @{$args{$unit}} )   | 
| 
616
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                   )   | 
| 
617
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
             }  | 
| 
618
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
             else  | 
| 
619
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
             {  | 
| 
620
 | 
93
 | 
 
 | 
 
 | 
 
 | 
 
 | 
407
 | 
                 $ical_string .= uc( ';' . $ical_name{$unit} . '=' .   | 
| 
621
 | 
93
 | 
 
 | 
 
 | 
 
 | 
 
 | 
271
 | 
                                 join(",", @{$args{$unit}} ) )   | 
| 
622
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
             }  | 
| 
623
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
              | 
| 
624
 | 
100
 | 
  
100
  
 | 
  
100
  
 | 
 
 | 
 
 | 
798
 | 
             if ( $unit eq 'months' ||  | 
| 
 
 | 
 
 | 
 
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
625
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                  $unit eq 'weeks' ||  | 
| 
626
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                  $unit eq 'days' )   | 
| 
627
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
             {  | 
| 
628
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                 # these units start in '1'  | 
| 
629
 | 
58
 | 
 
 | 
 
 | 
 
 | 
 
 | 
92
 | 
                 for ( @{$args{$unit}} )   | 
| 
 
 | 
58
 | 
 
 | 
 
 | 
 
 | 
 
 | 
153
 | 
    | 
| 
630
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                 {  | 
| 
631
 | 
211
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
368
 | 
                     die $unit . ' cannot be zero'   | 
| 
632
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                         unless $_;  | 
| 
633
 | 
211
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
506
 | 
                     $_-- if $_ > 0;  | 
| 
634
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                 }  | 
| 
635
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
             }  | 
| 
636
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
               | 
| 
637
 | 
100
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
405
 | 
             @{$args{$unit}} =  | 
| 
 
 | 
431
 | 
 
 | 
 
 | 
 
 | 
 
 | 
1949
 | 
    | 
| 
638
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                     grep {   | 
| 
639
 | 
100
 | 
 
 | 
 
 | 
 
 | 
 
 | 
220
 | 
                            $_ < $limits{ $unit } &&   | 
| 
640
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                            $_ >= - $limits{ $unit }   | 
| 
641
 | 
100
 | 
 
 | 
 
 | 
 
 | 
 
 | 
183
 | 
                          } @{$args{$unit}};  | 
| 
642
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
               | 
| 
643
 | 
100
 | 
  
100
  
 | 
  
100
  
 | 
 
 | 
 
 | 
472
 | 
             if ( $unit eq 'days' &&  | 
| 
 
 | 
 
 | 
 
 | 
  
 66
  
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
644
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                  ( $base_unit eq 'months' ||   | 
| 
645
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                    $level_unit[-1] eq 'months' ) )  | 
| 
646
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
             {   # month day  | 
| 
647
 | 
16
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
62
 | 
                     @{$args{$unit}} =   | 
| 
 
 | 
138
 | 
 
 | 
 
 | 
 
 | 
 
 | 
504
 | 
    | 
| 
648
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                         grep {   | 
| 
649
 | 
16
 | 
 
 | 
 
 | 
 
 | 
 
 | 
34
 | 
                                $_ < 31 && $_ >= -31   | 
| 
650
 | 
16
 | 
 
 | 
 
 | 
 
 | 
 
 | 
31
 | 
                              } @{$args{$unit}};  | 
| 
651
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
             }  | 
| 
652
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
653
 | 
100
 | 
  
100
  
 | 
  
100
  
 | 
 
 | 
 
 | 
463
 | 
             if ( $unit eq 'days' &&  | 
| 
 
 | 
 
 | 
 
 | 
  
 66
  
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
654
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                  ( $base_unit eq 'weeks' ||   | 
| 
655
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                    $level_unit[-1] eq 'weeks' ) )  | 
| 
656
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
             {   # week day  | 
| 
657
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                       | 
| 
658
 | 
10
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
29
 | 
                     @{$args{$unit}} =   | 
| 
 
 | 
10
 | 
 
 | 
 
 | 
 
 | 
 
 | 
66
 | 
    | 
| 
659
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                         grep {   | 
| 
660
 | 
10
 | 
 
 | 
 
 | 
 
 | 
 
 | 
21
 | 
                                $_ < 7 && $_ >= -7   | 
| 
661
 | 
10
 | 
 
 | 
 
 | 
 
 | 
 
 | 
17
 | 
                              } @{$args{$unit}};  | 
| 
662
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
663
 | 
10
 | 
 
 | 
 
 | 
 
 | 
 
 | 
19
 | 
                     for ( @{$args{$unit}} )   | 
| 
 
 | 
10
 | 
 
 | 
 
 | 
 
 | 
 
 | 
30
 | 
    | 
| 
664
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                     {  | 
| 
665
 | 
10
 | 
 
 | 
 
 | 
 
 | 
 
 | 
29
 | 
                         $_ = $_ - $weekdays_any{ $week_start_day } + 1;  | 
| 
666
 | 
10
 | 
 
 | 
 
 | 
 
 | 
 
 | 
47
 | 
                         $_ += 7 while $_ < 0;  | 
| 
667
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                     }  | 
| 
668
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
669
 | 
10
 | 
 
 | 
 
 | 
 
 | 
 
 | 
20
 | 
                     @{$args{$unit}} = sort @{$args{$unit}};  | 
| 
 
 | 
10
 | 
 
 | 
 
 | 
 
 | 
 
 | 
34
 | 
    | 
| 
 
 | 
10
 | 
 
 | 
 
 | 
 
 | 
 
 | 
28
 | 
    | 
| 
670
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
             }  | 
| 
671
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
672
 | 
100
 | 
 
 | 
 
 | 
 
 | 
 
 | 
352
 | 
             return DateTime::Set::ICal->empty_set   | 
| 
673
 | 
100
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
166
 | 
                 unless @{$args{$unit}};  # there are no args left  | 
| 
674
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
675
 | 
99
 | 
 
 | 
 
 | 
 
 | 
 
 | 
189
 | 
             push @duration, $args{$unit};  | 
| 
676
 | 
99
 | 
 
 | 
 
 | 
 
 | 
 
 | 
159
 | 
             push @level_unit, $unit;  | 
| 
677
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
678
 | 
99
 | 
 
 | 
 
 | 
 
 | 
 
 | 
202
 | 
             delete $args{$unit};  | 
| 
679
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
680
 | 
99
 | 
 
 | 
 
 | 
 
 | 
 
 | 
166
 | 
             $level++;  | 
| 
681
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     }  | 
| 
682
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
683
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     # TODO: use $span for selecting elements (using intersection)   | 
| 
684
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     # note - this may change the documented behaviour - check the pod first  | 
| 
685
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     # $span = delete $args{span};  | 
| 
686
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     # $span = DateTime::Span->new( %args ) if %args;  | 
| 
687
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
688
 | 
61
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
250
 | 
     die "invalid argument '@{[ keys %args ]}'"  | 
| 
 
 | 
1
 | 
 
 | 
 
 | 
 
 | 
 
 | 
17
 | 
    | 
| 
689
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         if keys %args;  | 
| 
690
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
      | 
| 
691
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     # --- SPLIT NEGATIVE/POSITIVE DURATIONS  | 
| 
692
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
693
 | 
60
 | 
 
 | 
 
 | 
 
 | 
 
 | 
98
 | 
     my @args;  | 
| 
694
 | 
60
 | 
 
 | 
 
 | 
 
 | 
 
 | 
125
 | 
     push @args, \@duration;  | 
| 
695
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
       | 
| 
696
 | 
60
 | 
 
 | 
 
 | 
 
 | 
 
 | 
236
 | 
     for ( my $i = 0; $i < @args; $i++ )  | 
| 
697
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     {  | 
| 
698
 | 
73
 | 
 
 | 
 
 | 
 
 | 
 
 | 
168
 | 
         my $dur1 = $args[$i];  | 
| 
699
 | 
73
 | 
 
 | 
 
 | 
 
 | 
 
 | 
131
 | 
         for ( 1 .. $#{$dur1} )  | 
| 
 
 | 
73
 | 
 
 | 
 
 | 
 
 | 
 
 | 
320
 | 
    | 
| 
700
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         {  | 
| 
701
 | 
121
 | 
 
 | 
 
 | 
 
 | 
 
 | 
187
 | 
             my @negatives = grep { $_ <  0 } @{$dur1->[$_]};  | 
| 
 
 | 
460
 | 
 
 | 
 
 | 
 
 | 
 
 | 
824
 | 
    | 
| 
 
 | 
121
 | 
 
 | 
 
 | 
 
 | 
 
 | 
237
 | 
    | 
| 
702
 | 
121
 | 
 
 | 
 
 | 
 
 | 
 
 | 
187
 | 
             my @positives = grep { $_ >= 0 } @{$dur1->[$_]};  | 
| 
 
 | 
460
 | 
 
 | 
 
 | 
 
 | 
 
 | 
846
 | 
    | 
| 
 
 | 
121
 | 
 
 | 
 
 | 
 
 | 
 
 | 
197
 | 
    | 
| 
703
 | 
121
 | 
  
100
  
 | 
  
100
  
 | 
 
 | 
 
 | 
827
 | 
             if ( @positives && @negatives )  | 
| 
704
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
             {  | 
| 
705
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                 # split  | 
| 
706
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                 # TODO: check if it really needs splitting  | 
| 
707
 | 
13
 | 
 
 | 
 
 | 
 
 | 
 
 | 
19
 | 
                 my $dur2 = [ @{$args[$i]} ];  | 
| 
 
 | 
13
 | 
 
 | 
 
 | 
 
 | 
 
 | 
40
 | 
    | 
| 
708
 | 
13
 | 
 
 | 
 
 | 
 
 | 
 
 | 
27
 | 
                 $dur2->[$_] = \@negatives;  | 
| 
709
 | 
13
 | 
 
 | 
 
 | 
 
 | 
 
 | 
35
 | 
                 $dur1->[$_] = \@positives;  | 
| 
710
 | 
13
 | 
 
 | 
 
 | 
 
 | 
 
 | 
77
 | 
                 push @args, $dur2;  | 
| 
711
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
             }  | 
| 
712
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         }  | 
| 
713
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     }  | 
| 
714
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
715
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     # --- CREATE THE SET  | 
| 
716
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
       | 
| 
717
 | 
60
 | 
 
 | 
 
 | 
 
 | 
 
 | 
99
 | 
     my $set;  | 
| 
718
 | 
60
 | 
 
 | 
 
 | 
 
 | 
 
 | 
140
 | 
     for ( @args )  | 
| 
719
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     {  | 
| 
720
 | 
73
 | 
 
 | 
 
 | 
 
 | 
 
 | 
260
 | 
         my @duration = @$_;  | 
| 
721
 | 
73
 | 
 
 | 
 
 | 
 
 | 
 
 | 
121
 | 
         my $total_durations = 1;  | 
| 
722
 | 
73
 | 
 
 | 
 
 | 
 
 | 
 
 | 
97
 | 
         my @total_level;  | 
| 
723
 | 
73
 | 
 
 | 
 
 | 
 
 | 
 
 | 
272
 | 
         for ( my $i = $#duration; $i > 0; $i-- )   | 
| 
724
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         {  | 
| 
725
 | 
121
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
1252
 | 
             if ( $i == $#duration )   | 
| 
726
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
             {  | 
| 
727
 | 
68
 | 
 
 | 
 
 | 
 
 | 
 
 | 
1230
 | 
                 $total_level[$i] = 1;  | 
| 
728
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
             }  | 
| 
729
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
             else   | 
| 
730
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
             {  | 
| 
731
 | 
53
 | 
 
 | 
 
 | 
 
 | 
 
 | 
109
 | 
                 $total_level[$i] = $total_level[$i + 1] *   | 
| 
732
 | 
53
 | 
 
 | 
 
 | 
 
 | 
 
 | 
86
 | 
                                    ( 1 + $#{ $duration[$i + 1] } );  | 
| 
733
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
             }  | 
| 
734
 | 
121
 | 
 
 | 
 
 | 
 
 | 
 
 | 
162
 | 
             $total_durations *= 1 + $#{ $duration[$i] };  | 
| 
 
 | 
121
 | 
 
 | 
 
 | 
 
 | 
 
 | 
394
 | 
    | 
| 
735
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         }  | 
| 
736
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
737
 | 
73
 | 
 
 | 
 
 | 
 
 | 
 
 | 
1958
 | 
         my $args =  {  | 
| 
738
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
             truncate_interval =>      $truncate_interval{ $base_unit },  | 
| 
739
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
             previous_unit_interval => $previous_unit_interval{ $base_unit },  | 
| 
740
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
             next_unit_interval =>     $next_unit_interval{ $base_unit },  | 
| 
741
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
               | 
| 
742
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
             duration =>        \@duration,   | 
| 
743
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
             total_durations => $total_durations,  | 
| 
744
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
             level_unit =>      \@level_unit,  | 
| 
745
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
             total_level =>     \@total_level,  | 
| 
746
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
               | 
| 
747
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
             interval =>        $interval,  | 
| 
748
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
             offset =>          $offset,  | 
| 
749
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
             week_start_day =>  $week_start_day,  | 
| 
750
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         };  | 
| 
751
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
           | 
| 
752
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         my $tmp = DateTime::Set::ICal->from_recurrence(  | 
| 
753
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                           next => sub {   | 
| 
754
 | 
1056
 | 
 
 | 
 
 | 
  
1056
  
 | 
 
 | 
570819
 | 
                               _get_next( $_[0], $args );   | 
| 
755
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                           },  | 
| 
756
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                           previous => sub {   | 
| 
757
 | 
522
 | 
 
 | 
 
 | 
  
522
  
 | 
 
 | 
115885
 | 
                               _get_previous( $_[0], $args );   | 
| 
758
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                           },  | 
| 
759
 | 
73
 | 
 
 | 
 
 | 
 
 | 
 
 | 
965
 | 
         );  | 
| 
760
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
           | 
| 
761
 | 
73
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
14466
 | 
         $set = defined $set ? $set->union( $tmp ) : $tmp;  | 
| 
762
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     }  | 
| 
763
 | 
60
 | 
 
 | 
 
 | 
 
 | 
 
 | 
1345
 | 
     $set->set_ical( include => [ $ical_string ] );   | 
| 
764
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     # warn "Creating set: ". $ical_string ." \n";  | 
| 
765
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
       | 
| 
766
 | 
60
 | 
 
 | 
 
 | 
 
 | 
 
 | 
345
 | 
     return $set;  | 
| 
767
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
       | 
| 
768
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 } # _create_recurrence  | 
| 
769
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
770
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
771
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 sub _get_occurrence_by_index {  | 
| 
772
 | 
3005
 | 
 
 | 
 
 | 
  
3005
  
 | 
 
 | 
4877
 | 
     my ( $base, $occurrence, $args ) = @_;  | 
| 
773
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     # TODO: memoize "occurrences" within an "INTERVAL" ???  | 
| 
774
 | 
3005
 | 
 
 | 
 
 | 
 
 | 
 
 | 
5455
 | 
     RETRY_OVERFLOW: for ( 0 .. 5 )    | 
| 
775
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     {  | 
| 
776
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         return undef   | 
| 
777
 | 
3113
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
6856
 | 
             if  $occurrence < 0;  | 
| 
778
 | 
3079
 | 
 
 | 
 
 | 
 
 | 
 
 | 
8008
 | 
         my $next = $base->clone;  | 
| 
779
 | 
3079
 | 
 
 | 
 
 | 
 
 | 
 
 | 
34984
 | 
         my $previous = $base;  | 
| 
780
 | 
3079
 | 
 
 | 
 
 | 
 
 | 
 
 | 
5413
 | 
         my @values = ( -1 );  | 
| 
781
 | 
3079
 | 
 
 | 
 
 | 
 
 | 
 
 | 
3653
 | 
         for my $j ( 1 .. $#{$args->{duration}} )   | 
| 
 
 | 
3079
 | 
 
 | 
 
 | 
 
 | 
 
 | 
8463
 | 
    | 
| 
782
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         {  | 
| 
783
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
             # decode the occurrence-number into a parameter-index  | 
| 
784
 | 
7559
 | 
 
 | 
 
 | 
 
 | 
 
 | 
69235
 | 
             my $i = int( $occurrence / $args->{total_level}[$j] );  | 
| 
785
 | 
7559
 | 
 
 | 
 
 | 
 
 | 
 
 | 
12244
 | 
             $occurrence -= $i * $args->{total_level}[$j];  | 
| 
786
 | 
7559
 | 
 
 | 
 
 | 
 
 | 
 
 | 
10660
 | 
             push @values, $i;  | 
| 
787
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
           | 
| 
788
 | 
7559
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
18729
 | 
             if ( $args->{duration}[$j][$i] < 0 )  | 
| 
789
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
             {  | 
| 
790
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                 # warn "negative unit\n";  | 
| 
791
 | 
437
 | 
 
 | 
 
 | 
 
 | 
 
 | 
1737
 | 
                 $next_unit{ $args->{level_unit}[$j - 1] }->(   | 
| 
792
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                     $next, $args->{week_start_day} );  | 
| 
793
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
             }  | 
| 
794
 | 
7559
 | 
 
 | 
 
 | 
 
 | 
 
 | 
177311
 | 
             _add( $next, $args->{level_unit}[$j], $args->{duration}[$j][$i] );  | 
| 
795
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
               | 
| 
796
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
             # overflow check  | 
| 
797
 | 
7559
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
2945364
 | 
             if ( $as_number{ $args->{level_unit}[$j - 1] }->(   | 
| 
798
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                     $next, $args->{week_start_day} ) !=  | 
| 
799
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                  $as_number{ $args->{level_unit}[$j - 1] }->(   | 
| 
800
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                     $previous, $args->{week_start_day} )  | 
| 
801
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                )  | 
| 
802
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
             {  | 
| 
803
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                 # calculate the "previous" occurrence-number  | 
| 
804
 | 
108
 | 
 
 | 
 
 | 
 
 | 
 
 | 
909
 | 
                 $occurrence = -1;  | 
| 
805
 | 
108
 | 
 
 | 
 
 | 
 
 | 
 
 | 
253
 | 
                 for ( 1 .. $j )   | 
| 
806
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                 {  | 
| 
807
 | 
203
 | 
 
 | 
 
 | 
 
 | 
 
 | 
846
 | 
                     $occurrence += $values[$_] * $args->{total_level}[$_];  | 
| 
808
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                 }  | 
| 
809
 | 
108
 | 
 
 | 
 
 | 
 
 | 
 
 | 
921
 | 
                 next RETRY_OVERFLOW;  | 
| 
810
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
             }  | 
| 
811
 | 
7451
 | 
 
 | 
 
 | 
 
 | 
 
 | 
68049
 | 
             $previous = $next->clone;  | 
| 
812
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         }  | 
| 
813
 | 
2971
 | 
 
 | 
 
 | 
 
 | 
 
 | 
50717
 | 
         return $next;  | 
| 
814
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     }  | 
| 
815
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
     return undef;   | 
| 
816
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 }  | 
| 
817
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
818
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
819
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 sub _get_previous {  | 
| 
820
 | 
522
 | 
 
 | 
 
 | 
  
522
  
 | 
 
 | 
2047
 | 
     my ( $self, $args ) = @_;  | 
| 
821
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
822
 | 
522
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
1736
 | 
     return $self if $self->is_infinite;  | 
| 
823
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
824
 | 
316
 | 
 
 | 
 
 | 
 
 | 
 
 | 
1785
 | 
     my $base = $args->{truncate_interval}->( $self, $args );  | 
| 
825
 | 
316
 | 
 
 | 
 
 | 
 
 | 
 
 | 
8040
 | 
     my ( $next, $i, $start, $end );  | 
| 
826
 | 
316
 | 
 
 | 
 
 | 
 
 | 
 
 | 
469
 | 
     my $init = 0;  | 
| 
827
 | 
316
 | 
 
 | 
 
 | 
 
 | 
 
 | 
477
 | 
     my $retry = 30;  | 
| 
828
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
829
 | 
316
 | 
 
 | 
 
 | 
 
 | 
 
 | 
1378
 | 
     INTERVAL: while(1) {  | 
| 
830
 | 
494
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
1608
 | 
             $args->{previous_unit_interval}->( $base, $args ) if $init;  | 
| 
831
 | 
494
 | 
 
 | 
 
 | 
 
 | 
 
 | 
62690
 | 
             $init = 1;  | 
| 
832
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
833
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
             # binary search  | 
| 
834
 | 
494
 | 
 
 | 
 
 | 
 
 | 
 
 | 
645
 | 
             $start = 0;  | 
| 
835
 | 
494
 | 
 
 | 
 
 | 
 
 | 
 
 | 
875
 | 
             $end = $args->{total_durations} - 1;  | 
| 
836
 | 
494
 | 
 
 | 
 
 | 
 
 | 
 
 | 
1304
 | 
             while ( $retry-- ) {  | 
| 
837
 | 
840
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
1977
 | 
                 if ( $end - $start < 3 )  | 
| 
838
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                 {  | 
| 
839
 | 
494
 | 
 
 | 
 
 | 
 
 | 
 
 | 
1287
 | 
                     for ( $i = $end; $i >= $start; $i-- )   | 
| 
840
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                     {  | 
| 
841
 | 
631
 | 
 
 | 
 
 | 
 
 | 
 
 | 
10146
 | 
                         $next = _get_occurrence_by_index ( $base, $i, $args );  | 
| 
842
 | 
631
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
7916
 | 
                         next INTERVAL unless defined $next;  | 
| 
843
 | 
631
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
9191
 | 
                         return $next if $next < $self;  | 
| 
844
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                     }  | 
| 
845
 | 
178
 | 
 
 | 
 
 | 
 
 | 
 
 | 
12077
 | 
                     next INTERVAL;  | 
| 
846
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                 }  | 
| 
847
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
848
 | 
346
 | 
 
 | 
 
 | 
 
 | 
 
 | 
677
 | 
                 $i = int( $start + ( $end - $start ) / 2 );  | 
| 
849
 | 
346
 | 
 
 | 
 
 | 
 
 | 
 
 | 
688
 | 
                 $next = _get_occurrence_by_index ( $base, $i, $args );  | 
| 
850
 | 
346
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
1602
 | 
                 next INTERVAL unless defined $next;  | 
| 
851
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
852
 | 
346
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
1205
 | 
                 if ( $next < $self )   | 
| 
853
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                 {  | 
| 
854
 | 
189
 | 
 
 | 
 
 | 
 
 | 
 
 | 
11804
 | 
                     $start = $i;  | 
| 
855
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                 }  | 
| 
856
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                 else   | 
| 
857
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                 {  | 
| 
858
 | 
157
 | 
 
 | 
 
 | 
 
 | 
 
 | 
10041
 | 
                     $end = $i - 1;  | 
| 
859
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                 }  | 
| 
860
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
             }  | 
| 
861
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
             return undef;   | 
| 
862
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     }  | 
| 
863
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 }  | 
| 
864
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
865
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
866
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 sub _get_next {  | 
| 
867
 | 
1056
 | 
 
 | 
 
 | 
  
1056
  
 | 
 
 | 
2570
 | 
     my ( $self, $args ) = @_;  | 
| 
868
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
869
 | 
1056
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
5015
 | 
     return $self if $self->is_infinite;  | 
| 
870
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
871
 | 
831
 | 
 
 | 
 
 | 
 
 | 
 
 | 
6100
 | 
     my $base = $args->{truncate_interval}->( $self, $args );  | 
| 
872
 | 
831
 | 
 
 | 
 
 | 
 
 | 
 
 | 
15660
 | 
     my ( $next, $i, $start, $end );  | 
| 
873
 | 
831
 | 
 
 | 
 
 | 
 
 | 
 
 | 
1232
 | 
     my $init = 0;  | 
| 
874
 | 
831
 | 
 
 | 
 
 | 
 
 | 
 
 | 
1324
 | 
     my $retry = 30;  | 
| 
875
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
       | 
| 
876
 | 
831
 | 
 
 | 
 
 | 
 
 | 
 
 | 
1236
 | 
     INTERVAL: while(1) {  | 
| 
877
 | 
1414
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
5287
 | 
             $args->{next_unit_interval}->( $base, $args ) if $init;  | 
| 
878
 | 
1414
 | 
 
 | 
 
 | 
 
 | 
 
 | 
160001
 | 
             $init = 1;  | 
| 
879
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
880
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
             # binary search  | 
| 
881
 | 
1414
 | 
 
 | 
 
 | 
 
 | 
 
 | 
2411
 | 
             $start = 0;  | 
| 
882
 | 
1414
 | 
 
 | 
 
 | 
 
 | 
 
 | 
2951
 | 
             $end = $args->{total_durations} - 1;  | 
| 
883
 | 
1414
 | 
 
 | 
 
 | 
 
 | 
 
 | 
3672
 | 
             while ( $retry-- ) {  | 
| 
884
 | 
1839
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
4751
 | 
                 if ( $end - $start < 3 )  | 
| 
885
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                 {  | 
| 
886
 | 
1413
 | 
 
 | 
 
 | 
 
 | 
 
 | 
2890
 | 
                     for $i ( $start .. $end )   | 
| 
887
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                     {  | 
| 
888
 | 
1602
 | 
 
 | 
 
 | 
 
 | 
 
 | 
16336
 | 
                         $next = _get_occurrence_by_index ( $base, $i, $args );  | 
| 
889
 | 
1602
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
6794
 | 
                         next INTERVAL unless defined $next;  | 
| 
890
 | 
1568
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
5218
 | 
                         return $next if $next > $self;  | 
| 
891
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                     }  | 
| 
892
 | 
549
 | 
 
 | 
 
 | 
 
 | 
 
 | 
37441
 | 
                     next INTERVAL;  | 
| 
893
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                 }  | 
| 
894
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
895
 | 
426
 | 
 
 | 
 
 | 
 
 | 
 
 | 
951
 | 
                 $i = int( $start + ( $end - $start ) / 2 );  | 
| 
896
 | 
426
 | 
 
 | 
 
 | 
 
 | 
 
 | 
927
 | 
                 $next = _get_occurrence_by_index ( $base, $i, $args );  | 
| 
897
 | 
426
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
1985
 | 
                 next INTERVAL unless defined $next;  | 
| 
898
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
899
 | 
426
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
1417
 | 
                 if ( $next > $self )   | 
| 
900
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                 {  | 
| 
901
 | 
212
 | 
 
 | 
 
 | 
 
 | 
 
 | 
13655
 | 
                     $end = $i;  | 
| 
902
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                 }  | 
| 
903
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                 else   | 
| 
904
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                 {  | 
| 
905
 | 
214
 | 
 
 | 
 
 | 
 
 | 
 
 | 
14124
 | 
                     $start = $i + 1;  | 
| 
906
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                 }  | 
| 
907
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
             }  | 
| 
908
 | 
1
 | 
 
 | 
 
 | 
 
 | 
 
 | 
13
 | 
             return undef;   | 
| 
909
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     }  | 
| 
910
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 }  | 
| 
911
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
912
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 1;  | 
| 
913
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
914
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 __END__  |