| line | stmt | bran | cond | sub | pod | time | code | 
| 1 |  |  |  |  |  |  | package Astro::App::Satpass2::Format::Template; | 
| 2 |  |  |  |  |  |  |  | 
| 3 | 8 |  |  | 8 |  | 1636 | use strict; | 
|  | 8 |  |  |  |  | 18 |  | 
|  | 8 |  |  |  |  | 255 |  | 
| 4 | 8 |  |  | 8 |  | 40 | use warnings; | 
|  | 8 |  |  |  |  | 22 |  | 
|  | 8 |  |  |  |  | 244 |  | 
| 5 |  |  |  |  |  |  |  | 
| 6 | 8 |  |  | 8 |  | 47 | use parent qw{ Astro::App::Satpass2::Format }; | 
|  | 8 |  |  |  |  | 22 |  | 
|  | 8 |  |  |  |  | 63 |  | 
| 7 |  |  |  |  |  |  |  | 
| 8 | 8 |  |  | 8 |  | 596 | use Astro::App::Satpass2::Locale qw{ __localize }; | 
|  | 8 |  |  |  |  | 18 |  | 
|  | 8 |  |  |  |  | 462 |  | 
| 9 |  |  |  |  |  |  | # use Astro::App::Satpass2::FormatValue; | 
| 10 | 8 |  |  | 8 |  | 3649 | use Astro::App::Satpass2::FormatValue::Formatter; | 
|  | 8 |  |  |  |  | 37 |  | 
|  | 8 |  |  |  |  | 287 |  | 
| 11 | 8 |  |  |  |  | 859 | use Astro::App::Satpass2::Utils qw{ | 
| 12 |  |  |  |  |  |  | instance | 
| 13 |  |  |  |  |  |  | ARRAY_REF | 
| 14 |  |  |  |  |  |  | HASH_REF | 
| 15 |  |  |  |  |  |  | SCALAR_REF | 
| 16 |  |  |  |  |  |  | @CARP_NOT | 
| 17 | 8 |  |  | 8 |  | 95 | }; | 
|  | 8 |  |  |  |  | 30 |  | 
| 18 | 8 |  |  | 8 |  | 3788 | use Astro::App::Satpass2::Wrap::Array; | 
|  | 8 |  |  |  |  | 33 |  | 
|  | 8 |  |  |  |  | 339 |  | 
| 19 | 8 |  |  | 8 |  | 72 | use Astro::Coord::ECI::TLE 0.059 qw{ :constants }; | 
|  | 8 |  |  |  |  | 132 |  | 
|  | 8 |  |  |  |  | 1444 |  | 
| 20 | 8 |  |  |  |  | 528 | use Astro::Coord::ECI::Utils 0.059 qw{ | 
| 21 |  |  |  |  |  |  | deg2rad embodies julianday PI rad2deg TWOPI | 
| 22 | 8 |  |  | 8 |  | 76 | }; | 
|  | 8 |  |  |  |  | 123 |  | 
| 23 | 8 |  |  | 8 |  | 55 | use Clone qw{ }; | 
|  | 8 |  |  |  |  | 22 |  | 
|  | 8 |  |  |  |  | 201 |  | 
| 24 | 8 |  |  | 8 |  | 46 | use POSIX qw{ floor }; | 
|  | 8 |  |  |  |  | 37 |  | 
|  | 8 |  |  |  |  | 82 |  | 
| 25 | 8 |  |  | 8 |  | 5227 | use Template; | 
|  | 8 |  |  |  |  | 161086 |  | 
|  | 8 |  |  |  |  | 283 |  | 
| 26 | 8 |  |  | 8 |  | 68 | use Template::Provider; | 
|  | 8 |  |  |  |  | 24 |  | 
|  | 8 |  |  |  |  | 158 |  | 
| 27 | 8 |  |  | 8 |  | 718 | use Text::Abbrev; | 
|  | 8 |  |  |  |  | 71 |  | 
|  | 8 |  |  |  |  | 438 |  | 
| 28 | 8 |  |  | 8 |  | 73 | use Text::Wrap qw{ wrap }; | 
|  | 8 |  |  |  |  | 34 |  | 
|  | 8 |  |  |  |  | 556 |  | 
| 29 |  |  |  |  |  |  |  | 
| 30 |  |  |  |  |  |  | our $VERSION = '0.052'; | 
| 31 |  |  |  |  |  |  |  | 
| 32 | 8 |  |  | 8 |  | 67 | use constant FORMAT_VALUE	=> 'Astro::App::Satpass2::FormatValue'; | 
|  | 8 |  |  |  |  | 24 |  | 
|  | 8 |  |  |  |  | 19744 |  | 
| 33 |  |  |  |  |  |  |  | 
| 34 |  |  |  |  |  |  | sub new { | 
| 35 | 9 |  |  | 9 | 1 | 3923 | my ($class, @args) = @_; | 
| 36 | 9 |  |  |  |  | 61 | 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 |  |  |  |  | 29 | $self->{canned_template} = {}; | 
| 41 |  |  |  |  |  |  |  | 
| 42 | 9 |  |  |  |  | 58 | $self->_new_tt( $self->permissive() ); | 
| 43 |  |  |  |  |  |  |  | 
| 44 | 9 |  |  |  |  | 43 | $self->{default} = {}; | 
| 45 | 9 |  |  |  |  | 49 | $self->{formatter_method} = {}; | 
| 46 |  |  |  |  |  |  |  | 
| 47 | 9 |  |  |  |  | 64 | return $self; | 
| 48 |  |  |  |  |  |  | } | 
| 49 |  |  |  |  |  |  |  | 
| 50 |  |  |  |  |  |  | sub _new_tt { | 
| 51 | 10 |  |  | 10 |  | 48 | my ( $self, $permissive ) = @_; | 
| 52 |  |  |  |  |  |  |  | 
| 53 | 10 | 50 |  |  |  | 102 | $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 |  |  |  |  | 194771 | 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 | 10 | my ( $self, @arg ) = @_; | 
| 74 | 1 | 50 |  |  |  | 5 | my $fmtr = HASH_REF eq ref $arg[0] ? $arg[0] : $arg[1]; | 
| 75 | 1 | 50 |  |  |  | 7 | 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 |  |  |  | 7 | or $self->wail( | 
| 80 |  |  |  |  |  |  | 'Formatter definition must have {name} defined' ); | 
| 81 |  |  |  |  |  |  | $self->{formatter_method}{$fmtr_name} | 
| 82 |  |  |  |  |  |  | and $self->{warner}->wail( | 
| 83 | 1 | 50 |  |  |  | 5 | "Formatter method $fmtr_name already exists" ); | 
| 84 |  |  |  |  |  |  | FORMAT_VALUE->can( $fmtr_name ) | 
| 85 |  |  |  |  |  |  | and $self->{warner}->wail( | 
| 86 | 1 | 50 |  |  |  | 17 | "Formatter $fmtr_name can not override built-in formatter" ); | 
| 87 | 1 |  |  |  |  | 10 | $self->{formatter_method}{$fmtr_name} = | 
| 88 |  |  |  |  |  |  | Astro::App::Satpass2::FormatValue::Formatter->new( $fmtr ); | 
| 89 | 1 |  |  |  |  | 5 | return $self; | 
| 90 |  |  |  |  |  |  | } | 
| 91 |  |  |  |  |  |  |  | 
| 92 |  |  |  |  |  |  | sub attribute_names { | 
| 93 | 17 |  |  | 17 | 1 | 41 | my ( $self ) = @_; | 
| 94 | 17 |  |  |  |  | 102 | 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 |  | 73 | my ( $self ) = @_; | 
| 121 | 72 |  |  |  |  | 101 | return ( _uniq( map { keys %{ $_ } } $self->{canned_template}, | 
|  | 72 |  |  |  |  | 549 |  | 
| 122 | 24 |  |  |  |  | 148 | __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 | 19 | my ( $self, $method, @args ) = @_; | 
| 152 | 7 | 50 |  |  |  | 43 | 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 |  | 576 | my ( $self, @arg ) = @_; | 
| 160 | 302 | 50 |  |  |  | 1333 | @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 | 4834 | 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 |  |  |  | 531 | ); | 
| 182 |  |  |  |  |  |  |  | 
| 183 | 62 | 100 |  |  |  | 348 | _is_format() and return $data{data}; | 
| 184 |  |  |  |  |  |  |  | 
| 185 |  |  |  |  |  |  | my $tplt = delete $data{template} | 
| 186 | 61 | 50 |  |  |  | 260 | or $self->wail( 'template argument is required' ); | 
| 187 |  |  |  |  |  |  |  | 
| 188 | 61 | 100 |  |  |  | 270 | my $tplt_name = SCALAR_REF eq ref $tplt ? ${ $tplt } : $tplt; | 
|  | 1 |  |  |  |  | 3 |  | 
| 189 |  |  |  |  |  |  |  | 
| 190 | 61 |  | 33 |  |  | 386 | $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 |  |  |  |  | 486 | }; | 
| 197 |  |  |  |  |  |  |  | 
| 198 | 61 |  | 33 |  |  | 419 | $data{provider} ||= $self->provider(); | 
| 199 |  |  |  |  |  |  |  | 
| 200 | 61 | 50 |  |  |  | 298 | 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 |  |  |  |  | 353 | $data{time} = $self->_wrap( | 
| 208 |  |  |  |  |  |  | data	=> { time => time }, | 
| 209 |  |  |  |  |  |  | report	=> $tplt_name, | 
| 210 |  |  |  |  |  |  | ); | 
| 211 |  |  |  |  |  |  | } | 
| 212 |  |  |  |  |  |  |  | 
| 213 | 61 |  |  |  |  | 468 | my $value_formatter = $self->value_formatter(); | 
| 214 |  |  |  |  |  |  |  | 
| 215 |  |  |  |  |  |  | $data{title} = $self->_wrap( | 
| 216 |  |  |  |  |  |  | default	=> $data{default}, | 
| 217 | 61 |  |  |  |  | 346 | report	=> $tplt_name, | 
| 218 |  |  |  |  |  |  | ); | 
| 219 |  |  |  |  |  |  | $data{TITLE_GRAVITY_BOTTOM} = | 
| 220 | 61 |  |  |  |  | 511 | $value_formatter->TITLE_GRAVITY_BOTTOM; | 
| 221 |  |  |  |  |  |  | $data{TITLE_GRAVITY_TOP} = | 
| 222 | 61 |  |  |  |  | 260 | $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 |  |  |  |  | 572 | }; | 
| 228 |  |  |  |  |  |  |  | 
| 229 |  |  |  |  |  |  | local $Template::Stash::LIST_OPS->{events} = sub { | 
| 230 | 3 |  |  | 3 |  | 72 | my @args = @_; | 
| 231 | 3 |  |  |  |  | 15 | $DB::single = 1; | 
| 232 | 3 |  |  |  |  | 21 | return $self->_all_events( $args[0] ); | 
| 233 | 61 |  |  |  |  | 449 | }; | 
| 234 |  |  |  |  |  |  |  | 
| 235 |  |  |  |  |  |  | local $Template::Stash::LIST_OPS->{fixed_width} = sub { | 
| 236 | 2 |  |  | 2 |  | 8 | my ( $list, $value ) = @_; | 
| 237 | 2 |  |  |  |  | 6 | foreach my $item ( @{ $list } ) { | 
|  | 2 |  |  |  |  | 6 |  | 
| 238 | 10 | 50 |  |  |  | 32 | my $code = $item->can( 'fixed_width' ) | 
| 239 |  |  |  |  |  |  | or next; | 
| 240 | 10 |  |  |  |  | 26 | $code->( $item, $value ); | 
| 241 |  |  |  |  |  |  | } | 
| 242 | 2 |  |  |  |  | 11 | return; | 
| 243 | 61 |  |  |  |  | 384 | }; | 
| 244 |  |  |  |  |  |  |  | 
| 245 |  |  |  |  |  |  | local $Template::Stash::LIST_OPS->{first_tle} = sub { | 
| 246 | 29 |  |  | 29 |  | 144 | my ( $list ) = @_; | 
| 247 | 29 |  |  |  |  | 108 | $DB::single = 1; | 
| 248 | 29 |  |  |  |  | 73 | foreach my $item ( @{ $list } ) { | 
|  | 29 |  |  |  |  | 102 |  | 
| 249 | 29 | 50 |  |  |  | 112 | embodies( $item->body(), 'Astro::Coord::ECI::TLE' ) | 
| 250 |  |  |  |  |  |  | and return $item; | 
| 251 |  |  |  |  |  |  | } | 
| 252 | 0 |  |  |  |  | 0 | return; | 
| 253 | 61 |  |  |  |  | 392 | }; | 
| 254 |  |  |  |  |  |  |  | 
| 255 |  |  |  |  |  |  | $data{localize} = sub { | 
| 256 | 28 |  |  | 28 |  | 79805 | return _localize( $tplt_name, @_ ); | 
| 257 | 61 |  |  |  |  | 368 | }; | 
| 258 |  |  |  |  |  |  |  | 
| 259 |  |  |  |  |  |  | # NOTE - must come after $data{localize} because | 
| 260 |  |  |  |  |  |  | # $data{format_detail} uses $data{localize} | 
| 261 |  |  |  |  |  |  | $data{format_detail} = sub { | 
| 262 | 173 |  |  | 173 |  | 8283 | my ( $kind, $evt ) = @_; | 
| 263 |  |  |  |  |  |  |  | 
| 264 | 173 | 50 |  |  |  | 575 | instance( $evt, FORMAT_VALUE ) | 
| 265 |  |  |  |  |  |  | or return; | 
| 266 | 173 | 50 |  |  |  | 686 | defined ( my $type = $evt->$kind( width => '' ) ) | 
| 267 |  |  |  |  |  |  | or return; | 
| 268 | 173 |  |  |  |  | 595 | $type =~ s/ \s+ \z //smx; | 
| 269 |  |  |  |  |  |  |  | 
| 270 | 173 |  |  |  |  | 550 | foreach my $name ( "$kind:$type", $kind ) { | 
| 271 | 329 | 100 |  |  |  | 1147 | defined ( my $tplt = $self->template( "$tplt:$name" ) ) | 
| 272 |  |  |  |  |  |  | or next; | 
| 273 |  |  |  |  |  |  | my $output = $self->_process( \$tplt, | 
| 274 |  |  |  |  |  |  | evt		=> $evt, | 
| 275 |  |  |  |  |  |  | localize	=> $data{localize}, | 
| 276 |  |  |  |  |  |  | sp		=> $data{sp}, | 
| 277 | 173 |  |  |  |  | 807 | ); | 
| 278 |  |  |  |  |  |  |  | 
| 279 | 173 |  |  |  |  | 560 | chomp $output; | 
| 280 | 173 |  |  |  |  | 1057 | return $output; | 
| 281 |  |  |  |  |  |  | } | 
| 282 | 0 |  |  |  |  | 0 | return __localize( | 
| 283 |  |  |  |  |  |  | text	=> [ '+template', "$tplt:$kind" ], | 
| 284 |  |  |  |  |  |  | ); | 
| 285 | 61 |  |  |  |  | 425 | }; | 
| 286 |  |  |  |  |  |  |  | 
| 287 | 61 |  |  |  |  | 504 | my $output = $self->_process( $tplt, %data ); | 
| 288 |  |  |  |  |  |  |  | 
| 289 |  |  |  |  |  |  | # TODO would love to use \h here, but that needs 5.10. | 
| 290 | 60 |  |  |  |  | 1365 | $output =~ s/ [ \t]+ (?= \n ) //sxmg; | 
| 291 |  |  |  |  |  |  | $data{title}->title_gravity() eq $data{TITLE_GRAVITY_BOTTOM} | 
| 292 | 60 | 100 |  |  |  | 442 | and $output =~ s/ \A \n //smx; | 
| 293 |  |  |  |  |  |  |  | 
| 294 | 60 |  |  |  |  | 1744 | return $output; | 
| 295 |  |  |  |  |  |  | } | 
| 296 |  |  |  |  |  |  |  | 
| 297 |  |  |  |  |  |  | sub gmt { | 
| 298 | 57 |  |  | 57 | 1 | 206 | my ( $self, @args ) = @_; | 
| 299 | 57 | 100 |  |  |  | 200 | if ( @args ) { | 
| 300 | 3 |  |  |  |  | 15 | $self->time_formatter()->gmt( @args ); | 
| 301 | 3 |  |  |  |  | 22 | return $self->SUPER::gmt( @args ); | 
| 302 |  |  |  |  |  |  | } else { | 
| 303 | 54 |  |  |  |  | 243 | return $self->SUPER::gmt(); | 
| 304 |  |  |  |  |  |  | } | 
| 305 |  |  |  |  |  |  | } | 
| 306 |  |  |  |  |  |  |  | 
| 307 |  |  |  |  |  |  | sub local_coord { | 
| 308 | 207 |  |  | 207 | 1 | 438 | my ( $self, @args ) = @_; | 
| 309 | 207 | 100 |  |  |  | 545 | if ( @args ) { | 
| 310 | 12 |  |  |  |  | 43 | my $val = $args[0]; | 
| 311 | 12 | 100 |  |  |  | 116 | defined $val | 
| 312 |  |  |  |  |  |  | or $val = $self->DEFAULT_LOCAL_COORD; | 
| 313 |  |  |  |  |  |  |  | 
| 314 | 12 | 50 |  |  |  | 70 | defined $self->template( $val ) | 
| 315 |  |  |  |  |  |  | or $self->wail( | 
| 316 |  |  |  |  |  |  | 'Unknown local coordinate specification', $val ); | 
| 317 |  |  |  |  |  |  |  | 
| 318 | 12 |  |  |  |  | 72 | return $self->SUPER::local_coord( @args ); | 
| 319 |  |  |  |  |  |  | } else { | 
| 320 | 195 |  |  |  |  | 746 | return $self->SUPER::local_coord(); | 
| 321 |  |  |  |  |  |  | } | 
| 322 |  |  |  |  |  |  | } | 
| 323 |  |  |  |  |  |  |  | 
| 324 |  |  |  |  |  |  | sub permissive { | 
| 325 | 10 |  |  | 10 | 1 | 887 | my ( $self, @args ) = @_; | 
| 326 | 10 | 100 |  |  |  | 37 | if ( @args ) { | 
| 327 | 1 | 50 | 25 |  |  | 10 | if ( $self->{permissive} xor $args[0] ) { | 
| 328 | 1 |  |  |  |  | 9 | $self->_new_tt( $args[0] ); | 
| 329 |  |  |  |  |  |  | } | 
| 330 | 1 |  |  |  |  | 4 | $self->{permissive} = $args[0]; | 
| 331 | 1 |  |  |  |  | 4 | return $self; | 
| 332 |  |  |  |  |  |  | } else { | 
| 333 | 9 |  |  |  |  | 53 | return $self->{permissive}; | 
| 334 |  |  |  |  |  |  | } | 
| 335 |  |  |  |  |  |  | } | 
| 336 |  |  |  |  |  |  |  | 
| 337 |  |  |  |  |  |  | sub template { | 
| 338 | 620 |  |  | 620 | 1 | 1295 | my ( $self, $name, @value ) = @_; | 
| 339 | 620 | 50 |  |  |  | 1485 | defined $name | 
| 340 |  |  |  |  |  |  | or $self->wail( 'Template name not specified' ); | 
| 341 |  |  |  |  |  |  |  | 
| 342 | 620 | 100 |  |  |  | 1294 | if ( @value ) { | 
| 343 | 3 |  |  |  |  | 6 | my $tplt_text; | 
| 344 | 3 | 50 | 33 |  |  | 731 | if ( ! defined $value[0] | 
|  |  |  | 33 |  |  |  |  | 
| 345 |  |  |  |  |  |  | || defined( $tplt_text = __localize( | 
| 346 |  |  |  |  |  |  | text	=> '+template', | 
| 347 |  |  |  |  |  |  | default	=> $value[0] ) | 
| 348 |  |  |  |  |  |  | ) | 
| 349 |  |  |  |  |  |  | && $value[0] eq $tplt_text | 
| 350 |  |  |  |  |  |  | ) { | 
| 351 | 0 |  |  |  |  | 0 | delete $self->{canned_template}{$name}; | 
| 352 |  |  |  |  |  |  | } else { | 
| 353 | 3 |  |  |  |  | 20 | $self->{canned_template}{$name} = $value[0]; | 
| 354 |  |  |  |  |  |  | } | 
| 355 |  |  |  |  |  |  |  | 
| 356 | 3 |  |  |  |  | 12 | return $self; | 
| 357 |  |  |  |  |  |  | } else { | 
| 358 |  |  |  |  |  |  | defined $self->{canned_template}{$name} | 
| 359 | 617 | 100 |  |  |  | 1542 | and return $self->{canned_template}{$name}; | 
| 360 | 613 |  |  |  |  | 2224 | return __localize( | 
| 361 |  |  |  |  |  |  | text	=> [ '+template', $name ], | 
| 362 |  |  |  |  |  |  | ); | 
| 363 |  |  |  |  |  |  | } | 
| 364 |  |  |  |  |  |  | } | 
| 365 |  |  |  |  |  |  |  | 
| 366 |  |  |  |  |  |  | sub tz { | 
| 367 | 16 |  |  | 16 | 1 | 67 | my ( $self, @args ) = @_; | 
| 368 | 16 | 50 |  |  |  | 44 | if ( @args ) { | 
| 369 | 16 |  |  |  |  | 88 | my $tf = $self->time_formatter(); | 
| 370 |  |  |  |  |  |  | # We go through the following because the time formatter may | 
| 371 |  |  |  |  |  |  | # modify the zone (e.g. if it's using DateTime, zones are | 
| 372 |  |  |  |  |  |  | # case-sensitive so we may have done case conversion before | 
| 373 |  |  |  |  |  |  | # storing). We want this object to have the time formatter's | 
| 374 |  |  |  |  |  |  | # version of the zone. | 
| 375 | 16 |  |  |  |  | 177 | $tf->tz( @args ); | 
| 376 | 16 |  |  |  |  | 46 | return $self->SUPER::tz( $tf->tz() ); | 
| 377 |  |  |  |  |  |  | } else { | 
| 378 | 0 |  |  |  |  | 0 | return $self->SUPER::tz(); | 
| 379 |  |  |  |  |  |  | } | 
| 380 |  |  |  |  |  |  | } | 
| 381 |  |  |  |  |  |  |  | 
| 382 |  |  |  |  |  |  | sub _all_events { | 
| 383 | 3 |  |  | 3 |  | 13 | my ( $self, $data ) = @_; | 
| 384 | 3 | 50 |  |  |  | 16 | ARRAY_REF eq ref $data or return; | 
| 385 |  |  |  |  |  |  |  | 
| 386 | 3 |  |  |  |  | 8 | my @events; | 
| 387 | 3 |  |  |  |  | 10 | foreach my $pass ( @{ $data } ) { | 
|  | 3 |  |  |  |  | 12 |  | 
| 388 | 3 |  |  |  |  | 20 | push @events, $pass->__raw_events(); | 
| 389 |  |  |  |  |  |  | } | 
| 390 | 3 | 50 |  |  |  | 19 | @events or return; | 
| 391 | 3 |  |  |  |  | 25 | @events = sort { $a->{time} <=> $b->{time} } @events; | 
|  | 16 |  |  |  |  | 46 |  | 
| 392 |  |  |  |  |  |  |  | 
| 393 | 3 |  |  |  |  | 12 | return [ map { $self->_wrap( data => $_ ) } @events ]; | 
|  | 13 |  |  |  |  | 39 |  | 
| 394 |  |  |  |  |  |  | } | 
| 395 |  |  |  |  |  |  |  | 
| 396 |  |  |  |  |  |  | #	_is_format() | 
| 397 |  |  |  |  |  |  | # | 
| 398 |  |  |  |  |  |  | #	Returns true if the format() method is above us on the call | 
| 399 |  |  |  |  |  |  | #	stack, otherwise returns false. | 
| 400 |  |  |  |  |  |  |  | 
| 401 | 8 |  |  | 8 |  | 72 | use constant REPORT_CALLER => __PACKAGE__ . '::format'; | 
|  | 8 |  |  |  |  | 21 |  | 
|  | 8 |  |  |  |  | 6537 |  | 
| 402 |  |  |  |  |  |  | sub _is_format { | 
| 403 | 62 |  |  | 62 |  | 180 | my $level = 2;	# Start with caller's caller. | 
| 404 | 62 |  |  |  |  | 797 | while ( my @info = caller( $level ) ) { | 
| 405 | 261 | 100 |  |  |  | 654 | REPORT_CALLER eq $info[3] | 
| 406 |  |  |  |  |  |  | and return $level; | 
| 407 | 260 |  |  |  |  | 1691 | $level++; | 
| 408 |  |  |  |  |  |  | } | 
| 409 | 61 |  |  |  |  | 338 | return; | 
| 410 |  |  |  |  |  |  | } | 
| 411 |  |  |  |  |  |  |  | 
| 412 |  |  |  |  |  |  | sub _localize { | 
| 413 | 28 |  |  | 28 |  | 90 | my ( $report, $source, $default ) = @_; | 
| 414 | 28 | 50 |  |  |  | 81 | defined $default | 
| 415 |  |  |  |  |  |  | or $default = $source; | 
| 416 | 28 | 0 |  |  |  | 78 | defined $report | 
|  |  | 50 |  |  |  |  |  | 
| 417 |  |  |  |  |  |  | or return defined $source ? $source : $default; | 
| 418 |  |  |  |  |  |  |  | 
| 419 | 28 |  |  |  |  | 123 | return scalar __localize( | 
| 420 |  |  |  |  |  |  | text	=> [ "-$report", 'string', $source ], | 
| 421 |  |  |  |  |  |  | default	=> $source, | 
| 422 |  |  |  |  |  |  | ); | 
| 423 |  |  |  |  |  |  | } | 
| 424 |  |  |  |  |  |  |  | 
| 425 |  |  |  |  |  |  | sub _process { | 
| 426 | 449 |  |  | 449 |  | 1947 | my ( $self, $tplt, %arg ) = @_; | 
| 427 |  |  |  |  |  |  | ARRAY_REF eq ref $arg{arg} | 
| 428 |  |  |  |  |  |  | and $arg{arg} = Astro::App::Satpass2::Wrap::Array->new( | 
| 429 | 449 | 100 |  |  |  | 2144 | $arg{arg} ); | 
| 430 | 449 |  |  |  |  | 693 | my $output; | 
| 431 | 449 |  |  |  |  | 919 | my $tt = $self->{tt}; | 
| 432 |  |  |  |  |  |  |  | 
| 433 | 449 |  |  |  |  | 616 | my $tplt_text; | 
| 434 | 449 | 100 | 100 |  |  | 1668 | not ref $tplt | 
| 435 |  |  |  |  |  |  | and defined( $tplt_text = $self->template( $tplt ) ) | 
| 436 |  |  |  |  |  |  | and $tplt = \$tplt_text; | 
| 437 |  |  |  |  |  |  |  | 
| 438 | 449 | 100 |  |  |  | 1861 | $tt->process( $tplt, \%arg, \$output ) | 
| 439 |  |  |  |  |  |  | or $self->wail( $tt->error() ); | 
| 440 | 448 |  |  |  |  | 113106 | return $output; | 
| 441 |  |  |  |  |  |  | } | 
| 442 |  |  |  |  |  |  |  | 
| 443 |  |  |  |  |  |  | # Cribbed shamelessly from List::MoreUtils. The author reserves the | 
| 444 |  |  |  |  |  |  | # right to relocate, rename or otherwise mung with this without notice | 
| 445 |  |  |  |  |  |  | # to anyone. Caveat user. | 
| 446 |  |  |  |  |  |  | sub _uniq { | 
| 447 | 25 |  |  | 25 |  | 87 | my %found; | 
| 448 | 25 |  |  |  |  | 82 | return ( grep { ! $found{$_}++ } @_ ); | 
|  | 679 |  |  |  |  | 1586 |  | 
| 449 |  |  |  |  |  |  | } | 
| 450 |  |  |  |  |  |  |  | 
| 451 |  |  |  |  |  |  | sub _wrap { | 
| 452 | 517 |  |  | 517 |  | 1924 | my ( $self, %arg ) = @_; | 
| 453 |  |  |  |  |  |  |  | 
| 454 | 517 |  |  |  |  | 1068 | my $data = $arg{data}; | 
| 455 | 517 |  |  |  |  | 898 | my $default = $arg{default}; | 
| 456 | 517 |  |  |  |  | 942 | my $report = $arg{report}; | 
| 457 |  |  |  |  |  |  |  | 
| 458 | 517 |  |  |  |  | 1042 | my $title = ! $data; | 
| 459 | 517 |  | 100 |  |  | 2109 | $data ||= {}; | 
| 460 | 517 |  | 66 |  |  | 1563 | $default ||= $self->__default(); | 
| 461 |  |  |  |  |  |  |  | 
| 462 | 517 | 50 | 66 |  |  | 1604 | if ( instance( $data, FORMAT_VALUE ) ) { | 
|  |  | 100 |  |  |  |  |  | 
|  |  | 100 |  |  |  |  |  | 
|  |  | 50 |  |  |  |  |  | 
| 463 |  |  |  |  |  |  | # Do nothing | 
| 464 |  |  |  |  |  |  | } elsif ( ! defined $data || HASH_REF eq ref $data ) { | 
| 465 | 449 |  |  |  |  | 1808 | my $value_formatter = $self->value_formatter(); | 
| 466 |  |  |  |  |  |  | $data = $value_formatter->new( | 
| 467 |  |  |  |  |  |  | data	=> $data, | 
| 468 |  |  |  |  |  |  | default	=> $default, | 
| 469 |  |  |  |  |  |  | date_format => $self->date_format(), | 
| 470 |  |  |  |  |  |  | desired_equinox_dynamical => | 
| 471 |  |  |  |  |  |  | $self->desired_equinox_dynamical(), | 
| 472 |  |  |  |  |  |  | provider	=> $self->provider(), | 
| 473 |  |  |  |  |  |  | round_time	=> $self->round_time(), | 
| 474 |  |  |  |  |  |  | time_format => $self->time_format(), | 
| 475 |  |  |  |  |  |  | time_formatter => $self->time_formatter(), | 
| 476 |  |  |  |  |  |  | local_coordinates => sub { | 
| 477 | 195 |  |  | 195 |  | 449 | my ( $data, @arg ) = @_; | 
| 478 |  |  |  |  |  |  | return $self->_process( $self->local_coord(), | 
| 479 |  |  |  |  |  |  | data	=> $data, | 
| 480 |  |  |  |  |  |  | arg		=> \@arg, | 
| 481 |  |  |  |  |  |  | title	=> $self->_wrap( | 
| 482 |  |  |  |  |  |  | default	=> $default, | 
| 483 |  |  |  |  |  |  | report	=> $report, | 
| 484 |  |  |  |  |  |  | ), | 
| 485 |  |  |  |  |  |  | localize	=> sub { | 
| 486 | 0 |  |  |  |  | 0 | return _localize( $report, @_ ); | 
| 487 |  |  |  |  |  |  | }, | 
| 488 | 195 |  |  |  |  | 619 | ); | 
| 489 |  |  |  |  |  |  | }, | 
| 490 |  |  |  |  |  |  | list_formatter => sub { | 
| 491 | 20 |  |  | 20 |  | 57 | my ( $data, @arg ) = @_; | 
| 492 | 20 |  |  |  |  | 74 | my $body = $data->body(); | 
| 493 | 20 | 100 |  |  |  | 403 | my $list_type = $body ? $body->__list_type() : 'inertial'; | 
| 494 | 20 |  |  |  |  | 167 | return $self->_process( "list_$list_type", | 
| 495 |  |  |  |  |  |  | data	=> $data, | 
| 496 |  |  |  |  |  |  | arg		=> \@arg, | 
| 497 |  |  |  |  |  |  | title	=> $self->_wrap( | 
| 498 |  |  |  |  |  |  | default => $default, | 
| 499 |  |  |  |  |  |  | report	=> $report, | 
| 500 |  |  |  |  |  |  | ), | 
| 501 |  |  |  |  |  |  | ); | 
| 502 |  |  |  |  |  |  | }, | 
| 503 | 449 |  |  |  |  | 1526 | report	=> $report, | 
| 504 |  |  |  |  |  |  | title	=> $title, | 
| 505 |  |  |  |  |  |  | warner	=> $self->warner(), | 
| 506 |  |  |  |  |  |  | ); | 
| 507 | 449 |  |  |  |  | 1114 | $data->add_formatter_method( values %{ $self->{formatter_method} } ); | 
|  | 449 |  |  |  |  | 1952 |  | 
| 508 |  |  |  |  |  |  | } elsif ( ARRAY_REF eq ref $data ) { | 
| 509 | 45 |  |  |  |  | 116 | $data = [ map { $self->_wrap( data => $_, report => $report ) } @{ $data } ]; | 
|  | 85 |  |  |  |  | 288 |  | 
|  | 45 |  |  |  |  | 146 |  | 
| 510 |  |  |  |  |  |  | } elsif ( embodies( $data, 'Astro::Coord::ECI' ) ) { | 
| 511 | 23 |  |  |  |  | 773 | $data = $self->_wrap( | 
| 512 |  |  |  |  |  |  | data	=> { body => $data }, | 
| 513 |  |  |  |  |  |  | report	=> $report, | 
| 514 |  |  |  |  |  |  | ); | 
| 515 |  |  |  |  |  |  | } | 
| 516 |  |  |  |  |  |  |  | 
| 517 | 517 |  |  |  |  | 2442 | return $data; | 
| 518 |  |  |  |  |  |  | } | 
| 519 |  |  |  |  |  |  |  | 
| 520 |  |  |  |  |  |  | __PACKAGE__->create_attribute_methods(); | 
| 521 |  |  |  |  |  |  |  | 
| 522 |  |  |  |  |  |  | 1; | 
| 523 |  |  |  |  |  |  |  | 
| 524 |  |  |  |  |  |  | __END__ |