| line | stmt | bran | cond | sub | pod | time | code | 
| 1 |  |  |  |  |  |  | package Astro::App::Satpass2::Format::Template; | 
| 2 |  |  |  |  |  |  |  | 
| 3 | 8 |  |  | 8 |  | 1767 | use strict; | 
|  | 8 |  |  |  |  | 25 |  | 
|  | 8 |  |  |  |  | 277 |  | 
| 4 | 8 |  |  | 8 |  | 75 | use warnings; | 
|  | 8 |  |  |  |  | 20 |  | 
|  | 8 |  |  |  |  | 244 |  | 
| 5 |  |  |  |  |  |  |  | 
| 6 | 8 |  |  | 8 |  | 53 | use parent qw{ Astro::App::Satpass2::Format }; | 
|  | 8 |  |  |  |  | 18 |  | 
|  | 8 |  |  |  |  | 76 |  | 
| 7 |  |  |  |  |  |  |  | 
| 8 | 8 |  |  | 8 |  | 433 | use Astro::App::Satpass2::Locale qw{ __localize }; | 
|  | 8 |  |  |  |  | 18 |  | 
|  | 8 |  |  |  |  | 450 |  | 
| 9 |  |  |  |  |  |  | # use Astro::App::Satpass2::FormatValue; | 
| 10 | 8 |  |  | 8 |  | 3801 | use Astro::App::Satpass2::FormatValue::Formatter; | 
|  | 8 |  |  |  |  | 26 |  | 
|  | 8 |  |  |  |  | 289 |  | 
| 11 | 8 |  |  |  |  | 883 | use Astro::App::Satpass2::Utils qw{ | 
| 12 |  |  |  |  |  |  | instance | 
| 13 |  |  |  |  |  |  | ARRAY_REF | 
| 14 |  |  |  |  |  |  | HASH_REF | 
| 15 |  |  |  |  |  |  | SCALAR_REF | 
| 16 |  |  |  |  |  |  | @CARP_NOT | 
| 17 | 8 |  |  | 8 |  | 57 | }; | 
|  | 8 |  |  |  |  | 28 |  | 
| 18 | 8 |  |  | 8 |  | 3725 | use Astro::App::Satpass2::Wrap::Array; | 
|  | 8 |  |  |  |  | 24 |  | 
|  | 8 |  |  |  |  | 340 |  | 
| 19 | 8 |  |  | 8 |  | 66 | use Astro::Coord::ECI::TLE 0.059 qw{ :constants }; | 
|  | 8 |  |  |  |  | 143 |  | 
|  | 8 |  |  |  |  | 1508 |  | 
| 20 | 8 |  |  |  |  | 546 | use Astro::Coord::ECI::Utils 0.059 qw{ | 
| 21 |  |  |  |  |  |  | deg2rad embodies julianday PI rad2deg TWOPI | 
| 22 | 8 |  |  | 8 |  | 113 | }; | 
|  | 8 |  |  |  |  | 125 |  | 
| 23 | 8 |  |  | 8 |  | 54 | use Clone qw{ }; | 
|  | 8 |  |  |  |  | 17 |  | 
|  | 8 |  |  |  |  | 212 |  | 
| 24 | 8 |  |  | 8 |  | 60 | use POSIX qw{ floor }; | 
|  | 8 |  |  |  |  | 33 |  | 
|  | 8 |  |  |  |  | 64 |  | 
| 25 | 8 |  |  | 8 |  | 5312 | use Template; | 
|  | 8 |  |  |  |  | 164482 |  | 
|  | 8 |  |  |  |  | 279 |  | 
| 26 | 8 |  |  | 8 |  | 68 | use Template::Provider; | 
|  | 8 |  |  |  |  | 21 |  | 
|  | 8 |  |  |  |  | 151 |  | 
| 27 | 8 |  |  | 8 |  | 748 | use Text::Abbrev; | 
|  | 8 |  |  |  |  | 65 |  | 
|  | 8 |  |  |  |  | 545 |  | 
| 28 | 8 |  |  | 8 |  | 53 | use Text::Wrap qw{ wrap }; | 
|  | 8 |  |  |  |  | 45 |  | 
|  | 8 |  |  |  |  | 535 |  | 
| 29 |  |  |  |  |  |  |  | 
| 30 |  |  |  |  |  |  | our $VERSION = '0.051'; | 
| 31 |  |  |  |  |  |  |  | 
| 32 | 8 |  |  | 8 |  | 62 | use constant FORMAT_VALUE	=> 'Astro::App::Satpass2::FormatValue'; | 
|  | 8 |  |  |  |  | 28 |  | 
|  | 8 |  |  |  |  | 19881 |  | 
| 33 |  |  |  |  |  |  |  | 
| 34 |  |  |  |  |  |  | sub new { | 
| 35 | 9 |  |  | 9 | 1 | 6224 | my ($class, @args) = @_; | 
| 36 | 9 |  |  |  |  | 75 | my $self = $class->SUPER::new( @args ); | 
| 37 |  |  |  |  |  |  |  | 
| 38 |  |  |  |  |  |  | # As of 0.020_002 the template definitions are in the | 
| 39 |  |  |  |  |  |  | # locale system. The attribute simply holds modifications. | 
| 40 | 9 |  |  |  |  | 27 | $self->{canned_template} = {}; | 
| 41 |  |  |  |  |  |  |  | 
| 42 | 9 |  |  |  |  | 63 | $self->_new_tt( $self->permissive() ); | 
| 43 |  |  |  |  |  |  |  | 
| 44 | 9 |  |  |  |  | 26 | $self->{default} = {}; | 
| 45 | 9 |  |  |  |  | 40 | $self->{formatter_method} = {}; | 
| 46 |  |  |  |  |  |  |  | 
| 47 | 9 |  |  |  |  | 67 | return $self; | 
| 48 |  |  |  |  |  |  | } | 
| 49 |  |  |  |  |  |  |  | 
| 50 |  |  |  |  |  |  | sub _new_tt { | 
| 51 | 10 |  |  | 10 |  | 33 | my ( $self, $permissive ) = @_; | 
| 52 |  |  |  |  |  |  |  | 
| 53 | 10 | 50 |  |  |  | 104 | $self->{tt} = Template->new( | 
| 54 |  |  |  |  |  |  | { | 
| 55 |  |  |  |  |  |  | LOAD_TEMPLATES => [ | 
| 56 |  |  |  |  |  |  | Template::Provider->new( | 
| 57 |  |  |  |  |  |  | ABSOLUTE	=> $permissive, | 
| 58 |  |  |  |  |  |  | RELATIVE	=> $permissive, | 
| 59 |  |  |  |  |  |  | ), | 
| 60 |  |  |  |  |  |  | ], | 
| 61 |  |  |  |  |  |  | } | 
| 62 |  |  |  |  |  |  | ) or $self->weep( | 
| 63 |  |  |  |  |  |  | "Failed to instantate tt: $Template::ERROR" ); | 
| 64 |  |  |  |  |  |  |  | 
| 65 | 10 |  |  |  |  | 201602 | return; | 
| 66 |  |  |  |  |  |  | } | 
| 67 |  |  |  |  |  |  |  | 
| 68 |  |  |  |  |  |  | sub add_formatter_method { | 
| 69 |  |  |  |  |  |  | # TODO I want the arguments to be ( $self, $fmtr ), but for the | 
| 70 |  |  |  |  |  |  | # moment I have to live with an unreleased version that passed the | 
| 71 |  |  |  |  |  |  | # name as the first argument. I will go to the desired signature as | 
| 72 |  |  |  |  |  |  | # soon as I get this version installed on my own machine. | 
| 73 | 1 |  |  | 1 | 1 | 6 | my ( $self, @arg ) = @_; | 
| 74 | 1 | 50 |  |  |  | 6 | my $fmtr = HASH_REF eq ref $arg[0] ? $arg[0] : $arg[1]; | 
| 75 | 1 | 50 |  |  |  | 6 | HASH_REF eq ref $fmtr | 
| 76 |  |  |  |  |  |  | or $self->wail( | 
| 77 |  |  |  |  |  |  | 'Formatter definition must be a HASH reference' ); | 
| 78 |  |  |  |  |  |  | defined( my $fmtr_name = $fmtr->{name} ) | 
| 79 | 1 | 50 |  |  |  | 5 | or $self->wail( | 
| 80 |  |  |  |  |  |  | 'Formatter definition must have {name} defined' ); | 
| 81 |  |  |  |  |  |  | $self->{formatter_method}{$fmtr_name} | 
| 82 |  |  |  |  |  |  | and $self->{warner}->wail( | 
| 83 | 1 | 50 |  |  |  | 6 | "Formatter method $fmtr_name already exists" ); | 
| 84 |  |  |  |  |  |  | FORMAT_VALUE->can( $fmtr_name ) | 
| 85 |  |  |  |  |  |  | and $self->{warner}->wail( | 
| 86 | 1 | 50 |  |  |  | 18 | "Formatter $fmtr_name can not override built-in formatter" ); | 
| 87 | 1 |  |  |  |  | 11 | $self->{formatter_method}{$fmtr_name} = | 
| 88 |  |  |  |  |  |  | Astro::App::Satpass2::FormatValue::Formatter->new( $fmtr ); | 
| 89 | 1 |  |  |  |  | 4 | return $self; | 
| 90 |  |  |  |  |  |  | } | 
| 91 |  |  |  |  |  |  |  | 
| 92 |  |  |  |  |  |  | sub attribute_names { | 
| 93 | 17 |  |  | 17 | 1 | 68 | my ( $self ) = @_; | 
| 94 | 17 |  |  |  |  | 100 | return ( $self->SUPER::attribute_names(), | 
| 95 |  |  |  |  |  |  | qw{ permissive }, | 
| 96 |  |  |  |  |  |  | ); | 
| 97 |  |  |  |  |  |  | } | 
| 98 |  |  |  |  |  |  |  | 
| 99 |  |  |  |  |  |  | sub config { | 
| 100 | 0 |  |  | 0 | 1 | 0 | my ( $self, %args ) = @_; | 
| 101 | 0 |  |  |  |  | 0 | my @data = $self->SUPER::config( %args ); | 
| 102 |  |  |  |  |  |  |  | 
| 103 |  |  |  |  |  |  | # TODO support for the {default} key. | 
| 104 |  |  |  |  |  |  |  | 
| 105 | 0 | 0 |  |  |  | 0 | foreach my $name ( | 
| 106 |  |  |  |  |  |  | sort $args{changes} ? | 
| 107 | 0 |  |  |  |  | 0 | keys %{ $self->{canned_template} } : | 
| 108 |  |  |  |  |  |  | $self->__list_templates() | 
| 109 |  |  |  |  |  |  | ) { | 
| 110 |  |  |  |  |  |  | push @data, [ template => $name, | 
| 111 | 0 |  |  |  |  | 0 | $self->{canned_template}{$name} ]; | 
| 112 |  |  |  |  |  |  | } | 
| 113 |  |  |  |  |  |  |  | 
| 114 | 0 | 0 |  |  |  | 0 | return wantarray ? @data : \@data; | 
| 115 |  |  |  |  |  |  | } | 
| 116 |  |  |  |  |  |  |  | 
| 117 |  |  |  |  |  |  | # Return the names of all known templates, in no particular order. No | 
| 118 |  |  |  |  |  |  | # arguments other than the invocant. | 
| 119 |  |  |  |  |  |  | sub __list_templates { | 
| 120 | 24 |  |  | 24 |  | 81 | my ( $self ) = @_; | 
| 121 | 72 |  |  |  |  | 127 | return ( _uniq( map { keys %{ $_ } } $self->{canned_template}, | 
|  | 72 |  |  |  |  | 573 |  | 
| 122 | 24 |  |  |  |  | 138 | __localize( | 
| 123 |  |  |  |  |  |  | text	=> '+template', | 
| 124 |  |  |  |  |  |  | default	=> {}, | 
| 125 |  |  |  |  |  |  | ) ) ); | 
| 126 |  |  |  |  |  |  | } | 
| 127 |  |  |  |  |  |  |  | 
| 128 |  |  |  |  |  |  | { | 
| 129 |  |  |  |  |  |  | my %decoder = ( | 
| 130 |  |  |  |  |  |  | template	=> sub { | 
| 131 |  |  |  |  |  |  | my ( $self, $method, @args ) = @_; | 
| 132 |  |  |  |  |  |  |  | 
| 133 |  |  |  |  |  |  | =begin comment | 
| 134 |  |  |  |  |  |  |  | 
| 135 |  |  |  |  |  |  | 1 == @args | 
| 136 |  |  |  |  |  |  | and return ( @args, $self->$method( @args ) ); | 
| 137 |  |  |  |  |  |  | $self->$method( @args ); | 
| 138 |  |  |  |  |  |  | return $self; | 
| 139 |  |  |  |  |  |  |  | 
| 140 |  |  |  |  |  |  | =end comment | 
| 141 |  |  |  |  |  |  |  | 
| 142 |  |  |  |  |  |  | =cut | 
| 143 |  |  |  |  |  |  |  | 
| 144 |  |  |  |  |  |  | 1 == @args | 
| 145 |  |  |  |  |  |  | or return $self->$method( @args ); | 
| 146 |  |  |  |  |  |  | return ( @args, $self->$method( @args ) ); | 
| 147 |  |  |  |  |  |  | }, | 
| 148 |  |  |  |  |  |  | ); | 
| 149 |  |  |  |  |  |  |  | 
| 150 |  |  |  |  |  |  | sub decode { | 
| 151 | 7 |  |  | 7 | 1 | 17 | my ( $self, $method, @args ) = @_; | 
| 152 | 7 | 50 |  |  |  | 47 | my $dcdr = $decoder{$method} | 
| 153 |  |  |  |  |  |  | or return $self->SUPER::decode( $method, @args ); | 
| 154 | 0 |  |  |  |  | 0 | goto $dcdr; | 
| 155 |  |  |  |  |  |  | } | 
| 156 |  |  |  |  |  |  | } | 
| 157 |  |  |  |  |  |  |  | 
| 158 |  |  |  |  |  |  | sub __default { | 
| 159 | 302 |  |  | 302 |  | 627 | my ( $self, @arg ) = @_; | 
| 160 | 302 | 50 |  |  |  | 1388 | @arg or return $self->{default}; | 
| 161 | 0 |  |  |  |  | 0 | my $action = shift @arg; | 
| 162 | 0 | 0 |  |  |  | 0 | @arg or return $self->{default}{$action}; | 
| 163 | 0 |  |  |  |  | 0 | my $attrib = shift @arg; | 
| 164 |  |  |  |  |  |  | defined $attrib | 
| 165 | 0 | 0 |  |  |  | 0 | or return delete $self->{default}{$action}; | 
| 166 | 0 | 0 |  |  |  | 0 | @arg or return $self->{default}{$action}{$attrib}; | 
| 167 | 0 |  |  |  |  | 0 | my $value = shift @arg; | 
| 168 |  |  |  |  |  |  | defined $value | 
| 169 | 0 | 0 |  |  |  | 0 | or return delete $self->{default}{$action}{$attrib}; | 
| 170 | 0 |  |  |  |  | 0 | $self->{default}{$action}{$attrib} = $value; | 
| 171 | 0 |  |  |  |  | 0 | return $value; | 
| 172 |  |  |  |  |  |  | } | 
| 173 |  |  |  |  |  |  |  | 
| 174 |  |  |  |  |  |  | sub format : method {	## no critic (ProhibitBuiltInHomonyms) | 
| 175 | 62 |  |  | 62 | 1 | 4114 | my ( $self, %data ) = @_; | 
| 176 |  |  |  |  |  |  |  | 
| 177 |  |  |  |  |  |  | exists $data{data} | 
| 178 |  |  |  |  |  |  | and $data{data} = $self->_wrap( | 
| 179 |  |  |  |  |  |  | data	=> $data{data}, | 
| 180 |  |  |  |  |  |  | report	=> $data{template}, | 
| 181 | 62 | 100 |  |  |  | 489 | ); | 
| 182 |  |  |  |  |  |  |  | 
| 183 | 62 | 100 |  |  |  | 392 | _is_format() and return $data{data}; | 
| 184 |  |  |  |  |  |  |  | 
| 185 |  |  |  |  |  |  | my $tplt = delete $data{template} | 
| 186 | 61 | 50 |  |  |  | 335 | or $self->wail( 'template argument is required' ); | 
| 187 |  |  |  |  |  |  |  | 
| 188 | 61 | 100 |  |  |  | 265 | my $tplt_name = SCALAR_REF eq ref $tplt ? ${ $tplt } : $tplt; | 
|  | 1 |  |  |  |  | 4 |  | 
| 189 |  |  |  |  |  |  |  | 
| 190 | 61 |  | 33 |  |  | 343 | $data{default} ||= $self->__default(); | 
| 191 |  |  |  |  |  |  |  | 
| 192 |  |  |  |  |  |  | $data{instantiate} = sub { | 
| 193 | 0 |  |  | 0 |  | 0 | my @args = @_; | 
| 194 | 0 |  |  |  |  | 0 | my $class = Astro::App::Satpass2::Utils::load_package( @args ); | 
| 195 | 0 |  |  |  |  | 0 | return $class->new(); | 
| 196 | 61 |  |  |  |  | 463 | }; | 
| 197 |  |  |  |  |  |  |  | 
| 198 | 61 |  | 33 |  |  | 448 | $data{provider} ||= $self->provider(); | 
| 199 |  |  |  |  |  |  |  | 
| 200 | 61 | 50 |  |  |  | 184 | if ( $data{time} ) { | 
| 201 |  |  |  |  |  |  | ref $data{time} | 
| 202 |  |  |  |  |  |  | or $data{time} = $self->_wrap( | 
| 203 |  |  |  |  |  |  | data => { time => $data{time} }, | 
| 204 | 0 | 0 |  |  |  | 0 | report	=> $tplt_name, | 
| 205 |  |  |  |  |  |  | ); | 
| 206 |  |  |  |  |  |  | } else { | 
| 207 | 61 |  |  |  |  | 330 | $data{time} = $self->_wrap( | 
| 208 |  |  |  |  |  |  | data	=> { time => time }, | 
| 209 |  |  |  |  |  |  | report	=> $tplt_name, | 
| 210 |  |  |  |  |  |  | ); | 
| 211 |  |  |  |  |  |  | } | 
| 212 |  |  |  |  |  |  |  | 
| 213 | 61 |  |  |  |  | 340 | my $value_formatter = $self->value_formatter(); | 
| 214 |  |  |  |  |  |  |  | 
| 215 |  |  |  |  |  |  | $data{title} = $self->_wrap( | 
| 216 |  |  |  |  |  |  | default	=> $data{default}, | 
| 217 | 61 |  |  |  |  | 300 | report	=> $tplt_name, | 
| 218 |  |  |  |  |  |  | ); | 
| 219 |  |  |  |  |  |  | $data{TITLE_GRAVITY_BOTTOM} = | 
| 220 | 61 |  |  |  |  | 510 | $value_formatter->TITLE_GRAVITY_BOTTOM; | 
| 221 |  |  |  |  |  |  | $data{TITLE_GRAVITY_TOP} = | 
| 222 | 61 |  |  |  |  | 280 | $value_formatter->TITLE_GRAVITY_TOP; | 
| 223 |  |  |  |  |  |  |  | 
| 224 |  |  |  |  |  |  | local $Template::Stash::LIST_OPS->{bodies} = sub { | 
| 225 | 0 |  |  | 0 |  | 0 | my ( $list ) = @_; | 
| 226 | 0 |  |  |  |  | 0 | return [ map { $_->body() } @{ $list } ]; | 
|  | 0 |  |  |  |  | 0 |  | 
|  | 0 |  |  |  |  | 0 |  | 
| 227 | 61 |  |  |  |  | 570 | }; | 
| 228 |  |  |  |  |  |  |  | 
| 229 |  |  |  |  |  |  | local $Template::Stash::LIST_OPS->{events} = sub { | 
| 230 | 3 |  |  | 3 |  | 64 | my @args = @_; | 
| 231 | 3 |  |  |  |  | 24 | return $self->_all_events( $args[0] ); | 
| 232 | 61 |  |  |  |  | 398 | }; | 
| 233 |  |  |  |  |  |  |  | 
| 234 |  |  |  |  |  |  | local $Template::Stash::LIST_OPS->{fixed_width} = sub { | 
| 235 | 2 |  |  | 2 |  | 11 | my ( $list, $value ) = @_; | 
| 236 | 2 |  |  |  |  | 7 | foreach my $item ( @{ $list } ) { | 
|  | 2 |  |  |  |  | 8 |  | 
| 237 | 10 | 50 |  |  |  | 40 | my $code = $item->can( 'fixed_width' ) | 
| 238 |  |  |  |  |  |  | or next; | 
| 239 | 10 |  |  |  |  | 28 | $code->( $item, $value ); | 
| 240 |  |  |  |  |  |  | } | 
| 241 | 2 |  |  |  |  | 17 | return; | 
| 242 | 61 |  |  |  |  | 401 | }; | 
| 243 |  |  |  |  |  |  |  | 
| 244 |  |  |  |  |  |  | $data{localize} = sub { | 
| 245 | 28 |  |  | 28 |  | 81406 | return _localize( $tplt_name, @_ ); | 
| 246 | 61 |  |  |  |  | 389 | }; | 
| 247 |  |  |  |  |  |  |  | 
| 248 |  |  |  |  |  |  | # NOTE - must come after $data{localize} because | 
| 249 |  |  |  |  |  |  | # $data{format_detail} uses $data{localize} | 
| 250 |  |  |  |  |  |  | $data{format_detail} = sub { | 
| 251 | 173 |  |  | 173 |  | 9126 | my ( $kind, $evt ) = @_; | 
| 252 |  |  |  |  |  |  |  | 
| 253 | 173 | 50 |  |  |  | 601 | instance( $evt, 'Astro::App::Satpass2::FormatValue' ) | 
| 254 |  |  |  |  |  |  | or return; | 
| 255 | 173 | 50 |  |  |  | 677 | defined ( my $type = $evt->$kind( width => '' ) ) | 
| 256 |  |  |  |  |  |  | or return; | 
| 257 | 173 |  |  |  |  | 689 | $type =~ s/ \s+ \z //smx; | 
| 258 |  |  |  |  |  |  |  | 
| 259 | 173 |  |  |  |  | 540 | foreach my $name ( "$kind:$type", $kind ) { | 
| 260 | 329 | 100 |  |  |  | 1138 | defined ( my $tplt = $self->template( "$tplt:$name" ) ) | 
| 261 |  |  |  |  |  |  | or next; | 
| 262 |  |  |  |  |  |  | my $output = $self->_process( \$tplt, | 
| 263 |  |  |  |  |  |  | evt		=> $evt, | 
| 264 |  |  |  |  |  |  | localize	=> $data{localize}, | 
| 265 |  |  |  |  |  |  | sp		=> $data{sp}, | 
| 266 | 173 |  |  |  |  | 755 | ); | 
| 267 |  |  |  |  |  |  |  | 
| 268 | 173 |  |  |  |  | 517 | chomp $output; | 
| 269 | 173 |  |  |  |  | 1169 | return $output; | 
| 270 |  |  |  |  |  |  | } | 
| 271 | 0 |  |  |  |  | 0 | return __localize( | 
| 272 |  |  |  |  |  |  | text	=> [ '+template', "$tplt:$kind" ], | 
| 273 |  |  |  |  |  |  | ); | 
| 274 | 61 |  |  |  |  | 453 | }; | 
| 275 |  |  |  |  |  |  |  | 
| 276 | 61 |  |  |  |  | 557 | my $output = $self->_process( $tplt, %data ); | 
| 277 |  |  |  |  |  |  |  | 
| 278 |  |  |  |  |  |  | # TODO would love to use \h here, but that needs 5.10. | 
| 279 | 60 |  |  |  |  | 1348 | $output =~ s/ [ \t]+ (?= \n ) //sxmg; | 
| 280 |  |  |  |  |  |  | $data{title}->title_gravity() eq $data{TITLE_GRAVITY_BOTTOM} | 
| 281 | 60 | 100 |  |  |  | 425 | and $output =~ s/ \A \n //smx; | 
| 282 |  |  |  |  |  |  |  | 
| 283 | 60 |  |  |  |  | 1378 | return $output; | 
| 284 |  |  |  |  |  |  | } | 
| 285 |  |  |  |  |  |  |  | 
| 286 |  |  |  |  |  |  | sub gmt { | 
| 287 | 57 |  |  | 57 | 1 | 219 | my ( $self, @args ) = @_; | 
| 288 | 57 | 100 |  |  |  | 212 | if ( @args ) { | 
| 289 | 3 |  |  |  |  | 18 | $self->time_formatter()->gmt( @args ); | 
| 290 | 3 |  |  |  |  | 24 | return $self->SUPER::gmt( @args ); | 
| 291 |  |  |  |  |  |  | } else { | 
| 292 | 54 |  |  |  |  | 270 | return $self->SUPER::gmt(); | 
| 293 |  |  |  |  |  |  | } | 
| 294 |  |  |  |  |  |  | } | 
| 295 |  |  |  |  |  |  |  | 
| 296 |  |  |  |  |  |  | sub local_coord { | 
| 297 | 207 |  |  | 207 | 1 | 440 | my ( $self, @args ) = @_; | 
| 298 | 207 | 100 |  |  |  | 535 | if ( @args ) { | 
| 299 | 12 |  |  |  |  | 47 | my $val = $args[0]; | 
| 300 | 12 | 100 |  |  |  | 121 | defined $val | 
| 301 |  |  |  |  |  |  | or $val = $self->DEFAULT_LOCAL_COORD; | 
| 302 |  |  |  |  |  |  |  | 
| 303 | 12 | 50 |  |  |  | 391 | defined $self->template( $val ) | 
| 304 |  |  |  |  |  |  | or $self->wail( | 
| 305 |  |  |  |  |  |  | 'Unknown local coordinate specification', $val ); | 
| 306 |  |  |  |  |  |  |  | 
| 307 | 12 |  |  |  |  | 91 | return $self->SUPER::local_coord( @args ); | 
| 308 |  |  |  |  |  |  | } else { | 
| 309 | 195 |  |  |  |  | 725 | return $self->SUPER::local_coord(); | 
| 310 |  |  |  |  |  |  | } | 
| 311 |  |  |  |  |  |  | } | 
| 312 |  |  |  |  |  |  |  | 
| 313 |  |  |  |  |  |  | sub permissive { | 
| 314 | 10 |  |  | 10 | 1 | 695 | my ( $self, @args ) = @_; | 
| 315 | 10 | 100 |  |  |  | 40 | if ( @args ) { | 
| 316 | 1 | 50 | 25 |  |  | 11 | if ( $self->{permissive} xor $args[0] ) { | 
| 317 | 1 |  |  |  |  | 8 | $self->_new_tt( $args[0] ); | 
| 318 |  |  |  |  |  |  | } | 
| 319 | 1 |  |  |  |  | 4 | $self->{permissive} = $args[0]; | 
| 320 | 1 |  |  |  |  | 4 | return $self; | 
| 321 |  |  |  |  |  |  | } else { | 
| 322 | 9 |  |  |  |  | 65 | return $self->{permissive}; | 
| 323 |  |  |  |  |  |  | } | 
| 324 |  |  |  |  |  |  | } | 
| 325 |  |  |  |  |  |  |  | 
| 326 |  |  |  |  |  |  | sub template { | 
| 327 | 620 |  |  | 620 | 1 | 1336 | my ( $self, $name, @value ) = @_; | 
| 328 | 620 | 50 |  |  |  | 1236 | defined $name | 
| 329 |  |  |  |  |  |  | or $self->wail( 'Template name not specified' ); | 
| 330 |  |  |  |  |  |  |  | 
| 331 | 620 | 100 |  |  |  | 1320 | if ( @value ) { | 
| 332 | 3 |  |  |  |  | 9 | my $tplt_text; | 
| 333 | 3 | 50 | 33 |  |  | 22 | if ( ! defined $value[0] | 
|  |  |  | 33 |  |  |  |  | 
| 334 |  |  |  |  |  |  | || defined( $tplt_text = __localize( | 
| 335 |  |  |  |  |  |  | text	=> '+template', | 
| 336 |  |  |  |  |  |  | default	=> $value[0] ) | 
| 337 |  |  |  |  |  |  | ) | 
| 338 |  |  |  |  |  |  | && $value[0] eq $tplt_text | 
| 339 |  |  |  |  |  |  | ) { | 
| 340 | 0 |  |  |  |  | 0 | delete $self->{canned_template}{$name}; | 
| 341 |  |  |  |  |  |  | } else { | 
| 342 | 3 |  |  |  |  | 13 | $self->{canned_template}{$name} = $value[0]; | 
| 343 |  |  |  |  |  |  | } | 
| 344 |  |  |  |  |  |  |  | 
| 345 | 3 |  |  |  |  | 12 | return $self; | 
| 346 |  |  |  |  |  |  | } else { | 
| 347 |  |  |  |  |  |  | defined $self->{canned_template}{$name} | 
| 348 | 617 | 100 |  |  |  | 1631 | and return $self->{canned_template}{$name}; | 
| 349 | 613 |  |  |  |  | 2246 | return __localize( | 
| 350 |  |  |  |  |  |  | text	=> [ '+template', $name ], | 
| 351 |  |  |  |  |  |  | ); | 
| 352 |  |  |  |  |  |  | } | 
| 353 |  |  |  |  |  |  | } | 
| 354 |  |  |  |  |  |  |  | 
| 355 |  |  |  |  |  |  | sub tz { | 
| 356 | 16 |  |  | 16 | 1 | 59 | my ( $self, @args ) = @_; | 
| 357 | 16 | 50 |  |  |  | 81 | if ( @args ) { | 
| 358 | 16 |  |  |  |  | 83 | my $tf = $self->time_formatter(); | 
| 359 |  |  |  |  |  |  | # We go through the following because the time formatter may | 
| 360 |  |  |  |  |  |  | # modify the zone (e.g. if it's using DateTime, zones are | 
| 361 |  |  |  |  |  |  | # case-sensitive so we may have done case conversion before | 
| 362 |  |  |  |  |  |  | # storing). We want this object to have the time formatter's | 
| 363 |  |  |  |  |  |  | # version of the zone. | 
| 364 | 16 |  |  |  |  | 151 | $tf->tz( @args ); | 
| 365 | 16 |  |  |  |  | 55 | return $self->SUPER::tz( $tf->tz() ); | 
| 366 |  |  |  |  |  |  | } else { | 
| 367 | 0 |  |  |  |  | 0 | return $self->SUPER::tz(); | 
| 368 |  |  |  |  |  |  | } | 
| 369 |  |  |  |  |  |  | } | 
| 370 |  |  |  |  |  |  |  | 
| 371 |  |  |  |  |  |  | sub _all_events { | 
| 372 | 3 |  |  | 3 |  | 15 | my ( $self, $data ) = @_; | 
| 373 | 3 | 50 |  |  |  | 22 | ARRAY_REF eq ref $data or return; | 
| 374 |  |  |  |  |  |  |  | 
| 375 | 3 |  |  |  |  | 7 | my @events; | 
| 376 | 3 |  |  |  |  | 9 | foreach my $pass ( @{ $data } ) { | 
|  | 3 |  |  |  |  | 19 |  | 
| 377 | 3 |  |  |  |  | 36 | push @events, $pass->__raw_events(); | 
| 378 |  |  |  |  |  |  | } | 
| 379 | 3 | 50 |  |  |  | 14 | @events or return; | 
| 380 | 3 |  |  |  |  | 28 | @events = sort { $a->{time} <=> $b->{time} } @events; | 
|  | 16 |  |  |  |  | 42 |  | 
| 381 |  |  |  |  |  |  |  | 
| 382 | 3 |  |  |  |  | 14 | return [ map { $self->_wrap( data => $_ ) } @events ]; | 
|  | 13 |  |  |  |  | 37 |  | 
| 383 |  |  |  |  |  |  | } | 
| 384 |  |  |  |  |  |  |  | 
| 385 |  |  |  |  |  |  | #	_is_format() | 
| 386 |  |  |  |  |  |  | # | 
| 387 |  |  |  |  |  |  | #	Returns true if the format() method is above us on the call | 
| 388 |  |  |  |  |  |  | #	stack, otherwise returns false. | 
| 389 |  |  |  |  |  |  |  | 
| 390 | 8 |  |  | 8 |  | 90 | use constant REPORT_CALLER => __PACKAGE__ . '::format'; | 
|  | 8 |  |  |  |  | 19 |  | 
|  | 8 |  |  |  |  | 6880 |  | 
| 391 |  |  |  |  |  |  | sub _is_format { | 
| 392 | 62 |  |  | 62 |  | 185 | my $level = 2;	# Start with caller's caller. | 
| 393 | 62 |  |  |  |  | 830 | while ( my @info = caller( $level ) ) { | 
| 394 | 261 | 100 |  |  |  | 630 | REPORT_CALLER eq $info[3] | 
| 395 |  |  |  |  |  |  | and return $level; | 
| 396 | 260 |  |  |  |  | 1951 | $level++; | 
| 397 |  |  |  |  |  |  | } | 
| 398 | 61 |  |  |  |  | 265 | return; | 
| 399 |  |  |  |  |  |  | } | 
| 400 |  |  |  |  |  |  |  | 
| 401 |  |  |  |  |  |  | sub _localize { | 
| 402 | 28 |  |  | 28 |  | 78 | my ( $report, $source, $default ) = @_; | 
| 403 | 28 | 50 |  |  |  | 82 | defined $default | 
| 404 |  |  |  |  |  |  | or $default = $source; | 
| 405 | 28 | 0 |  |  |  | 70 | defined $report | 
|  |  | 50 |  |  |  |  |  | 
| 406 |  |  |  |  |  |  | or return defined $source ? $source : $default; | 
| 407 |  |  |  |  |  |  |  | 
| 408 | 28 |  |  |  |  | 117 | return scalar __localize( | 
| 409 |  |  |  |  |  |  | text	=> [ "-$report", 'string', $source ], | 
| 410 |  |  |  |  |  |  | default	=> $source, | 
| 411 |  |  |  |  |  |  | ); | 
| 412 |  |  |  |  |  |  | } | 
| 413 |  |  |  |  |  |  |  | 
| 414 |  |  |  |  |  |  | sub _process { | 
| 415 | 449 |  |  | 449 |  | 2111 | my ( $self, $tplt, %arg ) = @_; | 
| 416 |  |  |  |  |  |  | ARRAY_REF eq ref $arg{arg} | 
| 417 |  |  |  |  |  |  | and $arg{arg} = Astro::App::Satpass2::Wrap::Array->new( | 
| 418 | 449 | 100 |  |  |  | 2340 | $arg{arg} ); | 
| 419 | 449 |  |  |  |  | 750 | my $output; | 
| 420 | 449 |  |  |  |  | 940 | my $tt = $self->{tt}; | 
| 421 |  |  |  |  |  |  |  | 
| 422 | 449 |  |  |  |  | 687 | my $tplt_text; | 
| 423 | 449 | 100 | 100 |  |  | 1774 | not ref $tplt | 
| 424 |  |  |  |  |  |  | and defined( $tplt_text = $self->template( $tplt ) ) | 
| 425 |  |  |  |  |  |  | and $tplt = \$tplt_text; | 
| 426 |  |  |  |  |  |  |  | 
| 427 | 449 | 100 |  |  |  | 1897 | $tt->process( $tplt, \%arg, \$output ) | 
| 428 |  |  |  |  |  |  | or $self->wail( $tt->error() ); | 
| 429 | 448 |  |  |  |  | 117916 | return $output; | 
| 430 |  |  |  |  |  |  | } | 
| 431 |  |  |  |  |  |  |  | 
| 432 |  |  |  |  |  |  | # Cribbed shamelessly from List::MoreUtils. The author reserves the | 
| 433 |  |  |  |  |  |  | # right to relocate, rename or otherwise mung with this without notice | 
| 434 |  |  |  |  |  |  | # to anyone. Caveat user. | 
| 435 |  |  |  |  |  |  | sub _uniq { | 
| 436 | 25 |  |  | 25 |  | 80 | my %found; | 
| 437 | 25 |  |  |  |  | 76 | return ( grep { ! $found{$_}++ } @_ ); | 
|  | 679 |  |  |  |  | 1752 |  | 
| 438 |  |  |  |  |  |  | } | 
| 439 |  |  |  |  |  |  |  | 
| 440 |  |  |  |  |  |  | sub _wrap { | 
| 441 | 517 |  |  | 517 |  | 1932 | my ( $self, %arg ) = @_; | 
| 442 |  |  |  |  |  |  |  | 
| 443 | 517 |  |  |  |  | 991 | my $data = $arg{data}; | 
| 444 | 517 |  |  |  |  | 879 | my $default = $arg{default}; | 
| 445 | 517 |  |  |  |  | 933 | my $report = $arg{report}; | 
| 446 |  |  |  |  |  |  |  | 
| 447 | 517 |  |  |  |  | 998 | my $title = ! $data; | 
| 448 | 517 |  | 100 |  |  | 2019 | $data ||= {}; | 
| 449 | 517 |  | 66 |  |  | 1539 | $default ||= $self->__default(); | 
| 450 |  |  |  |  |  |  |  | 
| 451 | 517 | 50 | 66 |  |  | 1671 | if ( instance( $data, FORMAT_VALUE ) ) { | 
|  |  | 100 |  |  |  |  |  | 
|  |  | 100 |  |  |  |  |  | 
|  |  | 50 |  |  |  |  |  | 
| 452 |  |  |  |  |  |  | # Do nothing | 
| 453 |  |  |  |  |  |  | } elsif ( ! defined $data || HASH_REF eq ref $data ) { | 
| 454 | 449 |  |  |  |  | 1574 | my $value_formatter = $self->value_formatter(); | 
| 455 |  |  |  |  |  |  | $data = $value_formatter->new( | 
| 456 |  |  |  |  |  |  | data	=> $data, | 
| 457 |  |  |  |  |  |  | default	=> $default, | 
| 458 |  |  |  |  |  |  | date_format => $self->date_format(), | 
| 459 |  |  |  |  |  |  | desired_equinox_dynamical => | 
| 460 |  |  |  |  |  |  | $self->desired_equinox_dynamical(), | 
| 461 |  |  |  |  |  |  | provider	=> $self->provider(), | 
| 462 |  |  |  |  |  |  | round_time	=> $self->round_time(), | 
| 463 |  |  |  |  |  |  | time_format => $self->time_format(), | 
| 464 |  |  |  |  |  |  | time_formatter => $self->time_formatter(), | 
| 465 |  |  |  |  |  |  | local_coordinates => sub { | 
| 466 | 195 |  |  | 195 |  | 488 | my ( $data, @arg ) = @_; | 
| 467 |  |  |  |  |  |  | return $self->_process( $self->local_coord(), | 
| 468 |  |  |  |  |  |  | data	=> $data, | 
| 469 |  |  |  |  |  |  | arg		=> \@arg, | 
| 470 |  |  |  |  |  |  | title	=> $self->_wrap( | 
| 471 |  |  |  |  |  |  | default	=> $default, | 
| 472 |  |  |  |  |  |  | report	=> $report, | 
| 473 |  |  |  |  |  |  | ), | 
| 474 |  |  |  |  |  |  | localize	=> sub { | 
| 475 | 0 |  |  |  |  | 0 | return _localize( $report, @_ ); | 
| 476 |  |  |  |  |  |  | }, | 
| 477 | 195 |  |  |  |  | 700 | ); | 
| 478 |  |  |  |  |  |  | }, | 
| 479 |  |  |  |  |  |  | list_formatter => sub { | 
| 480 | 20 |  |  | 20 |  | 47 | my ( $data, @arg ) = @_; | 
| 481 | 20 |  |  |  |  | 68 | my $body = $data->body(); | 
| 482 | 20 | 100 |  |  |  | 317 | my $list_type = $body ? $body->__list_type() : 'inertial'; | 
| 483 | 20 |  |  |  |  | 156 | return $self->_process( "list_$list_type", | 
| 484 |  |  |  |  |  |  | data	=> $data, | 
| 485 |  |  |  |  |  |  | arg		=> \@arg, | 
| 486 |  |  |  |  |  |  | title	=> $self->_wrap( | 
| 487 |  |  |  |  |  |  | default => $default, | 
| 488 |  |  |  |  |  |  | report	=> $report, | 
| 489 |  |  |  |  |  |  | ), | 
| 490 |  |  |  |  |  |  | ); | 
| 491 |  |  |  |  |  |  | }, | 
| 492 | 449 |  |  |  |  | 1482 | report	=> $report, | 
| 493 |  |  |  |  |  |  | title	=> $title, | 
| 494 |  |  |  |  |  |  | warner	=> $self->warner(), | 
| 495 |  |  |  |  |  |  | ); | 
| 496 | 449 |  |  |  |  | 1052 | $data->add_formatter_method( values %{ $self->{formatter_method} } ); | 
|  | 449 |  |  |  |  | 2019 |  | 
| 497 |  |  |  |  |  |  | } elsif ( ARRAY_REF eq ref $data ) { | 
| 498 | 45 |  |  |  |  | 148 | $data = [ map { $self->_wrap( data => $_, report => $report ) } @{ $data } ]; | 
|  | 85 |  |  |  |  | 335 |  | 
|  | 45 |  |  |  |  | 162 |  | 
| 499 |  |  |  |  |  |  | } elsif ( embodies( $data, 'Astro::Coord::ECI' ) ) { | 
| 500 | 23 |  |  |  |  | 796 | $data = $self->_wrap( | 
| 501 |  |  |  |  |  |  | data	=> { body => $data }, | 
| 502 |  |  |  |  |  |  | report	=> $report, | 
| 503 |  |  |  |  |  |  | ); | 
| 504 |  |  |  |  |  |  | } | 
| 505 |  |  |  |  |  |  |  | 
| 506 | 517 |  |  |  |  | 2704 | return $data; | 
| 507 |  |  |  |  |  |  | } | 
| 508 |  |  |  |  |  |  |  | 
| 509 |  |  |  |  |  |  | __PACKAGE__->create_attribute_methods(); | 
| 510 |  |  |  |  |  |  |  | 
| 511 |  |  |  |  |  |  | 1; | 
| 512 |  |  |  |  |  |  |  | 
| 513 |  |  |  |  |  |  | __END__ |