| line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
|
1
|
|
|
|
|
|
|
package Geo::Coder::Navteq; |
|
2
|
|
|
|
|
|
|
|
|
3
|
2
|
|
|
2
|
|
139769
|
use strict; |
|
|
2
|
|
|
|
|
6
|
|
|
|
2
|
|
|
|
|
239
|
|
|
4
|
2
|
|
|
2
|
|
13
|
use warnings; |
|
|
2
|
|
|
|
|
5
|
|
|
|
2
|
|
|
|
|
70
|
|
|
5
|
|
|
|
|
|
|
|
|
6
|
2
|
|
|
2
|
|
11
|
use Carp qw(croak); |
|
|
2
|
|
|
|
|
8
|
|
|
|
2
|
|
|
|
|
168
|
|
|
7
|
2
|
|
|
2
|
|
2109
|
use Encode (); |
|
|
2
|
|
|
|
|
68127
|
|
|
|
2
|
|
|
|
|
339
|
|
|
8
|
2
|
|
|
2
|
|
5156
|
use LWP::UserAgent; |
|
|
2
|
|
|
|
|
388291
|
|
|
|
2
|
|
|
|
|
194
|
|
|
9
|
2
|
|
|
2
|
|
29
|
use URI; |
|
|
2
|
|
|
|
|
4
|
|
|
|
2
|
|
|
|
|
54
|
|
|
10
|
2
|
|
|
2
|
|
3847
|
use XML::Simple (); |
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
11
|
|
|
|
|
|
|
|
|
12
|
|
|
|
|
|
|
our $VERSION = '0.03'; |
|
13
|
|
|
|
|
|
|
$VERSION = eval $VERSION; |
|
14
|
|
|
|
|
|
|
|
|
15
|
|
|
|
|
|
|
sub new { |
|
16
|
|
|
|
|
|
|
my ($class, @params) = @_; |
|
17
|
|
|
|
|
|
|
my %params = (@params % 2) ? (appkey => @params) : @params; |
|
18
|
|
|
|
|
|
|
|
|
19
|
|
|
|
|
|
|
croak q('appkey' is required) unless $params{appkey}; |
|
20
|
|
|
|
|
|
|
|
|
21
|
|
|
|
|
|
|
my $self = bless \ %params, $class; |
|
22
|
|
|
|
|
|
|
|
|
23
|
|
|
|
|
|
|
if ($params{ua}) { |
|
24
|
|
|
|
|
|
|
$self->ua($params{ua}); |
|
25
|
|
|
|
|
|
|
} |
|
26
|
|
|
|
|
|
|
else { |
|
27
|
|
|
|
|
|
|
$self->{ua} = LWP::UserAgent->new(agent => "$class/$VERSION"); |
|
28
|
|
|
|
|
|
|
} |
|
29
|
|
|
|
|
|
|
|
|
30
|
|
|
|
|
|
|
if ($self->{debug}) { |
|
31
|
|
|
|
|
|
|
my $dump_sub = sub { $_[0]->dump(maxlength => 0); return }; |
|
32
|
|
|
|
|
|
|
$self->ua->set_my_handler(request_send => $dump_sub); |
|
33
|
|
|
|
|
|
|
$self->ua->set_my_handler(response_done => $dump_sub); |
|
34
|
|
|
|
|
|
|
} |
|
35
|
|
|
|
|
|
|
elsif ($self->{compress}) { |
|
36
|
|
|
|
|
|
|
$self->ua->default_header(accept_encoding => 'gzip,deflate'); |
|
37
|
|
|
|
|
|
|
} |
|
38
|
|
|
|
|
|
|
|
|
39
|
|
|
|
|
|
|
# Each appkey has this url aautomatically added on registration. |
|
40
|
|
|
|
|
|
|
$self->{url} ||= 'http://localhost'; |
|
41
|
|
|
|
|
|
|
|
|
42
|
|
|
|
|
|
|
return $self; |
|
43
|
|
|
|
|
|
|
} |
|
44
|
|
|
|
|
|
|
|
|
45
|
|
|
|
|
|
|
sub response { $_[0]->{response} } |
|
46
|
|
|
|
|
|
|
|
|
47
|
|
|
|
|
|
|
sub ua { |
|
48
|
|
|
|
|
|
|
my ($self, $ua) = @_; |
|
49
|
|
|
|
|
|
|
if ($ua) { |
|
50
|
|
|
|
|
|
|
croak q('ua' must be (or derived from) an LWP::UserAgent') |
|
51
|
|
|
|
|
|
|
unless ref $ua and $ua->isa(q(LWP::UserAgent)); |
|
52
|
|
|
|
|
|
|
$self->{ua} = $ua; |
|
53
|
|
|
|
|
|
|
} |
|
54
|
|
|
|
|
|
|
return $self->{ua}; |
|
55
|
|
|
|
|
|
|
} |
|
56
|
|
|
|
|
|
|
|
|
57
|
|
|
|
|
|
|
sub geocode { |
|
58
|
|
|
|
|
|
|
my ($self, @params) = @_; |
|
59
|
|
|
|
|
|
|
my %params = (@params % 2) ? (location => @params) : @params; |
|
60
|
|
|
|
|
|
|
|
|
61
|
|
|
|
|
|
|
$self->_authenticate or return; |
|
62
|
|
|
|
|
|
|
|
|
63
|
|
|
|
|
|
|
my $location = $params{location} or return; |
|
64
|
|
|
|
|
|
|
$location = Encode::decode('utf-8', $location); |
|
65
|
|
|
|
|
|
|
|
|
66
|
|
|
|
|
|
|
my $uri = URI->new('http:/map24/webservices1.5'); |
|
67
|
|
|
|
|
|
|
$uri->host($self->_hostname); |
|
68
|
|
|
|
|
|
|
$uri->query_form( |
|
69
|
|
|
|
|
|
|
action => 'soap', |
|
70
|
|
|
|
|
|
|
bdom => $self->_bdom($location), |
|
71
|
|
|
|
|
|
|
fromAjax => 1, |
|
72
|
|
|
|
|
|
|
gzip => 1, |
|
73
|
|
|
|
|
|
|
mid => '***', |
|
74
|
|
|
|
|
|
|
request_id => ++$self->{request_id}, |
|
75
|
|
|
|
|
|
|
sid => $self->_session_id, |
|
76
|
|
|
|
|
|
|
writeTypeAttributes => 'false', |
|
77
|
|
|
|
|
|
|
xsltdir => 'ajax/2.3.0.4700/bdom_wb/', |
|
78
|
|
|
|
|
|
|
); |
|
79
|
|
|
|
|
|
|
|
|
80
|
|
|
|
|
|
|
my $res = $self->{response} = $self->ua->get( |
|
81
|
|
|
|
|
|
|
$uri, referer => $self->{url}, |
|
82
|
|
|
|
|
|
|
); |
|
83
|
|
|
|
|
|
|
return unless $res->is_success; |
|
84
|
|
|
|
|
|
|
|
|
85
|
|
|
|
|
|
|
my $xml = $res->decoded_content; |
|
86
|
|
|
|
|
|
|
return unless $xml; |
|
87
|
|
|
|
|
|
|
|
|
88
|
|
|
|
|
|
|
my $data = eval { $self->_parser->xml_in(\$xml) }; |
|
89
|
|
|
|
|
|
|
return unless $data; |
|
90
|
|
|
|
|
|
|
|
|
91
|
|
|
|
|
|
|
my $body = $data->{'soapenv:Body'}; |
|
92
|
|
|
|
|
|
|
|
|
93
|
|
|
|
|
|
|
if (my $err = $body->{'soapenv:Fault'}{faultstring}) { |
|
94
|
|
|
|
|
|
|
if ($err =~ /RequestHeader NOT authenticated/) { |
|
95
|
|
|
|
|
|
|
$self->_authenticate(1); |
|
96
|
|
|
|
|
|
|
return &geocode; |
|
97
|
|
|
|
|
|
|
} |
|
98
|
|
|
|
|
|
|
|
|
99
|
|
|
|
|
|
|
return; |
|
100
|
|
|
|
|
|
|
} |
|
101
|
|
|
|
|
|
|
|
|
102
|
|
|
|
|
|
|
my @results = @{ |
|
103
|
|
|
|
|
|
|
$body->{'tns:searchFreeResponse'}{MapSearchResponse}{Alternatives} |
|
104
|
|
|
|
|
|
|
|| [] |
|
105
|
|
|
|
|
|
|
}; |
|
106
|
|
|
|
|
|
|
if (@results) { |
|
107
|
|
|
|
|
|
|
$#results = 0 unless wantarray; |
|
108
|
|
|
|
|
|
|
|
|
109
|
|
|
|
|
|
|
# Convert from decimal minutes to decimal degrees. |
|
110
|
|
|
|
|
|
|
for my $result (@results) { |
|
111
|
|
|
|
|
|
|
do { $_ /= 60 if defined $_ } for |
|
112
|
|
|
|
|
|
|
@{$result->{Coordinate}}{qw(Latitude Longitude)}, |
|
113
|
|
|
|
|
|
|
@{$result->{PropertiesMinor}}{qw(X0 X1 Y0 Y1)}, |
|
114
|
|
|
|
|
|
|
} |
|
115
|
|
|
|
|
|
|
} |
|
116
|
|
|
|
|
|
|
|
|
117
|
|
|
|
|
|
|
return wantarray ? @results : $results[0]; |
|
118
|
|
|
|
|
|
|
} |
|
119
|
|
|
|
|
|
|
|
|
120
|
|
|
|
|
|
|
sub _authenticate { |
|
121
|
|
|
|
|
|
|
my ($self, $force) = @_; |
|
122
|
|
|
|
|
|
|
|
|
123
|
|
|
|
|
|
|
return 1 if not $force and $self->{auth_time}; |
|
124
|
|
|
|
|
|
|
|
|
125
|
|
|
|
|
|
|
# TODO: determine if there is a standard timeout when sessions need |
|
126
|
|
|
|
|
|
|
# to be reauthed. That would avoid a single doomed geocode request. |
|
127
|
|
|
|
|
|
|
|
|
128
|
|
|
|
|
|
|
my $uri = URI->new('http:/map24/webservices1.5'); |
|
129
|
|
|
|
|
|
|
$uri->host($self->_hostname); |
|
130
|
|
|
|
|
|
|
$uri->query_form( |
|
131
|
|
|
|
|
|
|
action => 'GetMap24Application', |
|
132
|
|
|
|
|
|
|
applicationkey => $self->{appkey}, |
|
133
|
|
|
|
|
|
|
cgi => 'Map24AuthenticationService', |
|
134
|
|
|
|
|
|
|
requestid => ++$self->{request_id}, |
|
135
|
|
|
|
|
|
|
sid => $self->_session_id, |
|
136
|
|
|
|
|
|
|
); |
|
137
|
|
|
|
|
|
|
|
|
138
|
|
|
|
|
|
|
my $res = $self->{response} = $self->ua->get( |
|
139
|
|
|
|
|
|
|
$uri, referer => $self->{url}, |
|
140
|
|
|
|
|
|
|
); |
|
141
|
|
|
|
|
|
|
return unless $res->is_success; |
|
142
|
|
|
|
|
|
|
|
|
143
|
|
|
|
|
|
|
my $xml = $res->decoded_content; |
|
144
|
|
|
|
|
|
|
return unless $xml; |
|
145
|
|
|
|
|
|
|
|
|
146
|
|
|
|
|
|
|
my $data = eval { $self->_parser->xml_in(\$xml) }; |
|
147
|
|
|
|
|
|
|
return unless $data; |
|
148
|
|
|
|
|
|
|
|
|
149
|
|
|
|
|
|
|
return unless $data->{'soapenv:Body'}{'tns:getMap24ApplicationResponse'} |
|
150
|
|
|
|
|
|
|
->{GetMap24ApplicationResponse}; |
|
151
|
|
|
|
|
|
|
|
|
152
|
|
|
|
|
|
|
$self->{auth_time} = time; |
|
153
|
|
|
|
|
|
|
|
|
154
|
|
|
|
|
|
|
return 1; |
|
155
|
|
|
|
|
|
|
} |
|
156
|
|
|
|
|
|
|
|
|
157
|
|
|
|
|
|
|
sub _parser { |
|
158
|
|
|
|
|
|
|
$_[0]->{parser} ||= XML::Simple->new( |
|
159
|
|
|
|
|
|
|
ContentKey => '-Value', |
|
160
|
|
|
|
|
|
|
ForceArray => ['item'], |
|
161
|
|
|
|
|
|
|
GroupTags => { |
|
162
|
|
|
|
|
|
|
Alternatives => 'item', |
|
163
|
|
|
|
|
|
|
PropertiesMajor => 'item', |
|
164
|
|
|
|
|
|
|
PropertiesMinor => 'item', |
|
165
|
|
|
|
|
|
|
}, |
|
166
|
|
|
|
|
|
|
KeyAttr => ['Key'], |
|
167
|
|
|
|
|
|
|
NoAttr => 1, |
|
168
|
|
|
|
|
|
|
); |
|
169
|
|
|
|
|
|
|
} |
|
170
|
|
|
|
|
|
|
|
|
171
|
|
|
|
|
|
|
{ |
|
172
|
|
|
|
|
|
|
my @chars = (0..9, 'a'..'z'); |
|
173
|
|
|
|
|
|
|
sub _hostname { |
|
174
|
|
|
|
|
|
|
my $rnd = join '', map { $chars[rand 36] } (1..8); |
|
175
|
|
|
|
|
|
|
return $rnd . '.tl.maptp50.map24.com'; |
|
176
|
|
|
|
|
|
|
} |
|
177
|
|
|
|
|
|
|
} |
|
178
|
|
|
|
|
|
|
|
|
179
|
|
|
|
|
|
|
sub _session_id { |
|
180
|
|
|
|
|
|
|
return $_[0]->{session_id} ||= 'AJAXSESS_' . time . '123_' . rand; |
|
181
|
|
|
|
|
|
|
} |
|
182
|
|
|
|
|
|
|
|
|
183
|
|
|
|
|
|
|
# The encoding scheme takes a SOAP message and converts it into a binary |
|
184
|
|
|
|
|
|
|
# representation of the resulting DOM. Only the location and session id will |
|
185
|
|
|
|
|
|
|
# vary between messages, so the bulk of the message is pre-encoded. |
|
186
|
|
|
|
|
|
|
sub _bdom { |
|
187
|
|
|
|
|
|
|
my ($self, $location) = @_; |
|
188
|
|
|
|
|
|
|
return '.74fsearchFree.7n_basicZ75Ltns.0WsearchFreeZ78vurn.0W' |
|
189
|
|
|
|
|
|
|
. 'Map24Geocoder51Z7D_.0G.0G.0GZ' |
|
190
|
|
|
|
|
|
|
. _encode_string($self->_session_id) . 'Z' |
|
191
|
|
|
|
|
|
|
. _encode_string($location) . 'XgzWgAgBWgCgDWgEgFXgJXgMWgGgNWgHgIX' |
|
192
|
|
|
|
|
|
|
. 'gLXgaVgOUXgbVgPUUXg0Xg1VD4fUXg8VgQUUUUU'; |
|
193
|
|
|
|
|
|
|
} |
|
194
|
|
|
|
|
|
|
|
|
195
|
|
|
|
|
|
|
{ |
|
196
|
|
|
|
|
|
|
my @encode_table = (0..9, 'a'..'z', 'A'..'Z', qw(. _)); |
|
197
|
|
|
|
|
|
|
my %decode_table = do { my $i = 0; map { $_ => $i++ } @encode_table }; |
|
198
|
|
|
|
|
|
|
|
|
199
|
|
|
|
|
|
|
sub _encode_string { |
|
200
|
|
|
|
|
|
|
my ($str) = @_; |
|
201
|
|
|
|
|
|
|
|
|
202
|
|
|
|
|
|
|
return 0 unless defined $str; |
|
203
|
|
|
|
|
|
|
|
|
204
|
|
|
|
|
|
|
$str=~ s{ ([^0-9A-Za-z]) }{ |
|
205
|
|
|
|
|
|
|
my $ord = ord $1; |
|
206
|
|
|
|
|
|
|
if (4096 > $ord) { |
|
207
|
|
|
|
|
|
|
join '', '.', @encode_table[$ord >> 6, $ord & 63]; |
|
208
|
|
|
|
|
|
|
} |
|
209
|
|
|
|
|
|
|
else { |
|
210
|
|
|
|
|
|
|
join '', '_', @encode_table[ |
|
211
|
|
|
|
|
|
|
$ord >> 24, $ord >> 18 & 63, $ord >> 12 & 63, |
|
212
|
|
|
|
|
|
|
$ord >> 16 & 63, $ord & 63 |
|
213
|
|
|
|
|
|
|
]; |
|
214
|
|
|
|
|
|
|
} |
|
215
|
|
|
|
|
|
|
}egx; |
|
216
|
|
|
|
|
|
|
|
|
217
|
|
|
|
|
|
|
my $prefix = _encode_number(length $str); |
|
218
|
|
|
|
|
|
|
|
|
219
|
|
|
|
|
|
|
return $encode_table[ $decode_table{ substr($prefix, 0, 1) } & 15] |
|
220
|
|
|
|
|
|
|
. substr($prefix, 1) . $str; |
|
221
|
|
|
|
|
|
|
} |
|
222
|
|
|
|
|
|
|
|
|
223
|
|
|
|
|
|
|
sub _encode_number { |
|
224
|
|
|
|
|
|
|
my ($num) = @_; |
|
225
|
|
|
|
|
|
|
return $encode_table[32] unless $num; |
|
226
|
|
|
|
|
|
|
|
|
227
|
|
|
|
|
|
|
my $len = length($num); |
|
228
|
|
|
|
|
|
|
my $chunks = int(($len - 1) / 3) + 2; |
|
229
|
|
|
|
|
|
|
my @s = ('D'); |
|
230
|
|
|
|
|
|
|
my $end = 0; |
|
231
|
|
|
|
|
|
|
|
|
232
|
|
|
|
|
|
|
for my $chunk (0 .. $chunks - 1) { |
|
233
|
|
|
|
|
|
|
my $i = $chunk * 3; |
|
234
|
|
|
|
|
|
|
my @c = (0, 0, 0); |
|
235
|
|
|
|
|
|
|
|
|
236
|
|
|
|
|
|
|
for my $j (0 .. 2) { |
|
237
|
|
|
|
|
|
|
if ($i >= $len) { |
|
238
|
|
|
|
|
|
|
$c[$j] = 15; |
|
239
|
|
|
|
|
|
|
$end = 1; |
|
240
|
|
|
|
|
|
|
} |
|
241
|
|
|
|
|
|
|
else { |
|
242
|
|
|
|
|
|
|
$c[$j] = ord(substr $num, $i, 1) - 48; |
|
243
|
|
|
|
|
|
|
$c[$j] = 0 if $c[$j] < 0 or $c[$j] > 9; |
|
244
|
|
|
|
|
|
|
} |
|
245
|
|
|
|
|
|
|
|
|
246
|
|
|
|
|
|
|
$i++ |
|
247
|
|
|
|
|
|
|
} |
|
248
|
|
|
|
|
|
|
my $val = $c[0] << 8 | $c[1] << 4 | $c[2]; |
|
249
|
|
|
|
|
|
|
push @s, @encode_table[$val >> 6, $val & 63]; |
|
250
|
|
|
|
|
|
|
|
|
251
|
|
|
|
|
|
|
last if $end; |
|
252
|
|
|
|
|
|
|
} |
|
253
|
|
|
|
|
|
|
unless ($end) { |
|
254
|
|
|
|
|
|
|
$s[-1] = $encode_table[ $decode_table{$s[-1]} | 15 ]; |
|
255
|
|
|
|
|
|
|
} |
|
256
|
|
|
|
|
|
|
|
|
257
|
|
|
|
|
|
|
return join '', @s; |
|
258
|
|
|
|
|
|
|
} |
|
259
|
|
|
|
|
|
|
} |
|
260
|
|
|
|
|
|
|
|
|
261
|
|
|
|
|
|
|
|
|
262
|
|
|
|
|
|
|
1; |
|
263
|
|
|
|
|
|
|
|
|
264
|
|
|
|
|
|
|
__END__ |