line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
5
|
|
|
5
|
|
68252
|
use strict; |
|
5
|
|
|
|
|
29
|
|
|
5
|
|
|
|
|
147
|
|
2
|
5
|
|
|
5
|
|
24
|
use warnings; |
|
5
|
|
|
|
|
9
|
|
|
5
|
|
|
|
|
139
|
|
3
|
|
|
|
|
|
|
|
4
|
5
|
|
|
5
|
|
114
|
use 5.006; |
|
5
|
|
|
|
|
13
|
|
5
|
|
|
|
|
|
|
|
6
|
|
|
|
|
|
|
package HTTP::BrowserDetect; |
7
|
|
|
|
|
|
|
|
8
|
|
|
|
|
|
|
our $VERSION = '3.37'; |
9
|
|
|
|
|
|
|
|
10
|
|
|
|
|
|
|
# Operating Systems |
11
|
|
|
|
|
|
|
our @OS_TESTS = qw( |
12
|
|
|
|
|
|
|
windows mac os2 |
13
|
|
|
|
|
|
|
unix linux vms |
14
|
|
|
|
|
|
|
bsd amiga brew |
15
|
|
|
|
|
|
|
bb10 rimtabletos |
16
|
|
|
|
|
|
|
chromeos ios |
17
|
|
|
|
|
|
|
firefoxos |
18
|
|
|
|
|
|
|
); |
19
|
|
|
|
|
|
|
|
20
|
|
|
|
|
|
|
# More precise Windows |
21
|
|
|
|
|
|
|
our @WINDOWS_TESTS = qw( |
22
|
|
|
|
|
|
|
win16 win3x win31 |
23
|
|
|
|
|
|
|
win95 win98 winnt |
24
|
|
|
|
|
|
|
winme win32 win2k |
25
|
|
|
|
|
|
|
winxp win2k3 winvista |
26
|
|
|
|
|
|
|
win7 win8 win8_0 |
27
|
|
|
|
|
|
|
win8_1 win10 win10_0 |
28
|
|
|
|
|
|
|
wince winphone winphone7 |
29
|
|
|
|
|
|
|
winphone7_5 winphone8 winphone8_1 |
30
|
|
|
|
|
|
|
winphone10 |
31
|
|
|
|
|
|
|
); |
32
|
|
|
|
|
|
|
|
33
|
|
|
|
|
|
|
# More precise Mac |
34
|
|
|
|
|
|
|
our @MAC_TESTS = qw( |
35
|
|
|
|
|
|
|
macosx mac68k macppc |
36
|
|
|
|
|
|
|
); |
37
|
|
|
|
|
|
|
|
38
|
|
|
|
|
|
|
# More precise Unix |
39
|
|
|
|
|
|
|
our @UNIX_TESTS = qw( |
40
|
|
|
|
|
|
|
sun sun4 sun5 |
41
|
|
|
|
|
|
|
suni86 irix irix5 |
42
|
|
|
|
|
|
|
irix6 hpux hpux9 |
43
|
|
|
|
|
|
|
hpux10 aix aix1 |
44
|
|
|
|
|
|
|
aix2 aix3 aix4 |
45
|
|
|
|
|
|
|
sco unixware mpras |
46
|
|
|
|
|
|
|
reliant dec sinix |
47
|
|
|
|
|
|
|
); |
48
|
|
|
|
|
|
|
|
49
|
|
|
|
|
|
|
# More precise BSDs |
50
|
|
|
|
|
|
|
our @BSD_TESTS = qw( |
51
|
|
|
|
|
|
|
freebsd |
52
|
|
|
|
|
|
|
); |
53
|
|
|
|
|
|
|
|
54
|
|
|
|
|
|
|
# Gaming devices |
55
|
|
|
|
|
|
|
our @GAMING_TESTS = qw( |
56
|
|
|
|
|
|
|
ps3gameos pspgameos |
57
|
|
|
|
|
|
|
); |
58
|
|
|
|
|
|
|
|
59
|
|
|
|
|
|
|
# Device related tests |
60
|
|
|
|
|
|
|
our @DEVICE_TESTS = qw( |
61
|
|
|
|
|
|
|
android audrey blackberry dsi iopener ipad |
62
|
|
|
|
|
|
|
iphone ipod kindle kindlefire n3ds palm ps3 psp wap webos |
63
|
|
|
|
|
|
|
mobile tablet |
64
|
|
|
|
|
|
|
); |
65
|
|
|
|
|
|
|
|
66
|
|
|
|
|
|
|
# Browsers |
67
|
|
|
|
|
|
|
our @BROWSER_TESTS = qw( |
68
|
|
|
|
|
|
|
mosaic netscape firefox |
69
|
|
|
|
|
|
|
chrome safari ie |
70
|
|
|
|
|
|
|
opera lynx links |
71
|
|
|
|
|
|
|
elinks neoplanet neoplanet2 |
72
|
|
|
|
|
|
|
avantgo emacs mozilla |
73
|
|
|
|
|
|
|
konqueror realplayer netfront |
74
|
|
|
|
|
|
|
mobile_safari obigo aol |
75
|
|
|
|
|
|
|
lotusnotes staroffice icab |
76
|
|
|
|
|
|
|
webtv browsex silk |
77
|
|
|
|
|
|
|
applecoremedia galeon seamonkey |
78
|
|
|
|
|
|
|
epiphany ucbrowser dalvik |
79
|
|
|
|
|
|
|
edge pubsub adm |
80
|
|
|
|
|
|
|
brave imagesearcherpro polaris |
81
|
|
|
|
|
|
|
edgelegacy samsung |
82
|
|
|
|
|
|
|
); |
83
|
|
|
|
|
|
|
|
84
|
|
|
|
|
|
|
our @IE_TESTS = qw( |
85
|
|
|
|
|
|
|
ie3 ie4 ie4up |
86
|
|
|
|
|
|
|
ie5 ie5up ie55 |
87
|
|
|
|
|
|
|
ie55up ie6 ie7 |
88
|
|
|
|
|
|
|
ie8 ie9 ie10 |
89
|
|
|
|
|
|
|
ie11 |
90
|
|
|
|
|
|
|
ie_compat_mode |
91
|
|
|
|
|
|
|
); |
92
|
|
|
|
|
|
|
|
93
|
|
|
|
|
|
|
our @OPERA_TESTS = qw( |
94
|
|
|
|
|
|
|
opera3 opera4 opera5 |
95
|
|
|
|
|
|
|
opera6 opera7 |
96
|
|
|
|
|
|
|
); |
97
|
|
|
|
|
|
|
|
98
|
|
|
|
|
|
|
our @AOL_TESTS = qw( |
99
|
|
|
|
|
|
|
aol3 aol4 |
100
|
|
|
|
|
|
|
aol5 aol6 |
101
|
|
|
|
|
|
|
); |
102
|
|
|
|
|
|
|
|
103
|
|
|
|
|
|
|
our @NETSCAPE_TESTS = qw( |
104
|
|
|
|
|
|
|
nav2 nav3 nav4 |
105
|
|
|
|
|
|
|
nav4up nav45 nav45up |
106
|
|
|
|
|
|
|
nav6 nav6up navgold |
107
|
|
|
|
|
|
|
); |
108
|
|
|
|
|
|
|
|
109
|
|
|
|
|
|
|
# Firefox variants |
110
|
|
|
|
|
|
|
our @FIREFOX_TESTS = qw( |
111
|
|
|
|
|
|
|
firebird iceweasel phoenix |
112
|
|
|
|
|
|
|
namoroka |
113
|
|
|
|
|
|
|
fxios |
114
|
|
|
|
|
|
|
); |
115
|
|
|
|
|
|
|
|
116
|
|
|
|
|
|
|
# Engine tests |
117
|
|
|
|
|
|
|
our @ENGINE_TESTS = qw( |
118
|
|
|
|
|
|
|
gecko trident webkit |
119
|
|
|
|
|
|
|
presto khtml edgehtml |
120
|
|
|
|
|
|
|
); |
121
|
|
|
|
|
|
|
|
122
|
|
|
|
|
|
|
# These bot names get turned into methods. Crazy, right? (I don't even think |
123
|
|
|
|
|
|
|
# this is documented anymore.) We'll leave this in place for back compat, but |
124
|
|
|
|
|
|
|
# we won't add any new methods moving forward. |
125
|
|
|
|
|
|
|
|
126
|
|
|
|
|
|
|
my @OLD_ROBOT_TESTS = qw( |
127
|
|
|
|
|
|
|
ahrefs |
128
|
|
|
|
|
|
|
altavista |
129
|
|
|
|
|
|
|
apache |
130
|
|
|
|
|
|
|
askjeeves |
131
|
|
|
|
|
|
|
baidu |
132
|
|
|
|
|
|
|
bingbot |
133
|
|
|
|
|
|
|
curl |
134
|
|
|
|
|
|
|
facebook |
135
|
|
|
|
|
|
|
getright |
136
|
|
|
|
|
|
|
golib |
137
|
|
|
|
|
|
|
google |
138
|
|
|
|
|
|
|
googleadsbot |
139
|
|
|
|
|
|
|
googleadsense |
140
|
|
|
|
|
|
|
googlebotimage |
141
|
|
|
|
|
|
|
googlebotnews |
142
|
|
|
|
|
|
|
googlebotvideo |
143
|
|
|
|
|
|
|
googlefavicon |
144
|
|
|
|
|
|
|
googlemobile |
145
|
|
|
|
|
|
|
indy |
146
|
|
|
|
|
|
|
infoseek |
147
|
|
|
|
|
|
|
ipsagent |
148
|
|
|
|
|
|
|
java |
149
|
|
|
|
|
|
|
linkchecker |
150
|
|
|
|
|
|
|
linkexchange |
151
|
|
|
|
|
|
|
lwp |
152
|
|
|
|
|
|
|
lycos |
153
|
|
|
|
|
|
|
malware |
154
|
|
|
|
|
|
|
mj12bot |
155
|
|
|
|
|
|
|
msn |
156
|
|
|
|
|
|
|
msnmobile |
157
|
|
|
|
|
|
|
msoffice |
158
|
|
|
|
|
|
|
nutch |
159
|
|
|
|
|
|
|
phplib |
160
|
|
|
|
|
|
|
puf |
161
|
|
|
|
|
|
|
rubylib |
162
|
|
|
|
|
|
|
slurp |
163
|
|
|
|
|
|
|
specialarchiver |
164
|
|
|
|
|
|
|
wget |
165
|
|
|
|
|
|
|
yahoo |
166
|
|
|
|
|
|
|
yandex |
167
|
|
|
|
|
|
|
yandeximages |
168
|
|
|
|
|
|
|
headlesschrome |
169
|
|
|
|
|
|
|
); |
170
|
|
|
|
|
|
|
|
171
|
|
|
|
|
|
|
our @ROBOT_TESTS = ( |
172
|
|
|
|
|
|
|
[ 'Applebot', 'apple' ], |
173
|
|
|
|
|
|
|
[ 'baiduspider', 'baidu' ], |
174
|
|
|
|
|
|
|
[ 'bitlybot', 'bitly' ], |
175
|
|
|
|
|
|
|
[ 'developers.google.com//web/snippet', 'google-plus-snippet' ], |
176
|
|
|
|
|
|
|
[ 'Discordbot', 'discordbot' ], |
177
|
|
|
|
|
|
|
[ 'embedly', 'embedly' ], |
178
|
|
|
|
|
|
|
[ 'facebookexternalhit', 'facebook' ], |
179
|
|
|
|
|
|
|
[ 'flipboard', 'flipboard' ], |
180
|
|
|
|
|
|
|
[ 'Google Page Speed', 'google-page-speed' ], |
181
|
|
|
|
|
|
|
[ 'ltx71', 'ltx71' ], |
182
|
|
|
|
|
|
|
[ 'linkedinbot', 'linkedin' ], |
183
|
|
|
|
|
|
|
[ 'nuzzel', 'nuzzel' ], |
184
|
|
|
|
|
|
|
[ 'outbrain', 'outbrain' ], |
185
|
|
|
|
|
|
|
[ 'pinterest/0.', 'pinterest' ], |
186
|
|
|
|
|
|
|
[ 'pinterestbot', 'pinterest' ], |
187
|
|
|
|
|
|
|
[ 'Pro-Sitemaps', 'pro-sitemaps' ], |
188
|
|
|
|
|
|
|
[ 'quora link preview', 'quora-link-preview' ], |
189
|
|
|
|
|
|
|
[ 'Qwantify', 'qwantify' ], |
190
|
|
|
|
|
|
|
[ 'redditbot', 'reddit', ], |
191
|
|
|
|
|
|
|
[ 'researchscan', 'researchscan' ], |
192
|
|
|
|
|
|
|
[ 'rogerbot', 'rogerbot' ], |
193
|
|
|
|
|
|
|
[ 'ShowyouBot', 'showyou' ], |
194
|
|
|
|
|
|
|
[ 'SkypeUriPreview', 'skype-uri-preview' ], |
195
|
|
|
|
|
|
|
[ 'slackbot', 'slack' ], |
196
|
|
|
|
|
|
|
[ 'Swiftbot', 'swiftbot' ], |
197
|
|
|
|
|
|
|
[ 'tumblr', 'tumblr' ], |
198
|
|
|
|
|
|
|
[ 'twitterbot', 'twitter' ], |
199
|
|
|
|
|
|
|
[ 'vkShare', 'vkshare' ], |
200
|
|
|
|
|
|
|
[ 'W3C_Validator', 'w3c-validator' ], |
201
|
|
|
|
|
|
|
[ 'WhatsApp', 'whatsapp' ], |
202
|
|
|
|
|
|
|
); |
203
|
|
|
|
|
|
|
|
204
|
|
|
|
|
|
|
our @MISC_TESTS = qw( |
205
|
|
|
|
|
|
|
dotnet x11 |
206
|
|
|
|
|
|
|
webview |
207
|
|
|
|
|
|
|
); |
208
|
|
|
|
|
|
|
|
209
|
|
|
|
|
|
|
our @ALL_TESTS = ( |
210
|
|
|
|
|
|
|
@OS_TESTS, @WINDOWS_TESTS, |
211
|
|
|
|
|
|
|
@MAC_TESTS, @UNIX_TESTS, |
212
|
|
|
|
|
|
|
@BSD_TESTS, @GAMING_TESTS, |
213
|
|
|
|
|
|
|
@DEVICE_TESTS, @BROWSER_TESTS, |
214
|
|
|
|
|
|
|
@IE_TESTS, @OPERA_TESTS, |
215
|
|
|
|
|
|
|
@AOL_TESTS, @NETSCAPE_TESTS, |
216
|
|
|
|
|
|
|
@FIREFOX_TESTS, @ENGINE_TESTS, |
217
|
|
|
|
|
|
|
@OLD_ROBOT_TESTS, @MISC_TESTS, |
218
|
|
|
|
|
|
|
); |
219
|
|
|
|
|
|
|
|
220
|
|
|
|
|
|
|
# https://support.google.com/webmasters/answer/1061943?hl=en |
221
|
|
|
|
|
|
|
|
222
|
|
|
|
|
|
|
my %ROBOT_NAMES = ( |
223
|
|
|
|
|
|
|
ahrefs => 'Ahrefs', |
224
|
|
|
|
|
|
|
altavista => 'AltaVista', |
225
|
|
|
|
|
|
|
'apache-http-client' => 'Apache HttpClient', |
226
|
|
|
|
|
|
|
apple => 'Apple', |
227
|
|
|
|
|
|
|
'archive-org' => 'Internet Archive', |
228
|
|
|
|
|
|
|
askjeeves => 'AskJeeves', |
229
|
|
|
|
|
|
|
baidu => 'Baidu', |
230
|
|
|
|
|
|
|
baiduspider => 'Baidu Spider', |
231
|
|
|
|
|
|
|
bingbot => 'Bingbot', |
232
|
|
|
|
|
|
|
bitly => 'Bitly', |
233
|
|
|
|
|
|
|
curl => 'curl', |
234
|
|
|
|
|
|
|
discordbot => 'Discord', |
235
|
|
|
|
|
|
|
embedly => 'Embedly', |
236
|
|
|
|
|
|
|
facebook => 'Facebook', |
237
|
|
|
|
|
|
|
facebookexternalhit => 'Facebook', |
238
|
|
|
|
|
|
|
flipboard => 'Flipboard', |
239
|
|
|
|
|
|
|
getright => 'GetRight', |
240
|
|
|
|
|
|
|
golib => 'Go language http library', |
241
|
|
|
|
|
|
|
google => 'Googlebot', |
242
|
|
|
|
|
|
|
'google-adsbot' => 'Google AdsBot', |
243
|
|
|
|
|
|
|
'google-adsense' => 'Google AdSense', |
244
|
|
|
|
|
|
|
'googlebot' => 'Googlebot', |
245
|
|
|
|
|
|
|
'googlebot-image' => 'Googlebot Images', |
246
|
|
|
|
|
|
|
'googlebot-mobile' => 'Googlebot Mobile', |
247
|
|
|
|
|
|
|
'googlebot-news' => 'Googlebot News', |
248
|
|
|
|
|
|
|
'googlebot-video' => 'Googlebot Video', |
249
|
|
|
|
|
|
|
'google-favicon' => 'Google Favicon', |
250
|
|
|
|
|
|
|
'google-mobile' => 'Googlebot Mobile', |
251
|
|
|
|
|
|
|
'google-page-speed' => 'Google Page Speed', |
252
|
|
|
|
|
|
|
'google-plus-snippet' => 'Google+ Snippet', |
253
|
|
|
|
|
|
|
'indy-library' => 'Indy Library', |
254
|
|
|
|
|
|
|
infoseek => 'InfoSeek', |
255
|
|
|
|
|
|
|
java => 'Java', |
256
|
|
|
|
|
|
|
'libwww-perl' => 'LWP::UserAgent', |
257
|
|
|
|
|
|
|
linkchecker => 'LinkChecker', |
258
|
|
|
|
|
|
|
linkedin => 'LinkedIn', |
259
|
|
|
|
|
|
|
linkexchange => 'LinkExchange', |
260
|
|
|
|
|
|
|
ltx71 => 'ltx71', |
261
|
|
|
|
|
|
|
lycos => 'Lycos', |
262
|
|
|
|
|
|
|
malware => 'Malware / hack attempt', |
263
|
|
|
|
|
|
|
'microsoft-office' => 'Microsoft Office', |
264
|
|
|
|
|
|
|
mj12bot => 'Majestic-12 DSearch', |
265
|
|
|
|
|
|
|
msn => 'MSN', |
266
|
|
|
|
|
|
|
'msn-mobile' => 'MSN Mobile', |
267
|
|
|
|
|
|
|
nutch => 'Apache Nutch', |
268
|
|
|
|
|
|
|
nuzzel => 'Nuzzel', |
269
|
|
|
|
|
|
|
outbrain => 'Outbrain', |
270
|
|
|
|
|
|
|
phplib => 'PHP http library', |
271
|
|
|
|
|
|
|
pinterest => 'Pinterest', |
272
|
|
|
|
|
|
|
'pro-sitemaps' => 'Pro Sitemap Service', |
273
|
|
|
|
|
|
|
puf => 'puf', |
274
|
|
|
|
|
|
|
'quora-link-preview' => 'Quora Link Preview', |
275
|
|
|
|
|
|
|
qwantify => 'Qwantify', |
276
|
|
|
|
|
|
|
researchscan => 'Researchscan RWTH Aachen', |
277
|
|
|
|
|
|
|
reddit => 'Reddit', |
278
|
|
|
|
|
|
|
robot => 'robot', |
279
|
|
|
|
|
|
|
rogerbot => 'Moz', |
280
|
|
|
|
|
|
|
'ruby-http-library' => 'Ruby http library', |
281
|
|
|
|
|
|
|
showyou => 'Showyou', |
282
|
|
|
|
|
|
|
'skype-uri-preview' => 'Skype URI Preview', |
283
|
|
|
|
|
|
|
slack => 'slack', |
284
|
|
|
|
|
|
|
swiftbot => 'Swiftbot', |
285
|
|
|
|
|
|
|
tumblr => 'Tumblr', |
286
|
|
|
|
|
|
|
twitter => 'Twitter', |
287
|
|
|
|
|
|
|
unknown => 'Unknown Bot', |
288
|
|
|
|
|
|
|
'verisign-ips-agent' => 'Verisign ips-agent', |
289
|
|
|
|
|
|
|
vkshare => 'VK Share', |
290
|
|
|
|
|
|
|
'w3c-validator' => 'W3C Validator', |
291
|
|
|
|
|
|
|
wget => 'Wget', |
292
|
|
|
|
|
|
|
whatsapp => 'WhatsApp', |
293
|
|
|
|
|
|
|
yahoo => 'Yahoo', |
294
|
|
|
|
|
|
|
'yahoo-slurp' => 'Yahoo! Slurp', |
295
|
|
|
|
|
|
|
yandex => 'Yandex', |
296
|
|
|
|
|
|
|
'yandex-images' => 'YandexImages', |
297
|
|
|
|
|
|
|
'headless-chrome' => 'HeadlessChrome', |
298
|
|
|
|
|
|
|
); |
299
|
|
|
|
|
|
|
|
300
|
|
|
|
|
|
|
my %ROBOT_IDS = ( |
301
|
|
|
|
|
|
|
ahrefs => 'ahrefs', |
302
|
|
|
|
|
|
|
altavista => 'altavista', |
303
|
|
|
|
|
|
|
apache => 'apache-http-client', |
304
|
|
|
|
|
|
|
askjeeves => 'askjeeves', |
305
|
|
|
|
|
|
|
baidu => 'baidu', |
306
|
|
|
|
|
|
|
baiduspider => 'baidu', |
307
|
|
|
|
|
|
|
bingbot => 'bingbot', |
308
|
|
|
|
|
|
|
curl => 'curl', |
309
|
|
|
|
|
|
|
facebook => 'facebook', |
310
|
|
|
|
|
|
|
getright => 'getright', |
311
|
|
|
|
|
|
|
golib => 'golib', |
312
|
|
|
|
|
|
|
google => 'googlebot', |
313
|
|
|
|
|
|
|
googleadsbot => 'google-adsbot', |
314
|
|
|
|
|
|
|
googleadsense => 'google-adsense', |
315
|
|
|
|
|
|
|
googlebotimage => 'googlebot-image', |
316
|
|
|
|
|
|
|
googlebotnews => 'googlebot-news', |
317
|
|
|
|
|
|
|
googlebotvideo => 'googlebot-video', |
318
|
|
|
|
|
|
|
googlefavicon => 'google-favicon', |
319
|
|
|
|
|
|
|
googlemobile => 'googlebot-mobile', |
320
|
|
|
|
|
|
|
indy => 'indy-library', |
321
|
|
|
|
|
|
|
infoseek => 'infoseek', |
322
|
|
|
|
|
|
|
ipsagent => 'verisign-ips-agent', |
323
|
|
|
|
|
|
|
java => 'java', |
324
|
|
|
|
|
|
|
linkchecker => 'linkchecker', |
325
|
|
|
|
|
|
|
linkexchange => 'linkexchange', |
326
|
|
|
|
|
|
|
ltx71 => 'ltx71', |
327
|
|
|
|
|
|
|
lwp => 'libwww-perl', |
328
|
|
|
|
|
|
|
lycos => 'lycos', |
329
|
|
|
|
|
|
|
malware => 'malware', |
330
|
|
|
|
|
|
|
mj12bot => 'mj12bot', |
331
|
|
|
|
|
|
|
msn => 'msn', |
332
|
|
|
|
|
|
|
msnmobile => 'msn-mobile', |
333
|
|
|
|
|
|
|
msoffice => 'microsoft-office', |
334
|
|
|
|
|
|
|
nutch => 'nutch', |
335
|
|
|
|
|
|
|
phplib => 'phplib', |
336
|
|
|
|
|
|
|
puf => 'puf', |
337
|
|
|
|
|
|
|
robot => 'robot', |
338
|
|
|
|
|
|
|
rubylib => 'ruby-http-library', |
339
|
|
|
|
|
|
|
researchscan => 'researchscan', |
340
|
|
|
|
|
|
|
slurp => 'yahoo-slurp', |
341
|
|
|
|
|
|
|
specialarchiver => 'archive-org', |
342
|
|
|
|
|
|
|
wget => 'wget', |
343
|
|
|
|
|
|
|
yahoo => 'yahoo', |
344
|
|
|
|
|
|
|
yandex => 'yandex', |
345
|
|
|
|
|
|
|
yandeximages => 'yandex-images', |
346
|
|
|
|
|
|
|
headlesschrome => 'headless-chrome', |
347
|
|
|
|
|
|
|
); |
348
|
|
|
|
|
|
|
|
349
|
|
|
|
|
|
|
my %BROWSER_NAMES = ( |
350
|
|
|
|
|
|
|
adm => 'Android Download Manager', |
351
|
|
|
|
|
|
|
aol => 'AOL Browser', |
352
|
|
|
|
|
|
|
applecoremedia => 'AppleCoreMedia', |
353
|
|
|
|
|
|
|
blackberry => 'BlackBerry', |
354
|
|
|
|
|
|
|
brave => 'Brave', |
355
|
|
|
|
|
|
|
browsex => 'BrowseX', |
356
|
|
|
|
|
|
|
chrome => 'Chrome', |
357
|
|
|
|
|
|
|
curl => 'curl', |
358
|
|
|
|
|
|
|
dalvik => 'Dalvik', |
359
|
|
|
|
|
|
|
dsi => 'Nintendo DSi', |
360
|
|
|
|
|
|
|
edge => 'Edge', |
361
|
|
|
|
|
|
|
elinks => 'ELinks', |
362
|
|
|
|
|
|
|
epiphany => 'Epiphany', |
363
|
|
|
|
|
|
|
firefox => 'Firefox', |
364
|
|
|
|
|
|
|
galeon => 'Galeon', |
365
|
|
|
|
|
|
|
icab => 'iCab', |
366
|
|
|
|
|
|
|
iceweasel => 'IceWeasel', |
367
|
|
|
|
|
|
|
ie => 'MSIE', |
368
|
|
|
|
|
|
|
imagesearcherpro => 'ImageSearcherPro', |
369
|
|
|
|
|
|
|
konqueror => 'Konqueror', |
370
|
|
|
|
|
|
|
links => 'Links', |
371
|
|
|
|
|
|
|
lotusnotes => 'Lotus Notes', |
372
|
|
|
|
|
|
|
lynx => 'Lynx', |
373
|
|
|
|
|
|
|
mobile_safari => 'Mobile Safari', |
374
|
|
|
|
|
|
|
mosaic => 'Mosaic', |
375
|
|
|
|
|
|
|
mozilla => 'Mozilla', |
376
|
|
|
|
|
|
|
n3ds => 'Nintendo 3DS', |
377
|
|
|
|
|
|
|
netfront => 'NetFront', |
378
|
|
|
|
|
|
|
netscape => 'Netscape', |
379
|
|
|
|
|
|
|
obigo => 'Obigo', |
380
|
|
|
|
|
|
|
opera => 'Opera', |
381
|
|
|
|
|
|
|
polaris => 'Polaris', |
382
|
|
|
|
|
|
|
pubsub => 'Safari RSS Reader', |
383
|
|
|
|
|
|
|
puf => 'puf', |
384
|
|
|
|
|
|
|
realplayer => 'RealPlayer', |
385
|
|
|
|
|
|
|
safari => 'Safari', |
386
|
|
|
|
|
|
|
samsung => 'Samsung', |
387
|
|
|
|
|
|
|
seamonkey => 'SeaMonkey', |
388
|
|
|
|
|
|
|
silk => 'Silk', |
389
|
|
|
|
|
|
|
staroffice => 'StarOffice', |
390
|
|
|
|
|
|
|
ucbrowser => 'UCBrowser', |
391
|
|
|
|
|
|
|
webtv => 'WebTV', |
392
|
|
|
|
|
|
|
); |
393
|
|
|
|
|
|
|
|
394
|
|
|
|
|
|
|
# Device names |
395
|
|
|
|
|
|
|
my %DEVICE_NAMES = ( |
396
|
|
|
|
|
|
|
android => 'Android', |
397
|
|
|
|
|
|
|
audrey => 'Audrey', |
398
|
|
|
|
|
|
|
blackberry => 'BlackBerry', |
399
|
|
|
|
|
|
|
dsi => 'Nintendo DSi', |
400
|
|
|
|
|
|
|
iopener => 'iopener', |
401
|
|
|
|
|
|
|
ipad => 'iPad', |
402
|
|
|
|
|
|
|
iphone => 'iPhone', |
403
|
|
|
|
|
|
|
ipod => 'iPod', |
404
|
|
|
|
|
|
|
kindle => 'Amazon Kindle', |
405
|
|
|
|
|
|
|
n3ds => 'Nintendo 3DS', |
406
|
|
|
|
|
|
|
palm => 'Palm', |
407
|
|
|
|
|
|
|
ps3 => 'Sony PlayStation 3', |
408
|
|
|
|
|
|
|
psp => 'Sony PlayStation Portable', |
409
|
|
|
|
|
|
|
wap => 'WAP capable phone', |
410
|
|
|
|
|
|
|
webos => 'webOS', |
411
|
|
|
|
|
|
|
); |
412
|
|
|
|
|
|
|
|
413
|
|
|
|
|
|
|
my %OS_NAMES = ( |
414
|
|
|
|
|
|
|
amiga => 'Amiga', |
415
|
|
|
|
|
|
|
android => 'Android', |
416
|
|
|
|
|
|
|
bb10 => 'BlackBerry 10', |
417
|
|
|
|
|
|
|
brew => 'Brew', |
418
|
|
|
|
|
|
|
chromeos => 'Chrome OS', |
419
|
|
|
|
|
|
|
firefoxos => 'Firefox OS', |
420
|
|
|
|
|
|
|
ios => 'iOS', |
421
|
|
|
|
|
|
|
linux => 'Linux', |
422
|
|
|
|
|
|
|
mac => 'Mac', |
423
|
|
|
|
|
|
|
macosx => 'Mac OS X', |
424
|
|
|
|
|
|
|
os2 => 'OS/2', |
425
|
|
|
|
|
|
|
ps3gameos => 'Playstation 3 GameOS', |
426
|
|
|
|
|
|
|
pspgameos => 'Playstation Portable GameOS', |
427
|
|
|
|
|
|
|
rimtabletos => 'RIM Tablet OS', |
428
|
|
|
|
|
|
|
unix => 'Unix', |
429
|
|
|
|
|
|
|
vms => 'VMS', |
430
|
|
|
|
|
|
|
win2k => 'Win2k', |
431
|
|
|
|
|
|
|
win2k3 => 'Win2k3', |
432
|
|
|
|
|
|
|
win3x => 'Win3x', |
433
|
|
|
|
|
|
|
win7 => 'Win7', |
434
|
|
|
|
|
|
|
win8 => 'Win8', |
435
|
|
|
|
|
|
|
win8_0 => 'Win8.0', |
436
|
|
|
|
|
|
|
win8_1 => 'Win8.1', |
437
|
|
|
|
|
|
|
win10 => 'Win10', |
438
|
|
|
|
|
|
|
win10_0 => 'Win10.0', |
439
|
|
|
|
|
|
|
win95 => 'Win95', |
440
|
|
|
|
|
|
|
win98 => 'Win98', |
441
|
|
|
|
|
|
|
winme => 'WinME', |
442
|
|
|
|
|
|
|
winnt => 'WinNT', |
443
|
|
|
|
|
|
|
winphone => 'Windows Phone', |
444
|
|
|
|
|
|
|
winvista => 'WinVista', |
445
|
|
|
|
|
|
|
winxp => 'WinXP', |
446
|
|
|
|
|
|
|
); |
447
|
|
|
|
|
|
|
|
448
|
|
|
|
|
|
|
# Safari build -> version map for versions prior to 3.0 |
449
|
|
|
|
|
|
|
# (since then, version appears in the user-agent string) |
450
|
|
|
|
|
|
|
|
451
|
|
|
|
|
|
|
my %safari_build_to_version = qw( |
452
|
|
|
|
|
|
|
48 0.8 |
453
|
|
|
|
|
|
|
51 0.8.1 |
454
|
|
|
|
|
|
|
60 0.8.2 |
455
|
|
|
|
|
|
|
73 0.9 |
456
|
|
|
|
|
|
|
74 1.0b2v74 |
457
|
|
|
|
|
|
|
85 1.0 |
458
|
|
|
|
|
|
|
85.7 1.0.2 |
459
|
|
|
|
|
|
|
85.8 1.0.3 |
460
|
|
|
|
|
|
|
100 1.1 |
461
|
|
|
|
|
|
|
100.1 1.1.1 |
462
|
|
|
|
|
|
|
125 1.2 |
463
|
|
|
|
|
|
|
125.1 1.2.1 |
464
|
|
|
|
|
|
|
125.7 1.2.2 |
465
|
|
|
|
|
|
|
125.9 1.2.3 |
466
|
|
|
|
|
|
|
125.11 1.2.4 |
467
|
|
|
|
|
|
|
312 1.3 |
468
|
|
|
|
|
|
|
312.3 1.3.1 |
469
|
|
|
|
|
|
|
312.5 1.3.2 |
470
|
|
|
|
|
|
|
412 2.0 |
471
|
|
|
|
|
|
|
412.5 2.0.1 |
472
|
|
|
|
|
|
|
416.12 2.0.2 |
473
|
|
|
|
|
|
|
417.8 2.0.3 |
474
|
|
|
|
|
|
|
419.3 2.0.4 |
475
|
|
|
|
|
|
|
); |
476
|
|
|
|
|
|
|
|
477
|
|
|
|
|
|
|
####################################################################################################### |
478
|
|
|
|
|
|
|
# BROWSER OBJECT |
479
|
|
|
|
|
|
|
|
480
|
|
|
|
|
|
|
my $default = undef; |
481
|
|
|
|
|
|
|
|
482
|
|
|
|
|
|
|
sub new { |
483
|
7151
|
|
|
7151
|
1
|
4369497
|
my ( $class, $user_agent ) = @_; |
484
|
|
|
|
|
|
|
|
485
|
7151
|
|
|
|
|
16064
|
my $self = {}; |
486
|
7151
|
|
|
|
|
14413
|
bless $self, $class; |
487
|
|
|
|
|
|
|
|
488
|
7151
|
100
|
|
|
|
17605
|
unless ( defined $user_agent ) { |
489
|
2
|
|
|
|
|
5
|
$user_agent = $ENV{'HTTP_USER_AGENT'}; |
490
|
|
|
|
|
|
|
} |
491
|
|
|
|
|
|
|
|
492
|
7151
|
100
|
|
|
|
20281
|
$self->{user_agent} = defined $user_agent ? $user_agent : q{}; |
493
|
7151
|
|
|
|
|
18636
|
$self->_init_core; |
494
|
|
|
|
|
|
|
|
495
|
7151
|
|
|
|
|
59588
|
return $self; |
496
|
|
|
|
|
|
|
} |
497
|
|
|
|
|
|
|
|
498
|
|
|
|
|
|
|
### Accessors for computed-on-demand test attributes |
499
|
|
|
|
|
|
|
|
500
|
|
|
|
|
|
|
foreach my $test ( @ENGINE_TESTS, @MISC_TESTS ) { |
501
|
|
|
|
|
|
|
## no critic (TestingAndDebugging::ProhibitNoStrict) |
502
|
5
|
|
|
5
|
|
39
|
no strict 'refs'; |
|
5
|
|
|
|
|
16
|
|
|
5
|
|
|
|
|
574
|
|
503
|
|
|
|
|
|
|
*{$test} = sub { |
504
|
22987
|
|
|
22987
|
|
1430169
|
my ($self) = @_; |
505
|
22987
|
|
100
|
|
|
73634
|
return $self->{tests}->{$test} || 0; |
506
|
|
|
|
|
|
|
}; |
507
|
|
|
|
|
|
|
} |
508
|
|
|
|
|
|
|
|
509
|
|
|
|
|
|
|
foreach my $test ( |
510
|
|
|
|
|
|
|
@OS_TESTS, @WINDOWS_TESTS, @MAC_TESTS, @UNIX_TESTS, |
511
|
|
|
|
|
|
|
@BSD_TESTS, @GAMING_TESTS |
512
|
|
|
|
|
|
|
) { |
513
|
|
|
|
|
|
|
## no critic (TestingAndDebugging::ProhibitNoStrict) |
514
|
5
|
|
|
5
|
|
33
|
no strict 'refs'; |
|
5
|
|
|
|
|
9
|
|
|
5
|
|
|
|
|
472
|
|
515
|
|
|
|
|
|
|
*{$test} = sub { |
516
|
50566
|
|
|
50566
|
|
7168792
|
my ($self) = @_; |
517
|
50566
|
100
|
|
|
|
113555
|
$self->_init_os() unless $self->{os_tests}; |
518
|
50566
|
|
100
|
|
|
157169
|
return $self->{os_tests}->{$test} || 0; |
519
|
|
|
|
|
|
|
}; |
520
|
|
|
|
|
|
|
} |
521
|
|
|
|
|
|
|
|
522
|
|
|
|
|
|
|
foreach my $test ( @BROWSER_TESTS, @FIREFOX_TESTS ) { |
523
|
|
|
|
|
|
|
## no critic (TestingAndDebugging::ProhibitNoStrict) |
524
|
5
|
|
|
5
|
|
30
|
no strict 'refs'; |
|
5
|
|
|
|
|
10
|
|
|
5
|
|
|
|
|
476
|
|
525
|
|
|
|
|
|
|
*{$test} = sub { |
526
|
58115
|
|
|
58115
|
|
4512160
|
my ($self) = @_; |
527
|
58115
|
|
100
|
|
|
192410
|
return $self->{browser_tests}->{$test} || 0; |
528
|
|
|
|
|
|
|
}; |
529
|
|
|
|
|
|
|
} |
530
|
|
|
|
|
|
|
|
531
|
|
|
|
|
|
|
foreach my $test (@OLD_ROBOT_TESTS) { |
532
|
|
|
|
|
|
|
## no critic (TestingAndDebugging::ProhibitNoStrict) |
533
|
5
|
|
|
5
|
|
31
|
no strict 'refs'; |
|
5
|
|
|
|
|
7
|
|
|
5
|
|
|
|
|
510
|
|
534
|
|
|
|
|
|
|
|
535
|
|
|
|
|
|
|
# For the 'robot' test, we return undef instead of 0 if it's |
536
|
|
|
|
|
|
|
# false, to match os() and browser() and the like. |
537
|
|
|
|
|
|
|
my $false_result = ( $test eq 'robot' ? undef : 0 ); |
538
|
|
|
|
|
|
|
|
539
|
|
|
|
|
|
|
*{$test} = sub { |
540
|
30595
|
|
|
30595
|
|
3575249
|
my ($self) = @_; |
541
|
30595
|
100
|
|
|
|
65384
|
$self->_init_robots() unless $self->{robot_tests}; |
542
|
30595
|
|
66
|
|
|
98636
|
return $self->{robot_tests}->{$test} || $false_result; |
543
|
|
|
|
|
|
|
}; |
544
|
|
|
|
|
|
|
} |
545
|
|
|
|
|
|
|
|
546
|
|
|
|
|
|
|
foreach my $test ( |
547
|
|
|
|
|
|
|
@NETSCAPE_TESTS, @IE_TESTS, @AOL_TESTS, |
548
|
|
|
|
|
|
|
@OPERA_TESTS |
549
|
|
|
|
|
|
|
) { |
550
|
|
|
|
|
|
|
## no critic (TestingAndDebugging::ProhibitNoStrict) |
551
|
5
|
|
|
5
|
|
40
|
no strict 'refs'; |
|
5
|
|
|
|
|
33
|
|
|
5
|
|
|
|
|
452
|
|
552
|
|
|
|
|
|
|
*{$test} = sub { |
553
|
24330
|
|
|
24330
|
|
3461321
|
my ($self) = @_; |
554
|
24330
|
100
|
|
|
|
53733
|
$self->_init_version() unless $self->{version_tests}; |
555
|
24330
|
|
100
|
|
|
79515
|
return $self->{version_tests}->{$test} || 0; |
556
|
|
|
|
|
|
|
}; |
557
|
|
|
|
|
|
|
} |
558
|
|
|
|
|
|
|
|
559
|
|
|
|
|
|
|
foreach my $test (@DEVICE_TESTS) { |
560
|
|
|
|
|
|
|
## no critic (TestingAndDebugging::ProhibitNoStrict) |
561
|
5
|
|
|
5
|
|
41
|
no strict 'refs'; |
|
5
|
|
|
|
|
17
|
|
|
5
|
|
|
|
|
66530
|
|
562
|
|
|
|
|
|
|
*{$test} = sub { |
563
|
22190
|
|
|
22190
|
|
1905089
|
my ($self) = @_; |
564
|
22190
|
100
|
|
|
|
61652
|
$self->_init_device() unless $self->{device_tests}; |
565
|
22190
|
|
100
|
|
|
92257
|
return $self->{device_tests}->{$test} || 0; |
566
|
|
|
|
|
|
|
}; |
567
|
|
|
|
|
|
|
} |
568
|
|
|
|
|
|
|
|
569
|
|
|
|
|
|
|
sub user_agent { |
570
|
1
|
|
|
1
|
1
|
7
|
my ( $self, $user_agent ) = @_; |
571
|
1
|
50
|
|
|
|
8
|
if ( defined($user_agent) ) { |
572
|
0
|
|
|
|
|
0
|
die |
573
|
|
|
|
|
|
|
'Calling HTTP::BrowserDetect::user_agent() with an argument is no longer allowed; please use new().'; |
574
|
|
|
|
|
|
|
} |
575
|
|
|
|
|
|
|
else { |
576
|
1
|
|
|
|
|
20
|
return $self->{user_agent}; |
577
|
|
|
|
|
|
|
} |
578
|
|
|
|
|
|
|
} |
579
|
|
|
|
|
|
|
|
580
|
|
|
|
|
|
|
### Code for initializing various pieces of the object. Since it would |
581
|
|
|
|
|
|
|
### be needlessly slow if we examined every user agent for every piece |
582
|
|
|
|
|
|
|
### of information we might possibly need, we only initialize things |
583
|
|
|
|
|
|
|
### when they're actually queried about. Specifically: |
584
|
|
|
|
|
|
|
### |
585
|
|
|
|
|
|
|
### _init_core() sets up: |
586
|
|
|
|
|
|
|
### $self->{browser_tests} |
587
|
|
|
|
|
|
|
### $self->{browser} |
588
|
|
|
|
|
|
|
### $self->{browser_string} |
589
|
|
|
|
|
|
|
### $self->{tests} |
590
|
|
|
|
|
|
|
### $self->{engine_version} |
591
|
|
|
|
|
|
|
### $self->{realplayer_version} |
592
|
|
|
|
|
|
|
### |
593
|
|
|
|
|
|
|
### _init_version() sets up: |
594
|
|
|
|
|
|
|
### $self->{version_tests} |
595
|
|
|
|
|
|
|
### $self->{major} |
596
|
|
|
|
|
|
|
### $self->{minor} |
597
|
|
|
|
|
|
|
### $self->{beta} |
598
|
|
|
|
|
|
|
### $self->{realplayer_version} |
599
|
|
|
|
|
|
|
### |
600
|
|
|
|
|
|
|
### _init_os() sets up: |
601
|
|
|
|
|
|
|
### $self->{os} |
602
|
|
|
|
|
|
|
### $self->{os_string} |
603
|
|
|
|
|
|
|
### $self->{os_tests} |
604
|
|
|
|
|
|
|
### $self->{os_version} |
605
|
|
|
|
|
|
|
### |
606
|
|
|
|
|
|
|
### _init_os_version() sets up: |
607
|
|
|
|
|
|
|
### $self->{os_version} |
608
|
|
|
|
|
|
|
### |
609
|
|
|
|
|
|
|
### _init_device() sets up: |
610
|
|
|
|
|
|
|
### $self->{device_tests} |
611
|
|
|
|
|
|
|
### $self->{device} |
612
|
|
|
|
|
|
|
### $self->{device_string} |
613
|
|
|
|
|
|
|
### |
614
|
|
|
|
|
|
|
### _init_robots() sets up: |
615
|
|
|
|
|
|
|
### $self->{robot} |
616
|
|
|
|
|
|
|
### $self->{robot_tests} |
617
|
|
|
|
|
|
|
### $self->{robot_string} |
618
|
|
|
|
|
|
|
### $self->{robot_version} |
619
|
|
|
|
|
|
|
### |
620
|
|
|
|
|
|
|
|
621
|
|
|
|
|
|
|
# Private method -- Set up the basics (browser and misc attributes) |
622
|
|
|
|
|
|
|
# for a new user-agent string |
623
|
|
|
|
|
|
|
sub _init_core { |
624
|
7151
|
|
|
7151
|
|
13037
|
my ( $self, $new_ua ) = @_; |
625
|
|
|
|
|
|
|
|
626
|
7151
|
|
|
|
|
21443
|
my $ua = lc $self->{user_agent}; |
627
|
|
|
|
|
|
|
|
628
|
|
|
|
|
|
|
# any UA via Google Translate gets this appended |
629
|
7151
|
|
|
|
|
15380
|
$ua =~ s{,gzip\(gfe\)\z}{}; |
630
|
|
|
|
|
|
|
|
631
|
|
|
|
|
|
|
# These get filled in immediately |
632
|
7151
|
|
|
|
|
13543
|
$self->{tests} = {}; |
633
|
7151
|
|
|
|
|
13619
|
$self->{browser_tests} = {}; |
634
|
|
|
|
|
|
|
|
635
|
7151
|
|
|
|
|
13165
|
my $tests = $self->{tests}; |
636
|
7151
|
|
|
|
|
14061
|
my $browser_tests = $self->{browser_tests}; |
637
|
7151
|
|
|
|
|
10531
|
my $browser = undef; |
638
|
7151
|
|
|
|
|
9318
|
my $browser_string = undef; |
639
|
|
|
|
|
|
|
|
640
|
|
|
|
|
|
|
# Detect engine |
641
|
7151
|
|
|
|
|
11415
|
$self->{engine_version} = undef; |
642
|
|
|
|
|
|
|
|
643
|
7151
|
100
|
100
|
|
|
73926
|
if ( $ua =~ m{edge/([\d\.]+)} ) { |
|
|
100
|
66
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
644
|
30
|
|
|
|
|
65
|
$tests->{edgehtml} = 1; |
645
|
30
|
|
|
|
|
72
|
$self->{engine_version} = $1; |
646
|
|
|
|
|
|
|
} |
647
|
|
|
|
|
|
|
elsif ( $ua =~ /trident\/([\w\.\d]*)/ ) { |
648
|
944
|
|
|
|
|
2256
|
$tests->{trident} = 1; |
649
|
944
|
|
|
|
|
2841
|
$self->{engine_version} = $1; |
650
|
|
|
|
|
|
|
} |
651
|
|
|
|
|
|
|
elsif ( index( $ua, 'gecko' ) != -1 && index( $ua, 'like gecko' ) == -1 ) |
652
|
|
|
|
|
|
|
{ |
653
|
732
|
|
|
|
|
1480
|
$tests->{gecko} = 1; |
654
|
732
|
100
|
|
|
|
4029
|
if ( $ua =~ /\([^)]*rv:([\w.\d]*)/ ) { |
655
|
660
|
|
|
|
|
1872
|
$self->{engine_version} = $1; |
656
|
|
|
|
|
|
|
} |
657
|
|
|
|
|
|
|
} |
658
|
|
|
|
|
|
|
elsif ( $ua =~ m{applewebkit/([\d.\+]+)} && not $tests->{edgehtml} ) { |
659
|
2532
|
|
|
|
|
6213
|
$tests->{webkit} = 1; |
660
|
2532
|
|
|
|
|
7219
|
$self->{engine_version} = $1; |
661
|
|
|
|
|
|
|
} |
662
|
|
|
|
|
|
|
elsif ( $ua =~ m{presto/([\d.]+)} ) { |
663
|
138
|
|
|
|
|
515
|
$tests->{presto} = 1; |
664
|
138
|
|
|
|
|
424
|
$self->{engine_version} = $1; |
665
|
|
|
|
|
|
|
} |
666
|
|
|
|
|
|
|
elsif ( $ua =~ m{khtml/([\d.]+)} ) { |
667
|
12
|
|
|
|
|
27
|
$tests->{khtml} = 1; |
668
|
12
|
|
|
|
|
36
|
$self->{engine_version} = $1; |
669
|
|
|
|
|
|
|
} |
670
|
|
|
|
|
|
|
|
671
|
|
|
|
|
|
|
# Detect browser |
672
|
|
|
|
|
|
|
|
673
|
7151
|
100
|
100
|
|
|
162329
|
if ( index( $ua, 'galeon' ) != -1 ) { |
|
|
100
|
100
|
|
|
|
|
|
|
100
|
66
|
|
|
|
|
|
|
100
|
100
|
|
|
|
|
|
|
100
|
100
|
|
|
|
|
|
|
100
|
100
|
|
|
|
|
|
|
100
|
100
|
|
|
|
|
|
|
100
|
100
|
|
|
|
|
|
|
100
|
100
|
|
|
|
|
|
|
100
|
100
|
|
|
|
|
|
|
100
|
100
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
674
|
|
|
|
|
|
|
|
675
|
|
|
|
|
|
|
# Needs to go above firefox |
676
|
|
|
|
|
|
|
|
677
|
12
|
|
|
|
|
19
|
$browser = 'galeon'; |
678
|
12
|
|
|
|
|
22
|
$browser_tests->{galeon} = 1; |
679
|
|
|
|
|
|
|
} |
680
|
|
|
|
|
|
|
elsif ( index( $ua, 'epiphany' ) != -1 ) { |
681
|
|
|
|
|
|
|
|
682
|
|
|
|
|
|
|
# Needs to go above firefox + mozilla |
683
|
|
|
|
|
|
|
|
684
|
6
|
|
|
|
|
9
|
$browser = 'epiphany'; |
685
|
6
|
|
|
|
|
15
|
$browser_tests->{epiphany} = 1; |
686
|
|
|
|
|
|
|
} |
687
|
|
|
|
|
|
|
elsif ( $ua =~ m{(?:edg|edga|edgios)/[\d.]+} ) { |
688
|
24
|
|
|
|
|
44
|
$browser = 'edge'; |
689
|
24
|
|
|
|
|
38
|
$browser_string = 'Edge'; |
690
|
|
|
|
|
|
|
|
691
|
24
|
|
|
|
|
45
|
$browser_tests->{edge} = 1; |
692
|
|
|
|
|
|
|
} |
693
|
|
|
|
|
|
|
elsif ( $ua =~ m{edge/[\d.]+} ) { |
694
|
30
|
|
|
|
|
52
|
$browser = 'edge'; |
695
|
30
|
|
|
|
|
39
|
$browser_string = 'Edge'; |
696
|
|
|
|
|
|
|
|
697
|
30
|
|
|
|
|
56
|
$browser_tests->{edgelegacy} = 1; |
698
|
|
|
|
|
|
|
} |
699
|
|
|
|
|
|
|
elsif ( |
700
|
|
|
|
|
|
|
$ua =~ m{ |
701
|
|
|
|
|
|
|
(firebird|iceweasel|phoenix|namoroka|firefox|fxios) |
702
|
|
|
|
|
|
|
\/ |
703
|
|
|
|
|
|
|
( [^.]* ) # Major version number is everything before first dot |
704
|
|
|
|
|
|
|
\. # The first dot |
705
|
|
|
|
|
|
|
( [\d]* ) # Minor version nnumber is digits after first dot |
706
|
|
|
|
|
|
|
}xo |
707
|
|
|
|
|
|
|
&& index( $ua, 'not firefox' ) == -1 |
708
|
|
|
|
|
|
|
) # Hack for Yahoo Slurp |
709
|
|
|
|
|
|
|
{ |
710
|
|
|
|
|
|
|
# Browser is Firefox, possibly under an alternate name |
711
|
|
|
|
|
|
|
|
712
|
636
|
|
|
|
|
1077
|
$browser = 'firefox'; |
713
|
636
|
100
|
|
|
|
2033
|
$browser_string = ucfirst( $1 eq 'fxios' ? $browser : $1 ); |
714
|
|
|
|
|
|
|
|
715
|
636
|
|
|
|
|
1316
|
$browser_tests->{$1} = 1; |
716
|
636
|
|
|
|
|
887
|
$browser_tests->{firefox} = 1; |
717
|
|
|
|
|
|
|
} |
718
|
|
|
|
|
|
|
elsif ( $ua =~ m{opera|opr\/} ) { |
719
|
|
|
|
|
|
|
|
720
|
|
|
|
|
|
|
# Browser is Opera |
721
|
|
|
|
|
|
|
|
722
|
264
|
|
|
|
|
499
|
$browser = 'opera'; |
723
|
264
|
|
|
|
|
636
|
$browser_tests->{opera} = 1; |
724
|
|
|
|
|
|
|
} |
725
|
|
|
|
|
|
|
elsif ($tests->{trident} |
726
|
|
|
|
|
|
|
|| index( $ua, 'msie' ) != -1 |
727
|
|
|
|
|
|
|
|| index( $ua, 'microsoft internet explorer' ) != -1 ) { |
728
|
|
|
|
|
|
|
|
729
|
|
|
|
|
|
|
# Browser is MSIE (possibly AOL branded) |
730
|
|
|
|
|
|
|
|
731
|
1730
|
|
|
|
|
3552
|
$browser = 'ie'; |
732
|
1730
|
|
|
|
|
3400
|
$browser_tests->{ie} = 1; |
733
|
|
|
|
|
|
|
|
734
|
1730
|
100
|
100
|
|
|
10072
|
if ( index( $ua, 'aol' ) != -1 |
735
|
|
|
|
|
|
|
|| index( $ua, 'america online browser' ) != -1 ) { |
736
|
42
|
|
|
|
|
69
|
$browser_string = 'AOL Browser'; |
737
|
42
|
|
|
|
|
81
|
$browser_tests->{aol} = 1; |
738
|
|
|
|
|
|
|
} |
739
|
|
|
|
|
|
|
|
740
|
|
|
|
|
|
|
# Disabled for now -- need to figure out how to deal with version numbers |
741
|
|
|
|
|
|
|
#elsif ( index ( $ua, 'acoobrowser' ) != -1 ) { |
742
|
|
|
|
|
|
|
# $browser_string = 'Acoo Browser'; |
743
|
|
|
|
|
|
|
#} |
744
|
|
|
|
|
|
|
#elsif ( index( $ua, 'avant' ) != -1 ) { |
745
|
|
|
|
|
|
|
# $browser_string = 'Avant Browser'; |
746
|
|
|
|
|
|
|
#} |
747
|
|
|
|
|
|
|
#elsif ( index( $ua, 'crazy browser' ) != -1 ) { |
748
|
|
|
|
|
|
|
# $browser_string = 'Crazy Browser'; |
749
|
|
|
|
|
|
|
#} |
750
|
|
|
|
|
|
|
#elsif ( index( $ua, 'deepnet explorer' ) != -1 ) { |
751
|
|
|
|
|
|
|
# $browser_string = 'Deepnet Explorer'; |
752
|
|
|
|
|
|
|
#} |
753
|
|
|
|
|
|
|
#elsif ( index( $ua, 'maxthon' ) != -1 ) { |
754
|
|
|
|
|
|
|
# $browser_string = 'Maxthon'; |
755
|
|
|
|
|
|
|
#} |
756
|
|
|
|
|
|
|
} |
757
|
|
|
|
|
|
|
elsif ( index( $ua, 'brave' ) != -1 ) { |
758
|
|
|
|
|
|
|
|
759
|
|
|
|
|
|
|
# Has to go above Chrome, it includes 'like Chrome/' |
760
|
|
|
|
|
|
|
|
761
|
12
|
|
|
|
|
22
|
$browser = 'brave'; |
762
|
12
|
|
|
|
|
26
|
$browser_tests->{$browser} = 1; |
763
|
|
|
|
|
|
|
} |
764
|
|
|
|
|
|
|
elsif ( index( $ua, 'silk' ) != -1 ) { |
765
|
|
|
|
|
|
|
|
766
|
|
|
|
|
|
|
# Has to go above Chrome, it includes 'like Chrome/' |
767
|
|
|
|
|
|
|
|
768
|
72
|
|
|
|
|
127
|
$browser = 'silk'; |
769
|
72
|
|
|
|
|
141
|
$browser_tests->{$browser} = 1; |
770
|
|
|
|
|
|
|
} |
771
|
|
|
|
|
|
|
elsif ( index( $ua, 'samsungbrowser' ) != -1 ) { |
772
|
|
|
|
|
|
|
|
773
|
|
|
|
|
|
|
# Has to go above Chrome, it includes 'Chrome/' |
774
|
6
|
|
|
|
|
11
|
$browser = 'samsung'; |
775
|
6
|
|
|
|
|
12
|
$browser_tests->{$browser} = 1; |
776
|
|
|
|
|
|
|
} |
777
|
|
|
|
|
|
|
elsif ( index( $ua, 'ucbrowser' ) != -1 ) { |
778
|
|
|
|
|
|
|
|
779
|
|
|
|
|
|
|
# Has to go above Safari, Mozilla and Chrome |
780
|
|
|
|
|
|
|
|
781
|
336
|
|
|
|
|
659
|
$browser = 'ucbrowser'; |
782
|
336
|
|
|
|
|
654
|
$browser_tests->{$browser} = 1; |
783
|
|
|
|
|
|
|
} |
784
|
|
|
|
|
|
|
elsif (index( $ua, 'chrome/' ) != -1 |
785
|
|
|
|
|
|
|
|| index( $ua, 'crios' ) != -1 ) { |
786
|
|
|
|
|
|
|
|
787
|
|
|
|
|
|
|
# Browser is Chrome |
788
|
|
|
|
|
|
|
|
789
|
1362
|
|
|
|
|
2426
|
$browser = 'chrome'; |
790
|
1362
|
|
|
|
|
2075
|
$browser_tests->{chrome} = 1; |
791
|
|
|
|
|
|
|
|
792
|
1362
|
100
|
|
|
|
3224
|
if ( index( $ua, 'chromium' ) != -1 ) { |
793
|
12
|
|
|
|
|
16
|
$browser_string = 'Chromium'; |
794
|
|
|
|
|
|
|
} |
795
|
|
|
|
|
|
|
} |
796
|
|
|
|
|
|
|
elsif (index( $ua, 'blackberry' ) != -1 |
797
|
|
|
|
|
|
|
|| index( $ua, 'bb10' ) != -1 |
798
|
|
|
|
|
|
|
|| index( $ua, 'rim tablet os' ) != -1 ) { |
799
|
|
|
|
|
|
|
|
800
|
|
|
|
|
|
|
# Has to go above Safari |
801
|
42
|
|
|
|
|
71
|
$browser = 'blackberry'; # test gets set during device check |
802
|
|
|
|
|
|
|
} |
803
|
|
|
|
|
|
|
elsif (( index( $ua, 'safari' ) != -1 ) |
804
|
|
|
|
|
|
|
|| ( index( $ua, 'applewebkit' ) != -1 ) ) { |
805
|
|
|
|
|
|
|
|
806
|
|
|
|
|
|
|
# Browser is Safari |
807
|
|
|
|
|
|
|
|
808
|
972
|
|
|
|
|
1954
|
$browser_tests->{safari} = 1; |
809
|
972
|
|
|
|
|
1440
|
$browser = 'safari'; |
810
|
972
|
100
|
100
|
|
|
4073
|
if ( index( $ua, ' mobile safari/' ) != -1 |
811
|
|
|
|
|
|
|
|| index( $ua, 'mobilesafari' ) != -1 ) { |
812
|
276
|
|
|
|
|
414
|
$browser_string = 'Mobile Safari'; |
813
|
276
|
|
|
|
|
426
|
$browser_tests->{mobile_safari} = 1; |
814
|
|
|
|
|
|
|
} |
815
|
972
|
100
|
|
|
|
2313
|
if ( index( $ua, 'puffin' ) != -1 ) { |
816
|
18
|
|
|
|
|
30
|
$browser_string = 'Puffin'; |
817
|
|
|
|
|
|
|
} |
818
|
|
|
|
|
|
|
} |
819
|
|
|
|
|
|
|
elsif ( index( $ua, 'neoplanet' ) != -1 ) { |
820
|
|
|
|
|
|
|
|
821
|
|
|
|
|
|
|
# Browser is Neoplanet |
822
|
|
|
|
|
|
|
|
823
|
0
|
|
|
|
|
0
|
$browser = 'ie'; |
824
|
0
|
|
|
|
|
0
|
$browser_tests->{$browser} = 1; |
825
|
0
|
|
|
|
|
0
|
$browser_tests->{neoplanet} = 1; |
826
|
0
|
0
|
|
|
|
0
|
$browser_tests->{neoplanet2} = 1 if ( index( $ua, '2.' ) != -1 ); |
827
|
|
|
|
|
|
|
} |
828
|
|
|
|
|
|
|
|
829
|
|
|
|
|
|
|
## The following browsers all need to be tested for *before* |
830
|
|
|
|
|
|
|
## Mozilla, otherwise we'll think they are Mozilla because they |
831
|
|
|
|
|
|
|
## look very much like it. |
832
|
|
|
|
|
|
|
elsif ( index( $ua, 'webtv' ) != -1 ) { |
833
|
0
|
|
|
|
|
0
|
$browser = 'webtv'; |
834
|
0
|
|
|
|
|
0
|
$browser_tests->{$browser} = 1; |
835
|
|
|
|
|
|
|
} |
836
|
|
|
|
|
|
|
elsif ( index( $ua, 'nintendo 3ds' ) != -1 ) { |
837
|
6
|
|
|
|
|
12
|
$browser = 'n3ds'; # Test gets set during device check |
838
|
|
|
|
|
|
|
} |
839
|
|
|
|
|
|
|
elsif ( index( $ua, 'nintendo dsi' ) != -1 ) { |
840
|
0
|
|
|
|
|
0
|
$browser = 'dsi'; # Test gets set during device check |
841
|
|
|
|
|
|
|
} |
842
|
|
|
|
|
|
|
elsif (index( $ua, 'playstation 3' ) != -1 |
843
|
|
|
|
|
|
|
|| index( $ua, 'playstation portable' ) != -1 |
844
|
|
|
|
|
|
|
|| index( $ua, 'netfront' ) != -1 ) { |
845
|
42
|
|
|
|
|
81
|
$browser = 'netfront'; |
846
|
42
|
|
|
|
|
87
|
$browser_tests->{$browser} = 1; |
847
|
|
|
|
|
|
|
} |
848
|
|
|
|
|
|
|
elsif ( index( $ua, 'browsex' ) != -1 ) { |
849
|
6
|
|
|
|
|
16
|
$browser = 'browsex'; |
850
|
6
|
|
|
|
|
13
|
$browser_tests->{$browser} = 1; |
851
|
|
|
|
|
|
|
} |
852
|
|
|
|
|
|
|
elsif ( index( $ua, 'polaris' ) != -1 ) { |
853
|
18
|
|
|
|
|
37
|
$browser = 'polaris'; |
854
|
18
|
|
|
|
|
38
|
$browser_tests->{$browser} = 1; |
855
|
|
|
|
|
|
|
} |
856
|
|
|
|
|
|
|
|
857
|
|
|
|
|
|
|
## At this point if it looks like Mozilla but we haven't found |
858
|
|
|
|
|
|
|
## anything else for it to be, it's probably Mozilla. |
859
|
|
|
|
|
|
|
elsif (index( $ua, 'mozilla' ) != -1 |
860
|
|
|
|
|
|
|
&& index( $ua, 'compatible' ) == -1 ) { |
861
|
|
|
|
|
|
|
|
862
|
|
|
|
|
|
|
# Browser is a Gecko-powered Netscape (i.e. Mozilla) version |
863
|
|
|
|
|
|
|
|
864
|
168
|
|
|
|
|
336
|
$browser = 'mozilla'; |
865
|
168
|
100
|
100
|
|
|
1154
|
if ( index( $ua, 'netscape' ) != -1 |
|
|
100
|
|
|
|
|
|
866
|
|
|
|
|
|
|
|| !$tests->{gecko} ) { |
867
|
108
|
|
|
|
|
189
|
$browser = 'netscape'; |
868
|
|
|
|
|
|
|
} |
869
|
|
|
|
|
|
|
elsif ( index( $ua, 'seamonkey' ) != -1 ) { |
870
|
6
|
|
|
|
|
10
|
$browser = 'seamonkey'; |
871
|
|
|
|
|
|
|
} |
872
|
168
|
|
|
|
|
345
|
$browser_tests->{$browser} = 1; |
873
|
168
|
|
|
|
|
274
|
$browser_tests->{netscape} = 1; |
874
|
168
|
|
|
|
|
284
|
$browser_tests->{mozilla} = ( $tests->{gecko} ); |
875
|
|
|
|
|
|
|
} |
876
|
|
|
|
|
|
|
|
877
|
|
|
|
|
|
|
## Long series of unlikely browsers (ones that don't look like Mozilla) |
878
|
|
|
|
|
|
|
elsif ( index( $ua, 'staroffice' ) != -1 ) { |
879
|
12
|
|
|
|
|
27
|
$browser = 'staroffice'; |
880
|
12
|
|
|
|
|
35
|
$browser_tests->{$browser} = 1; |
881
|
|
|
|
|
|
|
} |
882
|
|
|
|
|
|
|
elsif ( index( $ua, 'icab' ) != -1 ) { |
883
|
6
|
|
|
|
|
9
|
$browser = 'icab'; |
884
|
6
|
|
|
|
|
99
|
$browser_tests->{$browser} = 1; |
885
|
|
|
|
|
|
|
} |
886
|
|
|
|
|
|
|
elsif ( index( $ua, 'lotus-notes' ) != -1 ) { |
887
|
6
|
|
|
|
|
16
|
$browser = 'lotusnotes'; |
888
|
6
|
|
|
|
|
16
|
$browser_tests->{$browser} = 1; |
889
|
|
|
|
|
|
|
} |
890
|
|
|
|
|
|
|
elsif ( index( $ua, 'konqueror' ) != -1 ) { |
891
|
24
|
|
|
|
|
63
|
$browser = 'konqueror'; |
892
|
24
|
|
|
|
|
53
|
$browser_tests->{$browser} = 1; |
893
|
|
|
|
|
|
|
} |
894
|
|
|
|
|
|
|
elsif ( index( $ua, 'lynx' ) != -1 ) { |
895
|
6
|
|
|
|
|
15
|
$browser = 'lynx'; |
896
|
6
|
|
|
|
|
15
|
$browser_tests->{$browser} = 1; |
897
|
|
|
|
|
|
|
} |
898
|
|
|
|
|
|
|
elsif ( index( $ua, 'elinks' ) != -1 ) { |
899
|
6
|
|
|
|
|
14
|
$browser = 'elinks'; |
900
|
6
|
|
|
|
|
15
|
$browser_tests->{$browser} = 1; |
901
|
|
|
|
|
|
|
} |
902
|
|
|
|
|
|
|
elsif ( index( $ua, 'links' ) != -1 ) { |
903
|
12
|
|
|
|
|
29
|
$browser = 'links'; |
904
|
12
|
|
|
|
|
38
|
$browser_tests->{$browser} = 1; |
905
|
|
|
|
|
|
|
} |
906
|
|
|
|
|
|
|
elsif ( index( $ua, 'mosaic' ) != -1 ) { |
907
|
0
|
|
|
|
|
0
|
$browser = 'mosaic'; |
908
|
0
|
|
|
|
|
0
|
$browser_tests->{$browser} = 1; |
909
|
|
|
|
|
|
|
} |
910
|
|
|
|
|
|
|
elsif ( index( $ua, 'emacs' ) != -1 ) { |
911
|
6
|
|
|
|
|
12
|
$browser = 'emacs'; |
912
|
6
|
|
|
|
|
14
|
$browser_tests->{$browser} = 1; |
913
|
|
|
|
|
|
|
} |
914
|
|
|
|
|
|
|
elsif ( index( $ua, 'obigo' ) != -1 ) { |
915
|
30
|
|
|
|
|
61
|
$browser = 'obigo'; |
916
|
30
|
|
|
|
|
72
|
$browser_tests->{$browser} = 1; |
917
|
|
|
|
|
|
|
} |
918
|
|
|
|
|
|
|
elsif ( index( $ua, 'teleca' ) != -1 ) { |
919
|
54
|
|
|
|
|
118
|
$browser = 'obigo'; |
920
|
54
|
|
|
|
|
98
|
$browser_string = 'Teleca'; |
921
|
54
|
|
|
|
|
134
|
$browser_tests->{$browser} = 1; |
922
|
|
|
|
|
|
|
} |
923
|
|
|
|
|
|
|
elsif ( index( $ua, 'libcurl' ) != -1 || $ua =~ /^curl/ ) { |
924
|
36
|
|
|
|
|
82
|
$browser = 'curl'; # Test gets set during robot check |
925
|
|
|
|
|
|
|
} |
926
|
|
|
|
|
|
|
elsif ( index( $ua, 'puf/' ) != -1 ) { |
927
|
6
|
|
|
|
|
14
|
$browser = 'puf'; # Test gets set during robot check |
928
|
|
|
|
|
|
|
} |
929
|
|
|
|
|
|
|
elsif ( index( $ua, 'applecoremedia/' ) != -1 ) { |
930
|
6
|
|
|
|
|
19
|
$browser = 'applecoremedia'; |
931
|
6
|
|
|
|
|
15
|
$browser_tests->{$browser} = 1; |
932
|
|
|
|
|
|
|
} |
933
|
|
|
|
|
|
|
elsif ( index( $ua, 'androiddownloadmanager' ) != -1 ) { |
934
|
6
|
|
|
|
|
11
|
$browser = 'adm'; |
935
|
6
|
|
|
|
|
12
|
$browser_tests->{$browser} = 1; |
936
|
|
|
|
|
|
|
} |
937
|
|
|
|
|
|
|
elsif ( index( $ua, 'dalvik' ) != -1 ) { |
938
|
12
|
|
|
|
|
24
|
$browser = 'dalvik'; |
939
|
12
|
|
|
|
|
26
|
$browser_tests->{$browser} = 1; |
940
|
|
|
|
|
|
|
} |
941
|
|
|
|
|
|
|
elsif ( index( $ua, 'apple-pubsub' ) != -1 ) { |
942
|
6
|
|
|
|
|
11
|
$browser = 'pubsub'; |
943
|
6
|
|
|
|
|
17
|
$browser_tests->{$browser} = 1; |
944
|
|
|
|
|
|
|
} |
945
|
|
|
|
|
|
|
elsif ( index( $ua, 'imagesearcherpro' ) != -1 ) { |
946
|
6
|
|
|
|
|
13
|
$browser = 'imagesearcherpro'; |
947
|
6
|
|
|
|
|
17
|
$browser_tests->{$browser} = 1; |
948
|
|
|
|
|
|
|
} |
949
|
|
|
|
|
|
|
|
950
|
7151
|
|
|
|
|
13829
|
$self->{browser} = $browser; |
951
|
7151
|
100
|
100
|
|
|
27076
|
$self->{browser_string} = $browser_string || $BROWSER_NAMES{$browser} |
952
|
|
|
|
|
|
|
if defined $browser; |
953
|
|
|
|
|
|
|
|
954
|
|
|
|
|
|
|
# Other random tests |
955
|
|
|
|
|
|
|
|
956
|
7151
|
100
|
|
|
|
17155
|
$tests->{x11} = 1 if index( $ua, 'x11' ) != -1; |
957
|
7151
|
100
|
|
|
|
16111
|
$tests->{dotnet} = 1 if index( $ua, '.net clr' ) != -1; |
958
|
|
|
|
|
|
|
|
959
|
7151
|
100
|
|
|
|
14990
|
if ( index( $ua, 'realplayer' ) != -1 ) { |
960
|
|
|
|
|
|
|
|
961
|
|
|
|
|
|
|
# Hack for Realplayer -- fix the version and 'real' browser |
962
|
|
|
|
|
|
|
|
963
|
18
|
|
|
|
|
72
|
$self->_init_version; # Set appropriate tests for whatever the 'real' |
964
|
|
|
|
|
|
|
# browser is. |
965
|
|
|
|
|
|
|
|
966
|
|
|
|
|
|
|
# Now set the browser to Realplayer. |
967
|
18
|
|
|
|
|
37
|
$self->{browser} = 'realplayer'; |
968
|
18
|
|
|
|
|
34
|
$self->{browser_string} = 'RealPlayer'; |
969
|
18
|
|
|
|
|
35
|
$browser_tests->{realplayer} = 1; |
970
|
|
|
|
|
|
|
|
971
|
|
|
|
|
|
|
# Now override the version with the Realplayer version (but leave |
972
|
|
|
|
|
|
|
# alone the tests we already set, which might have been based on the |
973
|
|
|
|
|
|
|
# 'real' browser's version). |
974
|
18
|
|
|
|
|
40
|
$self->{realplayer_version} = undef; |
975
|
|
|
|
|
|
|
|
976
|
18
|
100
|
|
|
|
98
|
if ( $ua =~ /realplayer\/([\d+\.]+)/ ) { |
|
|
50
|
|
|
|
|
|
977
|
12
|
|
|
|
|
37
|
$self->{realplayer_version} = $1; |
978
|
|
|
|
|
|
|
( $self->{major}, $self->{minor} ) |
979
|
12
|
|
|
|
|
47
|
= split( /\./, $self->{realplayer_version} ); |
980
|
12
|
50
|
|
|
|
59
|
$self->{minor} = ".$self->{minor}" if defined $self->{minor}; |
981
|
|
|
|
|
|
|
} |
982
|
|
|
|
|
|
|
elsif ( $ua =~ /realplayer\s(\w+)/ ) { |
983
|
6
|
|
|
|
|
21
|
$self->{realplayer_version} = $1; |
984
|
|
|
|
|
|
|
} |
985
|
|
|
|
|
|
|
} |
986
|
|
|
|
|
|
|
|
987
|
7151
|
100
|
|
|
|
16949
|
if ( index( $ua, '(r1 ' ) != -1 ) { |
988
|
|
|
|
|
|
|
|
989
|
|
|
|
|
|
|
# Realplayer plugin -- don't override browser but do set property |
990
|
18
|
|
|
|
|
54
|
$browser_tests->{realplayer} = 1; |
991
|
|
|
|
|
|
|
} |
992
|
|
|
|
|
|
|
|
993
|
|
|
|
|
|
|
# Details: https://developer.chrome.com/multidevice/user-agent#webview_user_agent |
994
|
7151
|
100
|
100
|
|
|
16566
|
if ( ( $self->android && index( $ua, '; wv)' ) > 0 ) |
|
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
995
|
|
|
|
|
|
|
|| ( $self->chrome && $self->android && $self->browser_major >= 30 ) ) |
996
|
|
|
|
|
|
|
{ |
997
|
456
|
|
|
|
|
980
|
$tests->{webview} = 1; |
998
|
|
|
|
|
|
|
} |
999
|
|
|
|
|
|
|
|
1000
|
|
|
|
|
|
|
} |
1001
|
|
|
|
|
|
|
|
1002
|
|
|
|
|
|
|
# Any of these fragments within a user-agent generally indicates it's |
1003
|
|
|
|
|
|
|
# a robot. |
1004
|
|
|
|
|
|
|
my @ROBOT_FRAGMENTS = qw( |
1005
|
|
|
|
|
|
|
agent |
1006
|
|
|
|
|
|
|
analy |
1007
|
|
|
|
|
|
|
appender |
1008
|
|
|
|
|
|
|
babya |
1009
|
|
|
|
|
|
|
checker |
1010
|
|
|
|
|
|
|
bot |
1011
|
|
|
|
|
|
|
copy |
1012
|
|
|
|
|
|
|
crawl |
1013
|
|
|
|
|
|
|
explorador |
1014
|
|
|
|
|
|
|
fetch |
1015
|
|
|
|
|
|
|
find |
1016
|
|
|
|
|
|
|
ia_archive |
1017
|
|
|
|
|
|
|
index |
1018
|
|
|
|
|
|
|
netcraft |
1019
|
|
|
|
|
|
|
reap |
1020
|
|
|
|
|
|
|
resolver |
1021
|
|
|
|
|
|
|
sleuth |
1022
|
|
|
|
|
|
|
scan |
1023
|
|
|
|
|
|
|
service |
1024
|
|
|
|
|
|
|
spider |
1025
|
|
|
|
|
|
|
thumbtack-thunderdome |
1026
|
|
|
|
|
|
|
tiscali |
1027
|
|
|
|
|
|
|
validator |
1028
|
|
|
|
|
|
|
verif |
1029
|
|
|
|
|
|
|
webcapture |
1030
|
|
|
|
|
|
|
worm |
1031
|
|
|
|
|
|
|
zyborg |
1032
|
|
|
|
|
|
|
); |
1033
|
|
|
|
|
|
|
|
1034
|
|
|
|
|
|
|
my %ROBOT_FRAGMENT_EXCEPTIONS = ( |
1035
|
|
|
|
|
|
|
bot => ['cubot'], |
1036
|
|
|
|
|
|
|
); |
1037
|
|
|
|
|
|
|
|
1038
|
|
|
|
|
|
|
sub _init_robots { |
1039
|
8652
|
|
|
8652
|
|
12003
|
my $self = shift; |
1040
|
|
|
|
|
|
|
|
1041
|
8652
|
|
|
|
|
18781
|
my $ua = lc $self->{user_agent}; |
1042
|
8652
|
|
|
|
|
13159
|
my $tests = $self->{tests}; |
1043
|
8652
|
|
|
|
|
13452
|
my $browser_tests = $self->{browser_tests}; |
1044
|
|
|
|
|
|
|
|
1045
|
8652
|
|
|
|
|
19575
|
my $robot_tests = $self->{robot_tests} = {}; |
1046
|
8652
|
|
|
|
|
18183
|
my $id; |
1047
|
|
|
|
|
|
|
my $r; |
1048
|
|
|
|
|
|
|
|
1049
|
8652
|
|
|
|
|
0
|
my $robot_fragment; # The text that indicates it's a robot (we'll |
1050
|
|
|
|
|
|
|
# use this later to detect robot version, and |
1051
|
|
|
|
|
|
|
# maybe robot_string) |
1052
|
|
|
|
|
|
|
|
1053
|
8652
|
100
|
66
|
|
|
324703
|
if ( index( $ua, 'libwww-perl' ) != -1 || index( $ua, 'lwp-' ) != -1 ) { |
|
|
100
|
100
|
|
|
|
|
|
|
100
|
100
|
|
|
|
|
|
|
100
|
100
|
|
|
|
|
|
|
50
|
100
|
|
|
|
|
|
|
100
|
66
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
1054
|
18
|
|
|
|
|
36
|
$r = 'lwp'; |
1055
|
18
|
|
|
|
|
35
|
$robot_tests->{lib} = 1; |
1056
|
18
|
50
|
|
|
|
52
|
$robot_fragment = ( |
1057
|
|
|
|
|
|
|
( index( $ua, 'libwww-perl' ) != -1 ) ? 'libwww-perl' : 'lwp-' ); |
1058
|
|
|
|
|
|
|
} |
1059
|
|
|
|
|
|
|
elsif ( index( $ua, 'slurp' ) != -1 ) { |
1060
|
12
|
|
|
|
|
22
|
$r = 'slurp'; |
1061
|
12
|
|
|
|
|
34
|
$robot_tests->{yahoo} = 1; |
1062
|
|
|
|
|
|
|
} |
1063
|
|
|
|
|
|
|
elsif (index( $ua, 'yahoo' ) != -1 |
1064
|
|
|
|
|
|
|
&& index( $ua, 'jp.co.yahoo' ) == -1 ) { |
1065
|
6
|
|
|
|
|
12
|
$r = 'yahoo'; |
1066
|
|
|
|
|
|
|
} |
1067
|
|
|
|
|
|
|
elsif ( index( $ua, 'msnbot-mobile' ) != -1 ) { |
1068
|
6
|
|
|
|
|
16
|
$r = 'msnmobile'; |
1069
|
6
|
|
|
|
|
12
|
$robot_tests->{msn} = 1; |
1070
|
6
|
|
|
|
|
11
|
$robot_fragment = 'msnbot'; |
1071
|
|
|
|
|
|
|
} |
1072
|
|
|
|
|
|
|
elsif ( index( $ua, 'bingbot-mobile' ) != -1 ) { |
1073
|
0
|
|
|
|
|
0
|
$r = 'bingbot'; |
1074
|
0
|
|
|
|
|
0
|
$robot_tests->{bingbot} = 1; |
1075
|
0
|
|
|
|
|
0
|
$robot_fragment = 'bingbot'; |
1076
|
|
|
|
|
|
|
} |
1077
|
|
|
|
|
|
|
elsif ( index( $ua, 'msnbot' ) != -1 ) { |
1078
|
6
|
|
|
|
|
13
|
$r = 'msn'; |
1079
|
6
|
|
|
|
|
11
|
$robot_fragment = 'msnbot'; |
1080
|
|
|
|
|
|
|
} |
1081
|
|
|
|
|
|
|
elsif (index( $ua, 'binglocalsearch' ) != -1 |
1082
|
|
|
|
|
|
|
|| index( $ua, 'bingbot' ) != -1 |
1083
|
|
|
|
|
|
|
|| index( $ua, 'bingpreview' ) != -1 ) { |
1084
|
30
|
|
|
|
|
59
|
$r = 'bingbot'; |
1085
|
30
|
|
|
|
|
66
|
$robot_tests->{bingbot} = 1; |
1086
|
30
|
|
|
|
|
56
|
$robot_fragment = 'bingbot'; |
1087
|
|
|
|
|
|
|
} |
1088
|
|
|
|
|
|
|
elsif ( index( $ua, 'microsoft office existence discovery' ) != -1 ) { |
1089
|
6
|
|
|
|
|
12
|
$r = 'msoffice'; |
1090
|
6
|
|
|
|
|
12
|
$robot_fragment = 'office'; |
1091
|
|
|
|
|
|
|
} |
1092
|
|
|
|
|
|
|
elsif ( index( $ua, 'ahrefsbot' ) != -1 ) { |
1093
|
6
|
|
|
|
|
17
|
$r = 'ahrefs'; |
1094
|
|
|
|
|
|
|
} |
1095
|
|
|
|
|
|
|
elsif ( index( $ua, 'altavista' ) != -1 ) { |
1096
|
0
|
|
|
|
|
0
|
$r = 'altavista'; |
1097
|
|
|
|
|
|
|
} |
1098
|
|
|
|
|
|
|
elsif ( index( $ua, 'apache-httpclient' ) != -1 ) { |
1099
|
12
|
|
|
|
|
21
|
$r = 'apache'; |
1100
|
|
|
|
|
|
|
} |
1101
|
|
|
|
|
|
|
elsif ( $ua =~ m{\( *\) *\{ *\: *\; *} ) { |
1102
|
|
|
|
|
|
|
|
1103
|
|
|
|
|
|
|
# Shellcode for spawning a process, i.e. (){:;} with some kind of whitespace interleaved |
1104
|
6
|
|
|
|
|
13
|
$r = 'malware'; |
1105
|
|
|
|
|
|
|
} |
1106
|
|
|
|
|
|
|
elsif ( index( $ua, 'ask jeeves/teoma' ) != -1 ) { |
1107
|
0
|
|
|
|
|
0
|
$r = 'askjeeves'; |
1108
|
0
|
|
|
|
|
0
|
$robot_fragment = 'teoma'; |
1109
|
|
|
|
|
|
|
} |
1110
|
|
|
|
|
|
|
elsif ( index( $ua, 'baiduspider' ) != -1 ) { |
1111
|
18
|
|
|
|
|
31
|
$r = 'baidu'; |
1112
|
|
|
|
|
|
|
} |
1113
|
|
|
|
|
|
|
elsif ( index( $ua, 'libcurl' ) != -1 || $ua =~ /^curl/ ) { |
1114
|
36
|
|
|
|
|
66
|
$r = 'curl'; |
1115
|
36
|
|
|
|
|
71
|
$robot_tests->{lib} = 1; |
1116
|
|
|
|
|
|
|
} |
1117
|
|
|
|
|
|
|
elsif ( index( $ua, 'facebookexternalhit' ) != -1 ) { |
1118
|
6
|
|
|
|
|
12
|
$r = 'facebook'; |
1119
|
|
|
|
|
|
|
} |
1120
|
|
|
|
|
|
|
elsif ( index( $ua, 'getright' ) != -1 ) { |
1121
|
6
|
|
|
|
|
17
|
$r = 'getright'; |
1122
|
|
|
|
|
|
|
} |
1123
|
|
|
|
|
|
|
elsif ( index( $ua, 'adsbot-google' ) != -1 ) { |
1124
|
12
|
|
|
|
|
24
|
$r = 'googleadsbot'; |
1125
|
12
|
|
|
|
|
22
|
$robot_tests->{google} = 1; |
1126
|
12
|
|
|
|
|
19
|
$robot_fragment = 'adsbot-google'; |
1127
|
|
|
|
|
|
|
} |
1128
|
|
|
|
|
|
|
elsif ( index( $ua, 'mediapartners-google' ) != -1 ) { |
1129
|
6
|
|
|
|
|
11
|
$r = 'googleadsense'; |
1130
|
6
|
|
|
|
|
14
|
$robot_tests->{google} = 1; |
1131
|
6
|
|
|
|
|
12
|
$robot_fragment = 'mediapartners-google'; |
1132
|
|
|
|
|
|
|
} |
1133
|
|
|
|
|
|
|
elsif ( index( $ua, 'google favicon' ) != -1 ) { |
1134
|
6
|
|
|
|
|
13
|
$r = 'googlefavicon'; |
1135
|
6
|
|
|
|
|
13
|
$robot_tests->{google} = 1; |
1136
|
6
|
|
|
|
|
11
|
$robot_fragment = 'favicon'; |
1137
|
|
|
|
|
|
|
} |
1138
|
|
|
|
|
|
|
elsif ( index( $ua, 'googlebot-image' ) != -1 ) { |
1139
|
6
|
|
|
|
|
54
|
$r = 'googlebotimage'; |
1140
|
6
|
|
|
|
|
17
|
$robot_tests->{google} = 1; |
1141
|
6
|
|
|
|
|
14
|
$robot_fragment = 'googlebot-image'; |
1142
|
|
|
|
|
|
|
} |
1143
|
|
|
|
|
|
|
elsif ( index( $ua, 'googlebot-news' ) != -1 ) { |
1144
|
6
|
|
|
|
|
12
|
$r = 'googlebotnews'; |
1145
|
6
|
|
|
|
|
19
|
$robot_tests->{google} = 1; |
1146
|
6
|
|
|
|
|
15
|
$robot_fragment = 'googlebot-news'; |
1147
|
|
|
|
|
|
|
} |
1148
|
|
|
|
|
|
|
elsif ( index( $ua, 'googlebot-video' ) != -1 ) { |
1149
|
6
|
|
|
|
|
16
|
$r = 'googlebotvideo'; |
1150
|
6
|
|
|
|
|
15
|
$robot_tests->{google} = 1; |
1151
|
6
|
|
|
|
|
13
|
$robot_fragment = 'googlebot-video'; |
1152
|
|
|
|
|
|
|
} |
1153
|
|
|
|
|
|
|
elsif ( index( $ua, 'googlebot-mobile' ) != -1 ) { |
1154
|
18
|
|
|
|
|
38
|
$r = 'googlemobile'; |
1155
|
18
|
|
|
|
|
41
|
$robot_tests->{google} = 1; |
1156
|
18
|
|
|
|
|
31
|
$robot_fragment = 'googlebot-mobile'; |
1157
|
|
|
|
|
|
|
} |
1158
|
|
|
|
|
|
|
elsif ( index( $ua, 'googlebot' ) != -1 ) { |
1159
|
36
|
|
|
|
|
72
|
$r = 'google'; |
1160
|
|
|
|
|
|
|
} |
1161
|
|
|
|
|
|
|
elsif ( $ua =~ m{go.*package http} ) { |
1162
|
6
|
|
|
|
|
13
|
$r = 'golib'; |
1163
|
6
|
|
|
|
|
15
|
$robot_tests->{lib} = 1; |
1164
|
6
|
|
|
|
|
13
|
$robot_fragment = 'package'; |
1165
|
|
|
|
|
|
|
} |
1166
|
|
|
|
|
|
|
elsif ( $ua =~ m{^http_request} ) { |
1167
|
6
|
|
|
|
|
16
|
$r = 'phplib'; |
1168
|
6
|
|
|
|
|
17
|
$robot_tests->{lib} = 1; |
1169
|
6
|
|
|
|
|
14
|
$robot_fragment = 'http_request'; |
1170
|
|
|
|
|
|
|
} |
1171
|
|
|
|
|
|
|
elsif ( $ua =~ m{^http_request} ) { |
1172
|
0
|
|
|
|
|
0
|
$r = 'phplib'; |
1173
|
0
|
|
|
|
|
0
|
$robot_tests->{lib} = 1; |
1174
|
|
|
|
|
|
|
} |
1175
|
|
|
|
|
|
|
elsif ( index( $ua, 'indy library' ) != -1 ) { |
1176
|
6
|
|
|
|
|
14
|
$r = 'indy'; |
1177
|
6
|
|
|
|
|
17
|
$robot_tests->{lib} = 1; |
1178
|
|
|
|
|
|
|
} |
1179
|
|
|
|
|
|
|
elsif ( index( $ua, 'infoseek' ) != -1 ) { |
1180
|
0
|
|
|
|
|
0
|
$r = 'infoseek'; |
1181
|
|
|
|
|
|
|
} |
1182
|
|
|
|
|
|
|
elsif ( index( $ua, 'ips-agent' ) != -1 ) { |
1183
|
6
|
|
|
|
|
11
|
$r = 'ipsagent'; |
1184
|
6
|
|
|
|
|
9
|
$robot_fragment = 'ips-agent'; |
1185
|
|
|
|
|
|
|
} |
1186
|
|
|
|
|
|
|
elsif ( index( $ua, 'lecodechecker' ) != -1 ) { |
1187
|
0
|
|
|
|
|
0
|
$r = 'linkexchange'; |
1188
|
0
|
|
|
|
|
0
|
$robot_fragment = 'lecodechecker'; |
1189
|
|
|
|
|
|
|
} |
1190
|
|
|
|
|
|
|
elsif ( index( $ua, 'linkchecker' ) != -1 ) { |
1191
|
11
|
|
|
|
|
28
|
$r = 'linkchecker'; |
1192
|
|
|
|
|
|
|
} |
1193
|
|
|
|
|
|
|
elsif ( index( $ua, 'lycos' ) != -1 ) { |
1194
|
0
|
|
|
|
|
0
|
$r = 'lycos'; |
1195
|
|
|
|
|
|
|
} |
1196
|
|
|
|
|
|
|
elsif ( index( $ua, 'mechanize' ) != -1 ) { |
1197
|
12
|
|
|
|
|
24
|
$r = 'rubylib'; |
1198
|
12
|
|
|
|
|
27
|
$robot_tests->{lib} = 1; |
1199
|
12
|
|
|
|
|
20
|
$robot_fragment = 'mechanize'; |
1200
|
|
|
|
|
|
|
} |
1201
|
|
|
|
|
|
|
elsif ( index( $ua, 'mj12bot/' ) != -1 ) { |
1202
|
6
|
|
|
|
|
16
|
$r = 'mj12bot'; |
1203
|
|
|
|
|
|
|
} |
1204
|
|
|
|
|
|
|
elsif ( index( $ua, 'nutch' ) != -1 ) { |
1205
|
18
|
|
|
|
|
34
|
$r = 'nutch'; |
1206
|
|
|
|
|
|
|
} |
1207
|
|
|
|
|
|
|
elsif ( index( $ua, 'puf/' ) != -1 ) { |
1208
|
6
|
|
|
|
|
15
|
$r = 'puf'; |
1209
|
6
|
|
|
|
|
17
|
$robot_tests->{lib} = 1; |
1210
|
|
|
|
|
|
|
} |
1211
|
|
|
|
|
|
|
elsif ( index( $ua, 'scooter' ) != -1 ) { |
1212
|
0
|
|
|
|
|
0
|
$r = 'scooter'; |
1213
|
|
|
|
|
|
|
} |
1214
|
|
|
|
|
|
|
elsif ( index( $ua, 'special_archiver' ) != -1 ) { |
1215
|
6
|
|
|
|
|
16
|
$r = 'specialarchiver'; |
1216
|
6
|
|
|
|
|
14
|
$robot_fragment = 'special_archiver'; |
1217
|
|
|
|
|
|
|
} |
1218
|
|
|
|
|
|
|
elsif ( index( $ua, 'wget' ) == 0 ) { |
1219
|
12
|
|
|
|
|
22
|
$r = 'wget'; |
1220
|
|
|
|
|
|
|
} |
1221
|
|
|
|
|
|
|
elsif ( index( $ua, 'yandexbot' ) != -1 ) { |
1222
|
6
|
|
|
|
|
17
|
$r = 'yandex'; |
1223
|
|
|
|
|
|
|
} |
1224
|
|
|
|
|
|
|
elsif ( index( $ua, 'yandeximages' ) != -1 ) { |
1225
|
6
|
|
|
|
|
15
|
$r = 'yandeximages'; |
1226
|
|
|
|
|
|
|
} |
1227
|
|
|
|
|
|
|
elsif ( index( $ua, 'headlesschrome' ) != -1 ) { |
1228
|
6
|
|
|
|
|
17
|
$r = 'headlesschrome'; |
1229
|
|
|
|
|
|
|
} |
1230
|
|
|
|
|
|
|
elsif ( $ua =~ m{^java} && !$self->{browser} ) { |
1231
|
42
|
|
|
|
|
89
|
$r = 'java'; |
1232
|
42
|
|
|
|
|
108
|
$robot_tests->{lib} = 1; |
1233
|
|
|
|
|
|
|
} |
1234
|
|
|
|
|
|
|
elsif ( index( $ua, 'jdk' ) != -1 ) { |
1235
|
0
|
|
|
|
|
0
|
$r = 'java'; |
1236
|
0
|
|
|
|
|
0
|
$robot_tests->{lib} = 1; |
1237
|
0
|
|
|
|
|
0
|
$robot_fragment = 'jdk'; |
1238
|
|
|
|
|
|
|
} |
1239
|
|
|
|
|
|
|
elsif ( index( $ua, 'jakarta commons-httpclient' ) != -1 ) { |
1240
|
6
|
|
|
|
|
15
|
$r = 'java'; |
1241
|
6
|
|
|
|
|
17
|
$robot_tests->{lib} = 1; |
1242
|
6
|
|
|
|
|
13
|
$robot_fragment = 'jakarta'; |
1243
|
|
|
|
|
|
|
} |
1244
|
|
|
|
|
|
|
elsif ( index( $ua, 'google-http-java-client' ) != -1 ) { |
1245
|
6
|
|
|
|
|
17
|
$r = 'java'; |
1246
|
6
|
|
|
|
|
15
|
$robot_tests->{lib} = 1; |
1247
|
6
|
|
|
|
|
12
|
$robot_fragment = 'google'; |
1248
|
|
|
|
|
|
|
} |
1249
|
|
|
|
|
|
|
elsif ( index( $ua, 'researchscan.comsys.rwth-aachen.de' ) != -1 ) { |
1250
|
6
|
|
|
|
|
16
|
$r = 'researchscan'; |
1251
|
|
|
|
|
|
|
} |
1252
|
|
|
|
|
|
|
|
1253
|
|
|
|
|
|
|
# These @ROBOT_TESTS were added in 3.15. Some of them may need more |
1254
|
|
|
|
|
|
|
# individualized treatment, but get them identified as bots for now. |
1255
|
|
|
|
|
|
|
|
1256
|
|
|
|
|
|
|
# XXX |
1257
|
|
|
|
|
|
|
else { |
1258
|
|
|
|
|
|
|
TEST: |
1259
|
8209
|
|
|
|
|
20992
|
for my $set (@ROBOT_TESTS) { |
1260
|
245478
|
|
|
|
|
321798
|
my $match = lc $set->[0]; |
1261
|
|
|
|
|
|
|
|
1262
|
245478
|
100
|
|
|
|
454680
|
if ( index( $ua, lc($match) ) != -1 ) { |
1263
|
48
|
|
|
|
|
77
|
$id = $set->[1]; |
1264
|
48
|
|
|
|
|
101
|
$r = $id; |
1265
|
48
|
|
|
|
|
93
|
$robot_fragment = lc $match; |
1266
|
48
|
|
|
|
|
121
|
last TEST; |
1267
|
|
|
|
|
|
|
} |
1268
|
|
|
|
|
|
|
} |
1269
|
|
|
|
|
|
|
} |
1270
|
|
|
|
|
|
|
|
1271
|
8652
|
100
|
100
|
|
|
41210
|
if ( $browser_tests->{applecoremedia} |
|
|
|
100
|
|
|
|
|
1272
|
|
|
|
|
|
|
|| $browser_tests->{dalvik} |
1273
|
|
|
|
|
|
|
|| $browser_tests->{adm} ) { |
1274
|
29
|
|
|
|
|
67
|
$robot_tests->{lib} = 1; |
1275
|
|
|
|
|
|
|
} |
1276
|
|
|
|
|
|
|
|
1277
|
8652
|
100
|
|
|
|
47229
|
if ($r) { |
|
|
50
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
1278
|
|
|
|
|
|
|
|
1279
|
|
|
|
|
|
|
# Got a named robot |
1280
|
491
|
|
|
|
|
931
|
$robot_tests->{$r} = 1; |
1281
|
491
|
100
|
|
|
|
920
|
if ( !$id ) { |
1282
|
443
|
|
|
|
|
964
|
$id = $ROBOT_IDS{$r}; |
1283
|
|
|
|
|
|
|
} |
1284
|
|
|
|
|
|
|
|
1285
|
491
|
50
|
|
|
|
944
|
if ( !exists $robot_tests->{robot_id} ) { |
1286
|
491
|
|
|
|
|
834
|
$robot_tests->{robot_id} = $id; |
1287
|
|
|
|
|
|
|
} |
1288
|
|
|
|
|
|
|
|
1289
|
|
|
|
|
|
|
# This isn't all keyed on ids (yet) |
1290
|
491
|
|
33
|
|
|
1638
|
$self->{robot_string} = $ROBOT_NAMES{$id} || $ROBOT_NAMES{$r}; |
1291
|
491
|
|
|
|
|
783
|
$robot_tests->{robot} = $r; |
1292
|
491
|
100
|
|
|
|
1038
|
$robot_fragment = $r if !defined $robot_fragment; |
1293
|
|
|
|
|
|
|
} |
1294
|
|
|
|
|
|
|
elsif ( $ua =~ /seek (?! mo (?: toolbar )? \s+ \d+\.\d+ )/x ) { |
1295
|
|
|
|
|
|
|
|
1296
|
|
|
|
|
|
|
# Store the fragment for later, to determine full name |
1297
|
0
|
|
|
|
|
0
|
$robot_fragment = 'seek'; |
1298
|
0
|
|
|
|
|
0
|
$robot_tests->{robot} = 'unknown'; |
1299
|
|
|
|
|
|
|
} |
1300
|
|
|
|
|
|
|
elsif ( $ua =~ /search (?! [\w\s]* toolbar \b | bar \b | erpro \b )/x ) { |
1301
|
|
|
|
|
|
|
|
1302
|
|
|
|
|
|
|
# Store the fragment for later, to determine full name |
1303
|
42
|
|
|
|
|
91
|
$robot_fragment = 'search'; |
1304
|
42
|
|
|
|
|
107
|
$robot_tests->{robot} = 'unknown'; |
1305
|
|
|
|
|
|
|
} |
1306
|
|
|
|
|
|
|
elsif ( $self->{user_agent} =~ /([\w \/\.\-]+)[ \;\(\)]*\+https?\:/i ) { |
1307
|
|
|
|
|
|
|
|
1308
|
|
|
|
|
|
|
# Something followed by +http |
1309
|
245
|
|
|
|
|
1016
|
$self->{robot_string} = $1; |
1310
|
245
|
|
|
|
|
2203
|
$self->{robot_string} =~ s/^ *(.+?)[ \;\(\)]*?( *\/[\d\.]+ *)?$/$1/; |
1311
|
245
|
|
|
|
|
632
|
$robot_fragment = $1; |
1312
|
245
|
|
|
|
|
564
|
$robot_tests->{robot} = 'unknown'; |
1313
|
|
|
|
|
|
|
} |
1314
|
|
|
|
|
|
|
else { |
1315
|
|
|
|
|
|
|
# See if we have a simple fragment |
1316
|
|
|
|
|
|
|
FRAGMENT: |
1317
|
7874
|
|
|
|
|
14805
|
for my $fragment (@ROBOT_FRAGMENTS) { |
1318
|
207487
|
100
|
|
|
|
299250
|
if ( $ROBOT_FRAGMENT_EXCEPTIONS{$fragment} ) { |
1319
|
7832
|
|
|
|
|
10723
|
for my $exception ( |
1320
|
7832
|
50
|
|
|
|
20019
|
@{ $ROBOT_FRAGMENT_EXCEPTIONS{$fragment} || [] } ) { |
1321
|
7832
|
100
|
|
|
|
19420
|
if ( index( $ua, $exception ) != -1 ) { |
1322
|
7
|
|
|
|
|
18
|
next FRAGMENT; |
1323
|
|
|
|
|
|
|
} |
1324
|
|
|
|
|
|
|
} |
1325
|
|
|
|
|
|
|
} |
1326
|
|
|
|
|
|
|
|
1327
|
207480
|
100
|
|
|
|
356838
|
if ( index( $ua, $fragment ) != -1 ) { |
1328
|
311
|
|
|
|
|
557
|
$robot_fragment = $fragment; |
1329
|
311
|
|
|
|
|
629
|
$robot_tests->{robot} = 'unknown'; |
1330
|
311
|
|
|
|
|
581
|
last; |
1331
|
|
|
|
|
|
|
} |
1332
|
|
|
|
|
|
|
} |
1333
|
|
|
|
|
|
|
} |
1334
|
|
|
|
|
|
|
|
1335
|
8652
|
100
|
100
|
|
|
24687
|
if ( exists $robot_tests->{robot} && $robot_tests->{robot} eq 'unknown' ) |
1336
|
|
|
|
|
|
|
{ |
1337
|
598
|
|
|
|
|
1320
|
$robot_tests->{robot_id} = 'unknown'; |
1338
|
|
|
|
|
|
|
} |
1339
|
|
|
|
|
|
|
|
1340
|
8652
|
100
|
|
|
|
16474
|
if ( defined $robot_fragment ) { |
1341
|
|
|
|
|
|
|
|
1342
|
|
|
|
|
|
|
# Examine what surrounds the fragment; that leads us to the |
1343
|
|
|
|
|
|
|
# version and the string (if we haven't explicitly set one). |
1344
|
|
|
|
|
|
|
|
1345
|
1089
|
100
|
|
|
|
61277
|
if ( |
1346
|
|
|
|
|
|
|
$self->{user_agent} =~ m{\s* # Beginning whitespace |
1347
|
|
|
|
|
|
|
([\w .:,\-\@\/]* # Words before fragment |
1348
|
|
|
|
|
|
|
$robot_fragment # Match the fragment |
1349
|
|
|
|
|
|
|
[\w .:,\-\@\/]*) # Words after fragment |
1350
|
|
|
|
|
|
|
}ix |
1351
|
|
|
|
|
|
|
) { |
1352
|
1017
|
|
|
|
|
3420
|
my $full_string = $1; |
1353
|
1017
|
|
|
|
|
5170
|
$full_string =~ s/ *$//; # Trim whitespace at end |
1354
|
1017
|
100
|
100
|
|
|
4960
|
if ( |
|
|
|
66
|
|
|
|
|
1355
|
|
|
|
|
|
|
$self->{user_agent} eq $full_string |
1356
|
|
|
|
|
|
|
&& $self->{user_agent} =~ m{\/.*\/} |
1357
|
|
|
|
|
|
|
&& $self->{user_agent} =~ m{ |
1358
|
|
|
|
|
|
|
([\w]* # Words before fragment |
1359
|
|
|
|
|
|
|
$robot_fragment # Match the fragment |
1360
|
|
|
|
|
|
|
(\/[\d\.]+)? # Version |
1361
|
|
|
|
|
|
|
[\w]*) # Beta stuff |
1362
|
|
|
|
|
|
|
}ix |
1363
|
|
|
|
|
|
|
) { |
1364
|
|
|
|
|
|
|
# We matched the whole string, but it seems to |
1365
|
|
|
|
|
|
|
# make more sense as whitespace-separated |
1366
|
|
|
|
|
|
|
# 'thing/ver' tokens |
1367
|
36
|
|
|
|
|
108
|
$full_string = $1; |
1368
|
|
|
|
|
|
|
} |
1369
|
|
|
|
|
|
|
|
1370
|
|
|
|
|
|
|
# Figure out robot version based on the string |
1371
|
1017
|
100
|
66
|
|
|
9139
|
if ( $full_string |
1372
|
|
|
|
|
|
|
and $full_string =~ s/[\/ \.v]*(\d+)(\.\d+)?([\.\w]*)$// ) { |
1373
|
652
|
|
|
|
|
2847
|
$self->{robot_version} = [ $1, $2, $3 ]; |
1374
|
|
|
|
|
|
|
} |
1375
|
|
|
|
|
|
|
else { |
1376
|
365
|
|
|
|
|
852
|
$self->{robot_version} = undef; |
1377
|
|
|
|
|
|
|
} |
1378
|
|
|
|
|
|
|
|
1379
|
|
|
|
|
|
|
# Set robot_string, if we don't already have an explictly set |
1380
|
|
|
|
|
|
|
# one |
1381
|
1017
|
100
|
|
|
|
2751
|
if ( !defined $self->{robot_string} ) { |
1382
|
353
|
|
|
|
|
848
|
$self->{robot_string} = $full_string; |
1383
|
|
|
|
|
|
|
} |
1384
|
|
|
|
|
|
|
} |
1385
|
|
|
|
|
|
|
} |
1386
|
|
|
|
|
|
|
|
1387
|
8652
|
100
|
|
|
|
22998
|
if ( !exists( $self->{robot_version} ) ) { |
1388
|
6117
|
|
|
|
|
13258
|
$self->{robot_version} = undef; |
1389
|
|
|
|
|
|
|
} |
1390
|
|
|
|
|
|
|
} |
1391
|
|
|
|
|
|
|
|
1392
|
|
|
|
|
|
|
### OS tests, only run on demand |
1393
|
|
|
|
|
|
|
|
1394
|
|
|
|
|
|
|
sub _init_os { |
1395
|
7146
|
|
|
7146
|
|
10867
|
my $self = shift; |
1396
|
|
|
|
|
|
|
|
1397
|
7146
|
|
|
|
|
10712
|
my $tests = $self->{tests}; |
1398
|
7146
|
|
|
|
|
10916
|
my $browser_tests = $self->{browser_tests}; |
1399
|
7146
|
|
|
|
|
14632
|
my $ua = lc $self->{user_agent}; |
1400
|
|
|
|
|
|
|
|
1401
|
7146
|
|
|
|
|
14958
|
my $os_tests = $self->{os_tests} = {}; |
1402
|
7146
|
|
|
|
|
9478
|
my $os = undef; |
1403
|
7146
|
|
|
|
|
8674
|
my $os_string = undef; |
1404
|
|
|
|
|
|
|
|
1405
|
|
|
|
|
|
|
# Windows |
1406
|
|
|
|
|
|
|
|
1407
|
7146
|
50
|
|
|
|
19300
|
if ( index( $ua, '16bit' ) != -1 ) { |
1408
|
0
|
|
|
|
|
0
|
$os = 'windows'; |
1409
|
0
|
|
|
|
|
0
|
$os_string = '16-bit Windows'; |
1410
|
0
|
|
|
|
|
0
|
$os_tests->{win16} = $os_tests->{windows} = 1; |
1411
|
|
|
|
|
|
|
} |
1412
|
|
|
|
|
|
|
|
1413
|
7146
|
100
|
|
|
|
17194
|
if ( index( $ua, 'win' ) != -1 ) { |
1414
|
2958
|
100
|
66
|
|
|
52042
|
if ( index( $ua, 'win16' ) != -1 |
|
|
100
|
66
|
|
|
|
|
|
|
100
|
100
|
|
|
|
|
|
|
100
|
100
|
|
|
|
|
|
|
100
|
100
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
1415
|
|
|
|
|
|
|
|| index( $ua, 'windows 3' ) != -1 |
1416
|
|
|
|
|
|
|
|| index( $ua, 'windows 16-bit' ) != -1 ) { |
1417
|
12
|
|
|
|
|
28
|
$os_tests->{win16} = 1; |
1418
|
12
|
|
|
|
|
31
|
$os_tests->{win3x} = 1; |
1419
|
12
|
|
|
|
|
22
|
$os = 'windows'; |
1420
|
12
|
100
|
|
|
|
37
|
if ( index( $ua, 'windows 3.1' ) != -1 ) { |
1421
|
6
|
|
|
|
|
14
|
$os_tests->{win31} = 1; |
1422
|
6
|
|
|
|
|
14
|
$os_string = 'Win3x'; # FIXME bug compatibility |
1423
|
|
|
|
|
|
|
} |
1424
|
|
|
|
|
|
|
else { |
1425
|
6
|
|
|
|
|
13
|
$os_string = 'Win3x'; |
1426
|
|
|
|
|
|
|
} |
1427
|
|
|
|
|
|
|
} |
1428
|
|
|
|
|
|
|
elsif (index( $ua, 'win95' ) != -1 |
1429
|
|
|
|
|
|
|
|| index( $ua, 'windows 95' ) != -1 ) { |
1430
|
72
|
|
|
|
|
137
|
$os = 'windows'; |
1431
|
72
|
|
|
|
|
100
|
$os_string = 'Win95'; |
1432
|
72
|
|
|
|
|
208
|
$os_tests->{win95} = $os_tests->{win32} = 1; |
1433
|
|
|
|
|
|
|
} |
1434
|
|
|
|
|
|
|
elsif ( |
1435
|
|
|
|
|
|
|
index( $ua, 'win 9x 4.90' ) != -1 # whatever |
1436
|
|
|
|
|
|
|
|| index( $ua, 'windows me' ) != -1 |
1437
|
|
|
|
|
|
|
) { |
1438
|
30
|
|
|
|
|
46
|
$os = 'windows'; |
1439
|
30
|
|
|
|
|
35
|
$os_string = 'WinME'; |
1440
|
30
|
|
|
|
|
63
|
$os_tests->{winme} = $os_tests->{win32} = 1; |
1441
|
|
|
|
|
|
|
} |
1442
|
|
|
|
|
|
|
elsif (index( $ua, 'win98' ) != -1 |
1443
|
|
|
|
|
|
|
|| index( $ua, 'windows 98' ) != -1 ) { |
1444
|
24
|
|
|
|
|
46
|
$os = 'windows'; |
1445
|
24
|
|
|
|
|
33
|
$os_string = 'Win98'; |
1446
|
24
|
|
|
|
|
58
|
$os_tests->{win98} = $os_tests->{win32} = 1; |
1447
|
|
|
|
|
|
|
} |
1448
|
|
|
|
|
|
|
elsif ( index( $ua, 'windows 2000' ) != -1 ) { |
1449
|
12
|
|
|
|
|
24
|
$os = 'windows'; |
1450
|
12
|
|
|
|
|
18
|
$os_string = 'Win2k'; |
1451
|
12
|
|
|
|
|
28
|
$os_tests->{win2k} = $os_tests->{winnt} = $os_tests->{win32} = 1; |
1452
|
|
|
|
|
|
|
} |
1453
|
|
|
|
|
|
|
elsif ( index( $ua, 'windows ce' ) != -1 ) { |
1454
|
12
|
|
|
|
|
25
|
$os = 'windows'; |
1455
|
12
|
|
|
|
|
20
|
$os_string = 'WinCE'; |
1456
|
12
|
|
|
|
|
32
|
$os_tests->{wince} = 1; |
1457
|
|
|
|
|
|
|
} |
1458
|
|
|
|
|
|
|
elsif ( index( $ua, 'windows phone' ) != -1 ) { |
1459
|
54
|
|
|
|
|
111
|
$os = 'winphone'; |
1460
|
54
|
|
|
|
|
113
|
$os_tests->{winphone} = 1; |
1461
|
|
|
|
|
|
|
|
1462
|
54
|
100
|
|
|
|
255
|
if ( index( $ua, 'windows phone os 7.0' ) != -1 ) { |
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
1463
|
6
|
|
|
|
|
10
|
$os_tests->{winphone7} = 1; |
1464
|
|
|
|
|
|
|
} |
1465
|
|
|
|
|
|
|
elsif ( index( $ua, 'windows phone os 7.5' ) != -1 ) { |
1466
|
12
|
|
|
|
|
32
|
$os_tests->{winphone7_5} = 1; |
1467
|
|
|
|
|
|
|
} |
1468
|
|
|
|
|
|
|
elsif ( index( $ua, 'windows phone 8.0' ) != -1 ) { |
1469
|
12
|
|
|
|
|
22
|
$os_tests->{winphone8} = 1; |
1470
|
|
|
|
|
|
|
} |
1471
|
|
|
|
|
|
|
elsif ( index( $ua, 'windows phone 8.1' ) != -1 ) { |
1472
|
18
|
|
|
|
|
32
|
$os_tests->{winphone8_1} = 1; |
1473
|
|
|
|
|
|
|
} |
1474
|
|
|
|
|
|
|
elsif ( index( $ua, 'windows phone 10.0' ) != -1 ) { |
1475
|
6
|
|
|
|
|
15
|
$os_tests->{winphone10} = 1; |
1476
|
|
|
|
|
|
|
} |
1477
|
|
|
|
|
|
|
} |
1478
|
|
|
|
|
|
|
} |
1479
|
|
|
|
|
|
|
|
1480
|
7146
|
100
|
|
|
|
16074
|
if ( index( $ua, 'nt' ) != -1 ) { |
1481
|
3798
|
100
|
66
|
|
|
32582
|
if ( index( $ua, 'nt 5.0' ) != -1 |
|
|
100
|
100
|
|
|
|
|
|
|
100
|
100
|
|
|
|
|
|
|
100
|
66
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
1482
|
|
|
|
|
|
|
|| index( $ua, 'nt5' ) != -1 ) { |
1483
|
90
|
|
|
|
|
128
|
$os = 'windows'; |
1484
|
90
|
|
|
|
|
113
|
$os_string = 'Win2k'; |
1485
|
90
|
|
|
|
|
221
|
$os_tests->{win2k} = $os_tests->{winnt} = $os_tests->{win32} = 1; |
1486
|
|
|
|
|
|
|
} |
1487
|
|
|
|
|
|
|
elsif ( index( $ua, 'nt 5.1' ) != -1 ) { |
1488
|
984
|
|
|
|
|
1777
|
$os = 'windows'; |
1489
|
984
|
|
|
|
|
1741
|
$os_string = 'WinXP'; |
1490
|
984
|
|
|
|
|
2999
|
$os_tests->{winxp} = $os_tests->{winnt} = $os_tests->{win32} = 1; |
1491
|
|
|
|
|
|
|
} |
1492
|
|
|
|
|
|
|
elsif ( index( $ua, 'nt 5.2' ) != -1 ) { |
1493
|
126
|
|
|
|
|
222
|
$os = 'windows'; |
1494
|
126
|
|
|
|
|
209
|
$os_string = 'Win2k3'; |
1495
|
126
|
|
|
|
|
373
|
$os_tests->{win2k3} = $os_tests->{winnt} = $os_tests->{win32} = 1; |
1496
|
|
|
|
|
|
|
} |
1497
|
|
|
|
|
|
|
elsif ( index( $ua, 'nt 6.0' ) != -1 ) { |
1498
|
204
|
|
|
|
|
353
|
$os = 'windows'; |
1499
|
204
|
|
|
|
|
321
|
$os_string = 'WinVista'; |
1500
|
|
|
|
|
|
|
$os_tests->{winvista} = $os_tests->{winnt} = $os_tests->{win32} |
1501
|
204
|
|
|
|
|
582
|
= 1; |
1502
|
|
|
|
|
|
|
} |
1503
|
|
|
|
|
|
|
elsif ( index( $ua, 'nt 6.1' ) != -1 ) { |
1504
|
966
|
|
|
|
|
1588
|
$os = 'windows'; |
1505
|
966
|
|
|
|
|
1350
|
$os_string = 'Win7'; |
1506
|
966
|
|
|
|
|
2581
|
$os_tests->{win7} = $os_tests->{winnt} = $os_tests->{win32} = 1; |
1507
|
|
|
|
|
|
|
} |
1508
|
|
|
|
|
|
|
elsif ( index( $ua, 'nt 6.2' ) != -1 ) { |
1509
|
96
|
|
|
|
|
147
|
$os = 'windows'; |
1510
|
96
|
|
|
|
|
136
|
$os_string = 'Win8.0'; |
1511
|
|
|
|
|
|
|
$os_tests->{win8_0} = $os_tests->{win8} = $os_tests->{winnt} |
1512
|
96
|
|
|
|
|
279
|
= $os_tests->{win32} = 1; |
1513
|
|
|
|
|
|
|
} |
1514
|
|
|
|
|
|
|
elsif ( index( $ua, 'nt 6.3' ) != -1 ) { |
1515
|
78
|
|
|
|
|
115
|
$os = 'windows'; |
1516
|
78
|
|
|
|
|
100
|
$os_string = 'Win8.1'; |
1517
|
|
|
|
|
|
|
$os_tests->{win8_1} = $os_tests->{win8} = $os_tests->{winnt} |
1518
|
78
|
|
|
|
|
193
|
= $os_tests->{win32} = 1; |
1519
|
|
|
|
|
|
|
} |
1520
|
|
|
|
|
|
|
elsif ( index( $ua, 'nt 10.0' ) != -1 ) { |
1521
|
30
|
|
|
|
|
52
|
$os = 'windows'; |
1522
|
30
|
|
|
|
|
38
|
$os_string = 'Win10.0'; |
1523
|
|
|
|
|
|
|
$os_tests->{win10_0} = $os_tests->{win10} = $os_tests->{winnt} |
1524
|
30
|
|
|
|
|
103
|
= $os_tests->{win32} = 1; |
1525
|
|
|
|
|
|
|
} |
1526
|
|
|
|
|
|
|
elsif (index( $ua, 'winnt' ) != -1 |
1527
|
|
|
|
|
|
|
|| index( $ua, 'windows nt' ) != -1 |
1528
|
|
|
|
|
|
|
|| index( $ua, 'nt4' ) != -1 |
1529
|
|
|
|
|
|
|
|| index( $ua, 'nt3' ) != -1 ) { |
1530
|
54
|
|
|
|
|
102
|
$os = 'windows'; |
1531
|
54
|
|
|
|
|
72
|
$os_string = 'WinNT'; |
1532
|
54
|
|
|
|
|
137
|
$os_tests->{winnt} = $os_tests->{win32} = 1; |
1533
|
|
|
|
|
|
|
} |
1534
|
|
|
|
|
|
|
} |
1535
|
|
|
|
|
|
|
|
1536
|
7146
|
100
|
100
|
|
|
103173
|
if ($os) { |
|
|
100
|
100
|
|
|
|
|
|
|
100
|
100
|
|
|
|
|
|
|
100
|
100
|
|
|
|
|
|
|
100
|
66
|
|
|
|
|
|
|
100
|
33
|
|
|
|
|
|
|
100
|
33
|
|
|
|
|
|
|
100
|
33
|
|
|
|
|
|
|
100
|
33
|
|
|
|
|
|
|
50
|
33
|
|
|
|
|
|
|
50
|
33
|
|
|
|
|
|
|
50
|
33
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
1537
|
|
|
|
|
|
|
|
1538
|
|
|
|
|
|
|
# windows, set through some path above |
1539
|
2844
|
|
|
|
|
5079
|
$os_tests->{windows} = 1; |
1540
|
2844
|
50
|
|
|
|
7533
|
$os_tests->{win32} = 1 if index( $ua, 'win32' ) != -1; |
1541
|
|
|
|
|
|
|
} |
1542
|
|
|
|
|
|
|
elsif ( index( $ua, 'macintosh' ) != -1 || index( $ua, 'mac_' ) != -1 ) { |
1543
|
|
|
|
|
|
|
|
1544
|
|
|
|
|
|
|
# Mac operating systems |
1545
|
462
|
|
|
|
|
878
|
$os_tests->{mac} = 1; |
1546
|
462
|
100
|
|
|
|
879
|
if ( index( $ua, 'mac os x' ) != -1 ) { |
1547
|
438
|
|
|
|
|
587
|
$os = 'macosx'; |
1548
|
438
|
|
|
|
|
697
|
$os_tests->{$os} = 1; |
1549
|
|
|
|
|
|
|
} |
1550
|
|
|
|
|
|
|
else { |
1551
|
24
|
|
|
|
|
40
|
$os = 'mac'; |
1552
|
|
|
|
|
|
|
} |
1553
|
462
|
50
|
33
|
|
|
2949
|
if ( index( $ua, '68k' ) != -1 || index( $ua, '68000' ) != -1 ) { |
|
|
100
|
100
|
|
|
|
|
1554
|
0
|
|
|
|
|
0
|
$os_tests->{mac68k} = 1; |
1555
|
|
|
|
|
|
|
} |
1556
|
|
|
|
|
|
|
elsif ( index( $ua, 'ppc' ) != -1 || index( $ua, 'powerpc' ) != -1 ) { |
1557
|
126
|
|
|
|
|
189
|
$os_tests->{macppc} = 1; |
1558
|
|
|
|
|
|
|
} |
1559
|
|
|
|
|
|
|
} |
1560
|
|
|
|
|
|
|
elsif (index( $ua, 'ipod' ) != -1 |
1561
|
|
|
|
|
|
|
|| index( $ua, 'iphone' ) != -1 |
1562
|
|
|
|
|
|
|
|| index( $ua, 'ipad' ) != -1 ) { |
1563
|
|
|
|
|
|
|
|
1564
|
|
|
|
|
|
|
# iOS |
1565
|
378
|
|
|
|
|
639
|
$os = 'ios'; |
1566
|
378
|
|
|
|
|
811
|
$os_tests->{$os} = 1; |
1567
|
|
|
|
|
|
|
} |
1568
|
|
|
|
|
|
|
elsif ( index( $ua, 'android' ) != -1 ) { |
1569
|
|
|
|
|
|
|
|
1570
|
|
|
|
|
|
|
# Android |
1571
|
966
|
|
|
|
|
1458
|
$os = 'android'; # Test gets set in the device testing |
1572
|
|
|
|
|
|
|
} |
1573
|
|
|
|
|
|
|
elsif ( index( $ua, 'inux' ) != -1 ) { |
1574
|
|
|
|
|
|
|
|
1575
|
|
|
|
|
|
|
# Linux |
1576
|
492
|
|
|
|
|
718
|
$os = 'linux'; |
1577
|
492
|
|
|
|
|
1048
|
$os_tests->{linux} = $os_tests->{unix} = 1; |
1578
|
|
|
|
|
|
|
} |
1579
|
|
|
|
|
|
|
elsif ( $tests->{x11} && index( $ua, 'cros' ) != -1 ) { |
1580
|
|
|
|
|
|
|
|
1581
|
|
|
|
|
|
|
# ChromeOS |
1582
|
42
|
|
|
|
|
69
|
$os = 'chromeos'; |
1583
|
42
|
|
|
|
|
97
|
$os_tests->{chromeos} = 1; |
1584
|
|
|
|
|
|
|
} |
1585
|
|
|
|
|
|
|
## Long series of unlikely OSs |
1586
|
|
|
|
|
|
|
elsif ( index( $ua, 'amiga' ) != -1 ) { |
1587
|
6
|
|
|
|
|
10
|
$os = 'amiga'; |
1588
|
6
|
|
|
|
|
86
|
$os_tests->{$os} = 1; |
1589
|
|
|
|
|
|
|
} |
1590
|
|
|
|
|
|
|
elsif ( index( $ua, 'os/2' ) != -1 ) { |
1591
|
6
|
|
|
|
|
14
|
$os = 'os2'; |
1592
|
6
|
|
|
|
|
17
|
$os_tests->{$os} = 1; |
1593
|
|
|
|
|
|
|
} |
1594
|
|
|
|
|
|
|
elsif ( index( $ua, 'solaris' ) != -1 ) { |
1595
|
6
|
|
|
|
|
13
|
$os = 'unix'; |
1596
|
6
|
|
|
|
|
10
|
$os_string = 'Solaris'; |
1597
|
6
|
|
|
|
|
16
|
$os_tests->{sun} = $os_tests->{unix} = 1; |
1598
|
|
|
|
|
|
|
} |
1599
|
|
|
|
|
|
|
elsif ( index( $ua, 'samsung' ) == -1 && index( $ua, 'sun' ) != -1 ) { |
1600
|
0
|
|
|
|
|
0
|
$os = 'unix'; |
1601
|
0
|
|
|
|
|
0
|
$os_string = 'SunOS'; |
1602
|
0
|
|
|
|
|
0
|
$os_tests->{sun} = $os_tests->{unix} = 1; |
1603
|
0
|
0
|
|
|
|
0
|
$os_tests->{suni86} = 1 if index( $ua, 'i86' ) != -1; |
1604
|
0
|
0
|
|
|
|
0
|
$os_tests->{sun4} = 1 if index( $ua, 'sunos 4' ) != -1; |
1605
|
0
|
0
|
|
|
|
0
|
$os_tests->{sun5} = 1 if index( $ua, 'sunos 5' ) != -1; |
1606
|
|
|
|
|
|
|
} |
1607
|
|
|
|
|
|
|
elsif ( index( $ua, 'irix' ) != -1 ) { |
1608
|
0
|
|
|
|
|
0
|
$os = 'unix'; |
1609
|
0
|
|
|
|
|
0
|
$os_string = 'Irix'; |
1610
|
0
|
|
|
|
|
0
|
$os_tests->{irix} = $os_tests->{unix} = 1; |
1611
|
0
|
0
|
|
|
|
0
|
$os_tests->{irix5} = 1 if ( index( $ua, 'irix5' ) != -1 ); |
1612
|
0
|
0
|
|
|
|
0
|
$os_tests->{irix6} = 1 if ( index( $ua, 'irix6' ) != -1 ); |
1613
|
|
|
|
|
|
|
} |
1614
|
|
|
|
|
|
|
elsif ( index( $ua, 'hp-ux' ) != -1 ) { |
1615
|
0
|
|
|
|
|
0
|
$os = 'unix'; |
1616
|
0
|
|
|
|
|
0
|
$os_string = 'HP-UX'; |
1617
|
0
|
|
|
|
|
0
|
$os_tests->{hpux} = $os_tests->{unix} = 1; |
1618
|
0
|
0
|
|
|
|
0
|
$os_tests->{hpux9} = 1 if index( $ua, '09.' ) != -1; |
1619
|
0
|
0
|
|
|
|
0
|
$os_tests->{hpux10} = 1 if index( $ua, '10.' ) != -1; |
1620
|
|
|
|
|
|
|
} |
1621
|
|
|
|
|
|
|
elsif ( index( $ua, 'aix' ) != -1 ) { |
1622
|
0
|
|
|
|
|
0
|
$os = 'unix'; |
1623
|
0
|
|
|
|
|
0
|
$os_string = 'AIX'; |
1624
|
0
|
|
|
|
|
0
|
$os_tests->{aix} = $os_tests->{unix} = 1; |
1625
|
0
|
0
|
|
|
|
0
|
$os_tests->{aix1} = 1 if ( index( $ua, 'aix 1' ) != -1 ); |
1626
|
0
|
0
|
|
|
|
0
|
$os_tests->{aix2} = 1 if ( index( $ua, 'aix 2' ) != -1 ); |
1627
|
0
|
0
|
|
|
|
0
|
$os_tests->{aix3} = 1 if ( index( $ua, 'aix 3' ) != -1 ); |
1628
|
0
|
0
|
|
|
|
0
|
$os_tests->{aix4} = 1 if ( index( $ua, 'aix 4' ) != -1 ); |
1629
|
|
|
|
|
|
|
} |
1630
|
|
|
|
|
|
|
elsif ( $ua =~ m{\bsco\b} || index( $ua, 'unix_sv' ) != -1 ) { |
1631
|
0
|
|
|
|
|
0
|
$os = 'unix'; |
1632
|
0
|
|
|
|
|
0
|
$os_string = 'SCO Unix'; |
1633
|
0
|
|
|
|
|
0
|
$os_tests->{sco} = $os_tests->{unix} = 1; |
1634
|
|
|
|
|
|
|
} |
1635
|
|
|
|
|
|
|
elsif ( index( $ua, 'unix_system_v' ) != -1 ) { |
1636
|
0
|
|
|
|
|
0
|
$os = 'unix'; |
1637
|
0
|
|
|
|
|
0
|
$os_string = 'System V Unix'; |
1638
|
0
|
|
|
|
|
0
|
$os_tests->{unixware} = $os_tests->{unix} = 1; |
1639
|
|
|
|
|
|
|
} |
1640
|
|
|
|
|
|
|
elsif ( $ua =~ m{\bncr\b} ) { |
1641
|
0
|
|
|
|
|
0
|
$os = 'unix'; |
1642
|
0
|
|
|
|
|
0
|
$os_string = 'NCR Unix'; |
1643
|
0
|
|
|
|
|
0
|
$os_tests->{mpras} = $os_tests->{unix} = 1; |
1644
|
|
|
|
|
|
|
} |
1645
|
|
|
|
|
|
|
elsif ( index( $ua, 'reliantunix' ) != -1 ) { |
1646
|
0
|
|
|
|
|
0
|
$os = 'unix'; |
1647
|
0
|
|
|
|
|
0
|
$os_string = 'Reliant Unix'; |
1648
|
0
|
|
|
|
|
0
|
$os_tests->{reliant} = $os_tests->{unix} = 1; |
1649
|
|
|
|
|
|
|
} |
1650
|
|
|
|
|
|
|
elsif (index( $ua, 'dec' ) != -1 |
1651
|
|
|
|
|
|
|
|| index( $ua, 'osf1' ) != -1 |
1652
|
|
|
|
|
|
|
|| index( $ua, 'declpha' ) != -1 |
1653
|
|
|
|
|
|
|
|| index( $ua, 'alphaserver' ) != -1 |
1654
|
|
|
|
|
|
|
|| index( $ua, 'ultrix' ) != -1 |
1655
|
|
|
|
|
|
|
|| index( $ua, 'alphastation' ) != -1 ) { |
1656
|
0
|
|
|
|
|
0
|
$os = 'unix'; |
1657
|
0
|
|
|
|
|
0
|
$os_tests->{dec} = $os_tests->{unix} = 1; |
1658
|
|
|
|
|
|
|
} |
1659
|
|
|
|
|
|
|
elsif ( index( $ua, 'sinix' ) != -1 ) { |
1660
|
0
|
|
|
|
|
0
|
$os = 'unix'; |
1661
|
0
|
|
|
|
|
0
|
$os_tests->{sinix} = $os_tests->{unix} = 1; |
1662
|
|
|
|
|
|
|
} |
1663
|
|
|
|
|
|
|
elsif ( index( $ua, 'bsd' ) != -1 ) { |
1664
|
30
|
|
|
|
|
58
|
$os = 'unix'; |
1665
|
30
|
50
|
|
|
|
211
|
if ( $self->{user_agent} =~ m{(\w*bsd\w*)}i ) { |
1666
|
30
|
|
|
|
|
81
|
$os_string = $1; |
1667
|
|
|
|
|
|
|
} |
1668
|
30
|
|
|
|
|
72
|
$os_tests->{bsd} = $os_tests->{unix} = 1; |
1669
|
30
|
50
|
|
|
|
85
|
$os_tests->{freebsd} = 1 if index( $ua, 'freebsd' ) != -1; |
1670
|
|
|
|
|
|
|
} |
1671
|
|
|
|
|
|
|
elsif ( $tests->{x11} ) { |
1672
|
|
|
|
|
|
|
|
1673
|
|
|
|
|
|
|
# Some Unix we didn't identify |
1674
|
12
|
|
|
|
|
42
|
$os = 'unix'; |
1675
|
12
|
|
|
|
|
32
|
$os_tests->{unix} = 1; |
1676
|
|
|
|
|
|
|
} |
1677
|
|
|
|
|
|
|
elsif ( index( $ua, 'vax' ) != -1 || index( $ua, 'openvms' ) != -1 ) { |
1678
|
|
|
|
|
|
|
|
1679
|
0
|
|
|
|
|
0
|
$os = 'vms'; |
1680
|
0
|
|
|
|
|
0
|
$os_tests->{vms} = 1; |
1681
|
|
|
|
|
|
|
} |
1682
|
|
|
|
|
|
|
elsif ( index( $ua, 'bb10' ) != -1 ) { |
1683
|
12
|
|
|
|
|
23
|
$os = 'bb10'; |
1684
|
12
|
|
|
|
|
24
|
$os_tests->{bb10} = 1; |
1685
|
|
|
|
|
|
|
} |
1686
|
|
|
|
|
|
|
elsif ( index( $ua, 'rim tablet os' ) != -1 ) { |
1687
|
6
|
|
|
|
|
12
|
$os = 'rimtabletos'; |
1688
|
6
|
|
|
|
|
11
|
$os_tests->{rimtabletos} = 1; |
1689
|
|
|
|
|
|
|
} |
1690
|
|
|
|
|
|
|
elsif ( index( $ua, 'playstation 3' ) != -1 ) { |
1691
|
6
|
|
|
|
|
12
|
$os = 'ps3gameos'; |
1692
|
6
|
|
|
|
|
14
|
$os_tests->{ps3gameos} = 1; |
1693
|
|
|
|
|
|
|
} |
1694
|
|
|
|
|
|
|
elsif ( index( $ua, 'playstation portable' ) != -1 ) { |
1695
|
6
|
|
|
|
|
9
|
$os = 'pspgameos'; |
1696
|
6
|
|
|
|
|
15
|
$os_tests->{pspgameos} = 1; |
1697
|
|
|
|
|
|
|
} |
1698
|
|
|
|
|
|
|
elsif ( index( $ua, 'windows' ) != -1 ) { |
1699
|
|
|
|
|
|
|
|
1700
|
|
|
|
|
|
|
# Windows again, the super generic version |
1701
|
54
|
|
|
|
|
145
|
$os_tests->{windows} = 1; |
1702
|
|
|
|
|
|
|
} |
1703
|
|
|
|
|
|
|
elsif ( index( $ua, 'win32' ) != -1 ) { |
1704
|
18
|
|
|
|
|
53
|
$os_tests->{win32} = $os_tests->{windows} = 1; |
1705
|
|
|
|
|
|
|
} |
1706
|
|
|
|
|
|
|
elsif ( $self->{user_agent} =~ m{(brew)|(\bbmp\b)}i ) { |
1707
|
144
|
|
|
|
|
313
|
$os = 'brew'; |
1708
|
144
|
100
|
|
|
|
465
|
if ($1) { |
1709
|
102
|
|
|
|
|
164
|
$os_string = 'Brew'; |
1710
|
|
|
|
|
|
|
} |
1711
|
|
|
|
|
|
|
else { |
1712
|
42
|
|
|
|
|
70
|
$os_string = 'Brew MP'; |
1713
|
|
|
|
|
|
|
} |
1714
|
144
|
|
|
|
|
313
|
$os_tests->{brew} = 1; |
1715
|
|
|
|
|
|
|
} |
1716
|
|
|
|
|
|
|
else { |
1717
|
1656
|
|
|
|
|
3157
|
$os = undef; |
1718
|
|
|
|
|
|
|
} |
1719
|
|
|
|
|
|
|
|
1720
|
|
|
|
|
|
|
# To deal with FirefoxOS we seem to have to load-on-demand devices |
1721
|
|
|
|
|
|
|
# also, by calling ->mobile and ->tablet. We have to be careful; |
1722
|
|
|
|
|
|
|
# if we ever created a loop back from _init_devices to _init_os |
1723
|
|
|
|
|
|
|
# we'd run forever. |
1724
|
7146
|
100
|
100
|
|
|
16558
|
if ( !$os |
|
|
|
66
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
1725
|
|
|
|
|
|
|
&& $browser_tests->{firefox} |
1726
|
|
|
|
|
|
|
&& index( $ua, 'fennec' ) == -1 |
1727
|
|
|
|
|
|
|
&& ( $self->mobile || $self->tablet ) ) { |
1728
|
12
|
|
|
|
|
17
|
$os = 'firefoxos'; |
1729
|
12
|
|
|
|
|
24
|
$os_tests->{firefoxos} = 1; |
1730
|
|
|
|
|
|
|
} |
1731
|
|
|
|
|
|
|
|
1732
|
7146
|
|
|
|
|
13397
|
$self->{os} = $os; |
1733
|
7146
|
100
|
100
|
|
|
21335
|
if ( $os and !$os_string ) { |
1734
|
2460
|
|
|
|
|
4156
|
$os_string = $OS_NAMES{$os}; |
1735
|
|
|
|
|
|
|
} |
1736
|
7146
|
|
|
|
|
17097
|
$self->{os_string} = $os_string; |
1737
|
|
|
|
|
|
|
} |
1738
|
|
|
|
|
|
|
|
1739
|
|
|
|
|
|
|
sub _init_os_version { |
1740
|
2527
|
|
|
2527
|
|
3717
|
my ($self) = @_; |
1741
|
|
|
|
|
|
|
|
1742
|
2527
|
|
|
|
|
5619
|
my $os = $self->os; |
1743
|
2527
|
|
|
|
|
5343
|
my $os_string = $self->os_string; |
1744
|
2527
|
|
|
|
|
5902
|
my $ua = lc $self->{user_agent}; |
1745
|
|
|
|
|
|
|
|
1746
|
2527
|
|
|
|
|
3518
|
my $os_version = undef; |
1747
|
|
|
|
|
|
|
|
1748
|
2527
|
100
|
|
|
|
13518
|
if ( !defined $os ) { |
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
1749
|
|
|
|
|
|
|
|
1750
|
|
|
|
|
|
|
# Nothing is going to work if we have no OS. Skip everything. |
1751
|
|
|
|
|
|
|
} |
1752
|
|
|
|
|
|
|
elsif ( $os eq 'winphone' ) { |
1753
|
24
|
50
|
|
|
|
186
|
if ( $ua =~ m{windows phone (?:os )?(\d+)(\.?\d*)([\.\d]*)} ) { |
1754
|
24
|
|
|
|
|
96
|
$os_version = [ $1, $2, $3 ]; |
1755
|
|
|
|
|
|
|
} |
1756
|
|
|
|
|
|
|
} |
1757
|
|
|
|
|
|
|
elsif ( $os eq 'macosx' ) { |
1758
|
190
|
100
|
|
|
|
1109
|
if ( $ua =~ m{os x (\d+)[\._](\d+)[\._]?(\d*)} ) { |
1759
|
158
|
100
|
|
|
|
844
|
$os_version = [ $1, ".$2", length($3) ? ".$3" : q{} ]; |
1760
|
|
|
|
|
|
|
} |
1761
|
|
|
|
|
|
|
} |
1762
|
|
|
|
|
|
|
elsif ( $os eq 'ios' ) { |
1763
|
171
|
100
|
|
|
|
1110
|
if ( $ua =~ m{ os (\d+)[\._ ](\d+)[\._ ]?(\d*)} ) { |
1764
|
170
|
100
|
|
|
|
1025
|
$os_version = [ $1, ".$2", length($3) ? ".$3" : q{} ]; |
1765
|
|
|
|
|
|
|
} |
1766
|
|
|
|
|
|
|
} |
1767
|
|
|
|
|
|
|
elsif ( $os eq 'chromeos' ) { |
1768
|
22
|
50
|
|
|
|
140
|
if ( $ua =~ m{ cros \S* (\d+)(\.?\d*)([\.\d]*)} ) { |
1769
|
22
|
|
|
|
|
76
|
$os_version = [ $1, $2, $3 ]; |
1770
|
|
|
|
|
|
|
} |
1771
|
|
|
|
|
|
|
} |
1772
|
|
|
|
|
|
|
elsif ( $os eq 'android' ) { |
1773
|
454
|
100
|
|
|
|
2763
|
if ( $ua =~ m{android (\d+)(\.?\d*)([\w\-\.]*)[\;\)]} ) { |
1774
|
442
|
|
|
|
|
1673
|
$os_version = [ $1, $2, $3 ]; |
1775
|
|
|
|
|
|
|
} |
1776
|
|
|
|
|
|
|
} |
1777
|
|
|
|
|
|
|
elsif ( $os eq 'firefoxos' ) { |
1778
|
6
|
50
|
|
|
|
43
|
if ( $ua =~ m{firefox/(\d+)(\.?\d*)([\.\d]*)} ) { |
1779
|
6
|
|
|
|
|
24
|
$os_version = [ $1, $2, $3 ]; |
1780
|
|
|
|
|
|
|
} |
1781
|
|
|
|
|
|
|
} |
1782
|
|
|
|
|
|
|
elsif ( $os eq 'brew' ) { |
1783
|
71
|
100
|
|
|
|
576
|
if ( $ua =~ m{(brew|\bbmp) (\d+)(\.?\d*)([\.\d]*)} ) { |
1784
|
55
|
|
|
|
|
264
|
$os_version = [ $2, $3, $4 ]; |
1785
|
|
|
|
|
|
|
} |
1786
|
|
|
|
|
|
|
} |
1787
|
|
|
|
|
|
|
|
1788
|
|
|
|
|
|
|
# Set the version. It might be set to undef, in which case we know |
1789
|
|
|
|
|
|
|
# not to go through this next time. |
1790
|
2527
|
|
|
|
|
5169
|
$self->{os_version} = $os_version; |
1791
|
|
|
|
|
|
|
} |
1792
|
|
|
|
|
|
|
|
1793
|
|
|
|
|
|
|
### Version determination, only run on demand |
1794
|
|
|
|
|
|
|
|
1795
|
|
|
|
|
|
|
sub _init_version { |
1796
|
7108
|
|
|
7108
|
|
10443
|
my ($self) = @_; |
1797
|
|
|
|
|
|
|
|
1798
|
7108
|
|
|
|
|
17999
|
my $ua = lc $self->{user_agent}; |
1799
|
7108
|
|
|
|
|
10731
|
my $tests = $self->{tests}; |
1800
|
7108
|
|
|
|
|
9820
|
my $browser_tests = $self->{browser_tests}; |
1801
|
7108
|
|
|
|
|
10744
|
my $browser = $self->{browser}; |
1802
|
|
|
|
|
|
|
|
1803
|
7108
|
|
|
|
|
12609
|
$self->{version_tests} = {}; |
1804
|
7108
|
|
|
|
|
11341
|
my $version_tests = $self->{version_tests}; |
1805
|
|
|
|
|
|
|
|
1806
|
7108
|
|
|
|
|
10959
|
my ( $major, $minor, $beta ); |
1807
|
|
|
|
|
|
|
|
1808
|
|
|
|
|
|
|
### First figure out version numbers. First, we test if we're |
1809
|
|
|
|
|
|
|
### using a browser that needs some special method to determine |
1810
|
|
|
|
|
|
|
### the version. |
1811
|
|
|
|
|
|
|
|
1812
|
7108
|
100
|
100
|
|
|
81737
|
if ( defined $browser && $browser eq 'opera' ) { |
|
|
100
|
100
|
|
|
|
|
|
|
100
|
66
|
|
|
|
|
|
|
100
|
100
|
|
|
|
|
|
|
100
|
66
|
|
|
|
|
|
|
100
|
66
|
|
|
|
|
|
|
100
|
66
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
1813
|
|
|
|
|
|
|
|
1814
|
|
|
|
|
|
|
# Opera has a 'compatible; ' section, but lies sometimes. It needs |
1815
|
|
|
|
|
|
|
# special handling. |
1816
|
|
|
|
|
|
|
|
1817
|
|
|
|
|
|
|
# http://dev.opera.com/articles/view/opera-ua-string-changes/ |
1818
|
|
|
|
|
|
|
# http://my.opera.com/community/openweb/idopera/ |
1819
|
|
|
|
|
|
|
# Opera/9.80 (S60; SymbOS; Opera Mobi/320; U; sv) Presto/2.4.15 Version/10.00 |
1820
|
|
|
|
|
|
|
# Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/28.0.1500.52 Safari/537.36 OPR/15.0.1147.100 |
1821
|
|
|
|
|
|
|
|
1822
|
264
|
100
|
|
|
|
2847
|
if ( $ua =~ m{\AOpera.*\sVersion/(\d*)\.(\d*)\z}i ) { |
|
|
100
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
1823
|
90
|
|
|
|
|
248
|
$major = $1; |
1824
|
90
|
|
|
|
|
208
|
$minor = $2; |
1825
|
|
|
|
|
|
|
} |
1826
|
|
|
|
|
|
|
elsif ( $ua =~ m{\bOPR/(\d+)\.(\d+)}i ) { |
1827
|
48
|
|
|
|
|
122
|
$major = $1; |
1828
|
48
|
|
|
|
|
95
|
$minor = $2; |
1829
|
|
|
|
|
|
|
} |
1830
|
|
|
|
|
|
|
elsif ( $ua =~ m{Opera[ /](\d+).(\d+)}i ) { |
1831
|
126
|
|
|
|
|
337
|
$major = $1; |
1832
|
126
|
|
|
|
|
252
|
$minor = $2; |
1833
|
|
|
|
|
|
|
} |
1834
|
|
|
|
|
|
|
} |
1835
|
|
|
|
|
|
|
elsif ( $ua |
1836
|
|
|
|
|
|
|
=~ m{\b compatible; \s* [\w\-]* [/\s] ( [0-9]+ ) (?: .([0-9]+) (\S*) )? ;}x |
1837
|
|
|
|
|
|
|
) { |
1838
|
|
|
|
|
|
|
# MSIE and some others use a 'compatible' format |
1839
|
1883
|
|
|
|
|
8567
|
( $major, $minor, $beta ) = ( $1, $2, $3 ); |
1840
|
|
|
|
|
|
|
} |
1841
|
|
|
|
|
|
|
elsif ( !$browser ) { |
1842
|
|
|
|
|
|
|
|
1843
|
|
|
|
|
|
|
# Nothing else is going to work if $browser isn't defined; skip the |
1844
|
|
|
|
|
|
|
# specific approaches and go straight to the generic ones. |
1845
|
|
|
|
|
|
|
} |
1846
|
|
|
|
|
|
|
elsif ( $browser_tests->{edge} ) { |
1847
|
24
|
|
|
|
|
88
|
( $major, $minor, $beta ) |
1848
|
|
|
|
|
|
|
= $ua =~ m{Edge/(\d+)(?:\.(\d+))?([\.\d]+)?}i; |
1849
|
24
|
50
|
|
|
|
256
|
( $major, $minor, $beta ) |
1850
|
|
|
|
|
|
|
= $ua =~ m{(?:Edg|EdgA|EdgiOS)/(\d+)(?:\.(\d+))?([\.\d]+)?}i |
1851
|
|
|
|
|
|
|
unless defined $major; |
1852
|
|
|
|
|
|
|
} |
1853
|
|
|
|
|
|
|
elsif ( $browser_tests->{safari} ) { |
1854
|
|
|
|
|
|
|
|
1855
|
|
|
|
|
|
|
# Safari Version |
1856
|
|
|
|
|
|
|
|
1857
|
952
|
100
|
|
|
|
5776
|
if ( |
|
|
100
|
|
|
|
|
|
1858
|
|
|
|
|
|
|
0 |
1859
|
|
|
|
|
|
|
&& $ua =~ m{ # Disabled for bug compatibility |
1860
|
|
|
|
|
|
|
version/ |
1861
|
|
|
|
|
|
|
( \d+ ) # Major version number is everything before first dot |
1862
|
|
|
|
|
|
|
\. # First dot |
1863
|
|
|
|
|
|
|
( \d+ )? # Minor version number follows dot |
1864
|
|
|
|
|
|
|
}x |
1865
|
|
|
|
|
|
|
) { |
1866
|
|
|
|
|
|
|
# Safari starting with version 3.0 provides its own public version |
1867
|
|
|
|
|
|
|
( $major, $minor ) = ( $1, $2, undef ); |
1868
|
|
|
|
|
|
|
} |
1869
|
0
|
|
|
|
|
0
|
elsif ( $ua =~ m{ safari/ ( \d+ (?: \.\d+ )* ) }x ) { |
1870
|
874
|
50
|
|
|
|
4270
|
if ( my ( $safari_build, $safari_minor ) = split /\./, $1 ) { |
1871
|
874
|
|
|
|
|
2495
|
$major = int( $safari_build / 100 ); |
1872
|
874
|
|
|
|
|
1545
|
$minor = int( $safari_build % 100 ); |
1873
|
874
|
100
|
|
|
|
2201
|
$beta = ".$safari_minor" if defined $safari_minor; |
1874
|
|
|
|
|
|
|
} |
1875
|
|
|
|
|
|
|
} |
1876
|
|
|
|
|
|
|
elsif ( $ua =~ m{applewebkit\/([\d\.]{1,})}xi ) { |
1877
|
66
|
50
|
|
|
|
370
|
if ( my ( $safari_build, $safari_minor ) = split /\./, $1 ) { |
1878
|
66
|
|
|
|
|
202
|
$major = int( $safari_build / 100 ); |
1879
|
66
|
|
|
|
|
128
|
$minor = int( $safari_build % 100 ); |
1880
|
66
|
100
|
|
|
|
190
|
$beta = ".$safari_minor" if $safari_minor; |
1881
|
|
|
|
|
|
|
} |
1882
|
|
|
|
|
|
|
} |
1883
|
|
|
|
|
|
|
} |
1884
|
|
|
|
|
|
|
elsif ( $browser_tests->{fxios} ) { |
1885
|
6
|
|
|
|
|
45
|
( $major, $minor ) = $ua =~ m{ \b fxios/ (\d+) [.] (\d+) }x; |
1886
|
|
|
|
|
|
|
} |
1887
|
|
|
|
|
|
|
elsif ( $browser_tests->{ie} ) { |
1888
|
|
|
|
|
|
|
|
1889
|
|
|
|
|
|
|
# MSIE |
1890
|
|
|
|
|
|
|
|
1891
|
100
|
100
|
|
|
|
647
|
if ( $ua =~ m{\b msie \s ( [0-9\.]+ ) (?: [a-z]+ [a-z0-9]* )? ;}x ) { |
|
|
100
|
|
|
|
|
|
1892
|
|
|
|
|
|
|
|
1893
|
|
|
|
|
|
|
# Internet Explorer |
1894
|
18
|
|
|
|
|
85
|
( $major, $minor, $beta ) = split /\./, $1; |
1895
|
|
|
|
|
|
|
} |
1896
|
|
|
|
|
|
|
elsif ( $ua =~ m{\b rv: ( [0-9\.]+ ) \b}x ) { |
1897
|
|
|
|
|
|
|
|
1898
|
|
|
|
|
|
|
# MSIE masking as Gecko really well ;) |
1899
|
71
|
|
|
|
|
324
|
( $major, $minor, $beta ) = split /\./, $1; |
1900
|
|
|
|
|
|
|
} |
1901
|
|
|
|
|
|
|
} |
1902
|
|
|
|
|
|
|
elsif ( $browser eq 'n3ds' ) { |
1903
|
6
|
50
|
|
|
|
42
|
if ( $ua =~ m{Nintendo 3DS;.*\sVersion/(\d*)\.(\d*)}i ) { |
1904
|
6
|
|
|
|
|
15
|
$major = $1; |
1905
|
6
|
|
|
|
|
11
|
$minor = $2; |
1906
|
|
|
|
|
|
|
} |
1907
|
|
|
|
|
|
|
} |
1908
|
|
|
|
|
|
|
elsif ( $browser eq 'browsex' ) { |
1909
|
6
|
50
|
|
|
|
37
|
if ( $ua =~ m{BrowseX \((\d+)\.(\d+)([\d.]*)}i ) { |
1910
|
6
|
|
|
|
|
19
|
$major = $1; |
1911
|
6
|
|
|
|
|
10
|
$minor = $2; |
1912
|
6
|
|
|
|
|
11
|
$beta = $3; |
1913
|
|
|
|
|
|
|
} |
1914
|
|
|
|
|
|
|
} |
1915
|
|
|
|
|
|
|
elsif ( $ua =~ m{netscape6/(\d+)\.(\d+)([\d.]*)} ) { |
1916
|
|
|
|
|
|
|
|
1917
|
|
|
|
|
|
|
# Other cases get handled below, we just need this to skip the '6' |
1918
|
6
|
|
|
|
|
16
|
$major = $1; |
1919
|
6
|
|
|
|
|
10
|
$minor = $2; |
1920
|
6
|
|
|
|
|
12
|
$beta = $3; |
1921
|
|
|
|
|
|
|
} |
1922
|
|
|
|
|
|
|
elsif ( $browser eq 'brave' ) { |
1923
|
|
|
|
|
|
|
|
1924
|
|
|
|
|
|
|
# Note: since 0.7.10, Brave has changed the branding |
1925
|
|
|
|
|
|
|
# of GitHub's 'Electron' (http://electron.atom.io/) to 'Brave'. |
1926
|
|
|
|
|
|
|
# This means the browser string has both 'brave/' (the browser) |
1927
|
|
|
|
|
|
|
# and 'Brave/' (re-branded Electron) in it. |
1928
|
|
|
|
|
|
|
# The generic section below looks at $self->{browser_string}, which is 'Brave' |
1929
|
|
|
|
|
|
|
# (Electron) and not $self->{browser} which is 'brave'. |
1930
|
|
|
|
|
|
|
# Caveat parser. |
1931
|
12
|
50
|
|
|
|
76
|
if ( $ua =~ m{brave/(\d+)\.(\d+)([\d.]*)} ) { |
1932
|
12
|
|
|
|
|
31
|
$major = $1; |
1933
|
12
|
|
|
|
|
20
|
$minor = $2; |
1934
|
12
|
|
|
|
|
21
|
$beta = $3; |
1935
|
|
|
|
|
|
|
} |
1936
|
|
|
|
|
|
|
} |
1937
|
|
|
|
|
|
|
elsif ($browser eq 'chrome' |
1938
|
|
|
|
|
|
|
&& $ua =~ m{crios/(\d+)\.(\d+)([\d.]*)} ) { |
1939
|
18
|
|
|
|
|
62
|
$major = $1; |
1940
|
18
|
|
|
|
|
37
|
$minor = $2; |
1941
|
18
|
|
|
|
|
43
|
$beta = $3; |
1942
|
|
|
|
|
|
|
} |
1943
|
|
|
|
|
|
|
elsif ($browser eq 'pubsub' |
1944
|
|
|
|
|
|
|
&& $ua =~ m{apple-pubsub/(\d+)\.?(\d+)?([\d.]*)} ) { |
1945
|
6
|
|
|
|
|
15
|
$major = $1; |
1946
|
6
|
|
|
|
|
11
|
$minor = $2; |
1947
|
6
|
|
|
|
|
10
|
$beta = $3; |
1948
|
|
|
|
|
|
|
} |
1949
|
|
|
|
|
|
|
elsif ($browser eq 'obigo' |
1950
|
|
|
|
|
|
|
&& $self->{user_agent} =~ m{(obigo[\w\-]*|teleca)[\/ ]\w(\d+)(\w*)}i ) |
1951
|
|
|
|
|
|
|
{ |
1952
|
78
|
|
|
|
|
263
|
$major = $2; |
1953
|
78
|
|
|
|
|
156
|
$minor = q{}; |
1954
|
78
|
|
|
|
|
163
|
$beta = $3; |
1955
|
|
|
|
|
|
|
} |
1956
|
|
|
|
|
|
|
elsif ($browser eq 'polaris' |
1957
|
|
|
|
|
|
|
&& $ua =~ m{polaris[ \/](\d+)\.?(\d+)?([\d\.]*)} ) { |
1958
|
6
|
|
|
|
|
16
|
$major = $1; |
1959
|
6
|
|
|
|
|
12
|
$minor = $2; |
1960
|
6
|
|
|
|
|
11
|
$beta = $3; |
1961
|
|
|
|
|
|
|
} |
1962
|
|
|
|
|
|
|
elsif ($browser eq 'ucbrowser' |
1963
|
|
|
|
|
|
|
&& $ua =~ m{ucbrowser[\/ ]*(\d+)\.?(\d+)?([\d\.]*)} ) { |
1964
|
335
|
|
|
|
|
917
|
$major = $1; |
1965
|
335
|
|
|
|
|
605
|
$minor = $2; |
1966
|
335
|
|
|
|
|
724
|
$beta = $3; |
1967
|
|
|
|
|
|
|
} |
1968
|
|
|
|
|
|
|
elsif ( $browser eq 'samsung' && $ua =~ m{samsungbrowser/(\d+)\.(\d+)\s} ) |
1969
|
|
|
|
|
|
|
{ |
1970
|
6
|
|
|
|
|
18
|
$major = $1; |
1971
|
6
|
|
|
|
|
10
|
$minor = $2; |
1972
|
|
|
|
|
|
|
} |
1973
|
|
|
|
|
|
|
|
1974
|
|
|
|
|
|
|
# If we didn't match a browser-specific test, we look for |
1975
|
|
|
|
|
|
|
# '$browser/x.y.z' |
1976
|
7108
|
100
|
100
|
|
|
21230
|
if ( !defined $major && defined $self->{browser_string} ) { |
1977
|
2462
|
|
|
|
|
7087
|
my $version_index = index( $ua, lc "$self->{browser_string}/" ); |
1978
|
2462
|
100
|
|
|
|
4561
|
if ( $version_index != -1 ) { |
1979
|
2265
|
|
|
|
|
5073
|
my $version_str |
1980
|
|
|
|
|
|
|
= substr( $ua, $version_index + length($browser) ); |
1981
|
2265
|
100
|
|
|
|
11248
|
if ( $version_str =~ m{/(\d+)\.(\d+)([\w.]*)} ) { |
1982
|
2253
|
|
|
|
|
5160
|
$major = $1; |
1983
|
2253
|
|
|
|
|
3474
|
$minor = $2; |
1984
|
2253
|
|
|
|
|
4220
|
$beta = $3; |
1985
|
|
|
|
|
|
|
} |
1986
|
|
|
|
|
|
|
} |
1987
|
|
|
|
|
|
|
} |
1988
|
|
|
|
|
|
|
|
1989
|
|
|
|
|
|
|
# If that didn't work, we try 'Version/x.y.z' |
1990
|
7108
|
100
|
|
|
|
15283
|
if ( !defined $major ) { |
1991
|
1170
|
100
|
|
|
|
2960
|
if ( $ua =~ m{version/(\d+)\.(\d+)([\w.]*)} ) { |
1992
|
24
|
|
|
|
|
72
|
$major = $1; |
1993
|
24
|
|
|
|
|
40
|
$minor = $2; |
1994
|
24
|
|
|
|
|
42
|
$beta = $3; |
1995
|
|
|
|
|
|
|
} |
1996
|
|
|
|
|
|
|
} |
1997
|
|
|
|
|
|
|
|
1998
|
|
|
|
|
|
|
# If that didn't work, we start guessing. Just grab |
1999
|
|
|
|
|
|
|
# anything after a word and a slash. |
2000
|
7108
|
100
|
|
|
|
11647
|
if ( !defined $major ) { |
2001
|
|
|
|
|
|
|
|
2002
|
1146
|
|
|
|
|
6557
|
( $major, $minor, $beta ) = ( |
2003
|
|
|
|
|
|
|
$ua =~ m{ |
2004
|
|
|
|
|
|
|
\S+ # Greedily catch anything leading up to forward slash. |
2005
|
|
|
|
|
|
|
\/ # Version starts with a slash |
2006
|
|
|
|
|
|
|
[A-Za-z]* # Eat any letters before the major version |
2007
|
|
|
|
|
|
|
( [0-9]+ ) # Major version number is everything before the first dot |
2008
|
|
|
|
|
|
|
\. # The first dot |
2009
|
|
|
|
|
|
|
([\d]* ) # Minor version number is every digit after the first dot |
2010
|
|
|
|
|
|
|
# Throw away remaining numbers and dots |
2011
|
|
|
|
|
|
|
( [^\s]* ) # Beta version string is up to next space |
2012
|
|
|
|
|
|
|
}x |
2013
|
|
|
|
|
|
|
); |
2014
|
|
|
|
|
|
|
} |
2015
|
|
|
|
|
|
|
|
2016
|
|
|
|
|
|
|
# If that didn't work, try even more generic. |
2017
|
7108
|
100
|
|
|
|
14253
|
if ( !defined $major ) { |
2018
|
|
|
|
|
|
|
|
2019
|
324
|
50
|
|
|
|
1010
|
if ( $ua =~ /[A-Za-z]+\/(\d+)\;/ ) { |
2020
|
0
|
|
|
|
|
0
|
$major = $1; |
2021
|
0
|
|
|
|
|
0
|
$minor = 0; |
2022
|
|
|
|
|
|
|
} |
2023
|
|
|
|
|
|
|
} |
2024
|
|
|
|
|
|
|
|
2025
|
|
|
|
|
|
|
# If that didn't work, give up. |
2026
|
7108
|
100
|
|
|
|
12567
|
$major = 0 if !$major; |
2027
|
7108
|
100
|
|
|
|
12005
|
$minor = 0 if !$minor; |
2028
|
7108
|
100
|
100
|
|
|
22535
|
$beta = undef if ( defined $beta && $beta eq q{} ); |
2029
|
|
|
|
|
|
|
|
2030
|
|
|
|
|
|
|
# Now set version tests |
2031
|
|
|
|
|
|
|
|
2032
|
7108
|
100
|
|
|
|
15094
|
if ( $browser_tests->{netscape} ) { |
2033
|
|
|
|
|
|
|
|
2034
|
|
|
|
|
|
|
# Netscape browsers |
2035
|
168
|
100
|
|
|
|
1483
|
$version_tests->{nav2} = 1 if $major == 2; |
2036
|
168
|
100
|
|
|
|
381
|
$version_tests->{nav3} = 1 if $major == 3; |
2037
|
168
|
100
|
|
|
|
369
|
$version_tests->{nav4} = 1 if $major == 4; |
2038
|
168
|
100
|
|
|
|
448
|
$version_tests->{nav4up} = 1 if $major >= 4; |
2039
|
168
|
100
|
100
|
|
|
505
|
$version_tests->{nav45} = 1 if $major == 4 && $minor == 5; |
2040
|
168
|
100
|
100
|
|
|
771
|
$version_tests->{nav45up} = 1 |
|
|
|
100
|
|
|
|
|
2041
|
|
|
|
|
|
|
if ( $major == 4 && ".$minor" >= .5 ) |
2042
|
|
|
|
|
|
|
|| $major >= 5; |
2043
|
168
|
100
|
100
|
|
|
424
|
$version_tests->{navgold} = 1 |
2044
|
|
|
|
|
|
|
if defined $beta && ( index( $beta, 'gold' ) != -1 ); |
2045
|
168
|
100
|
100
|
|
|
521
|
$version_tests->{nav6} = 1 |
2046
|
|
|
|
|
|
|
if ( $major == 5 || $major == 6 ); # go figure |
2047
|
168
|
100
|
|
|
|
373
|
$version_tests->{nav6up} = 1 if $major >= 5; |
2048
|
|
|
|
|
|
|
|
2049
|
168
|
100
|
|
|
|
353
|
if ( $browser eq 'seamonkey' ) { |
2050
|
|
|
|
|
|
|
|
2051
|
|
|
|
|
|
|
# Ugh, seamonkey versions started back at 1. |
2052
|
6
|
|
|
|
|
11
|
$version_tests->{nav2} = 0; |
2053
|
6
|
|
|
|
|
10
|
$version_tests->{nav4up} = 1; |
2054
|
6
|
|
|
|
|
11
|
$version_tests->{nav45up} = 1; |
2055
|
6
|
|
|
|
|
10
|
$version_tests->{nav6} = 1; |
2056
|
6
|
|
|
|
|
13
|
$version_tests->{nav6up} = 1; |
2057
|
|
|
|
|
|
|
} |
2058
|
|
|
|
|
|
|
} |
2059
|
|
|
|
|
|
|
|
2060
|
7108
|
100
|
|
|
|
13157
|
if ( $browser_tests->{ie} ) { |
2061
|
1708
|
100
|
|
|
|
4980
|
$version_tests->{ie3} = 1 if ( $major == 3 ); |
2062
|
1708
|
100
|
|
|
|
4282
|
$version_tests->{ie4} = 1 if ( $major == 4 ); |
2063
|
1708
|
100
|
|
|
|
5769
|
$version_tests->{ie4up} = 1 if ( $major >= 4 ); |
2064
|
1708
|
100
|
|
|
|
3581
|
$version_tests->{ie5} = 1 if ( $major == 5 ); |
2065
|
1708
|
100
|
|
|
|
4151
|
$version_tests->{ie5up} = 1 if ( $major >= 5 ); |
2066
|
1708
|
100
|
100
|
|
|
4262
|
$version_tests->{ie55} = 1 if ( $major == 5 && $minor == 5 ); |
2067
|
1708
|
100
|
100
|
|
|
10616
|
$version_tests->{ie55up} = 1 if ( ".$minor" >= .5 || $major >= 6 ); |
2068
|
1708
|
100
|
|
|
|
4162
|
$version_tests->{ie6} = 1 if ( $major == 6 ); |
2069
|
1708
|
100
|
|
|
|
3480
|
$version_tests->{ie7} = 1 if ( $major == 7 ); |
2070
|
1708
|
100
|
|
|
|
3911
|
$version_tests->{ie8} = 1 if ( $major == 8 ); |
2071
|
1708
|
100
|
|
|
|
3604
|
$version_tests->{ie9} = 1 if ( $major == 9 ); |
2072
|
1708
|
100
|
|
|
|
3262
|
$version_tests->{ie10} = 1 if ( $major == 10 ); |
2073
|
1708
|
100
|
|
|
|
3897
|
$version_tests->{ie11} = 1 if ( $major == 11 ); |
2074
|
|
|
|
|
|
|
|
2075
|
|
|
|
|
|
|
$version_tests->{ie_compat_mode} |
2076
|
|
|
|
|
|
|
= ( $version_tests->{ie7} |
2077
|
|
|
|
|
|
|
&& $tests->{trident} |
2078
|
1708
|
|
100
|
|
|
5210
|
&& defined $self->engine_version |
2079
|
|
|
|
|
|
|
&& $self->engine_version >= 4 ); |
2080
|
|
|
|
|
|
|
} |
2081
|
|
|
|
|
|
|
|
2082
|
7108
|
100
|
|
|
|
15620
|
if ( $browser_tests->{aol} ) { |
2083
|
|
|
|
|
|
|
$version_tests->{aol3} = 1 |
2084
|
|
|
|
|
|
|
if ( index( $ua, 'aol 3.0' ) != -1 |
2085
|
41
|
100
|
66
|
|
|
221
|
|| $version_tests->{ie3} ); |
2086
|
|
|
|
|
|
|
$version_tests->{aol4} = 1 |
2087
|
|
|
|
|
|
|
if ( index( $ua, 'aol 4.0' ) != -1 ) |
2088
|
41
|
50
|
33
|
|
|
192
|
|| $version_tests->{ie4}; |
2089
|
41
|
50
|
|
|
|
116
|
$version_tests->{aol5} = 1 if index( $ua, 'aol 5.0' ) != -1; |
2090
|
41
|
100
|
|
|
|
107
|
$version_tests->{aol6} = 1 if index( $ua, 'aol 6.0' ) != -1; |
2091
|
41
|
50
|
|
|
|
105
|
$version_tests->{aoltv} = 1 if index( $ua, 'navio' ) != -1; |
2092
|
|
|
|
|
|
|
} |
2093
|
|
|
|
|
|
|
|
2094
|
7108
|
100
|
|
|
|
13687
|
if ( $browser_tests->{opera} ) { |
2095
|
264
|
100
|
66
|
|
|
1686
|
$version_tests->{opera3} = 1 |
2096
|
|
|
|
|
|
|
if index( $ua, 'opera 3' ) != -1 || index( $ua, 'opera/3' ) != -1; |
2097
|
264
|
50
|
66
|
|
|
1466
|
$version_tests->{opera4} = 1 |
|
|
|
33
|
|
|
|
|
2098
|
|
|
|
|
|
|
if ( index( $ua, 'opera 4' ) != -1 ) |
2099
|
|
|
|
|
|
|
|| ( index( $ua, 'opera/4' ) != -1 |
2100
|
|
|
|
|
|
|
&& ( index( $ua, 'nintendo dsi' ) == -1 ) ); |
2101
|
264
|
50
|
33
|
|
|
1340
|
$version_tests->{opera5} = 1 |
2102
|
|
|
|
|
|
|
if ( index( $ua, 'opera 5' ) != -1 ) |
2103
|
|
|
|
|
|
|
|| ( index( $ua, 'opera/5' ) != -1 ); |
2104
|
264
|
100
|
66
|
|
|
1445
|
$version_tests->{opera6} = 1 |
2105
|
|
|
|
|
|
|
if ( index( $ua, 'opera 6' ) != -1 ) |
2106
|
|
|
|
|
|
|
|| ( index( $ua, 'opera/6' ) != -1 ); |
2107
|
264
|
100
|
100
|
|
|
1313
|
$version_tests->{opera7} = 1 |
2108
|
|
|
|
|
|
|
if ( index( $ua, 'opera 7' ) != -1 ) |
2109
|
|
|
|
|
|
|
|| ( index( $ua, 'opera/7' ) != -1 ); |
2110
|
|
|
|
|
|
|
|
2111
|
|
|
|
|
|
|
} |
2112
|
|
|
|
|
|
|
|
2113
|
7108
|
|
|
|
|
14105
|
$minor = ".$minor"; |
2114
|
|
|
|
|
|
|
|
2115
|
7108
|
|
|
|
|
16564
|
$self->{major} = $major; |
2116
|
7108
|
|
|
|
|
14439
|
$self->{minor} = $minor; |
2117
|
7108
|
|
|
|
|
14783
|
$self->{beta} = $beta; |
2118
|
|
|
|
|
|
|
} |
2119
|
|
|
|
|
|
|
|
2120
|
|
|
|
|
|
|
### Device tests, only run on demand |
2121
|
|
|
|
|
|
|
|
2122
|
|
|
|
|
|
|
sub _init_device { |
2123
|
8222
|
|
|
8222
|
|
13324
|
my ($self) = @_; |
2124
|
|
|
|
|
|
|
|
2125
|
8222
|
|
|
|
|
18238
|
my $ua = lc $self->{user_agent}; |
2126
|
8222
|
|
|
|
|
12127
|
my $browser_tests = $self->{browser_tests}; |
2127
|
8222
|
|
|
|
|
11986
|
my $tests = $self->{tests}; |
2128
|
|
|
|
|
|
|
|
2129
|
8222
|
|
|
|
|
10318
|
my ( $device, $device_string ); |
2130
|
8222
|
|
|
|
|
15971
|
my $device_tests = $self->{device_tests} = {}; |
2131
|
|
|
|
|
|
|
|
2132
|
8222
|
100
|
100
|
|
|
258523
|
if ( index( $ua, 'windows phone' ) != -1 ) { |
|
|
100
|
100
|
|
|
|
|
|
|
100
|
100
|
|
|
|
|
|
|
100
|
100
|
|
|
|
|
|
|
100
|
100
|
|
|
|
|
|
|
100
|
66
|
|
|
|
|
|
|
100
|
100
|
|
|
|
|
|
|
100
|
66
|
|
|
|
|
|
|
50
|
100
|
|
|
|
|
|
|
50
|
66
|
|
|
|
|
|
|
50
|
100
|
|
|
|
|
|
|
50
|
66
|
|
|
|
|
|
|
100
|
66
|
|
|
|
|
|
|
100
|
66
|
|
|
|
|
|
|
100
|
66
|
|
|
|
|
|
|
100
|
100
|
|
|
|
|
|
|
100
|
66
|
|
|
|
|
|
|
|
66
|
|
|
|
|
|
|
|
66
|
|
|
|
|
|
|
|
66
|
|
|
|
|
|
|
|
66
|
|
|
|
|
2133
|
54
|
|
|
|
|
82
|
$device = 'winphone'; |
2134
|
|
|
|
|
|
|
|
2135
|
|
|
|
|
|
|
# Test is set in _init_os() |
2136
|
|
|
|
|
|
|
} |
2137
|
|
|
|
|
|
|
elsif (index( $ua, 'android' ) != -1 |
2138
|
|
|
|
|
|
|
|| index( $ua, 'silk-accelerated' ) != -1 ) { |
2139
|
|
|
|
|
|
|
|
2140
|
|
|
|
|
|
|
# Silk-accelerated indicates a 1st generation Kindle Fire, |
2141
|
|
|
|
|
|
|
# which may not have other indications of being an Android |
2142
|
|
|
|
|
|
|
# device. |
2143
|
972
|
|
|
|
|
1352
|
$device = 'android'; |
2144
|
972
|
|
|
|
|
1697
|
$device_tests->{$device} = 1; |
2145
|
|
|
|
|
|
|
} |
2146
|
|
|
|
|
|
|
elsif (index( $ua, 'blackberry' ) != -1 |
2147
|
|
|
|
|
|
|
|| index( $ua, 'bb10' ) != -1 |
2148
|
|
|
|
|
|
|
|| index( $ua, 'rim tablet os' ) != -1 ) { |
2149
|
42
|
|
|
|
|
64
|
$device = 'blackberry'; |
2150
|
42
|
|
|
|
|
77
|
$device_tests->{$device} = 1; |
2151
|
|
|
|
|
|
|
} |
2152
|
|
|
|
|
|
|
elsif ( index( $ua, 'ipod' ) != -1 ) { |
2153
|
18
|
|
|
|
|
25
|
$device = 'ipod'; |
2154
|
18
|
|
|
|
|
40
|
$device_tests->{$device} = 1; |
2155
|
|
|
|
|
|
|
} |
2156
|
|
|
|
|
|
|
elsif ( index( $ua, 'ipad' ) != -1 ) { |
2157
|
156
|
|
|
|
|
348
|
$device = 'ipad'; |
2158
|
156
|
|
|
|
|
457
|
$device_tests->{$device} = 1; |
2159
|
|
|
|
|
|
|
} |
2160
|
|
|
|
|
|
|
elsif ( index( $ua, 'iphone' ) != -1 ) { |
2161
|
204
|
|
|
|
|
309
|
$device = 'iphone'; |
2162
|
204
|
|
|
|
|
377
|
$device_tests->{$device} = 1; |
2163
|
|
|
|
|
|
|
} |
2164
|
|
|
|
|
|
|
elsif ( index( $ua, 'webos' ) != -1 ) { |
2165
|
6
|
|
|
|
|
33
|
$device = 'webos'; |
2166
|
6
|
|
|
|
|
16
|
$device_tests->{$device} = 1; |
2167
|
|
|
|
|
|
|
} |
2168
|
|
|
|
|
|
|
elsif ( index( $ua, 'kindle' ) != -1 ) { |
2169
|
12
|
|
|
|
|
21
|
$device = 'kindle'; |
2170
|
12
|
|
|
|
|
25
|
$device_tests->{$device} = 1; |
2171
|
|
|
|
|
|
|
} |
2172
|
|
|
|
|
|
|
elsif ( index( $ua, 'audrey' ) != -1 ) { |
2173
|
0
|
|
|
|
|
0
|
$device = 'audrey'; |
2174
|
0
|
|
|
|
|
0
|
$device_tests->{$device} = 1; |
2175
|
|
|
|
|
|
|
} |
2176
|
|
|
|
|
|
|
elsif ( index( $ua, 'i-opener' ) != -1 ) { |
2177
|
0
|
|
|
|
|
0
|
$device = 'iopener'; |
2178
|
0
|
|
|
|
|
0
|
$device_tests->{$device} = 1; |
2179
|
|
|
|
|
|
|
} |
2180
|
|
|
|
|
|
|
elsif ( index( $ua, 'avantgo' ) != -1 ) { |
2181
|
0
|
|
|
|
|
0
|
$device = 'avantgo'; |
2182
|
0
|
|
|
|
|
0
|
$device_tests->{$device} = 1; |
2183
|
0
|
|
|
|
|
0
|
$device_tests->{palm} = 1; |
2184
|
|
|
|
|
|
|
} |
2185
|
|
|
|
|
|
|
elsif ( index( $ua, 'palmos' ) != -1 ) { |
2186
|
0
|
|
|
|
|
0
|
$device = 'palm'; |
2187
|
0
|
|
|
|
|
0
|
$device_tests->{$device} = 1; |
2188
|
|
|
|
|
|
|
} |
2189
|
|
|
|
|
|
|
elsif ( index( $ua, 'playstation 3' ) != -1 ) { |
2190
|
6
|
|
|
|
|
11
|
$device = 'ps3'; |
2191
|
6
|
|
|
|
|
12
|
$device_tests->{$device} = 1; |
2192
|
|
|
|
|
|
|
} |
2193
|
|
|
|
|
|
|
elsif ( index( $ua, 'playstation portable' ) != -1 ) { |
2194
|
6
|
|
|
|
|
9
|
$device = 'psp'; |
2195
|
6
|
|
|
|
|
13
|
$device_tests->{$device} = 1; |
2196
|
|
|
|
|
|
|
} |
2197
|
|
|
|
|
|
|
elsif ( index( $ua, 'nintendo dsi' ) != -1 ) { |
2198
|
6
|
|
|
|
|
14
|
$device = 'dsi'; |
2199
|
6
|
|
|
|
|
18
|
$device_tests->{$device} = 1; |
2200
|
|
|
|
|
|
|
} |
2201
|
|
|
|
|
|
|
elsif ( index( $ua, 'nintendo 3ds' ) != -1 ) { |
2202
|
6
|
|
|
|
|
11
|
$device = 'n3ds'; |
2203
|
6
|
|
|
|
|
14
|
$device_tests->{$device} = 1; |
2204
|
|
|
|
|
|
|
} |
2205
|
|
|
|
|
|
|
elsif ( |
2206
|
|
|
|
|
|
|
$browser_tests->{obigo} |
2207
|
|
|
|
|
|
|
|| $browser_tests->{ucbrowser} |
2208
|
|
|
|
|
|
|
|| index( $ua, 'up.browser' ) != -1 |
2209
|
|
|
|
|
|
|
|| ( index( $ua, 'nokia' ) != -1 |
2210
|
|
|
|
|
|
|
&& index( $ua, 'windows phone' ) == -1 ) |
2211
|
|
|
|
|
|
|
|| index( $ua, 'alcatel' ) != -1 |
2212
|
|
|
|
|
|
|
|| $ua =~ m{\bbrew\b} |
2213
|
|
|
|
|
|
|
|| $ua =~ m{\bbmp\b} |
2214
|
|
|
|
|
|
|
|| index( $ua, 'ericsson' ) != -1 |
2215
|
|
|
|
|
|
|
|| index( $ua, 'sie-' ) == 0 |
2216
|
|
|
|
|
|
|
|| index( $ua, 'wmlib' ) != -1 |
2217
|
|
|
|
|
|
|
|| index( $ua, ' wap' ) != -1 |
2218
|
|
|
|
|
|
|
|| index( $ua, 'wap ' ) != -1 |
2219
|
|
|
|
|
|
|
|| index( $ua, 'wap/' ) != -1 |
2220
|
|
|
|
|
|
|
|| index( $ua, '-wap' ) != -1 |
2221
|
|
|
|
|
|
|
|| index( $ua, 'wap-' ) != -1 |
2222
|
|
|
|
|
|
|
|| index( $ua, 'wap' ) == 0 |
2223
|
|
|
|
|
|
|
|| index( $ua, 'wapper' ) != -1 |
2224
|
|
|
|
|
|
|
|| index( $ua, 'zetor' ) != -1 |
2225
|
|
|
|
|
|
|
) { |
2226
|
582
|
|
|
|
|
1317
|
$device = 'wap'; |
2227
|
582
|
|
|
|
|
1302
|
$device_tests->{$device} = 1; |
2228
|
|
|
|
|
|
|
} |
2229
|
|
|
|
|
|
|
|
2230
|
|
|
|
|
|
|
$device_tests->{tablet} = ( |
2231
|
|
|
|
|
|
|
index( $ua, 'ipad' ) != -1 |
2232
|
|
|
|
|
|
|
|| ( $browser_tests->{ie} |
2233
|
|
|
|
|
|
|
&& index( $ua, 'windows phone' ) == -1 |
2234
|
|
|
|
|
|
|
&& index( $ua, 'arm' ) != -1 ) |
2235
|
|
|
|
|
|
|
|| ( index( $ua, 'android' ) != -1 |
2236
|
|
|
|
|
|
|
&& index( $ua, 'mobile' ) == -1 |
2237
|
|
|
|
|
|
|
&& index( $ua, 'safari' ) != -1 ) |
2238
|
8222
|
|
66
|
|
|
251828
|
|| ( $browser_tests->{firefox} && index( $ua, 'tablet' ) != -1 ) |
2239
|
|
|
|
|
|
|
|| index( $ua, 'an10bg3' ) != -1 |
2240
|
|
|
|
|
|
|
|| index( $ua, 'an10bg3dt' ) != -1 |
2241
|
|
|
|
|
|
|
|| index( $ua, 'an10g2' ) != -1 |
2242
|
|
|
|
|
|
|
|| index( $ua, 'an7bg3' ) != -1 |
2243
|
|
|
|
|
|
|
|| index( $ua, 'an7dg3' ) != -1 |
2244
|
|
|
|
|
|
|
|| index( $ua, 'an7dg3childpad' ) != -1 |
2245
|
|
|
|
|
|
|
|| index( $ua, 'an7dg3st' ) != -1 |
2246
|
|
|
|
|
|
|
|| index( $ua, 'an7fg3' ) != -1 |
2247
|
|
|
|
|
|
|
|| index( $ua, 'an7g3' ) != -1 |
2248
|
|
|
|
|
|
|
|| index( $ua, 'an8cg3' ) != -1 |
2249
|
|
|
|
|
|
|
|| index( $ua, 'an8g3' ) != -1 |
2250
|
|
|
|
|
|
|
|| index( $ua, 'an9g3' ) != -1 |
2251
|
|
|
|
|
|
|
|| index( $ua, 'flyer' ) != -1 |
2252
|
|
|
|
|
|
|
|| index( $ua, 'hp-tablet' ) != -1 |
2253
|
|
|
|
|
|
|
|| index( $ua, 'jetstream' ) != -1 |
2254
|
|
|
|
|
|
|
|| index( $ua, 'kindle' ) != -1 |
2255
|
|
|
|
|
|
|
|| index( $ua, 'novo7' ) != -1 |
2256
|
|
|
|
|
|
|
|| index( $ua, 'opera tablet' ) != -1 |
2257
|
|
|
|
|
|
|
|| index( $ua, 'rim tablet' ) != -1 |
2258
|
|
|
|
|
|
|
|| index( $ua, 'transformer' ) != -1 |
2259
|
|
|
|
|
|
|
|| index( $ua, 'xoom' ) != -1 |
2260
|
|
|
|
|
|
|
); |
2261
|
|
|
|
|
|
|
|
2262
|
8222
|
100
|
|
|
|
18613
|
if ( !$device_tests->{tablet} ) { |
2263
|
|
|
|
|
|
|
$device_tests->{mobile} = ( |
2264
|
|
|
|
|
|
|
( $browser_tests->{firefox} && index( $ua, 'mobile' ) != -1 ) |
2265
|
|
|
|
|
|
|
|| ( $browser_tests->{ie} |
2266
|
|
|
|
|
|
|
&& index( $ua, 'windows phone' ) == -1 |
2267
|
|
|
|
|
|
|
&& index( $ua, 'arm' ) != -1 ) |
2268
|
|
|
|
|
|
|
|| index( $ua, 'windows phone' ) != -1 |
2269
|
|
|
|
|
|
|
|| index( $ua, 'up.browser' ) != -1 |
2270
|
|
|
|
|
|
|
|| index( $ua, 'nokia' ) != -1 |
2271
|
|
|
|
|
|
|
|| index( $ua, 'alcatel' ) != -1 |
2272
|
|
|
|
|
|
|
|| index( $ua, 'ericsson' ) != -1 |
2273
|
|
|
|
|
|
|
|| index( $ua, 'sie-' ) == 0 |
2274
|
|
|
|
|
|
|
|| index( $ua, 'wmlib' ) != -1 |
2275
|
|
|
|
|
|
|
|| index( $ua, ' wap' ) != -1 |
2276
|
|
|
|
|
|
|
|| index( $ua, 'wap ' ) != -1 |
2277
|
|
|
|
|
|
|
|| index( $ua, 'wap/' ) != -1 |
2278
|
|
|
|
|
|
|
|| index( $ua, '-wap' ) != -1 |
2279
|
|
|
|
|
|
|
|| index( $ua, 'wap-' ) != -1 |
2280
|
|
|
|
|
|
|
|| index( $ua, 'wap' ) == 0 |
2281
|
|
|
|
|
|
|
|| index( $ua, 'wapper' ) != -1 |
2282
|
|
|
|
|
|
|
|| index( $ua, 'blackberry' ) != -1 |
2283
|
|
|
|
|
|
|
|| index( $ua, 'mobile' ) != -1 |
2284
|
|
|
|
|
|
|
|| index( $ua, 'palm' ) != -1 |
2285
|
|
|
|
|
|
|
|| index( $ua, 'smartphone' ) != -1 |
2286
|
|
|
|
|
|
|
|| index( $ua, 'windows ce' ) != -1 |
2287
|
|
|
|
|
|
|
|| index( $ua, 'palmsource' ) != -1 |
2288
|
|
|
|
|
|
|
|| index( $ua, 'iphone' ) != -1 |
2289
|
|
|
|
|
|
|
|| index( $ua, 'ipod' ) != -1 |
2290
|
|
|
|
|
|
|
|| index( $ua, 'ipad' ) != -1 |
2291
|
|
|
|
|
|
|
|| ( index( $ua, 'opera mini' ) != -1 |
2292
|
|
|
|
|
|
|
&& index( $ua, 'tablet' ) == -1 ) |
2293
|
|
|
|
|
|
|
|| index( $ua, 'htc_' ) != -1 |
2294
|
|
|
|
|
|
|
|| index( $ua, 'symbian' ) != -1 |
2295
|
|
|
|
|
|
|
|| index( $ua, 'webos' ) != -1 |
2296
|
|
|
|
|
|
|
|| index( $ua, 'samsung' ) != -1 |
2297
|
|
|
|
|
|
|
|| index( $ua, 'zetor' ) != -1 |
2298
|
|
|
|
|
|
|
|| index( $ua, 'android' ) != -1 |
2299
|
|
|
|
|
|
|
|| index( $ua, 'symbos' ) != -1 |
2300
|
|
|
|
|
|
|
|| index( $ua, 'opera mobi' ) != -1 |
2301
|
|
|
|
|
|
|
|| index( $ua, 'fennec' ) != -1 |
2302
|
|
|
|
|
|
|
|| $ua =~ m{\bbrew\b} |
2303
|
|
|
|
|
|
|
|| index( $ua, 'obigo' ) != -1 |
2304
|
|
|
|
|
|
|
|| index( $ua, 'teleca' ) != -1 |
2305
|
|
|
|
|
|
|
|| index( $ua, 'polaris' ) != -1 |
2306
|
|
|
|
|
|
|
|| index( $ua, 'opera tablet' ) != -1 |
2307
|
|
|
|
|
|
|
|| index( $ua, 'rim tablet' ) != -1 |
2308
|
|
|
|
|
|
|
|| ( index( $ua, 'bb10' ) != -1 |
2309
|
|
|
|
|
|
|
&& index( $ua, 'mobile' ) != -1 ) |
2310
|
|
|
|
|
|
|
|| $device_tests->{psp} |
2311
|
|
|
|
|
|
|
|| $device_tests->{dsi} |
2312
|
7891
|
|
100
|
|
|
347855
|
|| $device_tests->{'n3ds'} |
2313
|
|
|
|
|
|
|
); |
2314
|
|
|
|
|
|
|
} |
2315
|
|
|
|
|
|
|
|
2316
|
8222
|
100
|
100
|
|
|
172782
|
if ( $browser_tests->{ucbrowser} |
|
|
100
|
100
|
|
|
|
|
|
|
100
|
100
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
2317
|
|
|
|
|
|
|
&& $self->{user_agent} |
2318
|
|
|
|
|
|
|
=~ m{ucweb/2.0\s*\(([^\;\)]*\;){3,4}\s*([^\;\)]*?)\s*\)}i ) { |
2319
|
276
|
|
|
|
|
909
|
$device_string = $2; |
2320
|
|
|
|
|
|
|
} |
2321
|
|
|
|
|
|
|
elsif ( $ua =~ /^(\bmot-[^ \/]+)/ ) { |
2322
|
12
|
|
|
|
|
56
|
$device_string = substr $self->{user_agent}, 0, length $1; |
2323
|
12
|
|
|
|
|
102
|
$device_string =~ s/^MOT-/Motorola /i; |
2324
|
|
|
|
|
|
|
} |
2325
|
|
|
|
|
|
|
elsif ( ( $browser_tests->{obigo} || index( $ua, 'brew' ) != -1 ) |
2326
|
|
|
|
|
|
|
&& $self->{user_agent} =~ m{\d+x\d+ ([\d\w\- ]+?)( \S+\/\S+)*$}i ) { |
2327
|
108
|
|
|
|
|
358
|
$device_string = $1; |
2328
|
|
|
|
|
|
|
} |
2329
|
|
|
|
|
|
|
elsif ( |
2330
|
|
|
|
|
|
|
$ua =~ /windows phone os [^\)]+ iemobile\/[^;]+; ([^;]+; [^;\)]+)/g ) |
2331
|
|
|
|
|
|
|
{ |
2332
|
|
|
|
|
|
|
# windows phone 7.x |
2333
|
|
|
|
|
|
|
$device_string = substr $self->{user_agent}, |
2334
|
18
|
|
|
|
|
101
|
pos($ua) - length $1, length $1; |
2335
|
18
|
|
|
|
|
73
|
$device_string =~ s/; / /; |
2336
|
|
|
|
|
|
|
} |
2337
|
|
|
|
|
|
|
elsif ( $ua |
2338
|
|
|
|
|
|
|
=~ /windows phone [^\)]+ iemobile\/[^;]+; arm; touch; ([^;]+; [^;\)]+)/g |
2339
|
|
|
|
|
|
|
) { |
2340
|
|
|
|
|
|
|
# windows phone 8.0 |
2341
|
|
|
|
|
|
|
$device_string = substr $self->{user_agent}, |
2342
|
12
|
|
|
|
|
52
|
pos($ua) - length $1, length $1; |
2343
|
12
|
|
|
|
|
37
|
$device_string =~ s/; / /; |
2344
|
|
|
|
|
|
|
} |
2345
|
|
|
|
|
|
|
elsif ( |
2346
|
|
|
|
|
|
|
$ua =~ /windows phone 8[^\)]+ iemobile\/[^;]+; ([^;]+; [^;\)]+)/g ) { |
2347
|
|
|
|
|
|
|
|
2348
|
|
|
|
|
|
|
# windows phone 8.1 |
2349
|
|
|
|
|
|
|
$device_string = substr $self->{user_agent}, |
2350
|
18
|
|
|
|
|
77
|
pos($ua) - length $1, length $1; |
2351
|
18
|
|
|
|
|
56
|
$device_string =~ s/; / /; |
2352
|
|
|
|
|
|
|
} |
2353
|
|
|
|
|
|
|
elsif ( $ua =~ /bb10; ([^;\)]+)/g ) { |
2354
|
|
|
|
|
|
|
$device_string = 'BlackBerry ' . substr $self->{user_agent}, |
2355
|
12
|
|
|
|
|
54
|
pos($ua) - length $1, length $1; |
2356
|
12
|
|
|
|
|
29
|
$device_string =~ s/Kbd/Q10/; |
2357
|
|
|
|
|
|
|
} |
2358
|
|
|
|
|
|
|
elsif ( $ua =~ /blackberry ([\w.]+)/ ) { |
2359
|
6
|
|
|
|
|
21
|
$device_string = "BlackBerry $1"; |
2360
|
|
|
|
|
|
|
} |
2361
|
|
|
|
|
|
|
elsif ( $ua =~ /blackberry(\d+)\// ) { |
2362
|
18
|
|
|
|
|
60
|
$device_string = "BlackBerry $1"; |
2363
|
|
|
|
|
|
|
} |
2364
|
|
|
|
|
|
|
elsif ( $ua =~ /silk-accelerated/ ) { |
2365
|
|
|
|
|
|
|
|
2366
|
|
|
|
|
|
|
# Only first generation Kindle Fires have that string |
2367
|
12
|
|
|
|
|
21
|
$device_string = 'Kindle Fire'; |
2368
|
12
|
|
|
|
|
19
|
$device_tests->{kindlefire} = 1; |
2369
|
|
|
|
|
|
|
} |
2370
|
|
|
|
|
|
|
elsif ( $self->{user_agent} =~ /android .*\; ([^;]*) build/i ) { |
2371
|
906
|
|
|
|
|
2393
|
my $model = $1; |
2372
|
906
|
100
|
100
|
|
|
3209
|
if ( $model =~ m{^KF} || $model =~ m{kindle fire}i ) { |
|
|
100
|
|
|
|
|
|
2373
|
|
|
|
|
|
|
|
2374
|
|
|
|
|
|
|
# We might hit this even if tablet() is false, if we have |
2375
|
|
|
|
|
|
|
# a Kindle Fire masquerading as a mobile device. |
2376
|
54
|
|
|
|
|
82
|
$device_string = 'Kindle Fire'; |
2377
|
54
|
|
|
|
|
96
|
$device_tests->{kindlefire} = 1; |
2378
|
|
|
|
|
|
|
} |
2379
|
|
|
|
|
|
|
elsif ( $device_tests->{tablet} ) { |
2380
|
78
|
|
|
|
|
213
|
$device_string = "Android tablet ($model)"; |
2381
|
|
|
|
|
|
|
} |
2382
|
|
|
|
|
|
|
else { |
2383
|
774
|
|
|
|
|
1840
|
$device_string = "Android ($model)"; |
2384
|
|
|
|
|
|
|
} |
2385
|
|
|
|
|
|
|
} |
2386
|
|
|
|
|
|
|
elsif ( $self->{user_agent} |
2387
|
|
|
|
|
|
|
=~ /\b((alcatel|huawei|lg|nokia|samsung|sonyericsson)[\w\-]*)\//i ) { |
2388
|
114
|
|
|
|
|
367
|
$device_string = $1; |
2389
|
|
|
|
|
|
|
} |
2390
|
|
|
|
|
|
|
elsif ( $self->{user_agent} =~ /CrKey/ ) { |
2391
|
6
|
|
|
|
|
14
|
$device = 'chromecast'; |
2392
|
6
|
|
|
|
|
8
|
$device_string = 'Chromecast'; |
2393
|
|
|
|
|
|
|
} |
2394
|
|
|
|
|
|
|
elsif ($device) { |
2395
|
558
|
|
|
|
|
1428
|
$device_string = $DEVICE_NAMES{$device}; |
2396
|
|
|
|
|
|
|
} |
2397
|
|
|
|
|
|
|
else { |
2398
|
6146
|
|
|
|
|
11060
|
$device_string = undef; |
2399
|
|
|
|
|
|
|
} |
2400
|
|
|
|
|
|
|
|
2401
|
8222
|
100
|
|
|
|
13174
|
if ($device) { |
2402
|
2076
|
|
|
|
|
5954
|
$self->{device} = $device; |
2403
|
|
|
|
|
|
|
} |
2404
|
|
|
|
|
|
|
else { |
2405
|
|
|
|
|
|
|
$self->{device} |
2406
|
6146
|
|
|
|
|
14405
|
= undef; # Means we cache the fact that we found nothing |
2407
|
|
|
|
|
|
|
} |
2408
|
|
|
|
|
|
|
|
2409
|
8222
|
100
|
|
|
|
19148
|
if ($device_string) { |
2410
|
2070
|
|
|
|
|
5054
|
$self->{device_string} = $device_string; |
2411
|
|
|
|
|
|
|
} |
2412
|
|
|
|
|
|
|
} |
2413
|
|
|
|
|
|
|
|
2414
|
|
|
|
|
|
|
### Now a big block of public accessors for tests and information |
2415
|
|
|
|
|
|
|
|
2416
|
|
|
|
|
|
|
sub browser { |
2417
|
1705
|
|
|
1705
|
1
|
734578
|
my ($self) = @_; |
2418
|
1705
|
50
|
|
|
|
4846
|
return undef unless defined $self->{user_agent}; |
2419
|
1705
|
|
|
|
|
7011
|
return $self->{browser}; |
2420
|
|
|
|
|
|
|
} |
2421
|
|
|
|
|
|
|
|
2422
|
|
|
|
|
|
|
sub browser_string { |
2423
|
1673
|
|
|
1673
|
1
|
707256
|
my ($self) = @_; |
2424
|
1673
|
50
|
|
|
|
4301
|
return undef unless defined $self->{user_agent}; |
2425
|
1673
|
|
|
|
|
5671
|
return $self->{browser_string}; |
2426
|
|
|
|
|
|
|
} |
2427
|
|
|
|
|
|
|
|
2428
|
|
|
|
|
|
|
sub robot { |
2429
|
2234
|
|
|
2234
|
1
|
1972665
|
my $self = shift; |
2430
|
|
|
|
|
|
|
|
2431
|
2234
|
100
|
|
|
|
9143
|
$self->_init_robots unless exists( $self->{robot_string} ); |
2432
|
2234
|
|
|
|
|
7568
|
return $self->{robot_tests}->{robot}; |
2433
|
|
|
|
|
|
|
} |
2434
|
|
|
|
|
|
|
|
2435
|
|
|
|
|
|
|
sub robot_string { |
2436
|
888
|
|
|
888
|
1
|
120157
|
my $self = shift; |
2437
|
|
|
|
|
|
|
|
2438
|
888
|
100
|
|
|
|
3197
|
$self->_init_robots unless exists( $self->{robot_string} ); |
2439
|
888
|
|
|
|
|
2260
|
return $self->{robot_string}; |
2440
|
|
|
|
|
|
|
} |
2441
|
|
|
|
|
|
|
|
2442
|
|
|
|
|
|
|
sub robot_name { |
2443
|
140
|
|
|
140
|
0
|
85139
|
my $self = shift; |
2444
|
140
|
|
|
|
|
421
|
return $self->robot_string; |
2445
|
|
|
|
|
|
|
} |
2446
|
|
|
|
|
|
|
|
2447
|
|
|
|
|
|
|
sub robot_id { |
2448
|
546
|
|
|
546
|
1
|
1409
|
my $self = shift; |
2449
|
|
|
|
|
|
|
return |
2450
|
|
|
|
|
|
|
$self->{robot_tests}->{robot_id} ? $self->{robot_tests}->{robot_id} |
2451
|
546
|
0
|
|
|
|
1765
|
: $self->robot ? $ROBOT_IDS{ $self->robot } |
|
|
50
|
|
|
|
|
|
2452
|
|
|
|
|
|
|
: undef; |
2453
|
|
|
|
|
|
|
} |
2454
|
|
|
|
|
|
|
|
2455
|
|
|
|
|
|
|
sub _robot_version { |
2456
|
415
|
|
|
415
|
|
647
|
my ($self) = @_; |
2457
|
415
|
50
|
|
|
|
1073
|
$self->_init_robots unless exists( $self->{robot_string} ); |
2458
|
415
|
50
|
|
|
|
883
|
if ( $self->{robot_version} ) { |
2459
|
415
|
|
|
|
|
540
|
return @{ $self->{robot_version} }; |
|
415
|
|
|
|
|
1680
|
|
2460
|
|
|
|
|
|
|
} |
2461
|
|
|
|
|
|
|
else { |
2462
|
0
|
|
|
|
|
0
|
return ( undef, undef, undef ); |
2463
|
|
|
|
|
|
|
} |
2464
|
|
|
|
|
|
|
} |
2465
|
|
|
|
|
|
|
|
2466
|
|
|
|
|
|
|
sub robot_version { |
2467
|
106
|
|
|
106
|
1
|
62717
|
my ($self) = @_; |
2468
|
106
|
|
|
|
|
243
|
my ( $major, $minor, $beta ) = $self->_robot_version; |
2469
|
106
|
50
|
|
|
|
293
|
if ( defined $major ) { |
2470
|
106
|
100
|
|
|
|
215
|
if ( defined $minor ) { |
2471
|
105
|
|
|
|
|
538
|
return "$major$minor"; |
2472
|
|
|
|
|
|
|
} |
2473
|
|
|
|
|
|
|
else { |
2474
|
1
|
|
|
|
|
5
|
return $major; |
2475
|
|
|
|
|
|
|
} |
2476
|
|
|
|
|
|
|
} |
2477
|
|
|
|
|
|
|
else { |
2478
|
0
|
|
|
|
|
0
|
return undef; |
2479
|
|
|
|
|
|
|
} |
2480
|
|
|
|
|
|
|
} |
2481
|
|
|
|
|
|
|
|
2482
|
|
|
|
|
|
|
sub robot_major { |
2483
|
102
|
|
|
102
|
1
|
49174
|
my ($self) = @_; |
2484
|
102
|
|
|
|
|
254
|
my ( $major, $minor, $beta ) = $self->_robot_version; |
2485
|
102
|
|
|
|
|
410
|
return $major; |
2486
|
|
|
|
|
|
|
} |
2487
|
|
|
|
|
|
|
|
2488
|
|
|
|
|
|
|
sub robot_minor { |
2489
|
101
|
|
|
101
|
1
|
45576
|
my ($self) = @_; |
2490
|
101
|
|
|
|
|
245
|
my ( $major, $minor, $beta ) = $self->_robot_version; |
2491
|
101
|
|
|
|
|
418
|
return $minor; |
2492
|
|
|
|
|
|
|
} |
2493
|
|
|
|
|
|
|
|
2494
|
|
|
|
|
|
|
sub robot_beta { |
2495
|
106
|
|
|
106
|
1
|
68288
|
my ($self) = @_; |
2496
|
106
|
|
|
|
|
351
|
my ( $major, $minor, $beta ) = $self->_robot_version; |
2497
|
106
|
|
|
|
|
440
|
return $beta; |
2498
|
|
|
|
|
|
|
} |
2499
|
|
|
|
|
|
|
|
2500
|
|
|
|
|
|
|
sub os { |
2501
|
4148
|
|
|
4148
|
1
|
619882
|
my ($self) = @_; |
2502
|
|
|
|
|
|
|
|
2503
|
4148
|
50
|
|
|
|
9388
|
return undef unless defined $self->{user_agent}; |
2504
|
4148
|
100
|
|
|
|
10460
|
$self->_init_os unless $self->{os_tests}; |
2505
|
4148
|
|
|
|
|
9442
|
return $self->{os}; |
2506
|
|
|
|
|
|
|
} |
2507
|
|
|
|
|
|
|
|
2508
|
|
|
|
|
|
|
sub os_string { |
2509
|
4101
|
|
|
4101
|
1
|
612182
|
my ($self) = @_; |
2510
|
|
|
|
|
|
|
|
2511
|
4101
|
50
|
|
|
|
8943
|
return undef unless defined $self->{user_agent}; |
2512
|
4101
|
100
|
|
|
|
8151
|
$self->_init_os unless $self->{os_tests}; |
2513
|
4101
|
|
|
|
|
8458
|
return $self->{os_string}; |
2514
|
|
|
|
|
|
|
} |
2515
|
|
|
|
|
|
|
|
2516
|
|
|
|
|
|
|
sub _os_version { |
2517
|
3978
|
|
|
3978
|
|
6623
|
my ($self) = @_; |
2518
|
3978
|
100
|
|
|
|
13003
|
$self->_init_os_version if !exists( $self->{os_version} ); |
2519
|
3978
|
100
|
|
|
|
7016
|
if ( $self->{os_version} ) { |
2520
|
1912
|
|
|
|
|
2550
|
return @{ $self->{os_version} }; |
|
1912
|
|
|
|
|
7005
|
|
2521
|
|
|
|
|
|
|
} |
2522
|
|
|
|
|
|
|
else { |
2523
|
2066
|
|
|
|
|
4992
|
return ( undef, undef, undef ); |
2524
|
|
|
|
|
|
|
} |
2525
|
|
|
|
|
|
|
} |
2526
|
|
|
|
|
|
|
|
2527
|
|
|
|
|
|
|
sub os_version { |
2528
|
1004
|
|
|
1004
|
1
|
248357
|
my ($self) = @_; |
2529
|
1004
|
|
|
|
|
2366
|
my ( $major, $minor, $beta ) = $self->_os_version; |
2530
|
1004
|
100
|
|
|
|
3569
|
return defined $major ? "$major$minor" : undef; |
2531
|
|
|
|
|
|
|
} |
2532
|
|
|
|
|
|
|
|
2533
|
|
|
|
|
|
|
sub os_major { |
2534
|
922
|
|
|
922
|
1
|
221273
|
my ($self) = @_; |
2535
|
922
|
|
|
|
|
2217
|
my ( $major, $minor, $beta ) = $self->_os_version; |
2536
|
922
|
|
|
|
|
2814
|
return $major; |
2537
|
|
|
|
|
|
|
} |
2538
|
|
|
|
|
|
|
|
2539
|
|
|
|
|
|
|
sub os_minor { |
2540
|
1034
|
|
|
1034
|
1
|
215688
|
my ($self) = @_; |
2541
|
1034
|
|
|
|
|
3391
|
my ( $major, $minor, $beta ) = $self->_os_version; |
2542
|
1034
|
|
|
|
|
2656
|
return $minor; |
2543
|
|
|
|
|
|
|
} |
2544
|
|
|
|
|
|
|
|
2545
|
|
|
|
|
|
|
sub os_beta { |
2546
|
1018
|
|
|
1018
|
1
|
267337
|
my ($self) = @_; |
2547
|
1018
|
|
|
|
|
2520
|
my ( $major, $minor, $beta ) = $self->_os_version; |
2548
|
1018
|
|
|
|
|
2751
|
return $beta; |
2549
|
|
|
|
|
|
|
} |
2550
|
|
|
|
|
|
|
|
2551
|
|
|
|
|
|
|
sub _realplayer_version { |
2552
|
0
|
|
|
0
|
|
0
|
my ($self) = @_; |
2553
|
|
|
|
|
|
|
|
2554
|
0
|
0
|
|
|
|
0
|
$self->_init_version unless $self->{version_tests}; |
2555
|
0
|
|
0
|
|
|
0
|
return $self->{realplayer_version} || 0; |
2556
|
|
|
|
|
|
|
} |
2557
|
|
|
|
|
|
|
|
2558
|
|
|
|
|
|
|
sub realplayer_browser { |
2559
|
752
|
|
|
752
|
1
|
88997
|
my ($self) = @_; |
2560
|
752
|
|
100
|
|
|
3580
|
return defined( $self->{browser} ) && $self->{browser} eq 'realplayer'; |
2561
|
|
|
|
|
|
|
} |
2562
|
|
|
|
|
|
|
|
2563
|
|
|
|
|
|
|
sub gecko_version { |
2564
|
710
|
|
|
710
|
1
|
81150
|
my ($self) = @_; |
2565
|
|
|
|
|
|
|
|
2566
|
710
|
100
|
|
|
|
1844
|
if ( $self->gecko ) { |
2567
|
76
|
|
|
|
|
217
|
return $self->{engine_version}; |
2568
|
|
|
|
|
|
|
} |
2569
|
|
|
|
|
|
|
else { |
2570
|
634
|
|
|
|
|
1464
|
return undef; |
2571
|
|
|
|
|
|
|
} |
2572
|
|
|
|
|
|
|
} |
2573
|
|
|
|
|
|
|
|
2574
|
|
|
|
|
|
|
sub version { |
2575
|
948
|
|
|
948
|
1
|
192865
|
my ($self) = @_; |
2576
|
948
|
100
|
|
|
|
2777
|
$self->_init_version() unless $self->{version_tests}; |
2577
|
|
|
|
|
|
|
|
2578
|
948
|
50
|
|
|
|
3854
|
return defined $self->{major} ? "$self->{major}$self->{minor}" : undef; |
2579
|
|
|
|
|
|
|
} |
2580
|
|
|
|
|
|
|
|
2581
|
|
|
|
|
|
|
sub major { |
2582
|
1150
|
|
|
1150
|
1
|
165505
|
my ($self) = @_; |
2583
|
1150
|
100
|
|
|
|
2961
|
$self->_init_version() unless $self->{version_tests}; |
2584
|
|
|
|
|
|
|
|
2585
|
1150
|
|
|
|
|
2290
|
my ($version) = $self->{major}; |
2586
|
1150
|
|
|
|
|
2993
|
return $version; |
2587
|
|
|
|
|
|
|
} |
2588
|
|
|
|
|
|
|
|
2589
|
|
|
|
|
|
|
sub minor { |
2590
|
969
|
|
|
969
|
1
|
192546
|
my ($self) = @_; |
2591
|
969
|
100
|
|
|
|
2709
|
$self->_init_version() unless $self->{version_tests}; |
2592
|
|
|
|
|
|
|
|
2593
|
969
|
|
|
|
|
1734
|
my ($version) = $self->{minor}; |
2594
|
969
|
|
|
|
|
2402
|
return $version; |
2595
|
|
|
|
|
|
|
} |
2596
|
|
|
|
|
|
|
|
2597
|
|
|
|
|
|
|
sub public_version { |
2598
|
919
|
|
|
919
|
1
|
178563
|
my ($self) = @_; |
2599
|
919
|
|
|
|
|
2483
|
my ( $major, $minor ) = $self->_public; |
2600
|
|
|
|
|
|
|
|
2601
|
919
|
|
50
|
|
|
2254
|
$minor ||= q{}; |
2602
|
919
|
50
|
|
|
|
3336
|
return defined $major ? "$major$minor" : undef; |
2603
|
|
|
|
|
|
|
} |
2604
|
|
|
|
|
|
|
|
2605
|
|
|
|
|
|
|
sub public_major { |
2606
|
855
|
|
|
855
|
1
|
165266
|
my ($self) = @_; |
2607
|
855
|
|
|
|
|
2312
|
my ( $major, $minor ) = $self->_public; |
2608
|
|
|
|
|
|
|
|
2609
|
855
|
|
|
|
|
2277
|
return $major; |
2610
|
|
|
|
|
|
|
} |
2611
|
|
|
|
|
|
|
|
2612
|
|
|
|
|
|
|
sub public_minor { |
2613
|
904
|
|
|
904
|
1
|
149974
|
my ($self) = @_; |
2614
|
904
|
|
|
|
|
2329
|
my ( $major, $minor ) = $self->_public; |
2615
|
|
|
|
|
|
|
|
2616
|
904
|
|
|
|
|
2392
|
return $minor; |
2617
|
|
|
|
|
|
|
} |
2618
|
|
|
|
|
|
|
|
2619
|
|
|
|
|
|
|
sub public_beta { |
2620
|
0
|
|
|
0
|
1
|
0
|
my ($self) = @_; |
2621
|
0
|
|
|
|
|
0
|
my ( $major, $minor, $beta ) = $self->_public; |
2622
|
|
|
|
|
|
|
|
2623
|
0
|
|
|
|
|
0
|
return $beta; |
2624
|
|
|
|
|
|
|
} |
2625
|
|
|
|
|
|
|
|
2626
|
|
|
|
|
|
|
sub browser_version { |
2627
|
6
|
|
|
6
|
1
|
3650
|
my ($self) = @_; |
2628
|
6
|
|
|
|
|
19
|
my ( $major, $minor ) = $self->_public; |
2629
|
6
|
|
100
|
|
|
22
|
$minor ||= q{}; |
2630
|
|
|
|
|
|
|
|
2631
|
6
|
100
|
|
|
|
38
|
return defined $major ? "$major$minor" : undef; |
2632
|
|
|
|
|
|
|
} |
2633
|
|
|
|
|
|
|
|
2634
|
|
|
|
|
|
|
sub browser_major { |
2635
|
1441
|
|
|
1441
|
1
|
550421
|
my ($self) = @_; |
2636
|
1441
|
|
|
|
|
3544
|
my ( $major, $minor ) = $self->_public; |
2637
|
|
|
|
|
|
|
|
2638
|
1441
|
|
|
|
|
7429
|
return $major; |
2639
|
|
|
|
|
|
|
} |
2640
|
|
|
|
|
|
|
|
2641
|
|
|
|
|
|
|
sub browser_minor { |
2642
|
895
|
|
|
895
|
1
|
535704
|
my ($self) = @_; |
2643
|
895
|
|
|
|
|
2284
|
my ( $major, $minor ) = $self->_public; |
2644
|
|
|
|
|
|
|
|
2645
|
895
|
|
|
|
|
3610
|
return $minor; |
2646
|
|
|
|
|
|
|
} |
2647
|
|
|
|
|
|
|
|
2648
|
|
|
|
|
|
|
sub browser_beta { |
2649
|
353
|
|
|
353
|
1
|
220749
|
my ($self) = @_; |
2650
|
353
|
|
|
|
|
955
|
my ( $major, $minor, $beta ) = $self->_public; |
2651
|
|
|
|
|
|
|
|
2652
|
353
|
|
|
|
|
1635
|
return $beta; |
2653
|
|
|
|
|
|
|
} |
2654
|
|
|
|
|
|
|
|
2655
|
|
|
|
|
|
|
sub _public { |
2656
|
5373
|
|
|
5373
|
|
8501
|
my ($self) = @_; |
2657
|
|
|
|
|
|
|
|
2658
|
|
|
|
|
|
|
# Return Public version of Safari. See RT #48727. |
2659
|
5373
|
100
|
|
|
|
10531
|
if ( $self->safari ) { |
2660
|
650
|
|
|
|
|
1946
|
my $ua = lc $self->{user_agent}; |
2661
|
|
|
|
|
|
|
|
2662
|
|
|
|
|
|
|
# Safari starting with version 3.0 provides its own public version |
2663
|
650
|
100
|
|
|
|
3428
|
if ( |
2664
|
|
|
|
|
|
|
$ua =~ m{ |
2665
|
|
|
|
|
|
|
version/ |
2666
|
|
|
|
|
|
|
( \d+ ) # Major version number is everything before first dot |
2667
|
|
|
|
|
|
|
( \. \d+ )? # Minor version number is first dot and following digits |
2668
|
|
|
|
|
|
|
}x |
2669
|
|
|
|
|
|
|
) { |
2670
|
455
|
|
|
|
|
2128
|
return ( $1, $2, undef ); |
2671
|
|
|
|
|
|
|
} |
2672
|
|
|
|
|
|
|
|
2673
|
|
|
|
|
|
|
# Safari before version 3.0 had only build numbers; use a lookup table |
2674
|
|
|
|
|
|
|
# provided by Apple to convert to version numbers |
2675
|
|
|
|
|
|
|
|
2676
|
195
|
100
|
|
|
|
942
|
if ( $ua =~ m{ safari/ ( \d+ (?: \.\d+ )* ) }x ) { |
2677
|
146
|
|
|
|
|
388
|
my $build = $1; |
2678
|
146
|
|
|
|
|
260
|
my $version = $safari_build_to_version{$build}; |
2679
|
146
|
100
|
|
|
|
330
|
unless ($version) { |
2680
|
|
|
|
|
|
|
|
2681
|
|
|
|
|
|
|
# if exact build -> version mapping doesn't exist, find next |
2682
|
|
|
|
|
|
|
# lower build |
2683
|
|
|
|
|
|
|
|
2684
|
101
|
|
|
|
|
746
|
for my $maybe_build ( |
2685
|
7427
|
|
|
|
|
9760
|
sort { $self->_cmp_versions( $b, $a ) } |
2686
|
|
|
|
|
|
|
keys %safari_build_to_version |
2687
|
|
|
|
|
|
|
) { |
2688
|
461
|
100
|
|
|
|
700
|
$version = $safari_build_to_version{$maybe_build}, last |
2689
|
|
|
|
|
|
|
if $self->_cmp_versions( $build, $maybe_build ) >= 0; |
2690
|
|
|
|
|
|
|
} |
2691
|
|
|
|
|
|
|
|
2692
|
|
|
|
|
|
|
# Special case for specific worm that uses a malformed user agent |
2693
|
101
|
100
|
|
|
|
411
|
return ( '1', '.2', undef ) if $ua =~ m{safari/12x}; |
2694
|
|
|
|
|
|
|
} |
2695
|
|
|
|
|
|
|
|
2696
|
140
|
100
|
|
|
|
295
|
return ( undef, undef, undef ) unless defined $version; |
2697
|
137
|
|
|
|
|
399
|
my ( $major, $minor ) = split /\./, $version; |
2698
|
137
|
|
|
|
|
223
|
my $beta; |
2699
|
137
|
100
|
|
|
|
409
|
$minor =~ s/(\D.*)// and $beta = $1; |
2700
|
137
|
|
|
|
|
267
|
$minor = ( '.' . $minor ); |
2701
|
137
|
100
|
|
|
|
554
|
return ( $major, $minor, ( $beta ? 1 : undef ) ); |
2702
|
|
|
|
|
|
|
} |
2703
|
|
|
|
|
|
|
} |
2704
|
|
|
|
|
|
|
|
2705
|
4772
|
100
|
|
|
|
14678
|
$self->_init_version() unless $self->{version_tests}; |
2706
|
4772
|
|
|
|
|
16315
|
return ( $self->{major}, $self->{minor}, $self->{beta} ); |
2707
|
|
|
|
|
|
|
} |
2708
|
|
|
|
|
|
|
|
2709
|
|
|
|
|
|
|
sub _cmp_versions { |
2710
|
7888
|
|
|
7888
|
|
10626
|
my ( $self, $a, $b ) = @_; |
2711
|
|
|
|
|
|
|
|
2712
|
7888
|
|
|
|
|
11701
|
my @a = split /\./, $a; |
2713
|
7888
|
|
|
|
|
10191
|
my @b = split /\./, $b; |
2714
|
|
|
|
|
|
|
|
2715
|
7888
|
|
|
|
|
11443
|
while (@b) { |
2716
|
9019
|
100
|
100
|
|
|
25355
|
return -1 if @a == 0 || $a[0] < $b[0]; |
2717
|
4713
|
100
|
66
|
|
|
13017
|
return 1 if @b == 0 || $b[0] < $a[0]; |
2718
|
1440
|
|
|
|
|
1645
|
shift @a; |
2719
|
1440
|
|
|
|
|
2284
|
shift @b; |
2720
|
|
|
|
|
|
|
} |
2721
|
|
|
|
|
|
|
|
2722
|
309
|
|
|
|
|
532
|
return @a <=> @b; |
2723
|
|
|
|
|
|
|
} |
2724
|
|
|
|
|
|
|
|
2725
|
|
|
|
|
|
|
sub engine { |
2726
|
1553
|
|
|
1553
|
1
|
601406
|
my ($self) = @_; |
2727
|
|
|
|
|
|
|
|
2728
|
|
|
|
|
|
|
return |
2729
|
1553
|
100
|
|
|
|
3649
|
!$self->engine_string ? undef |
|
|
100
|
|
|
|
|
|
2730
|
|
|
|
|
|
|
: $self->engine_string eq 'MSIE' ? 'ie' |
2731
|
|
|
|
|
|
|
: lc( $self->engine_string ); |
2732
|
|
|
|
|
|
|
} |
2733
|
|
|
|
|
|
|
|
2734
|
|
|
|
|
|
|
sub engine_string { |
2735
|
5538
|
|
|
5538
|
1
|
544361
|
my ($self) = @_; |
2736
|
|
|
|
|
|
|
|
2737
|
5538
|
100
|
|
|
|
10904
|
if ( $self->gecko ) { |
2738
|
740
|
|
|
|
|
2359
|
return 'Gecko'; |
2739
|
|
|
|
|
|
|
} |
2740
|
|
|
|
|
|
|
|
2741
|
4798
|
100
|
|
|
|
8822
|
if ( $self->trident ) { |
2742
|
978
|
|
|
|
|
3810
|
return 'Trident'; |
2743
|
|
|
|
|
|
|
} |
2744
|
|
|
|
|
|
|
|
2745
|
3820
|
100
|
|
|
|
6439
|
if ( $self->ie ) { |
2746
|
558
|
|
|
|
|
2227
|
return 'MSIE'; |
2747
|
|
|
|
|
|
|
} |
2748
|
|
|
|
|
|
|
|
2749
|
3262
|
100
|
|
|
|
5417
|
if ( $self->edgelegacy ) { |
2750
|
32
|
|
|
|
|
107
|
return 'EdgeHTML'; |
2751
|
|
|
|
|
|
|
} |
2752
|
|
|
|
|
|
|
|
2753
|
3230
|
100
|
|
|
|
5490
|
if ( $self->webkit ) { |
2754
|
2632
|
|
|
|
|
8935
|
return 'WebKit'; |
2755
|
|
|
|
|
|
|
} |
2756
|
|
|
|
|
|
|
|
2757
|
598
|
100
|
|
|
|
1318
|
if ( $self->presto ) { |
2758
|
140
|
|
|
|
|
504
|
return 'Presto'; |
2759
|
|
|
|
|
|
|
} |
2760
|
|
|
|
|
|
|
|
2761
|
458
|
100
|
|
|
|
865
|
if ( $self->netfront ) { |
2762
|
53
|
|
|
|
|
171
|
return 'NetFront'; |
2763
|
|
|
|
|
|
|
} |
2764
|
|
|
|
|
|
|
|
2765
|
405
|
100
|
|
|
|
830
|
if ( $self->khtml ) { |
2766
|
16
|
|
|
|
|
58
|
return 'KHTML'; |
2767
|
|
|
|
|
|
|
} |
2768
|
|
|
|
|
|
|
|
2769
|
389
|
|
|
|
|
936
|
return undef; |
2770
|
|
|
|
|
|
|
} |
2771
|
|
|
|
|
|
|
|
2772
|
|
|
|
|
|
|
sub engine_version { |
2773
|
1578
|
|
|
1578
|
1
|
447959
|
my ($self) = @_; |
2774
|
|
|
|
|
|
|
|
2775
|
|
|
|
|
|
|
return $self->{engine_version} |
2776
|
1578
|
100
|
100
|
|
|
15372
|
&& $self->{engine_version} =~ m{^(\d+(\.\d+)?)} ? $1 : undef; |
2777
|
|
|
|
|
|
|
} |
2778
|
|
|
|
|
|
|
|
2779
|
|
|
|
|
|
|
sub engine_major { |
2780
|
2190
|
|
|
2190
|
1
|
526204
|
my ($self) = @_; |
2781
|
|
|
|
|
|
|
|
2782
|
|
|
|
|
|
|
return $self->{engine_version} |
2783
|
2190
|
100
|
100
|
|
|
16510
|
&& $self->{engine_version} =~ m{^(\d+)} ? $1 : undef; |
2784
|
|
|
|
|
|
|
} |
2785
|
|
|
|
|
|
|
|
2786
|
|
|
|
|
|
|
sub engine_minor { |
2787
|
2093
|
|
|
2093
|
1
|
466230
|
my ($self) = @_; |
2788
|
|
|
|
|
|
|
|
2789
|
|
|
|
|
|
|
return $self->{engine_version} |
2790
|
2093
|
100
|
100
|
|
|
16369
|
&& $self->{engine_version} =~ m{^\d+(\.\d+)} ? $1 : undef; |
2791
|
|
|
|
|
|
|
} |
2792
|
|
|
|
|
|
|
|
2793
|
|
|
|
|
|
|
sub engine_beta { |
2794
|
1405
|
|
|
1405
|
1
|
500220
|
my ($self) = @_; |
2795
|
|
|
|
|
|
|
|
2796
|
|
|
|
|
|
|
return $self->{engine_version} |
2797
|
1405
|
100
|
100
|
|
|
14197
|
&& $self->{engine_version} =~ m{^\d+\.\d+([\.\d\+]*)} ? $1 : undef; |
2798
|
|
|
|
|
|
|
} |
2799
|
|
|
|
|
|
|
|
2800
|
|
|
|
|
|
|
sub beta { |
2801
|
735
|
|
|
735
|
1
|
89186
|
my ($self) = @_; |
2802
|
|
|
|
|
|
|
|
2803
|
735
|
100
|
|
|
|
2161
|
$self->_init_version unless $self->{version_tests}; |
2804
|
|
|
|
|
|
|
|
2805
|
735
|
|
|
|
|
1449
|
my ($version) = $self->{beta}; |
2806
|
735
|
|
|
|
|
1411
|
return $version; |
2807
|
|
|
|
|
|
|
} |
2808
|
|
|
|
|
|
|
|
2809
|
|
|
|
|
|
|
sub language { |
2810
|
1100
|
|
|
1100
|
1
|
291204
|
my ($self) = @_; |
2811
|
|
|
|
|
|
|
|
2812
|
1100
|
|
|
|
|
2647
|
my $parsed = $self->_language_country(); |
2813
|
1100
|
|
|
|
|
3623
|
return $parsed->{'language'}; |
2814
|
|
|
|
|
|
|
} |
2815
|
|
|
|
|
|
|
|
2816
|
|
|
|
|
|
|
sub country { |
2817
|
708
|
|
|
708
|
1
|
81917
|
my ($self) = @_; |
2818
|
|
|
|
|
|
|
|
2819
|
708
|
|
|
|
|
1799
|
my $parsed = $self->_language_country(); |
2820
|
708
|
|
|
|
|
2069
|
return $parsed->{'country'}; |
2821
|
|
|
|
|
|
|
} |
2822
|
|
|
|
|
|
|
|
2823
|
|
|
|
|
|
|
sub device { |
2824
|
4129
|
|
|
4129
|
1
|
657197
|
my ($self) = @_; |
2825
|
|
|
|
|
|
|
|
2826
|
4129
|
50
|
|
|
|
9737
|
$self->_init_device if !exists( $self->{device} ); |
2827
|
4129
|
|
|
|
|
9598
|
return $self->{device}; |
2828
|
|
|
|
|
|
|
} |
2829
|
|
|
|
|
|
|
|
2830
|
|
|
|
|
|
|
sub device_string { |
2831
|
1834
|
|
|
1834
|
1
|
298754
|
my ($self) = @_; |
2832
|
|
|
|
|
|
|
|
2833
|
1834
|
100
|
|
|
|
6202
|
$self->_init_device if !exists( $self->{device_string} ); |
2834
|
1834
|
|
|
|
|
4797
|
return $self->{device_string}; |
2835
|
|
|
|
|
|
|
} |
2836
|
|
|
|
|
|
|
|
2837
|
|
|
|
|
|
|
sub device_name { |
2838
|
684
|
|
|
684
|
1
|
77459
|
my ($self) = @_; |
2839
|
684
|
|
|
|
|
1514
|
return $self->device_string; |
2840
|
|
|
|
|
|
|
} |
2841
|
|
|
|
|
|
|
|
2842
|
|
|
|
|
|
|
sub _language_country { |
2843
|
1808
|
|
|
1808
|
|
3137
|
my ($self) = @_; |
2844
|
|
|
|
|
|
|
|
2845
|
1808
|
100
|
|
|
|
4068
|
if ( $self->safari ) { |
2846
|
255
|
100
|
66
|
|
|
569
|
if ( $self->major == 1 |
2847
|
|
|
|
|
|
|
&& $self->{user_agent} =~ m/\s ( [a-z]{2} ) \)/xms ) { |
2848
|
8
|
|
|
|
|
39
|
return { language => uc $1 }; |
2849
|
|
|
|
|
|
|
} |
2850
|
247
|
100
|
|
|
|
1230
|
if ( $self->{user_agent} =~ m/\s ([a-z]{2})-([A-Za-z]{2})/xms ) { |
2851
|
147
|
|
|
|
|
862
|
return { language => uc $1, country => uc $2 }; |
2852
|
|
|
|
|
|
|
} |
2853
|
|
|
|
|
|
|
} |
2854
|
|
|
|
|
|
|
|
2855
|
1653
|
100
|
100
|
|
|
3826
|
if ( $self->aol |
2856
|
|
|
|
|
|
|
&& $self->{user_agent} =~ m/;([A-Z]{2})_([A-Z]{2})\)/ ) { |
2857
|
3
|
|
|
|
|
19
|
return { language => $1, country => $2 }; |
2858
|
|
|
|
|
|
|
} |
2859
|
|
|
|
|
|
|
|
2860
|
1650
|
100
|
|
|
|
7771
|
if ( $self->{user_agent} =~ m/\b([a-z]{2})-([A-Za-z]{2})\b/xms ) { |
2861
|
342
|
|
|
|
|
1915
|
return { language => uc $1, country => uc $2 }; |
2862
|
|
|
|
|
|
|
} |
2863
|
|
|
|
|
|
|
|
2864
|
1308
|
100
|
|
|
|
3765
|
if ( $self->{user_agent} =~ m/\[([a-z]{2})\]/xms ) { |
2865
|
23
|
|
|
|
|
121
|
return { language => uc $1 }; |
2866
|
|
|
|
|
|
|
} |
2867
|
|
|
|
|
|
|
|
2868
|
1285
|
100
|
|
|
|
6593
|
if ( $self->{user_agent} =~ m/\(([^)]+)\)/xms ) { |
2869
|
1141
|
|
|
|
|
5321
|
my @parts = split( /;/, $1 ); |
2870
|
1141
|
|
|
|
|
2612
|
foreach my $part (@parts) { |
2871
|
|
|
|
|
|
|
|
2872
|
|
|
|
|
|
|
# 'wv' for WebView is not language code. Details here: https://developer.chrome.com/multidevice/user-agent#webview_user_agent |
2873
|
4859
|
100
|
66
|
|
|
12751
|
if ( $part =~ /^\s*([a-z]{2})\s*$/ |
|
|
|
100
|
|
|
|
|
2874
|
|
|
|
|
|
|
&& !( $self->webview && $1 eq 'wv' ) ) { |
2875
|
147
|
|
|
|
|
769
|
return { language => uc $1 }; |
2876
|
|
|
|
|
|
|
} |
2877
|
|
|
|
|
|
|
} |
2878
|
|
|
|
|
|
|
} |
2879
|
|
|
|
|
|
|
|
2880
|
1138
|
|
|
|
|
3972
|
return { language => undef, country => undef }; |
2881
|
|
|
|
|
|
|
} |
2882
|
|
|
|
|
|
|
|
2883
|
|
|
|
|
|
|
sub browser_properties { |
2884
|
1926
|
|
|
1926
|
1
|
441250
|
my ($self) = @_; |
2885
|
|
|
|
|
|
|
|
2886
|
1926
|
|
|
|
|
3363
|
my @browser_properties; |
2887
|
|
|
|
|
|
|
|
2888
|
1926
|
|
|
|
|
2897
|
my ( $test, $value ); |
2889
|
|
|
|
|
|
|
|
2890
|
1926
|
|
|
|
|
3031
|
while ( ( $test, $value ) = each %{ $self->{tests} } ) { |
|
3664
|
|
|
|
|
12144
|
|
2891
|
1738
|
50
|
|
|
|
4598
|
push @browser_properties, $test if $value; |
2892
|
|
|
|
|
|
|
} |
2893
|
1926
|
|
|
|
|
3290
|
while ( ( $test, $value ) = each %{ $self->{browser_tests} } ) { |
|
3680
|
|
|
|
|
9709
|
|
2894
|
1754
|
100
|
|
|
|
4457
|
push @browser_properties, $test if $value; |
2895
|
|
|
|
|
|
|
} |
2896
|
|
|
|
|
|
|
|
2897
|
1926
|
50
|
|
|
|
4239
|
$self->_init_device unless $self->{device_tests}; |
2898
|
1926
|
100
|
|
|
|
5120
|
$self->_init_os unless $self->{os_tests}; |
2899
|
1926
|
100
|
|
|
|
4846
|
$self->_init_robots unless $self->{robot_tests}; |
2900
|
1926
|
100
|
|
|
|
4334
|
$self->_init_version unless $self->{version_tests}; |
2901
|
|
|
|
|
|
|
|
2902
|
1926
|
|
|
|
|
2831
|
while ( ( $test, $value ) = each %{ $self->{device_tests} } ) { |
|
6237
|
|
|
|
|
14744
|
|
2903
|
4311
|
100
|
|
|
|
8276
|
push @browser_properties, $test if $value; |
2904
|
|
|
|
|
|
|
} |
2905
|
1926
|
|
|
|
|
2841
|
while ( ( $test, $value ) = each %{ $self->{os_tests} } ) { |
|
5779
|
|
|
|
|
12698
|
|
2906
|
3853
|
50
|
|
|
|
7219
|
push @browser_properties, $test if $value; |
2907
|
|
|
|
|
|
|
} |
2908
|
1926
|
|
|
|
|
2912
|
while ( ( $test, $value ) = each %{ $self->{robot_tests} } ) { |
|
2688
|
|
|
|
|
6670
|
|
2909
|
762
|
50
|
|
|
|
1509
|
push @browser_properties, $test if $value; |
2910
|
|
|
|
|
|
|
} |
2911
|
1926
|
|
|
|
|
2869
|
while ( ( $test, $value ) = each %{ $self->{version_tests} } ) { |
|
4357
|
|
|
|
|
9539
|
|
2912
|
2431
|
100
|
|
|
|
4569
|
push @browser_properties, $test if $value; |
2913
|
|
|
|
|
|
|
} |
2914
|
|
|
|
|
|
|
|
2915
|
|
|
|
|
|
|
# devices are a property too but it's not stored in %tests |
2916
|
|
|
|
|
|
|
# so I explicitly test for it and add it |
2917
|
1926
|
100
|
|
|
|
4979
|
push @browser_properties, 'device' if ( $self->device() ); |
2918
|
|
|
|
|
|
|
|
2919
|
1926
|
|
|
|
|
8548
|
@browser_properties = sort @browser_properties; |
2920
|
1926
|
|
|
|
|
6197
|
return @browser_properties; |
2921
|
|
|
|
|
|
|
} |
2922
|
|
|
|
|
|
|
|
2923
|
|
|
|
|
|
|
sub lib { |
2924
|
28
|
|
|
28
|
1
|
17278
|
my $self = shift; |
2925
|
28
|
100
|
|
|
|
103
|
$self->_init_robots() unless $self->{robot_tests}; |
2926
|
28
|
|
|
|
|
112
|
return $self->{robot_tests}->{lib}; |
2927
|
|
|
|
|
|
|
} |
2928
|
|
|
|
|
|
|
|
2929
|
|
|
|
|
|
|
sub all_robot_ids { |
2930
|
2
|
|
|
2
|
1
|
69
|
my $self = shift; |
2931
|
2
|
|
|
|
|
32
|
return keys %ROBOT_NAMES; |
2932
|
|
|
|
|
|
|
} |
2933
|
|
|
|
|
|
|
|
2934
|
|
|
|
|
|
|
# The list of U2F supported browsers is expected to increase: |
2935
|
|
|
|
|
|
|
# https://www.bit-tech.net/news/tech/software/w3c-adopts-fidos-webauthn-standard/1/ |
2936
|
|
|
|
|
|
|
|
2937
|
|
|
|
|
|
|
sub u2f { |
2938
|
0
|
|
|
0
|
1
|
0
|
my $self = shift; |
2939
|
|
|
|
|
|
|
|
2940
|
|
|
|
|
|
|
# Chrome version 41 and up can U2F |
2941
|
0
|
0
|
0
|
|
|
0
|
return 1 |
|
|
|
0
|
|
|
|
|
2942
|
|
|
|
|
|
|
if $self->chrome |
2943
|
|
|
|
|
|
|
&& $self->browser_major |
2944
|
|
|
|
|
|
|
&& $self->browser_major >= 41; |
2945
|
|
|
|
|
|
|
|
2946
|
|
|
|
|
|
|
# Opera versions 40 and >= 42 can U2F |
2947
|
0
|
0
|
0
|
|
|
0
|
return 1 |
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
2948
|
|
|
|
|
|
|
if $self->opera |
2949
|
|
|
|
|
|
|
&& $self->browser_major |
2950
|
|
|
|
|
|
|
&& ( $self->browser_major == 40 |
2951
|
|
|
|
|
|
|
|| $self->browser_major >= 42 ); |
2952
|
|
|
|
|
|
|
|
2953
|
0
|
|
|
|
|
0
|
return undef; |
2954
|
|
|
|
|
|
|
} |
2955
|
|
|
|
|
|
|
|
2956
|
|
|
|
|
|
|
# These method are only used by the test suite. |
2957
|
|
|
|
|
|
|
sub _all_tests { |
2958
|
1
|
|
|
1
|
|
5415703
|
return @ALL_TESTS; |
2959
|
|
|
|
|
|
|
} |
2960
|
|
|
|
|
|
|
|
2961
|
|
|
|
|
|
|
sub _robot_names { |
2962
|
1
|
|
|
1
|
|
41
|
return %ROBOT_NAMES; |
2963
|
|
|
|
|
|
|
} |
2964
|
|
|
|
|
|
|
|
2965
|
|
|
|
|
|
|
sub _robot_tests { |
2966
|
2
|
|
|
2
|
|
5594763
|
return @ROBOT_TESTS; |
2967
|
|
|
|
|
|
|
} |
2968
|
|
|
|
|
|
|
|
2969
|
|
|
|
|
|
|
sub _robot_ids { |
2970
|
1
|
|
|
1
|
|
20
|
return %ROBOT_IDS; |
2971
|
|
|
|
|
|
|
} |
2972
|
|
|
|
|
|
|
|
2973
|
|
|
|
|
|
|
1; |
2974
|
|
|
|
|
|
|
|
2975
|
|
|
|
|
|
|
# ABSTRACT: Determine Web browser, version, and platform from an HTTP user agent string |
2976
|
|
|
|
|
|
|
|
2977
|
|
|
|
|
|
|
__END__ |