| line | stmt | bran | cond | sub | pod | time | code | 
| 1 |  |  |  |  |  |  | package Date::ManipX::Almanac::Date; | 
| 2 |  |  |  |  |  |  |  | 
| 3 | 3 |  |  | 3 |  | 544585 | use 5.010; | 
|  | 3 |  |  |  |  | 25 |  | 
| 4 |  |  |  |  |  |  |  | 
| 5 | 3 |  |  | 3 |  | 25 | use strict; | 
|  | 3 |  |  |  |  | 7 |  | 
|  | 3 |  |  |  |  | 61 |  | 
| 6 | 3 |  |  | 3 |  | 15 | use warnings; | 
|  | 3 |  |  |  |  | 6 |  | 
|  | 3 |  |  |  |  | 118 |  | 
| 7 |  |  |  |  |  |  |  | 
| 8 | 3 |  |  | 3 |  | 1032 | use Astro::Coord::ECI 0.119;	# For clone() to work. | 
|  | 3 |  |  |  |  | 30649 |  | 
|  | 3 |  |  |  |  | 118 |  | 
| 9 | 3 |  |  | 3 |  | 21 | use Astro::Coord::ECI::Utils 0.119 qw{ TWOPI }; | 
|  | 3 |  |  |  |  | 56 |  | 
|  | 3 |  |  |  |  | 165 |  | 
| 10 | 3 |  |  | 3 |  | 20 | use Carp; | 
|  | 3 |  |  |  |  | 6 |  | 
|  | 3 |  |  |  |  | 172 |  | 
| 11 | 3 |  |  | 3 |  | 3247 | use Date::Manip::Date; | 
|  | 3 |  |  |  |  | 286719 |  | 
|  | 3 |  |  |  |  | 132 |  | 
| 12 | 3 |  |  | 3 |  | 1776 | use Module::Load (); | 
|  | 3 |  |  |  |  | 3553 |  | 
|  | 3 |  |  |  |  | 69 |  | 
| 13 | 3 |  |  | 3 |  | 22 | use Scalar::Util (); | 
|  | 3 |  |  |  |  | 7 |  | 
|  | 3 |  |  |  |  | 44 |  | 
| 14 | 3 |  |  | 3 |  | 1616 | use Text::ParseWords (); | 
|  | 3 |  |  |  |  | 4067 |  | 
|  | 3 |  |  |  |  | 132 |  | 
| 15 |  |  |  |  |  |  |  | 
| 16 |  |  |  |  |  |  | our $VERSION = '0.001_02'; | 
| 17 |  |  |  |  |  |  |  | 
| 18 | 3 |  |  | 3 |  | 23 | use constant DEFAULT_TWILIGHT	=> 'civil'; | 
|  | 3 |  |  |  |  | 6 |  | 
|  | 3 |  |  |  |  | 212 |  | 
| 19 | 3 |  |  | 3 |  | 21 | use constant REF_ARRAY	=> ref []; | 
|  | 3 |  |  |  |  | 6 |  | 
|  | 3 |  |  |  |  | 164 |  | 
| 20 | 3 |  |  | 3 |  | 19 | use constant REF_HASH	=> ref {}; | 
|  | 3 |  |  |  |  | 5 |  | 
|  | 3 |  |  |  |  | 136 |  | 
| 21 | 3 |  |  | 3 |  | 19 | use constant METERS_PER_KILOMETER	=> 1000; | 
|  | 3 |  |  |  |  | 5 |  | 
|  | 3 |  |  |  |  | 13670 |  | 
| 22 |  |  |  |  |  |  |  | 
| 23 |  |  |  |  |  |  | sub new { | 
| 24 | 6 |  |  | 6 | 1 | 3604 | my ( $class, @args ) = @_; | 
| 25 | 6 |  |  |  |  | 24 | return $class->_new( new => @args ); | 
| 26 |  |  |  |  |  |  | } | 
| 27 |  |  |  |  |  |  |  | 
| 28 |  |  |  |  |  |  | sub _new { | 
| 29 | 7 |  |  | 7 |  | 49 | my ( $class, $new_method, @args ) = @_; | 
| 30 |  |  |  |  |  |  |  | 
| 31 | 7 |  |  |  |  | 16 | my @config; | 
| 32 | 7 | 100 | 66 |  |  | 33 | if ( @args && REF_ARRAY eq ref $args[-1] ) { | 
| 33 | 1 |  |  |  |  | 2 | @config = @{ pop @args }; | 
|  | 1 |  |  |  |  | 4 |  | 
| 34 | 1 |  |  |  |  | 5 | state $method_map = { | 
| 35 |  |  |  |  |  |  | new	=> 'new_config', | 
| 36 |  |  |  |  |  |  | }; | 
| 37 | 1 |  | 33 |  |  | 5 | $new_method = $method_map->{$new_method} // $new_method; | 
| 38 |  |  |  |  |  |  | } | 
| 39 |  |  |  |  |  |  |  | 
| 40 | 7 |  |  |  |  | 17 | my ( $dmd, $from ); | 
| 41 | 7 | 100 |  |  |  | 36 | if ( ref $class ) { | 
|  |  | 50 |  |  |  |  |  | 
| 42 | 4 |  |  |  |  | 10 | $from = $class; | 
| 43 | 4 |  |  |  |  | 14 | $dmd = $class->dmd()->$new_method(); | 
| 44 |  |  |  |  |  |  | } elsif ( Scalar::Util::blessed( $args[0] ) ) { | 
| 45 | 0 |  |  |  |  | 0 | $from = shift @args; | 
| 46 | 0 | 0 |  |  |  | 0 | $dmd = Date::Manip::Date->$new_method( | 
| 47 |  |  |  |  |  |  | $from->isa( __PACKAGE__ ) ? $from->dmd() : $from | 
| 48 |  |  |  |  |  |  | ); | 
| 49 |  |  |  |  |  |  | } else { | 
| 50 | 3 |  |  |  |  | 42 | $dmd = Date::Manip::Date->$new_method(); | 
| 51 |  |  |  |  |  |  | } | 
| 52 |  |  |  |  |  |  |  | 
| 53 | 7 |  | 66 |  |  | 38538 | my $self = bless { | 
| 54 |  |  |  |  |  |  | dmd	=> $dmd, | 
| 55 |  |  |  |  |  |  | }, ref $class || $class; | 
| 56 |  |  |  |  |  |  |  | 
| 57 | 7 |  |  |  |  | 29 | $self->_init_almanac( $from ); | 
| 58 |  |  |  |  |  |  |  | 
| 59 |  |  |  |  |  |  | @config | 
| 60 | 7 | 100 |  |  |  | 23 | and $self->config( @config ); | 
| 61 |  |  |  |  |  |  |  | 
| 62 | 7 | 100 |  |  |  | 28 | $self->get_config( 'sky' ) | 
| 63 |  |  |  |  |  |  | or $self->_config_almanac_default_sky(); | 
| 64 | 7 | 100 |  |  |  | 19 | defined $self->get_config( 'twilight' ) | 
| 65 |  |  |  |  |  |  | or $self->_config_almanac_var_twilight( | 
| 66 |  |  |  |  |  |  | twilight => DEFAULT_TWILIGHT ); | 
| 67 |  |  |  |  |  |  |  | 
| 68 |  |  |  |  |  |  | @args | 
| 69 | 7 | 50 |  |  |  | 18 | and $self->parse( @args ); | 
| 70 |  |  |  |  |  |  |  | 
| 71 | 7 |  |  |  |  | 30 | return $self; | 
| 72 |  |  |  |  |  |  | } | 
| 73 |  |  |  |  |  |  |  | 
| 74 |  |  |  |  |  |  | sub new_config { | 
| 75 | 1 |  |  | 1 | 1 | 520 | my ( $class, @args ) = @_; | 
| 76 | 1 |  |  |  |  | 3 | return $class->_new( new_config => @args ); | 
| 77 |  |  |  |  |  |  | } | 
| 78 |  |  |  |  |  |  |  | 
| 79 |  |  |  |  |  |  | sub new_date { | 
| 80 | 1 |  |  | 1 | 1 | 464 | my ( $class, @args ) = @_; | 
| 81 |  |  |  |  |  |  | # return $class->_new( new_date => @args ); | 
| 82 | 1 |  |  |  |  | 5 | return $class->new( @args ); | 
| 83 |  |  |  |  |  |  | } | 
| 84 |  |  |  |  |  |  |  | 
| 85 |  |  |  |  |  |  | sub calc { | 
| 86 | 0 |  |  | 0 | 1 | 0 | my ( $self, $obj, @args ) = @_; | 
| 87 | 0 | 0 | 0 |  |  | 0 | Scalar::Util::blessed( $obj ) | 
| 88 |  |  |  |  |  |  | and $obj->isa( __PACKAGE__ ) | 
| 89 |  |  |  |  |  |  | and $obj = $obj->dmd(); | 
| 90 | 0 |  |  |  |  | 0 | return $self->dmd()->calc( $obj, @args ); | 
| 91 |  |  |  |  |  |  | } | 
| 92 |  |  |  |  |  |  |  | 
| 93 |  |  |  |  |  |  | sub cmp : method {	## no critic (ProhibitBuiltinHomonyms) | 
| 94 | 0 |  |  | 0 | 1 | 0 | my ( $self, $date ) = @_; | 
| 95 | 0 | 0 |  |  |  | 0 | $date->isa( __PACKAGE__ ) | 
| 96 |  |  |  |  |  |  | and $date = $date->dmd(); | 
| 97 | 0 |  |  |  |  | 0 | return $self->dmd()->cmp( $date ); | 
| 98 |  |  |  |  |  |  | } | 
| 99 |  |  |  |  |  |  |  | 
| 100 |  |  |  |  |  |  | sub config { | 
| 101 | 30 |  |  | 30 | 1 | 9692 | my ( $self, @arg ) = @_; | 
| 102 |  |  |  |  |  |  |  | 
| 103 | 30 |  |  |  |  | 65 | delete $self->{err}; | 
| 104 |  |  |  |  |  |  |  | 
| 105 | 30 |  |  |  |  | 73 | while ( @arg ) { | 
| 106 | 45 |  |  |  |  | 120 | my ( $name, $val ) = splice @arg, 0, 2; | 
| 107 |  |  |  |  |  |  |  | 
| 108 | 45 |  |  |  |  | 97 | state $config = { | 
| 109 |  |  |  |  |  |  | almanacconfigfile	=> \&_config_almanac_config_file, | 
| 110 |  |  |  |  |  |  | defaults	=> \&_config_almanac_default, | 
| 111 |  |  |  |  |  |  | elevation	=> \&_config_almanac_var_elevation, | 
| 112 |  |  |  |  |  |  | language	=> \&_config_almanac_var_language, | 
| 113 |  |  |  |  |  |  | latitude	=> \&_config_almanac_var_latitude, | 
| 114 |  |  |  |  |  |  | location	=> \&_config_almanac_var_location, | 
| 115 |  |  |  |  |  |  | longitude	=> \&_config_almanac_var_longitude, | 
| 116 |  |  |  |  |  |  | name	=> \&_config_almanac_var_name, | 
| 117 |  |  |  |  |  |  | sky		=> \&_config_almanac_var_sky, | 
| 118 |  |  |  |  |  |  | twilight	=> \&_config_almanac_var_twilight, | 
| 119 |  |  |  |  |  |  | }; | 
| 120 |  |  |  |  |  |  |  | 
| 121 | 45 | 100 |  |  |  | 146 | if ( my $code = $config->{ lc $name } ) { | 
| 122 | 43 |  |  |  |  | 95 | $code->( $self, $name, $val ); | 
| 123 |  |  |  |  |  |  | } else { | 
| 124 | 2 |  |  |  |  | 7 | $self->dmd()->config( $name, $val ); | 
| 125 |  |  |  |  |  |  | } | 
| 126 |  |  |  |  |  |  | } | 
| 127 |  |  |  |  |  |  |  | 
| 128 | 30 |  |  |  |  | 32734 | return; | 
| 129 |  |  |  |  |  |  | } | 
| 130 |  |  |  |  |  |  |  | 
| 131 |  |  |  |  |  |  | sub dmd { | 
| 132 | 76 |  |  | 76 | 1 | 139 | my ( $self ) = @_; | 
| 133 | 76 |  |  |  |  | 355 | return $self->{dmd}; | 
| 134 |  |  |  |  |  |  | } | 
| 135 |  |  |  |  |  |  |  | 
| 136 |  |  |  |  |  |  | sub err { | 
| 137 | 0 |  |  | 0 | 1 | 0 | my ( $self ) = @_; | 
| 138 | 0 |  | 0 |  |  | 0 | return $self->{err} // $self->dmd()->err(); | 
| 139 |  |  |  |  |  |  | } | 
| 140 |  |  |  |  |  |  |  | 
| 141 |  |  |  |  |  |  | sub get_config { | 
| 142 | 51 |  |  | 51 | 1 | 7085 | my ( $self, @arg ) = @_; | 
| 143 | 51 |  |  |  |  | 91 | delete $self->{err}; | 
| 144 | 51 |  |  |  |  | 81 | my @rslt; | 
| 145 |  |  |  |  |  |  |  | 
| 146 | 51 |  |  |  |  | 94 | foreach my $name ( @arg ) { | 
| 147 | 63 |  |  |  |  | 178 | state $mine = { map { $_ => 1 } qw{ | 
|  | 21 |  |  |  |  | 48 |  | 
| 148 |  |  |  |  |  |  | elevation latitude location longitude name sky twilight } }; | 
| 149 | 63 | 100 |  |  |  | 149 | if ( $mine->{$name} ) { | 
| 150 |  |  |  |  |  |  | my $code = $self->can( "_get_config_$name" ) || sub { | 
| 151 | 47 |  | 100 | 39 |  | 364 | $_[0]{config}{$name} }; | 
|  | 39 |  |  |  |  | 169 |  | 
| 152 | 47 |  |  |  |  | 118 | push @rslt, scalar $code->( $self ); | 
| 153 |  |  |  |  |  |  | } else { | 
| 154 | 16 |  |  |  |  | 42 | push @rslt, $self->dmd()->get_config( $name ); | 
| 155 |  |  |  |  |  |  | } | 
| 156 |  |  |  |  |  |  | } | 
| 157 |  |  |  |  |  |  |  | 
| 158 | 51 | 100 |  |  |  | 519 | return 1 == @rslt ? $rslt[0] : @rslt; | 
| 159 |  |  |  |  |  |  | } | 
| 160 |  |  |  |  |  |  |  | 
| 161 |  |  |  |  |  |  | sub input { | 
| 162 | 3 |  |  | 3 | 0 | 39343 | my ( $self ) = @_; | 
| 163 | 3 |  |  |  |  | 13 | return $self->{input}; | 
| 164 |  |  |  |  |  |  | } | 
| 165 |  |  |  |  |  |  |  | 
| 166 |  |  |  |  |  |  | sub list_events { | 
| 167 | 0 |  |  | 0 | 0 | 0 | my ( $self, @args ) = @_; | 
| 168 | 0 | 0 | 0 |  |  | 0 | Scalar::Util::blessed( $args[0] ) | 
| 169 |  |  |  |  |  |  | and $args[0]->isa( __PACKAGE__ ) | 
| 170 |  |  |  |  |  |  | and $args[0] = $args[0]->dmd(); | 
| 171 | 0 |  |  |  |  | 0 | return $self->dmd()->list_events( @args ); | 
| 172 |  |  |  |  |  |  | } | 
| 173 |  |  |  |  |  |  |  | 
| 174 |  |  |  |  |  |  | sub parse { | 
| 175 | 11 |  |  | 11 | 1 | 28 | my ( $self, $string ) = @_; | 
| 176 | 11 |  |  |  |  | 32 | my ( $idate, @event ) = $self->__parse_pre( $string ); | 
| 177 | 11 |  | 33 |  |  | 35 | return $self->dmd()->parse( $idate ) || $self->__parse_post( @event ); | 
| 178 |  |  |  |  |  |  | } | 
| 179 |  |  |  |  |  |  |  | 
| 180 |  |  |  |  |  |  | sub parse_time { | 
| 181 | 0 |  |  | 0 | 1 | 0 | my ( $self, $string ) = @_; | 
| 182 | 0 |  |  |  |  | 0 | my ( $idate, @event ) = $self->__parse_pre( $string ); | 
| 183 | 0 |  | 0 |  |  | 0 | return $self->dmd()->parse_time( $idate ) || $self->__parse_post( @event ); | 
| 184 |  |  |  |  |  |  | } | 
| 185 |  |  |  |  |  |  |  | 
| 186 |  |  |  |  |  |  | sub _config_almanac_config_file { | 
| 187 |  |  |  |  |  |  | # my ( $self, $name, $fn ) = @_; | 
| 188 | 2 |  |  | 2 |  | 8 | my ( $self, undef, $fn ) = @_; | 
| 189 |  |  |  |  |  |  | open my $fh, '<:encoding(utf-8)', $fn	## no critic (RequireBriefOpen) | 
| 190 | 2 | 50 |  | 2 |  | 70 | or do { | 
|  | 2 |  |  |  |  | 14 |  | 
|  | 2 |  |  |  |  | 5 |  | 
|  | 2 |  |  |  |  | 12 |  | 
| 191 | 0 |  |  |  |  | 0 | warn "ERROR: [almanac_config_file] unable to open file $fn: $!"; | 
| 192 | 0 |  |  |  |  | 0 | return 1; | 
| 193 |  |  |  |  |  |  | }; | 
| 194 | 2 |  |  |  |  | 2464 | my $config_file_processed; | 
| 195 | 2 |  |  |  |  | 57 | while ( <$fh> ) { | 
| 196 | 18 | 100 |  |  |  | 107 | m/ \S /smx | 
| 197 |  |  |  |  |  |  | or next; | 
| 198 | 16 | 50 |  |  |  | 47 | m/ \A \s* [#] /smx | 
| 199 |  |  |  |  |  |  | and next; | 
| 200 | 16 |  |  |  |  | 44 | s/ \A \s+ //smx; | 
| 201 | 16 |  |  |  |  | 92 | s/ \s+ \z //smx; | 
| 202 | 16 |  |  |  |  | 190 | my ( $name, $val ) = split qr< \s* = \s* >smx, $_, 2; | 
| 203 | 16 | 50 |  |  |  | 65 | if ( m/ \A [*] ( .* ) /smx ) { | 
| 204 |  |  |  |  |  |  | # TODO retire exception for *almanac once I'm fully to new | 
| 205 |  |  |  |  |  |  | # config file structure. | 
| 206 | 0 |  |  |  |  | 0 | state $allow = { map { $_ => 1 } qw{ almanac } }; | 
|  | 0 |  |  |  |  | 0 |  | 
| 207 | 0 | 0 |  |  |  | 0 | unless ( $allow->{ lc $1 } ) { | 
| 208 | 0 |  |  |  |  | 0 | warn "WARNING: [almanac_config_file] section '$_' ", | 
| 209 |  |  |  |  |  |  | "not allowed in AlmanacConfigFile $fn line $.\n"; | 
| 210 | 0 |  |  |  |  | 0 | last; | 
| 211 |  |  |  |  |  |  | } | 
| 212 |  |  |  |  |  |  | } else { | 
| 213 | 16 | 50 |  |  |  | 56 | if ( $name =~ m/ \A ConfigFile \z /smxi ) { | 
|  |  | 50 |  |  |  |  |  | 
| 214 | 0 |  |  |  |  | 0 | $config_file_processed = 1; | 
| 215 |  |  |  |  |  |  | } elsif ( $config_file_processed ) { | 
| 216 | 0 |  |  |  |  | 0 | warn "Config item '$name' after ConfigFile in $fn line $.\n"; | 
| 217 |  |  |  |  |  |  | } | 
| 218 | 16 |  |  |  |  | 49 | $self->config( $name, $val ); | 
| 219 |  |  |  |  |  |  | } | 
| 220 |  |  |  |  |  |  | } | 
| 221 | 2 |  |  |  |  | 42 | close $fh; | 
| 222 | 2 |  |  |  |  | 18 | return; | 
| 223 |  |  |  |  |  |  | } | 
| 224 |  |  |  |  |  |  |  | 
| 225 |  |  |  |  |  |  | sub _config_almanac_default { | 
| 226 | 1 |  |  | 1 |  | 4 | my ( $self, $name, $val ) = @_; | 
| 227 | 1 |  |  |  |  | 3 | %{ $self->{config} } = (); | 
|  | 1 |  |  |  |  | 13 |  | 
| 228 | 1 |  |  |  |  | 4 | delete $self->{lang}; | 
| 229 | 1 |  | 33 |  |  | 4 | my $rslt = $self->dmd()->config( $name, $val ) || | 
| 230 |  |  |  |  |  |  | $self->_update_language() || | 
| 231 |  |  |  |  |  |  | $self->_config_almanac_default_sky() || | 
| 232 |  |  |  |  |  |  | $self->_config_almanac_var_twilight( twilight => DEFAULT_TWILIGHT ); | 
| 233 | 1 |  |  |  |  | 6 | return $rslt; | 
| 234 |  |  |  |  |  |  | } | 
| 235 |  |  |  |  |  |  |  | 
| 236 |  |  |  |  |  |  | sub _config_almanac_default_sky { | 
| 237 | 3 |  |  | 3 |  | 7 | my ( $self ) = @_; | 
| 238 | 3 |  |  |  |  | 11 | return $self->_config_almanac_var_sky( sky => [ qw{ | 
| 239 |  |  |  |  |  |  | Astro::Coord::ECI::Sun | 
| 240 |  |  |  |  |  |  | Astro::Coord::ECI::Moon | 
| 241 |  |  |  |  |  |  | } ], | 
| 242 |  |  |  |  |  |  | ); | 
| 243 |  |  |  |  |  |  | } | 
| 244 |  |  |  |  |  |  |  | 
| 245 |  |  |  |  |  |  | sub _config_almanac_var_language { | 
| 246 | 8 |  |  | 8 |  | 20 | my ( $self, $name, $val ) = @_; | 
| 247 | 8 |  |  |  |  | 14 | my $rslt; | 
| 248 | 8 | 50 |  |  |  | 21 | $rslt = $self->dmd()->config( $name, $val ) | 
| 249 |  |  |  |  |  |  | and return $rslt; | 
| 250 |  |  |  |  |  |  |  | 
| 251 |  |  |  |  |  |  | # FIXME Doing ourselves after the embedded DMD object can result in | 
| 252 |  |  |  |  |  |  | # an inconsistency if DMD supports a language but we do not. But I | 
| 253 |  |  |  |  |  |  | # see no way to avoid this in all cases, because the embedded object | 
| 254 |  |  |  |  |  |  | # may have been configured in some way (such as a configuration | 
| 255 |  |  |  |  |  |  | # file) that we can't intercept. | 
| 256 | 8 |  |  |  |  | 67542 | return $self->_update_language(); | 
| 257 |  |  |  |  |  |  | } | 
| 258 |  |  |  |  |  |  |  | 
| 259 |  |  |  |  |  |  | sub _update_language { | 
| 260 | 9 |  |  | 9 |  | 9419 | my ( $self ) = @_; | 
| 261 | 9 |  |  |  |  | 34 | my $lang = lc $self->get_config( 'language' ); | 
| 262 |  |  |  |  |  |  |  | 
| 263 |  |  |  |  |  |  | exists $self->{lang} | 
| 264 |  |  |  |  |  |  | and $lang eq $self->{lang} | 
| 265 | 9 | 50 | 66 |  |  | 55 | and return 0; | 
| 266 |  |  |  |  |  |  |  | 
| 267 | 9 | 50 |  |  |  | 26 | my $mod = __load_language( $lang ) | 
| 268 |  |  |  |  |  |  | or return 1; | 
| 269 |  |  |  |  |  |  |  | 
| 270 | 9 |  |  |  |  | 28 | $self->{lang}{lang}			= $lang; | 
| 271 | 9 |  |  |  |  | 18 | $self->{lang}{mod}			= $mod; | 
| 272 | 9 |  |  |  |  | 15 | delete $self->{lang}{obj}; | 
| 273 |  |  |  |  |  |  |  | 
| 274 | 9 |  |  |  |  | 33 | return 0; | 
| 275 |  |  |  |  |  |  | } | 
| 276 |  |  |  |  |  |  |  | 
| 277 |  |  |  |  |  |  | # We isolate this so we can hook it to something different during | 
| 278 |  |  |  |  |  |  | # testing if need be. | 
| 279 |  |  |  |  |  |  | sub __load_language { | 
| 280 | 9 |  |  | 9 |  | 20 | my ( $lang ) = @_; | 
| 281 |  |  |  |  |  |  |  | 
| 282 | 9 |  |  |  |  | 30 | my $module = "Date::ManipX::Almanac::Lang::\L$lang"; | 
| 283 | 9 |  |  |  |  | 22 | local $@ = undef; | 
| 284 | 9 | 50 |  |  |  | 19 | eval { | 
| 285 | 9 |  |  |  |  | 35 | Module::Load::load( $module ); | 
| 286 | 9 |  |  |  |  | 561 | 1; | 
| 287 |  |  |  |  |  |  | } and return $module; | 
| 288 | 0 |  |  |  |  | 0 | warn "ERROR: [language] invalid: $lang\n"; | 
| 289 | 0 |  |  |  |  | 0 | return 0; | 
| 290 |  |  |  |  |  |  | } | 
| 291 |  |  |  |  |  |  |  | 
| 292 |  |  |  |  |  |  | sub _config_almanac_var_twilight { | 
| 293 | 9 |  |  | 9 |  | 24 | my ( $self, $name, $val ) = @_; | 
| 294 |  |  |  |  |  |  |  | 
| 295 | 9 |  |  |  |  | 15 | my $set_val; | 
| 296 | 9 | 50 |  |  |  | 24 | if ( defined $val ) { | 
| 297 | 9 | 50 |  |  |  | 38 | if ( Astro::Coord::ECI::Utils::looks_like_number( $val ) ) { | 
| 298 | 0 |  |  |  |  | 0 | $set_val = - Astro::Coord::ECI::Utils::deg2rad( abs $val ); | 
| 299 |  |  |  |  |  |  | } else { | 
| 300 | 9 | 50 |  |  |  | 25 | defined( $set_val = $self->_get_twilight_qual( $val ) ) | 
| 301 |  |  |  |  |  |  | or return $self->_my_config_err( | 
| 302 |  |  |  |  |  |  | "Do not recognize '$val' twilight" ); | 
| 303 |  |  |  |  |  |  | } | 
| 304 |  |  |  |  |  |  | } | 
| 305 |  |  |  |  |  |  |  | 
| 306 | 9 |  |  |  |  | 26 | $self->{config}{twilight} = $val; | 
| 307 | 9 |  |  |  |  | 17 | $self->{config}{_twilight} = $set_val; | 
| 308 |  |  |  |  |  |  | $self->{config}{location} | 
| 309 | 9 | 100 |  |  |  | 29 | and $self->{config}{location}->set( $name => $set_val ); | 
| 310 |  |  |  |  |  |  |  | 
| 311 | 9 |  |  |  |  | 92 | return; | 
| 312 |  |  |  |  |  |  | } | 
| 313 |  |  |  |  |  |  |  | 
| 314 |  |  |  |  |  |  | sub _config_var_is_eci { | 
| 315 | 35 |  |  | 35 |  | 82 | my ( undef, undef, $val ) = @_; | 
| 316 | 35 | 50 | 66 |  |  | 239 | ref $val | 
|  |  |  | 66 |  |  |  |  | 
| 317 |  |  |  |  |  |  | and Scalar::Util::blessed( $val ) | 
| 318 |  |  |  |  |  |  | and $val->isa( 'Astro::Coord::ECI' ) | 
| 319 |  |  |  |  |  |  | or return; | 
| 320 | 23 |  |  |  |  | 83 | return $val; | 
| 321 |  |  |  |  |  |  | } | 
| 322 |  |  |  |  |  |  |  | 
| 323 |  |  |  |  |  |  | # This ought to be in Astro::Coord::ECI::Utils | 
| 324 |  |  |  |  |  |  | sub _hms2rad { | 
| 325 | 2 |  |  | 2 |  | 214 | my ( $hms ) = @_; | 
| 326 | 2 |  |  |  |  | 22 | my ( $hr, $min, $sec ) = split qr < : >smx, $hms; | 
| 327 | 2 |  | 50 |  |  | 18 | $_ ||= 0 for $sec, $min, $hr; | 
| 328 | 2 |  |  |  |  | 20 | return TWOPI * ( ( ( $sec / 60 ) + $min ) / 60 + $hr ) / 24; | 
| 329 |  |  |  |  |  |  | } | 
| 330 |  |  |  |  |  |  |  | 
| 331 |  |  |  |  |  |  | sub _config_var_is_eci_class { | 
| 332 | 23 |  |  | 23 |  | 52 | my ( $self, $name, $val ) = @_; | 
| 333 | 23 |  |  |  |  | 30 | my $rslt; | 
| 334 | 23 | 100 |  |  |  | 63 | $rslt = $self->_config_var_is_eci( $name, $val ) | 
| 335 |  |  |  |  |  |  | and return $rslt; | 
| 336 | 12 | 50 |  |  |  | 27 | if ( ! ref $val ) { | 
| 337 | 12 |  |  |  |  | 40 | my ( $class, @arg ) = Text::ParseWords::shellwords( $val ); | 
| 338 | 12 |  |  |  |  | 1357 | Module::Load::load( $class ); | 
| 339 |  |  |  |  |  |  | state $factory = { | 
| 340 |  |  |  |  |  |  | 'Astro::Coord::ECI::Star'	=> sub { | 
| 341 | 2 |  |  | 2 |  | 9 | my ( $name, $ra, $decl, $rng ) = @_; | 
| 342 | 2 |  |  |  |  | 72 | return Astro::Coord::ECI::Star->new( | 
| 343 |  |  |  |  |  |  | name	=> $name, | 
| 344 |  |  |  |  |  |  | )->position( | 
| 345 |  |  |  |  |  |  | _hms2rad( $ra ), | 
| 346 |  |  |  |  |  |  | Astro::Coord::ECI::Utils::deg2rad( $decl ), | 
| 347 |  |  |  |  |  |  | $rng, | 
| 348 |  |  |  |  |  |  | ); | 
| 349 |  |  |  |  |  |  | }, | 
| 350 | 12 |  |  |  |  | 22484 | }; | 
| 351 | 12 |  | 100 | 10 |  | 159 | my $code = $factory->{$class} || sub { $class->new() }; | 
|  | 10 |  |  |  |  | 65 |  | 
| 352 | 12 |  |  |  |  | 38 | my $obj = $code->( @arg ); | 
| 353 | 12 | 50 |  |  |  | 4681 | if ( $rslt = $self->_config_var_is_eci( $name, $obj ) ) { | 
| 354 | 12 |  |  |  |  | 66 | return $rslt; | 
| 355 |  |  |  |  |  |  | } | 
| 356 |  |  |  |  |  |  | } | 
| 357 |  |  |  |  |  |  | $self->_my_config_err( | 
| 358 | 0 |  |  |  |  | 0 | "$val must be an Astro::Coord::ECI object or class" ); | 
| 359 | 0 |  |  |  |  | 0 | return; | 
| 360 |  |  |  |  |  |  | } | 
| 361 |  |  |  |  |  |  |  | 
| 362 |  |  |  |  |  |  | sub _config_almanac_var_elevation { | 
| 363 | 3 |  |  | 3 |  | 19 | my ( $self, $name, $val ) = @_; | 
| 364 | 3 | 50 | 33 |  |  | 23 | if ( defined $val && | 
| 365 |  |  |  |  |  |  | Astro::Coord::ECI::Utils::looks_like_number( $val ) ) { | 
| 366 | 3 |  |  |  |  | 9 | $self->{config}{$name} = $val; | 
| 367 | 3 |  |  |  |  | 7 | delete $self->{config}{location}; | 
| 368 | 3 |  |  |  |  | 9 | return; | 
| 369 |  |  |  |  |  |  | } else { | 
| 370 | 0 |  |  |  |  | 0 | return $self->_my_config_err( "\u$name must be a number" ); | 
| 371 |  |  |  |  |  |  | } | 
| 372 |  |  |  |  |  |  | } | 
| 373 |  |  |  |  |  |  |  | 
| 374 |  |  |  |  |  |  | sub _config_almanac_var_latitude { | 
| 375 | 3 |  |  | 3 |  | 10 | my ( $self, $name, $val ) = @_; | 
| 376 | 3 | 50 | 33 |  |  | 48 | if ( defined $val && | 
|  |  |  | 33 |  |  |  |  | 
|  |  |  | 33 |  |  |  |  | 
| 377 |  |  |  |  |  |  | Astro::Coord::ECI::Utils::looks_like_number( $val ) && | 
| 378 |  |  |  |  |  |  | $val >= -90 && $val <= 90 ) { | 
| 379 | 3 |  |  |  |  | 12 | $self->{config}{$name} = $val; | 
| 380 | 3 |  |  |  |  | 9 | delete $self->{config}{location}; | 
| 381 | 3 |  |  |  |  | 10 | return; | 
| 382 |  |  |  |  |  |  | } else { | 
| 383 | 0 |  |  |  |  | 0 | return $self->_my_config_err( | 
| 384 |  |  |  |  |  |  | "\u$name must be a number between -90 and 90 degrees" ); | 
| 385 |  |  |  |  |  |  | } | 
| 386 |  |  |  |  |  |  | } | 
| 387 |  |  |  |  |  |  |  | 
| 388 |  |  |  |  |  |  | sub _config_almanac_var_location { | 
| 389 | 6 |  |  | 6 |  | 14 | my ( $self, $name, $val ) = @_; | 
| 390 | 6 |  |  |  |  | 8 | my $loc; | 
| 391 | 6 | 100 |  |  |  | 27 | if ( ! defined $val ) { | 
| 392 | 4 |  |  |  |  | 9 | $loc = undef; | 
| 393 | 4 |  |  |  |  | 14 | delete @{ $self->{config} }{ | 
| 394 | 4 |  |  |  |  | 7 | qw{ elevation latitude longitude name } }; | 
| 395 |  |  |  |  |  |  | } else { | 
| 396 | 2 | 50 |  |  |  | 8 | $loc = $self->_config_var_is_eci_class( $name, $val ) | 
| 397 |  |  |  |  |  |  | or return 1; | 
| 398 | 2 |  |  |  |  | 8 | my ( $lat, $lon, $ele ) = $loc->geodetic(); | 
| 399 | 2 |  |  |  |  | 78 | $self->{config}{elevation} = $ele * METERS_PER_KILOMETER; | 
| 400 | 2 |  |  |  |  | 7 | $self->{config}{latitude} = Astro::Coord::ECI::Utils::rad2deg( $lat ); | 
| 401 | 2 |  |  |  |  | 14 | $self->{config}{longitude} = Astro::Coord::ECI::Utils::rad2deg( $lon ); | 
| 402 | 2 |  |  |  |  | 11 | $self->{config}{name} = $loc->get( 'name' ); | 
| 403 |  |  |  |  |  |  | } | 
| 404 |  |  |  |  |  |  |  | 
| 405 |  |  |  |  |  |  | defined $self->{config}{_twilight} | 
| 406 |  |  |  |  |  |  | and defined $loc | 
| 407 | 6 | 100 | 100 |  |  | 63 | and $loc->set( twilight => $self->{config}{_twilight} ); | 
| 408 | 6 | 100 |  |  |  | 132 | $_->set( station => $loc ) for @{ $self->{config}{sky} || [] }; | 
|  | 6 |  |  |  |  | 46 |  | 
| 409 | 6 |  |  |  |  | 470 | $self->{config}{location} = $loc; | 
| 410 |  |  |  |  |  |  |  | 
| 411 |  |  |  |  |  |  | # NOTE we do this because when the Lang object initializes itself it | 
| 412 |  |  |  |  |  |  | # consults the first sky object's station attribute (set above) to | 
| 413 |  |  |  |  |  |  | # figure out whether it is in the Northern or Southern hemisphere. | 
| 414 |  |  |  |  |  |  | # The object will be re-created when we actually try to perform a | 
| 415 |  |  |  |  |  |  | # parse. | 
| 416 | 6 |  |  |  |  | 12 | delete $self->{lang}{obj}; | 
| 417 |  |  |  |  |  |  |  | 
| 418 | 6 |  |  |  |  | 20 | return; | 
| 419 |  |  |  |  |  |  | } | 
| 420 |  |  |  |  |  |  |  | 
| 421 |  |  |  |  |  |  | sub _config_almanac_var_longitude { | 
| 422 | 3 |  |  | 3 |  | 9 | my ( $self, $name, $val ) = @_; | 
| 423 | 3 | 50 | 33 |  |  | 57 | if ( defined $val && | 
|  |  |  | 33 |  |  |  |  | 
|  |  |  | 33 |  |  |  |  | 
| 424 |  |  |  |  |  |  | Astro::Coord::ECI::Utils::looks_like_number( $val ) && | 
| 425 |  |  |  |  |  |  | $val >= -180 && $val <= 180 ) { | 
| 426 | 3 |  |  |  |  | 12 | $self->{config}{$name} = $val; | 
| 427 | 3 |  |  |  |  | 7 | delete $self->{config}{location}; | 
| 428 | 3 |  |  |  |  | 10 | return; | 
| 429 |  |  |  |  |  |  | } else { | 
| 430 | 0 |  |  |  |  | 0 | return $self->_my_config_err( | 
| 431 |  |  |  |  |  |  | "\u$name must be a number between -180 and 180 degrees" ); | 
| 432 |  |  |  |  |  |  | } | 
| 433 |  |  |  |  |  |  | } | 
| 434 |  |  |  |  |  |  |  | 
| 435 |  |  |  |  |  |  | sub _config_almanac_var_name { | 
| 436 | 3 |  |  | 3 |  | 9 | my ( $self, $name, $val ) = @_; | 
| 437 | 3 | 50 |  |  |  | 8 | if ( defined $val ) { | 
| 438 | 3 |  |  |  |  | 8 | $self->{config}{$name} = $val; | 
| 439 |  |  |  |  |  |  | } else { | 
| 440 | 0 |  |  |  |  | 0 | delete $self->{config}{$name}; | 
| 441 |  |  |  |  |  |  | } | 
| 442 | 3 |  |  |  |  | 6 | delete $self->{config}{location}; | 
| 443 | 3 |  |  |  |  | 10 | return; | 
| 444 |  |  |  |  |  |  | } | 
| 445 |  |  |  |  |  |  |  | 
| 446 |  |  |  |  |  |  | sub _config_almanac_var_sky { | 
| 447 | 15 |  |  | 15 |  | 35 | my ( $self, $name, $values ) = @_; | 
| 448 |  |  |  |  |  |  |  | 
| 449 | 15 |  |  |  |  | 25 | my @sky; | 
| 450 | 15 | 100 |  |  |  | 38 | unless ( ref $values ) { | 
| 451 | 7 | 100 | 66 |  |  | 33 | if ( defined( $values ) && $values ne '' ) { | 
| 452 | 6 |  |  |  |  | 42 | $values = [ $values ]; | 
| 453 | 6 | 100 |  |  |  | 11 | @sky = @{ $self->{config}{sky} || [] }; | 
|  | 6 |  |  |  |  | 44 |  | 
| 454 |  |  |  |  |  |  | } else { | 
| 455 | 1 |  |  |  |  | 3 | $values = []; | 
| 456 | 1 |  |  |  |  | 3 | @{ $self->{config}{sky} } = (); | 
|  | 1 |  |  |  |  | 18 |  | 
| 457 |  |  |  |  |  |  | } | 
| 458 |  |  |  |  |  |  | } | 
| 459 |  |  |  |  |  |  |  | 
| 460 | 15 |  |  |  |  | 28 | foreach my $val ( @{ $values } ) { | 
|  | 15 |  |  |  |  | 37 |  | 
| 461 | 21 | 50 |  |  |  | 57 | my $body = $self->_config_var_is_eci_class( $name, $val ) | 
| 462 |  |  |  |  |  |  | or return 1; | 
| 463 | 21 |  |  |  |  | 53 | push @sky, $body; | 
| 464 | 21 | 100 |  |  |  | 50 | if ( my $loc = $self->_get_config_location() ) { | 
| 465 | 6 |  |  |  |  | 22 | $sky[-1]->set( station => $loc ); | 
| 466 |  |  |  |  |  |  | } | 
| 467 |  |  |  |  |  |  | } | 
| 468 |  |  |  |  |  |  |  | 
| 469 | 15 |  |  |  |  | 434 | @{ $self->{config}{sky} } = @sky; | 
|  | 15 |  |  |  |  | 67 |  | 
| 470 |  |  |  |  |  |  |  | 
| 471 |  |  |  |  |  |  | # NOTE we do this to force re-creation of the Lang object, which | 
| 472 |  |  |  |  |  |  | # then picks up the new sky. | 
| 473 | 15 |  |  |  |  | 33 | delete $self->{lang}{obj}; | 
| 474 |  |  |  |  |  |  |  | 
| 475 | 15 |  |  |  |  | 51 | return; | 
| 476 |  |  |  |  |  |  | } | 
| 477 |  |  |  |  |  |  |  | 
| 478 |  |  |  |  |  |  | sub _get_config_location { | 
| 479 | 40 |  |  | 40 |  | 77 | my ( $self ) = @_; | 
| 480 |  |  |  |  |  |  | my $cfg = $self->{config} | 
| 481 | 40 | 100 |  |  |  | 105 | or return; | 
| 482 |  |  |  |  |  |  | $cfg->{location} | 
| 483 | 35 | 100 |  |  |  | 128 | and return $cfg->{location}; | 
| 484 |  |  |  |  |  |  | defined $cfg->{latitude} | 
| 485 |  |  |  |  |  |  | and defined $cfg->{longitude} | 
| 486 | 17 | 100 | 66 |  |  | 74 | or return; | 
| 487 | 3 |  |  |  |  | 15 | my $loc = Astro::Coord::ECI->new(); | 
| 488 |  |  |  |  |  |  | defined $cfg->{name} | 
| 489 | 3 | 50 |  |  |  | 203 | and $loc->set( name => $cfg->{name} ); | 
| 490 |  |  |  |  |  |  | defined $cfg->{_twilight} | 
| 491 | 3 | 100 |  |  |  | 76 | and $loc->set( twilight => $cfg->{_twilight} ); | 
| 492 |  |  |  |  |  |  | $loc->geodetic( | 
| 493 |  |  |  |  |  |  | Astro::Coord::ECI::Utils::deg2rad( $cfg->{latitude} ), | 
| 494 |  |  |  |  |  |  | Astro::Coord::ECI::Utils::deg2rad( $cfg->{longitude} ), | 
| 495 | 3 |  | 50 |  |  | 60 | ( $cfg->{elevation} || 0 ) / METERS_PER_KILOMETER, | 
| 496 |  |  |  |  |  |  | ); | 
| 497 | 3 | 100 |  |  |  | 685 | $_->set( station => $loc ) for @{ $self->{config}{sky} || [] }; | 
|  | 3 |  |  |  |  | 20 |  | 
| 498 |  |  |  |  |  |  |  | 
| 499 |  |  |  |  |  |  | # NOTE we do this because when the Lang object initializes itself it | 
| 500 |  |  |  |  |  |  | # consults the first sky object's station attribute (set above) to | 
| 501 |  |  |  |  |  |  | # figure out whether it is in the Northern or Southern hemisphere. | 
| 502 |  |  |  |  |  |  | # The object will be re-created when we actually try to perform a | 
| 503 |  |  |  |  |  |  | # parse. | 
| 504 | 3 |  |  |  |  | 179 | delete $self->{lang}{obj}; | 
| 505 |  |  |  |  |  |  |  | 
| 506 | 3 |  |  |  |  | 13 | return( $cfg->{location} = $loc ); | 
| 507 |  |  |  |  |  |  | } | 
| 508 |  |  |  |  |  |  |  | 
| 509 |  |  |  |  |  |  | sub _get_twilight_qual { | 
| 510 | 12 |  |  | 12 |  | 70 | my ( undef, $qual ) = @_;	# Invocant not used | 
| 511 | 12 | 50 |  |  |  | 38 | defined $qual | 
| 512 |  |  |  |  |  |  | or return $qual; | 
| 513 | 12 |  |  |  |  | 31 | state $twi_name = { | 
| 514 |  |  |  |  |  |  | civil		=> Astro::Coord::ECI::Utils::deg2rad( -6 ), | 
| 515 |  |  |  |  |  |  | nautical	=> Astro::Coord::ECI::Utils::deg2rad( -12 ), | 
| 516 |  |  |  |  |  |  | astronomical	=> Astro::Coord::ECI::Utils::deg2rad( -18 ), | 
| 517 |  |  |  |  |  |  | }; | 
| 518 | 12 |  |  |  |  | 82 | return $twi_name->{ lc $qual }; | 
| 519 |  |  |  |  |  |  | } | 
| 520 |  |  |  |  |  |  |  | 
| 521 |  |  |  |  |  |  | sub _init_almanac { | 
| 522 | 7 |  |  | 7 |  | 17 | my ( $self, $from ) = @_; | 
| 523 | 7 | 100 | 66 |  |  | 54 | if ( Scalar::Util::blessed( $from ) && $from->isa( __PACKAGE__ ) ) { | 
| 524 | 4 |  |  |  |  | 12 | state $cfg_var = [ qw{ language location sky twilight } ]; | 
| 525 | 4 |  |  |  |  | 6 | my %cfg; | 
| 526 | 4 |  |  |  |  | 9 | @cfg{ @{ $cfg_var } } = $from->get_config( @{ $cfg_var } ); | 
|  | 4 |  |  |  |  | 15 |  | 
|  | 4 |  |  |  |  | 13 |  | 
| 527 |  |  |  |  |  |  | # We clone because these objects have state. | 
| 528 |  |  |  |  |  |  | # TODO this requires at least 0.118_01. | 
| 529 | 4 |  |  |  |  | 9 | @{ $cfg{sky} } = map { $_->clone() } @{ $cfg{sky} }; | 
|  | 4 |  |  |  |  | 154 |  | 
|  | 9 |  |  |  |  | 56 |  | 
|  | 4 |  |  |  |  | 11 |  | 
| 530 | 4 |  |  |  |  | 16 | $self->config( %cfg ); | 
| 531 |  |  |  |  |  |  | } else { | 
| 532 | 3 |  |  |  |  | 14 | $self->_init_almanac_language( 1 ); | 
| 533 | 3 | 50 |  |  |  | 11 | if ( my $lang = $self->get_config( 'language' ) ) { | 
| 534 | 3 |  |  |  |  | 13 | $self->_config_almanac_var_language( language => $lang ); | 
| 535 |  |  |  |  |  |  | } | 
| 536 | 3 |  |  |  |  | 14 | %{ $self->{config} } = (); | 
|  | 3 |  |  |  |  | 9 |  | 
| 537 |  |  |  |  |  |  | } | 
| 538 | 7 |  |  |  |  | 18 | return; | 
| 539 |  |  |  |  |  |  | } | 
| 540 |  |  |  |  |  |  |  | 
| 541 |  |  |  |  |  |  | sub _init_almanac_language { | 
| 542 | 3 |  |  | 3 |  | 8 | my ( $self, $force ) = @_; | 
| 543 |  |  |  |  |  |  |  | 
| 544 |  |  |  |  |  |  | not $force | 
| 545 |  |  |  |  |  |  | and exists $self->{lang} | 
| 546 | 3 | 0 | 33 |  |  | 11 | and return; | 
| 547 |  |  |  |  |  |  |  | 
| 548 | 3 |  |  |  |  | 14 | $self->{lang}		= {}; | 
| 549 |  |  |  |  |  |  |  | 
| 550 | 3 |  |  |  |  | 7 | return; | 
| 551 |  |  |  |  |  |  | } | 
| 552 |  |  |  |  |  |  |  | 
| 553 |  |  |  |  |  |  | sub _my_config_err { | 
| 554 | 0 |  |  | 0 |  | 0 | my ( undef, $err ) = @_; | 
| 555 | 0 |  |  |  |  | 0 | warn "ERROR: [config_var] $err\n"; | 
| 556 | 0 |  |  |  |  | 0 | return 1; | 
| 557 |  |  |  |  |  |  | } | 
| 558 |  |  |  |  |  |  |  | 
| 559 |  |  |  |  |  |  | sub __parse_pre { | 
| 560 | 14 |  |  | 14 |  | 11006 | my ( $self, $string ) = @_; | 
| 561 |  |  |  |  |  |  | wantarray | 
| 562 | 14 | 50 |  |  |  | 42 | or confess 'Bug - __parse_pre() must be called in list context'; | 
| 563 | 14 |  |  |  |  | 29 | delete $self->{err}; | 
| 564 | 14 |  |  |  |  | 29 | $self->{input} = $string; | 
| 565 | 14 | 50 |  |  |  | 24 | @{ $self->{config}{sky} || [] } | 
|  | 14 | 50 |  |  |  | 52 |  | 
| 566 |  |  |  |  |  |  | or return $string; | 
| 567 |  |  |  |  |  |  |  | 
| 568 |  |  |  |  |  |  | $self->{lang}{obj} ||= $self->{lang}{mod}->__new( | 
| 569 |  |  |  |  |  |  | sky		=> $self->{config}{sky}, | 
| 570 | 14 |  | 66 |  |  | 59 | ); | 
| 571 | 14 |  |  |  |  | 58 | return $self->{lang}{obj}->__parse_pre( $string ); | 
| 572 |  |  |  |  |  |  | } | 
| 573 |  |  |  |  |  |  |  | 
| 574 |  |  |  |  |  |  | sub __parse_post { | 
| 575 | 11 |  |  | 11 |  | 66139 | my ( $self, $body, $event, undef ) = @_; | 
| 576 | 11 | 50 | 33 |  |  | 62 | defined $body | 
| 577 |  |  |  |  |  |  | and defined $event | 
| 578 |  |  |  |  |  |  | or return; | 
| 579 |  |  |  |  |  |  |  | 
| 580 | 11 | 50 |  |  |  | 39 | $self->_get_config_location() | 
| 581 |  |  |  |  |  |  | or return $self->_set_err( "[parse] Location not configured" ); | 
| 582 |  |  |  |  |  |  |  | 
| 583 | 11 | 50 |  |  |  | 74 | my $code = $self->can( "__parse_post__$event" ) | 
| 584 |  |  |  |  |  |  | or confess "Bug - event $event not implemented"; | 
| 585 |  |  |  |  |  |  |  | 
| 586 |  |  |  |  |  |  | # TODO support for systems that do not use this epoch. | 
| 587 | 11 |  |  |  |  | 37 | $body->universal( $self->secs_since_1970_GMT() ); | 
| 588 |  |  |  |  |  |  |  | 
| 589 | 11 |  |  |  |  | 11571 | goto $code; | 
| 590 |  |  |  |  |  |  | } | 
| 591 |  |  |  |  |  |  |  | 
| 592 |  |  |  |  |  |  | sub _set_err { | 
| 593 | 0 |  |  | 0 |  | 0 | my ( $self, $err ) = @_; | 
| 594 |  |  |  |  |  |  |  | 
| 595 | 0 |  |  |  |  | 0 | $self->{err} = $err; | 
| 596 | 0 |  |  |  |  | 0 | return 1; | 
| 597 |  |  |  |  |  |  | } | 
| 598 |  |  |  |  |  |  |  | 
| 599 |  |  |  |  |  |  | sub __parse_post__horizon { | 
| 600 | 3 |  |  | 3 |  | 14 | my ( $self, $body, undef, $detail ) = @_; | 
| 601 |  |  |  |  |  |  |  | 
| 602 | 3 |  |  |  |  | 13 | my $almanac_horizon = $body->get( 'station' )->get( | 
| 603 |  |  |  |  |  |  | 'almanac_horizon' ); | 
| 604 |  |  |  |  |  |  |  | 
| 605 | 3 |  |  |  |  | 123 | my ( $time, $which ); | 
| 606 | 3 |  |  |  |  | 7 | while ( 1 ) { | 
| 607 | 5 |  |  |  |  | 75 | ( $time, $which ) = $body->next_elevation( $almanac_horizon, 1 ); | 
| 608 | 5 | 100 |  |  |  | 197831 | $which == $detail | 
| 609 |  |  |  |  |  |  | and last; | 
| 610 |  |  |  |  |  |  | } | 
| 611 |  |  |  |  |  |  |  | 
| 612 | 3 |  |  |  |  | 27 | $self->secs_since_1970_GMT( $time ); | 
| 613 |  |  |  |  |  |  |  | 
| 614 | 3 |  |  |  |  | 2217 | return; | 
| 615 |  |  |  |  |  |  | } | 
| 616 |  |  |  |  |  |  |  | 
| 617 |  |  |  |  |  |  | sub __parse_post__meridian { | 
| 618 | 2 |  |  | 2 |  | 7 | my ( $self, $body, undef, $detail ) = @_; | 
| 619 |  |  |  |  |  |  |  | 
| 620 | 2 |  |  |  |  | 4 | my ( $time, $which ); | 
| 621 | 2 |  |  |  |  | 4 | while ( 1 ) { | 
| 622 | 3 |  |  |  |  | 16 | ( $time, $which ) = $body->next_meridian(); | 
| 623 | 3 | 100 |  |  |  | 42905 | $which == $detail | 
| 624 |  |  |  |  |  |  | and last; | 
| 625 |  |  |  |  |  |  | } | 
| 626 |  |  |  |  |  |  |  | 
| 627 | 2 |  |  |  |  | 22 | $self->secs_since_1970_GMT( $time ); | 
| 628 |  |  |  |  |  |  |  | 
| 629 | 2 |  |  |  |  | 1239 | return; | 
| 630 |  |  |  |  |  |  | } | 
| 631 |  |  |  |  |  |  |  | 
| 632 |  |  |  |  |  |  | sub __parse_post__quarter { | 
| 633 | 3 |  |  | 3 |  | 11 | my ( $self, $body, undef, $detail ) = @_; | 
| 634 |  |  |  |  |  |  |  | 
| 635 | 3 |  |  |  |  | 20 | my $time = $body->next_quarter( $detail ); | 
| 636 |  |  |  |  |  |  |  | 
| 637 | 3 |  |  |  |  | 42485 | $self->secs_since_1970_GMT( $time ); | 
| 638 |  |  |  |  |  |  |  | 
| 639 | 3 |  |  |  |  | 3541 | return; | 
| 640 |  |  |  |  |  |  | } | 
| 641 |  |  |  |  |  |  |  | 
| 642 |  |  |  |  |  |  | sub __parse_post__twilight { | 
| 643 | 3 |  |  | 3 |  | 11 | my ( $self, $body, undef, $detail, $qual ) = @_; | 
| 644 |  |  |  |  |  |  |  | 
| 645 | 3 |  |  |  |  | 11 | my $station = $body->get( 'station' ); | 
| 646 | 3 |  | 66 |  |  | 77 | my $twilight = $station->get( 'almanac_horizon' ) + ( | 
| 647 |  |  |  |  |  |  | $self->_get_twilight_qual( $qual ) // $station->get( 'twilight' ) ); | 
| 648 |  |  |  |  |  |  |  | 
| 649 | 3 |  |  |  |  | 36 | my ( $time, $which ); | 
| 650 | 3 |  |  |  |  | 8 | while ( 1 ) { | 
| 651 | 4 |  |  |  |  | 12 | ( $time, $which ) = $body->next_elevation( $twilight, 0 ); | 
| 652 | 4 | 100 |  |  |  | 85708 | $which == $detail | 
| 653 |  |  |  |  |  |  | and last; | 
| 654 |  |  |  |  |  |  | } | 
| 655 |  |  |  |  |  |  |  | 
| 656 | 3 |  |  |  |  | 13 | $self->secs_since_1970_GMT( $time ); | 
| 657 |  |  |  |  |  |  |  | 
| 658 | 3 |  |  |  |  | 1888 | return; | 
| 659 |  |  |  |  |  |  | } | 
| 660 |  |  |  |  |  |  |  | 
| 661 |  |  |  |  |  |  | # Implemented as a subroutine so I can authortest for changes. This was | 
| 662 |  |  |  |  |  |  | # the list as of Date::Manip::Date version 6.85. The list is generated | 
| 663 |  |  |  |  |  |  | # by tools/dmd_public_interface. | 
| 664 |  |  |  |  |  |  | sub __date_manip_date_public_interface { | 
| 665 | 3 |  |  | 3 |  | 21 | return ( qw{ | 
| 666 |  |  |  |  |  |  | base | 
| 667 |  |  |  |  |  |  | calc | 
| 668 |  |  |  |  |  |  | cmp | 
| 669 |  |  |  |  |  |  | complete | 
| 670 |  |  |  |  |  |  | config | 
| 671 |  |  |  |  |  |  | convert | 
| 672 |  |  |  |  |  |  | err | 
| 673 |  |  |  |  |  |  | get_config | 
| 674 |  |  |  |  |  |  | holiday | 
| 675 |  |  |  |  |  |  | input | 
| 676 |  |  |  |  |  |  | is_business_day | 
| 677 |  |  |  |  |  |  | is_date | 
| 678 |  |  |  |  |  |  | is_delta | 
| 679 |  |  |  |  |  |  | is_recur | 
| 680 |  |  |  |  |  |  | list_events | 
| 681 |  |  |  |  |  |  | list_holidays | 
| 682 |  |  |  |  |  |  | nearest_business_day | 
| 683 |  |  |  |  |  |  | new | 
| 684 |  |  |  |  |  |  | new_config | 
| 685 |  |  |  |  |  |  | new_date | 
| 686 |  |  |  |  |  |  | new_delta | 
| 687 |  |  |  |  |  |  | new_recur | 
| 688 |  |  |  |  |  |  | next | 
| 689 |  |  |  |  |  |  | next_business_day | 
| 690 |  |  |  |  |  |  | parse | 
| 691 |  |  |  |  |  |  | parse_date | 
| 692 |  |  |  |  |  |  | parse_format | 
| 693 |  |  |  |  |  |  | parse_time | 
| 694 |  |  |  |  |  |  | prev | 
| 695 |  |  |  |  |  |  | prev_business_day | 
| 696 |  |  |  |  |  |  | printf | 
| 697 |  |  |  |  |  |  | secs_since_1970_GMT | 
| 698 |  |  |  |  |  |  | set | 
| 699 |  |  |  |  |  |  | tz | 
| 700 |  |  |  |  |  |  | value | 
| 701 |  |  |  |  |  |  | version | 
| 702 |  |  |  |  |  |  | week_of_year | 
| 703 |  |  |  |  |  |  | } ); | 
| 704 |  |  |  |  |  |  | } | 
| 705 |  |  |  |  |  |  |  | 
| 706 |  |  |  |  |  |  | { | 
| 707 |  |  |  |  |  |  | local $@ = undef; | 
| 708 |  |  |  |  |  |  | *_my_set_subname = eval { | 
| 709 |  |  |  |  |  |  | require Sub::Util; | 
| 710 |  |  |  |  |  |  | Sub::Util->can( 'set_subname' ); | 
| 711 |  |  |  |  |  |  | } || sub { $_[1] }; | 
| 712 |  |  |  |  |  |  | } | 
| 713 |  |  |  |  |  |  |  | 
| 714 |  |  |  |  |  |  | foreach my $method ( __date_manip_date_public_interface() ) { | 
| 715 |  |  |  |  |  |  | __PACKAGE__->can( $method ) | 
| 716 |  |  |  |  |  |  | and next; | 
| 717 |  |  |  |  |  |  | Date::Manip::Date->can( $method ) | 
| 718 |  |  |  |  |  |  | or next; | 
| 719 | 3 |  |  | 3 |  | 29 | no strict qw{ refs }; | 
|  | 3 |  |  |  |  | 7 |  | 
|  | 3 |  |  |  |  | 337 |  | 
| 720 |  |  |  |  |  |  | *$method = _my_set_subname( $method => sub { | 
| 721 | 34 |  |  | 34 | 0 | 1217 | my ( $self, @arg ) = @_; | 
|  |  |  |  | 34 | 0 |  |  | 
|  |  |  |  | 34 | 0 |  |  | 
|  |  |  |  | 34 | 0 |  |  | 
|  |  |  |  | 34 | 0 |  |  | 
|  |  |  |  | 34 | 0 |  |  | 
|  |  |  |  | 34 | 0 |  |  | 
|  |  |  |  | 34 | 0 |  |  | 
|  |  |  |  | 34 | 0 |  |  | 
|  |  |  |  | 34 | 0 |  |  | 
|  |  |  |  | 34 | 0 |  |  | 
|  |  |  |  | 34 | 0 |  |  | 
|  |  |  |  | 34 | 0 |  |  | 
|  |  |  |  | 34 | 0 |  |  | 
|  |  |  |  | 34 | 0 |  |  | 
|  |  |  |  | 34 | 0 |  |  | 
|  |  |  |  | 34 | 0 |  |  | 
|  |  |  |  | 34 | 0 |  |  | 
|  |  |  |  | 34 | 0 |  |  | 
|  |  |  |  | 34 | 0 |  |  | 
|  |  |  |  | 34 | 0 |  |  | 
|  |  |  |  | 34 | 0 |  |  | 
|  |  |  |  | 34 | 0 |  |  | 
|  |  |  |  | 34 | 0 |  |  | 
|  |  |  |  | 34 | 0 |  |  | 
| 722 | 34 |  |  |  |  | 93 | return $self->dmd()->$method( @arg ); | 
| 723 |  |  |  |  |  |  | }, | 
| 724 |  |  |  |  |  |  | ); | 
| 725 |  |  |  |  |  |  | } | 
| 726 |  |  |  |  |  |  |  | 
| 727 |  |  |  |  |  |  | 1; | 
| 728 |  |  |  |  |  |  |  | 
| 729 |  |  |  |  |  |  | __END__ |