| line | stmt | bran | cond | sub | pod | time | code | 
| 1 |  |  |  |  |  |  | package Travel::Status::DE::URA; | 
| 2 |  |  |  |  |  |  |  | 
| 3 | 5 |  |  | 5 |  | 86703 | use strict; | 
|  | 5 |  |  |  |  | 6 |  | 
|  | 5 |  |  |  |  | 111 |  | 
| 4 | 5 |  |  | 5 |  | 15 | use warnings; | 
|  | 5 |  |  |  |  | 5 |  | 
|  | 5 |  |  |  |  | 83 |  | 
| 5 | 5 |  |  | 5 |  | 66 | use 5.010; | 
|  | 5 |  |  |  |  | 8 |  | 
| 6 | 5 |  |  | 5 |  | 15 | use utf8; | 
|  | 5 |  |  |  |  | 5 |  | 
|  | 5 |  |  |  |  | 18 |  | 
| 7 |  |  |  |  |  |  |  | 
| 8 | 5 |  |  | 5 |  | 2572 | no if $] >= 5.018, warnings => 'experimental::smartmatch'; | 
|  | 5 |  |  |  |  | 35 |  | 
|  | 5 |  |  |  |  | 20 |  | 
| 9 |  |  |  |  |  |  |  | 
| 10 |  |  |  |  |  |  | our $VERSION = '2.00'; | 
| 11 |  |  |  |  |  |  |  | 
| 12 |  |  |  |  |  |  | # create CONSTANTS for different Return Types | 
| 13 |  |  |  |  |  |  | use constant { | 
| 14 | 5 |  |  |  |  | 1031 | TYPE_STOP       => 0, | 
| 15 |  |  |  |  |  |  | TYPE_PREDICTION => 1, | 
| 16 |  |  |  |  |  |  | TYPE_MESSAGE    => 2, | 
| 17 |  |  |  |  |  |  | TYPE_BASE       => 3, | 
| 18 |  |  |  |  |  |  | TYPE_URA        => 4, | 
| 19 | 5 |  |  | 5 |  | 376 | }; | 
|  | 5 |  |  |  |  | 5 |  | 
| 20 |  |  |  |  |  |  |  | 
| 21 | 5 |  |  | 5 |  | 17 | use Carp qw(confess cluck); | 
|  | 5 |  |  |  |  | 3 |  | 
|  | 5 |  |  |  |  | 238 |  | 
| 22 | 5 |  |  | 5 |  | 3530 | use DateTime; | 
|  | 5 |  |  |  |  | 423967 |  | 
|  | 5 |  |  |  |  | 171 |  | 
| 23 | 5 |  |  | 5 |  | 1396 | use Encode qw(encode decode); | 
|  | 5 |  |  |  |  | 20244 |  | 
|  | 5 |  |  |  |  | 279 |  | 
| 24 | 5 |  |  | 5 |  | 2230 | use List::MoreUtils qw(firstval none uniq); | 
|  | 5 |  |  |  |  | 32634 |  | 
|  | 5 |  |  |  |  | 20 |  | 
| 25 | 5 |  |  | 5 |  | 4934 | use LWP::UserAgent; | 
|  | 5 |  |  |  |  | 140319 |  | 
|  | 5 |  |  |  |  | 121 |  | 
| 26 | 5 |  |  | 5 |  | 2257 | use Text::CSV; | 
|  | 5 |  |  |  |  | 35557 |  | 
|  | 5 |  |  |  |  | 22 |  | 
| 27 | 5 |  |  | 5 |  | 2045 | use Travel::Status::DE::URA::Result; | 
|  | 5 |  |  |  |  | 10 |  | 
|  | 5 |  |  |  |  | 22 |  | 
| 28 | 5 |  |  | 5 |  | 1830 | use Travel::Status::DE::URA::Stop; | 
|  | 5 |  |  |  |  | 9 |  | 
|  | 5 |  |  |  |  | 18 |  | 
| 29 |  |  |  |  |  |  |  | 
| 30 |  |  |  |  |  |  | sub new { | 
| 31 | 13 |  |  | 13 | 1 | 223487 | my ( $class, %opt ) = @_; | 
| 32 |  |  |  |  |  |  |  | 
| 33 | 13 |  | 50 |  |  | 15 | my %lwp_options = %{ $opt{lwp_options} // { timeout => 10 } }; | 
|  | 13 |  |  |  |  | 111 |  | 
| 34 |  |  |  |  |  |  |  | 
| 35 | 13 |  |  |  |  | 94 | my $ua = LWP::UserAgent->new(%lwp_options); | 
| 36 | 13 |  |  |  |  | 10715 | my $response; | 
| 37 |  |  |  |  |  |  |  | 
| 38 | 13 | 100 | 66 |  |  | 80 | if ( not( $opt{ura_base} and $opt{ura_version} ) ) { | 
| 39 | 3 |  |  |  |  | 550 | confess('ura_base and ura_version are mandatory'); | 
| 40 |  |  |  |  |  |  | } | 
| 41 |  |  |  |  |  |  |  | 
| 42 |  |  |  |  |  |  | my $self = { | 
| 43 |  |  |  |  |  |  | datetime => $opt{datetime} | 
| 44 |  |  |  |  |  |  | // DateTime->now( time_zone => 'Europe/Berlin' ), | 
| 45 |  |  |  |  |  |  | developer_mode => $opt{developer_mode}, | 
| 46 |  |  |  |  |  |  | ura_base       => $opt{ura_base}, | 
| 47 |  |  |  |  |  |  | ura_version    => $opt{ura_version}, | 
| 48 |  |  |  |  |  |  | full_routes    => $opt{calculate_routes} // 0, | 
| 49 |  |  |  |  |  |  | hide_past      => $opt{hide_past} // 1, | 
| 50 |  |  |  |  |  |  | stop           => $opt{stop}, | 
| 51 |  |  |  |  |  |  | via            => $opt{via}, | 
| 52 |  |  |  |  |  |  | via_id         => $opt{via_id}, | 
| 53 |  |  |  |  |  |  | stop_id        => $opt{stop_id}, | 
| 54 |  |  |  |  |  |  | line_id        => $opt{line_id}, | 
| 55 |  |  |  |  |  |  | circle         => $opt{circle}, | 
| 56 | 10 |  | 66 |  |  | 65 | post           => { | 
|  |  |  | 100 |  |  |  |  | 
|  |  |  | 100 |  |  |  |  | 
| 57 |  |  |  |  |  |  | StopAlso => 'False', | 
| 58 |  |  |  |  |  |  |  | 
| 59 |  |  |  |  |  |  | # for easier debugging ordered in the returned order | 
| 60 |  |  |  |  |  |  | ReturnList => 'stoppointname,stopid,stoppointindicator,' | 
| 61 |  |  |  |  |  |  | . 'latitude,longitude,lineid,linename,' | 
| 62 |  |  |  |  |  |  | . 'directionid,destinationtext,vehicleid,tripid,estimatedtime' | 
| 63 |  |  |  |  |  |  | }, | 
| 64 |  |  |  |  |  |  | }; | 
| 65 |  |  |  |  |  |  |  | 
| 66 | 10 | 50 |  |  |  | 17946 | if ( $opt{with_stops} ) { | 
| 67 | 0 |  |  |  |  | 0 | $self->{post}{StopAlso} = 'True'; | 
| 68 |  |  |  |  |  |  | } | 
| 69 |  |  |  |  |  |  |  | 
| 70 |  |  |  |  |  |  | $self->{ura_instant_url} | 
| 71 | 10 |  |  |  |  | 33 | = $self->{ura_base} . '/instant_V' . $self->{ura_version}; | 
| 72 |  |  |  |  |  |  |  | 
| 73 | 10 |  |  |  |  | 22 | bless( $self, $class ); | 
| 74 |  |  |  |  |  |  |  | 
| 75 | 10 |  |  |  |  | 35 | $ua->env_proxy; | 
| 76 |  |  |  |  |  |  |  | 
| 77 | 10 | 50 |  |  |  | 13825 | if ( substr( $self->{ura_instant_url}, 0, 5 ) ne 'file:' ) { | 
| 78 |  |  |  |  |  |  |  | 
| 79 |  |  |  |  |  |  | # filter by stop_id only if full_routes is not set | 
| 80 | 0 | 0 | 0 |  |  | 0 | if ( not $self->{full_routes} and $self->{stop_id} ) { | 
| 81 | 0 |  |  |  |  | 0 | $self->{post}{StopID} = $self->{stop_id}; | 
| 82 |  |  |  |  |  |  |  | 
| 83 |  |  |  |  |  |  | # filter for via as well to make via work | 
| 84 | 0 | 0 |  |  |  | 0 | if ( defined $self->{via_id} ) { | 
| 85 | 0 |  |  |  |  | 0 | $self->{post}{StopID} .= q{,} . $self->{via_id}; | 
| 86 |  |  |  |  |  |  | } | 
| 87 |  |  |  |  |  |  | } | 
| 88 |  |  |  |  |  |  |  | 
| 89 |  |  |  |  |  |  | # filter by line | 
| 90 | 0 | 0 |  |  |  | 0 | if ( $self->{line_id} ) { | 
| 91 | 0 |  |  |  |  | 0 | $self->{post}{LineID} = $self->{line_id}; | 
| 92 |  |  |  |  |  |  | } | 
| 93 |  |  |  |  |  |  |  | 
| 94 |  |  |  |  |  |  | # filter for Stops in circle (lon,lat,dist) | 
| 95 | 0 | 0 |  |  |  | 0 | if ( $self->{circle} ) { | 
| 96 | 0 |  |  |  |  | 0 | $self->{post}{Circle} = $self->{circle}; | 
| 97 |  |  |  |  |  |  | } | 
| 98 |  |  |  |  |  |  |  | 
| 99 | 0 |  |  |  |  | 0 | $response = $ua->post( $self->{ura_instant_url}, $self->{post} ); | 
| 100 |  |  |  |  |  |  | } | 
| 101 |  |  |  |  |  |  | else { | 
| 102 | 10 |  |  |  |  | 39 | $response = $ua->get( $self->{ura_instant_url} ); | 
| 103 |  |  |  |  |  |  | } | 
| 104 |  |  |  |  |  |  |  | 
| 105 | 10 | 100 |  |  |  | 209813 | if ( $response->is_error ) { | 
| 106 | 1 |  |  |  |  | 9 | $self->{errstr} = $response->status_line; | 
| 107 | 1 |  |  |  |  | 20 | return $self; | 
| 108 |  |  |  |  |  |  | } | 
| 109 |  |  |  |  |  |  |  | 
| 110 | 9 |  |  |  |  | 119 | my $raw_str = $response->decoded_content; | 
| 111 |  |  |  |  |  |  |  | 
| 112 | 9 | 50 |  |  |  | 543171 | if ( $self->{developer_mode} ) { | 
| 113 | 0 |  |  |  |  | 0 | say decode( 'UTF-8', $raw_str ); | 
| 114 |  |  |  |  |  |  | } | 
| 115 |  |  |  |  |  |  |  | 
| 116 |  |  |  |  |  |  | # Fix encoding in case we're running through test files | 
| 117 | 9 | 50 |  |  |  | 56 | if ( substr( $self->{ura_instant_url}, 0, 5 ) eq 'file:' ) { | 
| 118 | 9 |  |  |  |  | 39 | $raw_str = encode( 'UTF-8', $raw_str ); | 
| 119 |  |  |  |  |  |  | } | 
| 120 | 9 |  |  |  |  | 270306 | $self->parse_raw_data($raw_str); | 
| 121 |  |  |  |  |  |  |  | 
| 122 | 9 |  |  |  |  | 21988 | return $self; | 
| 123 |  |  |  |  |  |  | } | 
| 124 |  |  |  |  |  |  |  | 
| 125 |  |  |  |  |  |  | sub parse_raw_data { | 
| 126 | 9 |  |  | 9 | 0 | 26 | my ( $self, $raw_str ) = @_; | 
| 127 | 9 |  |  |  |  | 139 | my $csv = Text::CSV->new( { binary => 1 } ); | 
| 128 |  |  |  |  |  |  |  | 
| 129 | 9 |  |  |  |  | 51735 | for my $dep ( split( /\r\n/, $raw_str ) ) { | 
| 130 | 155673 |  |  |  |  | 413503 | $dep =~ s{^\[}{}; | 
| 131 | 155673 |  |  |  |  | 289460 | $dep =~ s{\]$}{}; | 
| 132 |  |  |  |  |  |  |  | 
| 133 | 155673 |  |  |  |  | 275513 | $csv->parse($dep); | 
| 134 | 155673 |  |  |  |  | 44540197 | my @fields = $csv->fields; | 
| 135 |  |  |  |  |  |  |  | 
| 136 |  |  |  |  |  |  | # encode all fields | 
| 137 | 155673 |  |  |  |  | 950109 | for my $i ( 1, 11 ) { | 
| 138 | 311346 |  |  |  |  | 3479971 | $fields[$i] = encode( 'UTF-8', $fields[$i] ); | 
| 139 |  |  |  |  |  |  | } | 
| 140 |  |  |  |  |  |  |  | 
| 141 | 155673 |  |  |  |  | 2393929 | push( @{ $self->{raw_list} }, \@fields ); | 
|  | 155673 |  |  |  |  | 216056 |  | 
| 142 |  |  |  |  |  |  |  | 
| 143 | 155673 |  |  |  |  | 131232 | my $type = $fields[0]; | 
| 144 |  |  |  |  |  |  |  | 
| 145 | 155673 | 100 |  |  |  | 304972 | if ( $type == TYPE_STOP ) { | 
| 146 | 9891 |  |  |  |  | 7278 | my $stop_name = $fields[1]; | 
| 147 | 9891 |  |  |  |  | 6239 | my $stop_id   = $fields[2]; | 
| 148 | 9891 |  |  |  |  | 6921 | my $longitude = $fields[3]; | 
| 149 | 9891 |  |  |  |  | 6188 | my $latitude  = $fields[4]; | 
| 150 |  |  |  |  |  |  |  | 
| 151 |  |  |  |  |  |  | # create Stop Dict | 
| 152 | 9891 | 50 |  |  |  | 17187 | if ( not exists $self->{stops}{$stop_id} ) { | 
| 153 | 9891 |  |  |  |  | 14534 | $self->{stops}{$stop_id} = Travel::Status::DE::URA::Stop->new( | 
| 154 |  |  |  |  |  |  | name      => decode( 'UTF-8', $stop_name ), | 
| 155 |  |  |  |  |  |  | id        => $stop_id, | 
| 156 |  |  |  |  |  |  | longitude => $longitude, | 
| 157 |  |  |  |  |  |  | latitude  => $latitude, | 
| 158 |  |  |  |  |  |  | ); | 
| 159 |  |  |  |  |  |  | } | 
| 160 |  |  |  |  |  |  | } | 
| 161 | 155673 | 100 |  |  |  | 208157 | if ( $type == TYPE_PREDICTION ) { | 
| 162 | 145773 |  |  |  |  | 102176 | push( @{ $self->{stop_names} }, $fields[1] ); | 
|  | 145773 |  |  |  |  | 235912 |  | 
| 163 |  |  |  |  |  |  | } | 
| 164 |  |  |  |  |  |  | } | 
| 165 |  |  |  |  |  |  |  | 
| 166 | 9 |  |  |  |  | 27757 | @{ $self->{stop_names} } = uniq @{ $self->{stop_names} }; | 
|  | 9 |  |  |  |  | 16178 |  | 
|  | 9 |  |  |  |  | 53568 |  | 
| 167 |  |  |  |  |  |  |  | 
| 168 | 9 |  |  |  |  | 1745 | return $self; | 
| 169 |  |  |  |  |  |  | } | 
| 170 |  |  |  |  |  |  |  | 
| 171 |  |  |  |  |  |  | sub get_stop_by_name { | 
| 172 | 3 |  |  | 3 | 1 | 1153 | my ( $self, $name ) = @_; | 
| 173 |  |  |  |  |  |  |  | 
| 174 | 3 |  |  |  |  | 7 | my $nname = lc($name); | 
| 175 | 3 |  |  | 1098 |  | 12 | my $actual_match = firstval { $nname eq lc($_) } @{ $self->{stop_names} }; | 
|  | 1098 |  |  |  |  | 678 |  | 
|  | 3 |  |  |  |  | 43 |  | 
| 176 |  |  |  |  |  |  |  | 
| 177 | 3 | 100 |  |  |  | 13 | if ($actual_match) { | 
| 178 | 2 |  |  |  |  | 7 | return $actual_match; | 
| 179 |  |  |  |  |  |  | } | 
| 180 |  |  |  |  |  |  |  | 
| 181 | 1 |  |  |  |  | 1 | return ( grep { $_ =~ m{$name}i } @{ $self->{stop_names} } ); | 
|  | 901 |  |  |  |  | 952 |  | 
|  | 1 |  |  |  |  | 5 |  | 
| 182 |  |  |  |  |  |  | } | 
| 183 |  |  |  |  |  |  |  | 
| 184 |  |  |  |  |  |  | sub get_stops { | 
| 185 | 0 |  |  | 0 | 1 | 0 | my ($self) = @_; | 
| 186 |  |  |  |  |  |  |  | 
| 187 | 0 |  |  |  |  | 0 | return $self->{stops}; | 
| 188 |  |  |  |  |  |  | } | 
| 189 |  |  |  |  |  |  |  | 
| 190 |  |  |  |  |  |  | sub errstr { | 
| 191 | 2 |  |  | 2 | 1 | 1646 | my ($self) = @_; | 
| 192 |  |  |  |  |  |  |  | 
| 193 | 2 |  |  |  |  | 12 | return $self->{errstr}; | 
| 194 |  |  |  |  |  |  | } | 
| 195 |  |  |  |  |  |  |  | 
| 196 |  |  |  |  |  |  | sub results { | 
| 197 | 12 |  |  | 12 | 1 | 68141 | my ( $self, %opt ) = @_; | 
| 198 | 12 |  |  |  |  | 25 | my @results; | 
| 199 |  |  |  |  |  |  |  | 
| 200 | 12 |  | 66 |  |  | 117 | my $full_routes = $opt{calculate_routes} // $self->{full_routes} // 0; | 
|  |  |  | 50 |  |  |  |  | 
| 201 | 12 |  | 66 |  |  | 73 | my $hide_past   = $opt{hide_past}        // $self->{hide_past}   // 1; | 
|  |  |  | 50 |  |  |  |  | 
| 202 | 12 |  | 33 |  |  | 152 | my $line_id     = $opt{line_id}          // $self->{line_id}; | 
| 203 | 12 |  | 66 |  |  | 161 | my $stop        = $opt{stop}             // $self->{stop}; | 
| 204 | 12 |  | 33 |  |  | 51 | my $stop_id     = $opt{stop_id}          // $self->{stop_id}; | 
| 205 | 12 |  | 66 |  |  | 39 | my $via         = $opt{via}              // $self->{via}; | 
| 206 | 12 |  | 33 |  |  | 39 | my $via_id      = $opt{via_id}           // $self->{via_id}; | 
| 207 |  |  |  |  |  |  |  | 
| 208 | 12 |  |  |  |  | 20 | my $dt_now = $self->{datetime}; | 
| 209 | 12 |  |  |  |  | 83 | my $ts_now = $dt_now->epoch; | 
| 210 |  |  |  |  |  |  |  | 
| 211 | 12 | 100 | 66 |  |  | 257 | if ( $via or $via_id ) { | 
| 212 | 2 |  |  |  |  | 4 | $full_routes = 1; | 
| 213 |  |  |  |  |  |  | } | 
| 214 |  |  |  |  |  |  |  | 
| 215 | 12 |  |  |  |  | 20 | for my $dep ( @{ $self->{raw_list} } ) { | 
|  | 12 |  |  |  |  | 52 |  | 
| 216 |  |  |  |  |  |  |  | 
| 217 |  |  |  |  |  |  | my ( | 
| 218 |  |  |  |  |  |  | $type,        $stopname, $stopid,    $stopindicator, | 
| 219 |  |  |  |  |  |  | $longitude,   $latitude, $lineid,    $linename, | 
| 220 |  |  |  |  |  |  | $directionid, $dest,     $vehicleid, $tripid, | 
| 221 |  |  |  |  |  |  | $timestamp | 
| 222 | 190267 |  |  |  |  | 115018 | ) = @{$dep}; | 
|  | 190267 |  |  |  |  | 597267 |  | 
| 223 | 190267 |  |  |  |  | 169392 | my ( @route_pre, @route_post ); | 
| 224 |  |  |  |  |  |  |  | 
| 225 |  |  |  |  |  |  | # only work on Prediction informations | 
| 226 | 190267 | 100 |  |  |  | 239622 | if ( $type != TYPE_PREDICTION ) { | 
| 227 | 12100 |  |  |  |  | 10570 | next; | 
| 228 |  |  |  |  |  |  | } | 
| 229 |  |  |  |  |  |  |  | 
| 230 | 178167 | 50 | 33 |  |  | 234035 | if ( $line_id and not( $lineid eq $line_id ) ) { | 
| 231 | 0 |  |  |  |  | 0 | next; | 
| 232 |  |  |  |  |  |  | } | 
| 233 |  |  |  |  |  |  |  | 
| 234 | 178167 | 100 | 100 |  |  | 357800 | if ( $stop and not( $stopname eq $stop ) ) { | 
| 235 | 111872 |  |  |  |  | 107927 | next; | 
| 236 |  |  |  |  |  |  | } | 
| 237 |  |  |  |  |  |  |  | 
| 238 | 66295 | 50 | 33 |  |  | 94356 | if ( $stop_id and not( $stopid eq $stop_id ) ) { | 
| 239 | 0 |  |  |  |  | 0 | next; | 
| 240 |  |  |  |  |  |  | } | 
| 241 |  |  |  |  |  |  |  | 
| 242 | 66295 | 50 |  |  |  | 80606 | if ( not $timestamp ) { | 
| 243 | 0 |  |  |  |  | 0 | cluck("departure element without timestamp: $dep"); | 
| 244 | 0 |  |  |  |  | 0 | next; | 
| 245 |  |  |  |  |  |  | } | 
| 246 |  |  |  |  |  |  |  | 
| 247 | 66295 |  |  |  |  | 55315 | $timestamp /= 1000; | 
| 248 |  |  |  |  |  |  |  | 
| 249 | 66295 | 100 | 66 |  |  | 135916 | if ( $hide_past and $ts_now > $timestamp ) { | 
| 250 | 32394 |  |  |  |  | 30180 | next; | 
| 251 |  |  |  |  |  |  | } | 
| 252 |  |  |  |  |  |  |  | 
| 253 | 33901 |  |  |  |  | 78791 | my $dt_dep = DateTime->from_epoch( | 
| 254 |  |  |  |  |  |  | epoch     => $timestamp, | 
| 255 |  |  |  |  |  |  | time_zone => 'Europe/Berlin' | 
| 256 |  |  |  |  |  |  | ); | 
| 257 | 33901 |  |  |  |  | 10771736 | my $ts_dep = $dt_dep->epoch; | 
| 258 |  |  |  |  |  |  |  | 
| 259 | 33901 | 100 |  |  |  | 179809 | if ($full_routes) { | 
| 260 |  |  |  |  |  |  | my @route | 
| 261 | 22577 |  |  |  |  | 77498 | = map { [ $_->[12] / 1000, $_->[1], $_->[2], $_->[4], $_->[5] ] } | 
| 262 | 12261129 |  |  |  |  | 11662508 | grep { $_->[11] == $tripid } | 
| 263 | 757 |  |  |  |  | 1364 | grep { $_->[0] == 1 } @{ $self->{raw_list} }; | 
|  | 13093829 |  |  |  |  | 12422907 |  | 
|  | 757 |  |  |  |  | 24638 |  | 
| 264 |  |  |  |  |  |  |  | 
| 265 | 757 |  |  |  |  | 2306 | @route_pre  = grep { $_->[0] < $ts_dep } @route; | 
|  | 22577 |  |  |  |  | 23712 |  | 
| 266 | 757 |  |  |  |  | 1704 | @route_post = grep { $_->[0] > $ts_dep } @route; | 
|  | 22577 |  |  |  |  | 18769 |  | 
| 267 |  |  |  |  |  |  |  | 
| 268 | 757 | 100 | 100 |  |  | 14010 | if ( $via | 
| 269 | 10790 |  |  | 10790 |  | 9520 | and none { $_->[1] eq $via } @route_post ) | 
| 270 |  |  |  |  |  |  | { | 
| 271 | 740 |  |  |  |  | 18423 | next; | 
| 272 |  |  |  |  |  |  | } | 
| 273 |  |  |  |  |  |  |  | 
| 274 | 17 | 50 | 33 |  |  | 103 | if ( $via_id | 
| 275 | 0 |  |  | 0 |  | 0 | and none { $_->[2] eq $via_id } @route_post ) | 
| 276 |  |  |  |  |  |  | { | 
| 277 | 0 |  |  |  |  | 0 | next; | 
| 278 |  |  |  |  |  |  | } | 
| 279 |  |  |  |  |  |  |  | 
| 280 | 17 | 50 |  |  |  | 64 | if ($hide_past) { | 
| 281 | 0 |  |  |  |  | 0 | @route_pre = grep { $_->[0] >= $ts_now } @route_pre; | 
|  | 0 |  |  |  |  | 0 |  | 
| 282 |  |  |  |  |  |  | } | 
| 283 |  |  |  |  |  |  |  | 
| 284 | 207 |  |  |  |  | 205 | @route_pre = map { $_->[0] } | 
| 285 | 553 |  |  |  |  | 413 | sort { $a->[1] <=> $b->[1] } | 
| 286 | 17 |  |  |  |  | 47 | map { [ $_, $_->[0] ] } @route_pre; | 
|  | 207 |  |  |  |  | 408 |  | 
| 287 | 497 |  |  |  |  | 433 | @route_post = map { $_->[0] } | 
| 288 | 1960 |  |  |  |  | 1270 | sort { $a->[1] <=> $b->[1] } | 
| 289 | 17 |  |  |  |  | 67 | map { [ $_, $_->[0] ] } @route_post; | 
|  | 497 |  |  |  |  | 616 |  | 
| 290 |  |  |  |  |  |  |  | 
| 291 |  |  |  |  |  |  | @route_pre = map { | 
| 292 | 17 |  |  |  |  | 91 | Travel::Status::DE::URA::Stop->new( | 
|  | 207 |  |  |  |  | 717 |  | 
| 293 |  |  |  |  |  |  | datetime => DateTime->from_epoch( | 
| 294 |  |  |  |  |  |  | epoch     => $_->[0], | 
| 295 |  |  |  |  |  |  | time_zone => 'Europe/Berlin' | 
| 296 |  |  |  |  |  |  | ), | 
| 297 |  |  |  |  |  |  | name      => decode( 'UTF-8', $_->[1] ), | 
| 298 |  |  |  |  |  |  | id        => $_->[2], | 
| 299 |  |  |  |  |  |  | longitude => $_->[3], | 
| 300 |  |  |  |  |  |  | latitude  => $_->[4], | 
| 301 |  |  |  |  |  |  | ) | 
| 302 |  |  |  |  |  |  | } @route_pre; | 
| 303 |  |  |  |  |  |  | @route_post = map { | 
| 304 | 17 |  |  |  |  | 52 | Travel::Status::DE::URA::Stop->new( | 
|  | 497 |  |  |  |  | 1294 |  | 
| 305 |  |  |  |  |  |  | datetime => DateTime->from_epoch( | 
| 306 |  |  |  |  |  |  | epoch     => $_->[0], | 
| 307 |  |  |  |  |  |  | time_zone => 'Europe/Berlin' | 
| 308 |  |  |  |  |  |  | ), | 
| 309 |  |  |  |  |  |  | name      => decode( 'UTF-8', $_->[1] ), | 
| 310 |  |  |  |  |  |  | id        => $_->[2], | 
| 311 |  |  |  |  |  |  | longitude => $_->[3], | 
| 312 |  |  |  |  |  |  | latitude  => $_->[4], | 
| 313 |  |  |  |  |  |  | ) | 
| 314 |  |  |  |  |  |  | } @route_post; | 
| 315 |  |  |  |  |  |  | } | 
| 316 |  |  |  |  |  |  |  | 
| 317 |  |  |  |  |  |  | push( | 
| 318 | 33161 |  |  |  |  | 111303 | @results, | 
| 319 |  |  |  |  |  |  | Travel::Status::DE::URA::Result->new( | 
| 320 |  |  |  |  |  |  | datetime       => $dt_dep, | 
| 321 |  |  |  |  |  |  | dt_now         => $dt_now, | 
| 322 |  |  |  |  |  |  | line           => $linename, | 
| 323 |  |  |  |  |  |  | line_id        => $lineid, | 
| 324 |  |  |  |  |  |  | destination    => $dest, | 
| 325 |  |  |  |  |  |  | route_pre      => [@route_pre], | 
| 326 |  |  |  |  |  |  | route_post     => [@route_post], | 
| 327 |  |  |  |  |  |  | stop           => $stopname, | 
| 328 |  |  |  |  |  |  | stop_id        => $stopid, | 
| 329 |  |  |  |  |  |  | stop_indicator => $stopindicator, | 
| 330 |  |  |  |  |  |  | ) | 
| 331 |  |  |  |  |  |  | ); | 
| 332 |  |  |  |  |  |  | } | 
| 333 |  |  |  |  |  |  |  | 
| 334 | 33161 |  |  |  |  | 40700 | @results = map { $_->[0] } | 
| 335 | 397196 |  |  |  |  | 253317 | sort { $a->[1] <=> $b->[1] } | 
| 336 | 12 |  |  |  |  | 171 | map { [ $_, $_->datetime->epoch ] } @results; | 
|  | 33161 |  |  |  |  | 233842 |  | 
| 337 |  |  |  |  |  |  |  | 
| 338 | 12 |  |  |  |  | 99682 | return @results; | 
| 339 |  |  |  |  |  |  | } | 
| 340 |  |  |  |  |  |  |  | 
| 341 |  |  |  |  |  |  | # static | 
| 342 |  |  |  |  |  |  | sub get_services { | 
| 343 |  |  |  |  |  |  | return ( | 
| 344 |  |  |  |  |  |  | { | 
| 345 | 0 |  |  | 0 | 0 |  | ura_base    => 'http://ivu.aseag.de/interfaces/ura', | 
| 346 |  |  |  |  |  |  | ura_version => 1, | 
| 347 |  |  |  |  |  |  | name        => 'Aachener Straßenbahn und Energieversorgungs AG', | 
| 348 |  |  |  |  |  |  | shortname   => 'ASEAG', | 
| 349 |  |  |  |  |  |  | }, | 
| 350 |  |  |  |  |  |  | { | 
| 351 |  |  |  |  |  |  | ura_base    => 'http://countdown.api.tfl.gov.uk/interfaces/ura', | 
| 352 |  |  |  |  |  |  | ura_version => 1, | 
| 353 |  |  |  |  |  |  | name        => 'Transport for London', | 
| 354 |  |  |  |  |  |  | shortname   => 'TfL', | 
| 355 |  |  |  |  |  |  | } | 
| 356 |  |  |  |  |  |  | ); | 
| 357 |  |  |  |  |  |  | } | 
| 358 |  |  |  |  |  |  |  | 
| 359 |  |  |  |  |  |  | 1; | 
| 360 |  |  |  |  |  |  |  | 
| 361 |  |  |  |  |  |  | __END__ |