ua-parser-js 1.0.33 → 2.0.0-alpha.1

Sign up to get free protection for your applications and to get access to all the features.
package/src/ua-parser.js CHANGED
@@ -1,6 +1,6 @@
1
1
  /////////////////////////////////////////////////////////////////////////////////
2
- /* UAParser.js v1.0.33
3
- Copyright © 2012-2021 Faisal Salman <f@faisalman.com>
2
+ /* UAParser.js v2.0.0-alpha.1
3
+ Copyright © 2012-2023 Faisal Salman <f@faisalman.com>
4
4
  MIT License *//*
5
5
  Detect Browser, Engine, OS, CPU, and Device type/model from User-Agent data.
6
6
  Supports browser & node.js environment.
@@ -17,7 +17,7 @@
17
17
  /////////////
18
18
 
19
19
 
20
- var LIBVERSION = '1.0.33',
20
+ var LIBVERSION = '2.0.0-alpha.1',
21
21
  EMPTY = '',
22
22
  UNKNOWN = '?',
23
23
  FUNC_TYPE = 'function',
@@ -37,42 +37,78 @@
37
37
  SMARTTV = 'smarttv',
38
38
  WEARABLE = 'wearable',
39
39
  EMBEDDED = 'embedded',
40
- UA_MAX_LENGTH = 350;
41
-
42
- var AMAZON = 'Amazon',
43
- APPLE = 'Apple',
44
- ASUS = 'ASUS',
45
- BLACKBERRY = 'BlackBerry',
46
- BROWSER = 'Browser',
47
- CHROME = 'Chrome',
48
- EDGE = 'Edge',
49
- FIREFOX = 'Firefox',
50
- GOOGLE = 'Google',
51
- HUAWEI = 'Huawei',
52
- LG = 'LG',
53
- MICROSOFT = 'Microsoft',
54
- MOTOROLA = 'Motorola',
55
- OPERA = 'Opera',
56
- SAMSUNG = 'Samsung',
57
- SHARP = 'Sharp',
58
- SONY = 'Sony',
59
- XIAOMI = 'Xiaomi',
60
- ZEBRA = 'Zebra',
61
- FACEBOOK = 'Facebook';
40
+ USER_AGENT = 'user-agent',
41
+ UA_MAX_LENGTH = 350,
42
+ BRANDS = 'brands',
43
+ FULLVERLIST = 'fullVersionList',
44
+ PLATFORM = 'platform',
45
+ PLATFORMVER = 'platformVersion',
46
+ BITNESS = 'bitness',
47
+ CH_HEADER = 'sec-ch-ua',
48
+ CH_HEADER_FULL_VER_LIST = CH_HEADER + '-full-version-list',
49
+ CH_HEADER_ARCH = CH_HEADER + '-arch',
50
+ CH_HEADER_BITNESS = CH_HEADER + '-bitness',
51
+ CH_HEADER_MOBILE = CH_HEADER + '-mobile',
52
+ CH_HEADER_MODEL = CH_HEADER + '-model',
53
+ CH_HEADER_PLATFORM = CH_HEADER + '-platform',
54
+ CH_HEADER_PLATFORM_VER = CH_HEADER_PLATFORM + '-version',
55
+ CH_ALL_VALUES = ['brands', 'fullVersionList', MOBILE, MODEL, 'platform', 'platformVersion', ARCHITECTURE, 'bitness'],
56
+ UA_BROWSER = 'browser',
57
+ UA_CPU = 'cpu',
58
+ UA_DEVICE = 'device',
59
+ UA_ENGINE = 'engine',
60
+ UA_OS = 'os',
61
+ UA_RESULT = 'result',
62
+ AMAZON = 'Amazon',
63
+ APPLE = 'Apple',
64
+ ASUS = 'ASUS',
65
+ BLACKBERRY = 'BlackBerry',
66
+ GOOGLE = 'Google',
67
+ HUAWEI = 'Huawei',
68
+ LG = 'LG',
69
+ MICROSOFT = 'Microsoft',
70
+ MOTOROLA = 'Motorola',
71
+ SAMSUNG = 'Samsung',
72
+ SHARP = 'Sharp',
73
+ SONY = 'Sony',
74
+ XIAOMI = 'Xiaomi',
75
+ ZEBRA = 'Zebra',
76
+ PREFIX_MOBILE = 'Mobile ',
77
+ SUFFIX_BROWSER = ' Browser',
78
+ CHROME = 'Chrome',
79
+ EDGE = 'Edge',
80
+ FIREFOX = 'Firefox',
81
+ OPERA = 'Opera',
82
+ FACEBOOK = 'Facebook',
83
+ WINDOWS = 'Windows';
84
+
85
+ var NAVIGATOR = (typeof window !== UNDEF_TYPE && window.navigator) ?
86
+ window.navigator :
87
+ undefined,
88
+ NAVIGATOR_UADATA = (NAVIGATOR && NAVIGATOR.userAgentData) ?
89
+ NAVIGATOR.userAgentData :
90
+ undefined;
62
91
 
63
92
  ///////////
64
93
  // Helper
65
94
  //////////
66
95
 
67
- var extend = function (regexes, extensions) {
68
- var mergedRegexes = {};
69
- for (var i in regexes) {
70
- if (extensions[i] && extensions[i].length % 2 === 0) {
71
- mergedRegexes[i] = extensions[i].concat(regexes[i]);
96
+ var assignFromEntries = function (arr) {
97
+ for (var i in arr) {
98
+ var propName = arr[i];
99
+ if (typeof propName == OBJ_TYPE && propName.length == 2) {
100
+ this[propName[0]] = propName[1];
72
101
  } else {
73
- mergedRegexes[i] = regexes[i];
102
+ this[propName] = undefined;
74
103
  }
75
104
  }
105
+ return this;
106
+ },
107
+ extend = function (regexes, extensions) {
108
+ var mergedRegexes = {};
109
+ for (var i in regexes) {
110
+ mergedRegexes[i] = extensions[i] && extensions[i].length % 2 === 0 ? extensions[i].concat(regexes[i]) : regexes[i];
111
+ }
76
112
  return mergedRegexes;
77
113
  },
78
114
  enumerize = function (arr) {
@@ -83,17 +119,44 @@
83
119
  return enums;
84
120
  },
85
121
  has = function (str1, str2) {
122
+ if (typeof str1 === OBJ_TYPE && str1.length > 0) {
123
+ for (var i in str1) {
124
+ if (lowerize(str1[i]) == lowerize(str2)) return true;
125
+ }
126
+ return false;
127
+ }
86
128
  return typeof str1 === STR_TYPE ? lowerize(str2).indexOf(lowerize(str1)) !== -1 : false;
87
129
  },
130
+ isExtensions = function (obj) {
131
+ for (var prop in obj) {
132
+ return /^(browser|cpu|device|engine|os)$/.test(prop);
133
+ }
134
+ },
135
+ itemListToArray = function (header) {
136
+ if (!header) return undefined;
137
+ var arr = [];
138
+ var tokens = strip(/\\?\"/g, header).split(', ');
139
+ for (var i = 0; i < tokens.length; i++) {
140
+ var token = tokens[i].split(';v=');
141
+ arr[i] = { brand : token[0], version : token[1] };
142
+ }
143
+ return arr;
144
+ },
88
145
  lowerize = function (str) {
89
- return str.toLowerCase();
146
+ return typeof(str) === STR_TYPE ? str.toLowerCase() : str;
90
147
  },
91
148
  majorize = function (version) {
92
- return typeof(version) === STR_TYPE ? version.replace(/[^\d\.]/g, EMPTY).split('.')[0] : undefined;
149
+ return typeof(version) === STR_TYPE ? strip(/[^\d\.]/g, version).split('.')[0] : undefined;
150
+ },
151
+ strip = function (pattern, str) {
152
+ return str.replace(pattern, EMPTY);
153
+ },
154
+ stripQuotes = function (val) {
155
+ return typeof val === STR_TYPE ? strip(/\"/g, val) : val;
93
156
  },
94
157
  trim = function (str, len) {
95
158
  if (typeof(str) === STR_TYPE) {
96
- str = str.replace(/^\s\s*/, EMPTY);
159
+ str = strip(/^\s\s*/, str);
97
160
  return typeof(len) === UNDEF_TYPE ? str : str.substring(0, UA_MAX_LENGTH);
98
161
  }
99
162
  };
@@ -104,6 +167,8 @@
104
167
 
105
168
  var rgxMapper = function (ua, arrays) {
106
169
 
170
+ if(!ua || !arrays) return;
171
+
107
172
  var i = 0, j, k, p, q, matches, match;
108
173
 
109
174
  // loop through all regexes maps
@@ -116,6 +181,7 @@
116
181
  // try matching uastring with regexes
117
182
  while (j < regex.length && !matches) {
118
183
 
184
+ if (!regex[j]) { break; }
119
185
  matches = regex[j++].exec(ua);
120
186
 
121
187
  if (!!matches) {
@@ -204,12 +270,13 @@
204
270
  // Regex map
205
271
  /////////////
206
272
 
207
- var regexes = {
273
+ var defaultRegexes = {
208
274
 
209
275
  browser : [[
210
276
 
277
+ // Most common regardless engine
211
278
  /\b(?:crmo|crios)\/([\w\.]+)/i // Chrome for Android/iOS
212
- ], [VERSION, [NAME, 'Chrome']], [
279
+ ], [VERSION, [NAME, PREFIX_MOBILE + 'Chrome']], [
213
280
  /edg(?:e|ios|a)?\/([\w\.]+)/i // Microsoft Edge
214
281
  ], [VERSION, [NAME, 'Edge']], [
215
282
 
@@ -232,12 +299,13 @@
232
299
  /(?:ms|\()(ie) ([\w\.]+)/i, // Internet Explorer
233
300
 
234
301
  // Webkit/KHTML based // Flock/RockMelt/Midori/Epiphany/Silk/Skyfire/Bolt/Iron/Iridium/PhantomJS/Bowser/QupZilla/Falkon
235
- /(flock|rockmelt|midori|epiphany|silk|skyfire|ovibrowser|bolt|iron|vivaldi|iridium|phantomjs|bowser|quark|qupzilla|falkon|rekonq|puffin|brave|whale|qqbrowserlite|qq|duckduckgo)\/([-\w\.]+)/i,
236
- // Rekonq/Puffin/Brave/Whale/QQBrowserLite/QQ, aka ShouQ
302
+ /(flock|rockmelt|midori|epiphany|silk|skyfire|ovibrowser|bolt|iron|vivaldi|iridium|phantomjs|bowser|quark|qupzilla|falkon|rekonq|puffin|brave|whale(?!.+naver)|qqbrowserlite|qq|duckduckgo)\/([-\w\.]+)/i,
303
+ // Rekonq/Puffin/Brave/Whale/QQBrowserLite/QQ//Vivaldi/DuckDuckGo
304
+ /(heytap|ovi)browser\/([\d\.]+)/i, // HeyTap/Ovi
237
305
  /(weibo)__([\d\.]+)/i // Weibo
238
306
  ], [NAME, VERSION], [
239
307
  /(?:\buc? ?browser|(?:juc.+)ucweb)[\/ ]?([\w\.]+)/i // UCBrowser
240
- ], [VERSION, [NAME, 'UC'+BROWSER]], [
308
+ ], [VERSION, [NAME, 'UCBrowser']], [
241
309
  /microm.+\bqbcore\/([\w\.]+)/i, // WeChat Desktop for Windows Built-in Browser
242
310
  /\bqbcore\/([\w\.]+).+microm/i
243
311
  ], [VERSION, [NAME, 'WeChat(Win) Desktop']], [
@@ -247,10 +315,10 @@
247
315
  ], [VERSION, [NAME, 'Konqueror']], [
248
316
  /trident.+rv[: ]([\w\.]{1,9})\b.+like gecko/i // IE11
249
317
  ], [VERSION, [NAME, 'IE']], [
250
- /yabrowser\/([\w\.]+)/i // Yandex
318
+ /ya(?:search)?browser\/([\w\.]+)/i // Yandex
251
319
  ], [VERSION, [NAME, 'Yandex']], [
252
320
  /(avast|avg)\/([\w\.]+)/i // Avast/AVG Secure Browser
253
- ], [[NAME, /(.+)/, '$1 Secure '+BROWSER], VERSION], [
321
+ ], [[NAME, /(.+)/, '$1 Secure' + SUFFIX_BROWSER], VERSION], [
254
322
  /\bfocus\/([\w\.]+)/i // Firefox Focus
255
323
  ], [VERSION, [NAME, FIREFOX+' Focus']], [
256
324
  /\bopt\/([\w\.]+)/i // Opera Touch
@@ -262,13 +330,13 @@
262
330
  /coast\/([\w\.]+)/i // Opera Coast
263
331
  ], [VERSION, [NAME, OPERA+' Coast']], [
264
332
  /miuibrowser\/([\w\.]+)/i // MIUI Browser
265
- ], [VERSION, [NAME, 'MIUI '+BROWSER]], [
266
- /fxios\/([-\w\.]+)/i // Firefox for iOS
267
- ], [VERSION, [NAME, FIREFOX]], [
333
+ ], [VERSION, [NAME, 'MIUI' + SUFFIX_BROWSER]], [
334
+ /fxios\/([\w\.-]+)/i // Firefox for iOS
335
+ ], [VERSION, [NAME, PREFIX_MOBILE + 'Firefox']], [
268
336
  /\bqihu|(qi?ho?o?|360)browser/i // 360
269
- ], [[NAME, '360 '+BROWSER]], [
337
+ ], [[NAME, '360' + SUFFIX_BROWSER]], [
270
338
  /(oculus|samsung|sailfish|huawei)browser\/([\w\.]+)/i
271
- ], [[NAME, /(.+)/, '$1 '+BROWSER], VERSION], [ // Oculus/Samsung/Sailfish/Huawei Browser
339
+ ], [[NAME, /(.+)/, '$1' + SUFFIX_BROWSER], VERSION], [ // Oculus/Samsung/Sailfish/Huawei Browser
272
340
  /(comodo_dragon)\/([\w\.]+)/i // Comodo Dragon
273
341
  ], [[NAME, /_/g, ' '], VERSION], [
274
342
  /(electron)\/([\w\.]+) safari/i, // Electron-based App
@@ -283,12 +351,16 @@
283
351
  // WebView
284
352
  /((?:fban\/fbios|fb_iab\/fb4a)(?!.+fbav)|;fbav\/([\w\.]+);)/i // Facebook App for iOS & Android
285
353
  ], [[NAME, FACEBOOK], VERSION], [
354
+ /(kakao(?:talk|story))[\/ ]([\w\.]+)/i, // Kakao App
355
+ /(naver)\(.*?(\d+\.[\w\.]+).*\)/i, // Naver InApp
286
356
  /safari (line)\/([\w\.]+)/i, // Line App for iOS
287
357
  /\b(line)\/([\w\.]+)\/iab/i, // Line App for Android
288
358
  /(chromium|instagram)[\/ ]([-\w\.]+)/i // Chromium/Instagram
289
359
  ], [NAME, VERSION], [
290
360
  /\bgsa\/([\w\.]+) .*safari\//i // Google Search Appliance on iOS
291
361
  ], [VERSION, [NAME, 'GSA']], [
362
+ /musical_ly(?:.+app_?version\/|_)([\w\.]+)/i // TikTok
363
+ ], [VERSION, [NAME, 'TikTok']], [
292
364
 
293
365
  /headlesschrome(?:\/([\w\.]+)| )/i // Chrome Headless
294
366
  ], [VERSION, [NAME, CHROME+' Headless']], [
@@ -297,14 +369,19 @@
297
369
  ], [[NAME, CHROME+' WebView'], VERSION], [
298
370
 
299
371
  /droid.+ version\/([\w\.]+)\b.+(?:mobile safari|safari)/i // Android Browser
300
- ], [VERSION, [NAME, 'Android '+BROWSER]], [
372
+ ], [VERSION, [NAME, 'Android' + SUFFIX_BROWSER]], [
373
+
374
+ /chrome\/([\w\.]+) mobile/i // Chrome Mobile
375
+ ], [VERSION, [NAME, PREFIX_MOBILE + 'Chrome']], [
301
376
 
302
377
  /(chrome|omniweb|arora|[tizenoka]{5} ?browser)\/v?([\w\.]+)/i // Chrome/OmniWeb/Arora/Tizen/Nokia
303
378
  ], [NAME, VERSION], [
304
379
 
305
- /version\/([\w\.\,]+) .*mobile\/\w+ (safari)/i // Mobile Safari
306
- ], [VERSION, [NAME, 'Mobile Safari']], [
307
- /version\/([\w(\.|\,)]+) .*(mobile ?safari|safari)/i // Safari & Safari Mobile
380
+ /version\/([\w\.\,]+) .*mobile(?:\/\w+ | ?)safari/i // Safari Mobile
381
+ ], [VERSION, [NAME, PREFIX_MOBILE + 'Safari']], [
382
+ /iphone .*mobile(?:\/\w+ | ?)safari/i
383
+ ], [[NAME, PREFIX_MOBILE + 'Safari']], [
384
+ /version\/([\w\.\,]+) .*(safari)/i // Safari
308
385
  ], [VERSION, NAME], [
309
386
  /webkit.+?(mobile ?safari|safari)(\/[\w\.]+)/i // Safari < 3.0
310
387
  ], [NAME, [VERSION, strMapper, oldSafariMap]], [
@@ -313,6 +390,8 @@
313
390
  ], [NAME, VERSION], [
314
391
 
315
392
  // Gecko based
393
+ /(?:mobile|tablet);.*(firefox)\/([\w\.-]+)/i // Firefox Mobile
394
+ ], [[NAME, PREFIX_MOBILE + 'Firefox'], VERSION], [
316
395
  /(navigator|netscape\d?)\/([-\w\.]+)/i // Netscape
317
396
  ], [[NAME, 'Netscape'], VERSION], [
318
397
  /mobile vr; rv:([\w\.]+)\).+firefox/i // Firefox Reality
@@ -329,21 +408,20 @@
329
408
  // Other
330
409
  /(polaris|lynx|dillo|icab|doris|amaya|w3m|netsurf|sleipnir|obigo|mosaic|(?:go|ice|up)[\. ]?browser)[-\/ ]?v?([\w\.]+)/i,
331
410
  // Polaris/Lynx/Dillo/iCab/Doris/Amaya/w3m/NetSurf/Sleipnir/Obigo/Mosaic/Go/ICE/UP.Browser
332
- /(links) \(([\w\.]+)/i // Links
411
+ /(links) \(([\w\.]+)/i, // Links
412
+ /panasonic;(viera)/i // Panasonic Viera
333
413
  ], [NAME, VERSION], [
334
414
 
335
415
  /(cobalt)\/([\w\.]+)/i // Cobalt
336
- ], [NAME, [VERSION, /master.|lts./, ""]]
416
+ ], [NAME, [VERSION, /[^\d\.]+./, EMPTY]]
337
417
  ],
338
418
 
339
419
  cpu : [[
340
420
 
341
- /(?:(amd|x(?:(?:86|64)[-_])?|wow|win)64)[;\)]/i // AMD64 (x64)
421
+ /\b(?:(amd|x|x86[-_]?|wow|win)64)\b/i // AMD64 (x64)
342
422
  ], [[ARCHITECTURE, 'amd64']], [
343
423
 
344
- /(ia32(?=;))/i // IA32 (quicktime)
345
- ], [[ARCHITECTURE, lowerize]], [
346
-
424
+ /(ia32(?=;))/i, // IA32 (quicktime)
347
425
  /((?:i[346]|x)86)[;\)]/i // IA32 (x86)
348
426
  ], [[ARCHITECTURE, 'ia32']], [
349
427
 
@@ -372,19 +450,18 @@
372
450
 
373
451
  //////////////////////////
374
452
  // MOBILES & TABLETS
375
- // Ordered by popularity
376
453
  /////////////////////////
377
454
 
378
455
  // Samsung
379
456
  /\b(sch-i[89]0\d|shw-m380s|sm-[ptx]\w{2,4}|gt-[pn]\d{2,4}|sgh-t8[56]9|nexus 10)/i
380
457
  ], [MODEL, [VENDOR, SAMSUNG], [TYPE, TABLET]], [
381
- /\b((?:s[cgp]h|gt|sm)-\w+|galaxy nexus)/i,
458
+ /\b((?:s[cgp]h|gt|sm)-\w+|sc[g-]?[\d]+a?|galaxy nexus)/i,
382
459
  /samsung[- ]([-\w]+)/i,
383
460
  /sec-(sgh\w+)/i
384
461
  ], [MODEL, [VENDOR, SAMSUNG], [TYPE, MOBILE]], [
385
462
 
386
463
  // Apple
387
- /\((ip(?:hone|od)[\w ]*);/i // iPod/iPhone
464
+ /(?:\/|\()(ip(?:hone|od)[\w, ]*)(?:\/|;)/i // iPod/iPhone
388
465
  ], [MODEL, [VENDOR, APPLE], [TYPE, MOBILE]], [
389
466
  /\((ipad);[-\w\),; ]+apple/i, // iPad
390
467
  /applecoremedia\/[\w\.]+ \((ipad)/i,
@@ -393,6 +470,10 @@
393
470
  /(macintosh);/i
394
471
  ], [MODEL, [VENDOR, APPLE]], [
395
472
 
473
+ // Sharp
474
+ /\b(sh-?[altvz]?\d\d[a-ekm]?)/i
475
+ ], [MODEL, [VENDOR, SHARP], [TYPE, MOBILE]], [
476
+
396
477
  // Huawei
397
478
  /\b((?:ag[rs][23]?|bah2?|sht?|btv)-a?[lw]\d{2})\b(?!.+d\/s)/i
398
479
  ], [MODEL, [VENDOR, HUAWEI], [TYPE, TABLET]], [
@@ -470,7 +551,7 @@
470
551
 
471
552
  // Amazon
472
553
  /(alexa)webm/i,
473
- /(kf[a-z]{2}wi)( bui|\))/i, // Kindle Fire without Silk
554
+ /(kf[a-z]{2}wi|aeo[c-r]{2})( bui|\))/i, // Kindle Fire without Silk / Echo Show
474
555
  /(kf[a-z]+)( bui|\)).+silk\//i // Kindle Fire HD
475
556
  ], [MODEL, [VENDOR, AMAZON], [TYPE, TABLET]], [
476
557
  /((?:sd|kf)[0349hijorstuw]+)( bui|\)).+silk\//i // Fire Phone
@@ -496,7 +577,7 @@
496
577
 
497
578
  // ZTE
498
579
  /(zte)[- ]([\w ]+?)(?: bui|\/|\))/i,
499
- /(alcatel|geeksphone|nexian|panasonic|sony(?!-bra))[-_ ]?([-\w]*)/i // Alcatel/GeeksPhone/Nexian/Panasonic/Sony
580
+ /(alcatel|geeksphone|nexian|panasonic(?!(?:;|\.))|sony(?!-bra))[-_ ]?([-\w]*)/i // Alcatel/GeeksPhone/Nexian/Panasonic/Sony
500
581
  ], [VENDOR, [MODEL, /_/g, ' '], [TYPE, MOBILE]], [
501
582
 
502
583
  // Acer
@@ -508,10 +589,6 @@
508
589
  /\bmz-([-\w]{2,})/i
509
590
  ], [MODEL, [VENDOR, 'Meizu'], [TYPE, MOBILE]], [
510
591
 
511
- // Sharp
512
- /\b(sh-?[altvz]?\d\d[a-ekm]?)/i
513
- ], [MODEL, [VENDOR, SHARP], [TYPE, MOBILE]], [
514
-
515
592
  // MIXED
516
593
  /(blackberry|benq|palm(?=\-)|sonyericsson|acer|asus|dell|meizu|motorola|polytron)[-_ ]?([-\w]*)/i,
517
594
  // BlackBerry/BenQ/Palm/Sony-Ericsson/Acer/Asus/Dell/Meizu/Motorola/Polytron
@@ -523,89 +600,27 @@
523
600
  /(oppo) ?([\w ]+) bui/i // OPPO
524
601
  ], [VENDOR, MODEL, [TYPE, MOBILE]], [
525
602
 
603
+ /(kobo)\s(ereader|touch)/i, // Kobo
526
604
  /(archos) (gamepad2?)/i, // Archos
527
605
  /(hp).+(touchpad(?!.+tablet)|tablet)/i, // HP TouchPad
528
- /(kindle)\/([\w\.]+)/i, // Kindle
529
- /(nook)[\w ]+build\/(\w+)/i, // Nook
530
- /(dell) (strea[kpr\d ]*[\dko])/i, // Dell Streak
531
- /(le[- ]+pan)[- ]+(\w{1,9}) bui/i, // Le Pan Tablets
532
- /(trinity)[- ]*(t\d{3}) bui/i, // Trinity Tablets
533
- /(gigaset)[- ]+(q\w{1,9}) bui/i, // Gigaset Tablets
534
- /(vodafone) ([\w ]+)(?:\)| bui)/i // Vodafone
606
+ /(kindle)\/([\w\.]+)/i // Kindle
535
607
  ], [VENDOR, MODEL, [TYPE, TABLET]], [
536
608
 
537
609
  /(surface duo)/i // Surface Duo
538
610
  ], [MODEL, [VENDOR, MICROSOFT], [TYPE, TABLET]], [
539
611
  /droid [\d\.]+; (fp\du?)(?: b|\))/i // Fairphone
540
612
  ], [MODEL, [VENDOR, 'Fairphone'], [TYPE, MOBILE]], [
541
- /(u304aa)/i // AT&T
542
- ], [MODEL, [VENDOR, 'AT&T'], [TYPE, MOBILE]], [
543
- /\bsie-(\w*)/i // Siemens
544
- ], [MODEL, [VENDOR, 'Siemens'], [TYPE, MOBILE]], [
545
- /\b(rct\w+) b/i // RCA Tablets
546
- ], [MODEL, [VENDOR, 'RCA'], [TYPE, TABLET]], [
547
- /\b(venue[\d ]{2,7}) b/i // Dell Venue Tablets
548
- ], [MODEL, [VENDOR, 'Dell'], [TYPE, TABLET]], [
549
- /\b(q(?:mv|ta)\w+) b/i // Verizon Tablet
550
- ], [MODEL, [VENDOR, 'Verizon'], [TYPE, TABLET]], [
551
- /\b(?:barnes[& ]+noble |bn[rt])([\w\+ ]*) b/i // Barnes & Noble Tablet
552
- ], [MODEL, [VENDOR, 'Barnes & Noble'], [TYPE, TABLET]], [
553
- /\b(tm\d{3}\w+) b/i
554
- ], [MODEL, [VENDOR, 'NuVision'], [TYPE, TABLET]], [
555
- /\b(k88) b/i // ZTE K Series Tablet
556
- ], [MODEL, [VENDOR, 'ZTE'], [TYPE, TABLET]], [
557
- /\b(nx\d{3}j) b/i // ZTE Nubia
558
- ], [MODEL, [VENDOR, 'ZTE'], [TYPE, MOBILE]], [
559
- /\b(gen\d{3}) b.+49h/i // Swiss GEN Mobile
560
- ], [MODEL, [VENDOR, 'Swiss'], [TYPE, MOBILE]], [
561
- /\b(zur\d{3}) b/i // Swiss ZUR Tablet
562
- ], [MODEL, [VENDOR, 'Swiss'], [TYPE, TABLET]], [
563
- /\b((zeki)?tb.*\b) b/i // Zeki Tablets
564
- ], [MODEL, [VENDOR, 'Zeki'], [TYPE, TABLET]], [
565
- /\b([yr]\d{2}) b/i,
566
- /\b(dragon[- ]+touch |dt)(\w{5}) b/i // Dragon Touch Tablet
567
- ], [[VENDOR, 'Dragon Touch'], MODEL, [TYPE, TABLET]], [
568
- /\b(ns-?\w{0,9}) b/i // Insignia Tablets
569
- ], [MODEL, [VENDOR, 'Insignia'], [TYPE, TABLET]], [
570
- /\b((nxa|next)-?\w{0,9}) b/i // NextBook Tablets
571
- ], [MODEL, [VENDOR, 'NextBook'], [TYPE, TABLET]], [
572
- /\b(xtreme\_)?(v(1[045]|2[015]|[3469]0|7[05])) b/i // Voice Xtreme Phones
573
- ], [[VENDOR, 'Voice'], MODEL, [TYPE, MOBILE]], [
574
- /\b(lvtel\-)?(v1[12]) b/i // LvTel Phones
575
- ], [[VENDOR, 'LvTel'], MODEL, [TYPE, MOBILE]], [
576
- /\b(ph-1) /i // Essential PH-1
577
- ], [MODEL, [VENDOR, 'Essential'], [TYPE, MOBILE]], [
578
- /\b(v(100md|700na|7011|917g).*\b) b/i // Envizen Tablets
579
- ], [MODEL, [VENDOR, 'Envizen'], [TYPE, TABLET]], [
580
- /\b(trio[-\w\. ]+) b/i // MachSpeed Tablets
581
- ], [MODEL, [VENDOR, 'MachSpeed'], [TYPE, TABLET]], [
582
- /\btu_(1491) b/i // Rotor Tablets
583
- ], [MODEL, [VENDOR, 'Rotor'], [TYPE, TABLET]], [
584
613
  /(shield[\w ]+) b/i // Nvidia Shield Tablets
585
614
  ], [MODEL, [VENDOR, 'Nvidia'], [TYPE, TABLET]], [
586
615
  /(sprint) (\w+)/i // Sprint Phones
587
616
  ], [VENDOR, MODEL, [TYPE, MOBILE]], [
588
617
  /(kin\.[onetw]{3})/i // Microsoft Kin
589
618
  ], [[MODEL, /\./g, ' '], [VENDOR, MICROSOFT], [TYPE, MOBILE]], [
590
- /droid.+; (cc6666?|et5[16]|mc[239][23]x?|vc8[03]x?)\)/i // Zebra
619
+ /droid.+; ([c6]+|et5[16]|mc[239][23]x?|vc8[03]x?)\)/i // Zebra
591
620
  ], [MODEL, [VENDOR, ZEBRA], [TYPE, TABLET]], [
592
621
  /droid.+; (ec30|ps20|tc[2-8]\d[kx])\)/i
593
622
  ], [MODEL, [VENDOR, ZEBRA], [TYPE, MOBILE]], [
594
623
 
595
- ///////////////////
596
- // CONSOLES
597
- ///////////////////
598
-
599
- /(ouya)/i, // Ouya
600
- /(nintendo) ([wids3utch]+)/i // Nintendo
601
- ], [VENDOR, MODEL, [TYPE, CONSOLE]], [
602
- /droid.+; (shield) bui/i // Nvidia
603
- ], [MODEL, [VENDOR, 'Nvidia'], [TYPE, CONSOLE]], [
604
- /(playstation [345portablevi]+)/i // Playstation
605
- ], [MODEL, [VENDOR, SONY], [TYPE, CONSOLE]], [
606
- /\b(xbox(?: one)?(?!; xbox))[\); ]/i // Microsoft Xbox
607
- ], [MODEL, [VENDOR, MICROSOFT], [TYPE, CONSOLE]], [
608
-
609
624
  ///////////////////
610
625
  // SMARTTVS
611
626
  ///////////////////
@@ -625,27 +640,45 @@
625
640
  /\(dtv[\);].+(aquos)/i,
626
641
  /(aquos-tv[\w ]+)\)/i // Sharp
627
642
  ], [MODEL, [VENDOR, SHARP], [TYPE, SMARTTV]],[
628
- /(bravia[\w ]+)( bui|\))/i // Sony
643
+ /(bravia[\w ]+)( bui|\))/i // Sony
629
644
  ], [MODEL, [VENDOR, SONY], [TYPE, SMARTTV]], [
630
645
  /(mitv-\w{5}) bui/i // Xiaomi
631
646
  ], [MODEL, [VENDOR, XIAOMI], [TYPE, SMARTTV]], [
647
+ /Hbbtv.*(technisat) (.*);/i // TechniSAT
648
+ ], [VENDOR, MODEL, [TYPE, SMARTTV]], [
632
649
  /\b(roku)[\dx]*[\)\/]((?:dvp-)?[\d\.]*)/i, // Roku
633
- /hbbtv\/\d+\.\d+\.\d+ +\([\w ]*; *(\w[^;]*);([^;]*)/i // HbbTV devices
650
+ /hbbtv\/\d+\.\d+\.\d+ +\([\w\+ ]*; *([\w\d][^;]*);([^;]*)/i // HbbTV devices
634
651
  ], [[VENDOR, trim], [MODEL, trim], [TYPE, SMARTTV]], [
635
652
  /\b(android tv|smart[- ]?tv|opera tv|tv; rv:)\b/i // SmartTV from Unidentified Vendors
636
653
  ], [[TYPE, SMARTTV]], [
637
654
 
655
+ ///////////////////
656
+ // CONSOLES
657
+ ///////////////////
658
+
659
+ /(ouya)/i, // Ouya
660
+ /(nintendo) (\w+)/i // Nintendo
661
+ ], [VENDOR, MODEL, [TYPE, CONSOLE]], [
662
+ /droid.+; (shield) bui/i // Nvidia
663
+ ], [MODEL, [VENDOR, 'Nvidia'], [TYPE, CONSOLE]], [
664
+ /(playstation \w+)/i // Playstation
665
+ ], [MODEL, [VENDOR, SONY], [TYPE, CONSOLE]], [
666
+ /\b(xbox(?: one)?(?!; xbox))[\); ]/i // Microsoft Xbox
667
+ ], [MODEL, [VENDOR, MICROSOFT], [TYPE, CONSOLE]], [
668
+
638
669
  ///////////////////
639
670
  // WEARABLES
640
671
  ///////////////////
641
672
 
642
673
  /((pebble))app/i // Pebble
643
674
  ], [VENDOR, MODEL, [TYPE, WEARABLE]], [
675
+ /(watch)(?: ?os[,\/]|\d,\d\/)[\d\.]+/i // Apple Watch
676
+ ], [MODEL, [VENDOR, APPLE], [TYPE, WEARABLE]], [
644
677
  /droid.+; (glass) \d/i // Google Glass
645
678
  ], [MODEL, [VENDOR, GOOGLE], [TYPE, WEARABLE]], [
646
679
  /droid.+; (wt63?0{2,3})\)/i
647
680
  ], [MODEL, [VENDOR, ZEBRA], [TYPE, WEARABLE]], [
648
- /(quest( 2)?)/i // Oculus Quest
681
+ /(quest( 2| pro)?)/i // Oculus Quest
649
682
  ], [MODEL, [VENDOR, FACEBOOK], [TYPE, WEARABLE]], [
650
683
 
651
684
  ///////////////////
@@ -654,6 +687,8 @@
654
687
 
655
688
  /(tesla)(?: qtcarbrowser|\/[-\w\.]+)/i // Tesla
656
689
  ], [VENDOR, [TYPE, EMBEDDED]], [
690
+ /(aeobc)\b/i // Echo Dot
691
+ ], [MODEL, [VENDOR, AMAZON], [TYPE, EMBEDDED]], [
657
692
 
658
693
  ////////////////////
659
694
  // MIXED (GENERIC)
@@ -683,7 +718,8 @@
683
718
  /(webkit|trident|netfront|netsurf|amaya|lynx|w3m|goanna)\/([\w\.]+)/i, // WebKit/Trident/NetFront/NetSurf/Amaya/Lynx/w3m/Goanna
684
719
  /ekioh(flow)\/([\w\.]+)/i, // Flow
685
720
  /(khtml|tasman|links)[\/ ]\(?([\w\.]+)/i, // KHTML/Tasman/Links
686
- /(icab)[\/ ]([23]\.[\d\.]+)/i // iCab
721
+ /(icab)[\/ ]([23]\.[\d\.]+)/i, // iCab
722
+ /\b(libweb)/i
687
723
  ], [NAME, VERSION], [
688
724
 
689
725
  /rv\:([\w\.]{1,9})\b.+(gecko)/i // Gecko
@@ -700,15 +736,16 @@
700
736
  /(windows)[\/ ]?([ntce\d\. ]+\w)(?!.+xbox)/i
701
737
  ], [NAME, [VERSION, strMapper, windowsVersionMap]], [
702
738
  /(win(?=3|9|n)|win 9x )([nt\d\.]+)/i
703
- ], [[NAME, 'Windows'], [VERSION, strMapper, windowsVersionMap]], [
739
+ ], [[NAME, WINDOWS], [VERSION, strMapper, windowsVersionMap]], [
704
740
 
705
741
  // iOS/macOS
706
742
  /ip[honead]{2,4}\b(?:.*os ([\w]+) like mac|; opera)/i, // iOS
743
+ /ios;fbsv\/([\d\.]+)/i,
707
744
  /cfnetwork\/.+darwin/i
708
745
  ], [[VERSION, /_/g, '.'], [NAME, 'iOS']], [
709
746
  /(mac os x) ?([\w\. ]*)/i,
710
747
  /(macintosh|mac_powerpc\b)(?!.+haiku)/i // Mac OS
711
- ], [[NAME, 'Mac OS'], [VERSION, /_/g, '.']], [
748
+ ], [[NAME, 'macOS'], [VERSION, /_/g, '.']], [
712
749
 
713
750
  // Mobile OSes
714
751
  /droid ([\w\.]+)\b.+(android[- ]x86|harmonyos)/i // Android-x86/HarmonyOS
@@ -727,15 +764,22 @@
727
764
  /web0s;.+rt(tv)/i,
728
765
  /\b(?:hp)?wos(?:browser)?\/([\w\.]+)/i // WebOS
729
766
  ], [VERSION, [NAME, 'webOS']], [
767
+ /watch(?: ?os[,\/]|\d,\d\/)([\d\.]+)/i // watchOS
768
+ ], [VERSION, [NAME, 'watchOS']], [
730
769
 
731
770
  // Google Chromecast
732
771
  /crkey\/([\d\.]+)/i // Google Chromecast
733
772
  ], [VERSION, [NAME, CHROME+'cast']], [
734
- /(cros) [\w]+ ([\w\.]+\w)/i // Chromium OS
735
- ], [[NAME, 'Chromium OS'], VERSION],[
773
+ /(cros) [\w]+(?:\)| ([\w\.]+)\b)/i // Chromium OS
774
+ ], [[NAME, "Chrome OS"], VERSION],[
775
+
776
+ // Smart TVs
777
+ /panasonic;(viera)/i, // Panasonic Viera
778
+ /(netrange)mmh/i, // Netrange
779
+ /(nettv)\/(\d+\.[\w\.]+)/i, // NetTV
736
780
 
737
781
  // Console
738
- /(nintendo|playstation) ([wids345portablevuch]+)/i, // Nintendo/Playstation
782
+ /(nintendo|playstation) (\w+)/i, // Nintendo/Playstation
739
783
  /(xbox); +xbox ([^\);]+)/i, // Microsoft Xbox (360, One, X, S, Series X, Series S)
740
784
 
741
785
  // Other
@@ -753,86 +797,307 @@
753
797
  ], [[NAME, 'Solaris'], VERSION], [
754
798
  /((?:open)?solaris)[-\/ ]?([\w\.]*)/i, // Solaris
755
799
  /(aix) ((\d)(?=\.|\)| )[\w\.])*/i, // AIX
756
- /\b(beos|os\/2|amigaos|morphos|openvms|fuchsia|hp-ux)/i, // BeOS/OS2/AmigaOS/MorphOS/OpenVMS/Fuchsia/HP-UX
800
+ /\b(beos|os\/2|amigaos|morphos|openvms|fuchsia|hp-ux|serenityos)/i, // BeOS/OS2/AmigaOS/MorphOS/OpenVMS/Fuchsia/HP-UX/SerenityOS
757
801
  /(unix) ?([\w\.]*)/i // UNIX
758
802
  ], [NAME, VERSION]
759
803
  ]
760
804
  };
761
805
 
806
+ /////////////////
807
+ // Factories
808
+ ////////////////
809
+
810
+ var defaultProps = (function () {
811
+ var props = { init : {}, isIgnore : {}, isIgnoreRgx : {}, toString : {}};
812
+ assignFromEntries.call(props.init, [
813
+ [UA_BROWSER, [NAME, VERSION, MAJOR]],
814
+ [UA_CPU, [ARCHITECTURE]],
815
+ [UA_DEVICE, [TYPE, MODEL, VENDOR]],
816
+ [UA_ENGINE, [NAME, VERSION]],
817
+ [UA_OS, [NAME, VERSION]]
818
+ ]);
819
+ assignFromEntries.call(props.isIgnore, [
820
+ [UA_BROWSER, [VERSION, MAJOR]],
821
+ [UA_ENGINE, [VERSION]],
822
+ [UA_OS, [VERSION]]
823
+ ]);
824
+ assignFromEntries.call(props.isIgnoreRgx, [
825
+ [UA_BROWSER, / ?browser$/i],
826
+ [UA_OS, / ?os$/i]
827
+ ]);
828
+ assignFromEntries.call(props.toString, [
829
+ [UA_BROWSER, [NAME, VERSION]],
830
+ [UA_CPU, [ARCHITECTURE]],
831
+ [UA_DEVICE, [VENDOR, MODEL]],
832
+ [UA_ENGINE, [NAME, VERSION]],
833
+ [UA_OS, [NAME, VERSION]]
834
+ ]);
835
+ return props;
836
+ })();
837
+
838
+ var createUAParserData = function (itemType, ua, rgxMap, uaCH) {
839
+
840
+ var init_props = defaultProps.init[itemType],
841
+ is_ignoreProps = defaultProps.isIgnore[itemType] || 0,
842
+ is_ignoreRgx = defaultProps.isIgnoreRgx[itemType] || 0,
843
+ toString_props = defaultProps.toString[itemType] || 0;
844
+
845
+ function UAParserData () {
846
+ assignFromEntries.call(this, init_props);
847
+ }
848
+ UAParserData.prototype.withClientHints = function () {
849
+
850
+ // nodejs / non-client-hints browsers
851
+ if (!NAVIGATOR_UADATA) {
852
+ return new UAParserItem(itemType, ua, rgxMap, uaCH).parseCH().get();
853
+ }
854
+
855
+ // browsers based on chromium 85+
856
+ return NAVIGATOR_UADATA
857
+ .getHighEntropyValues(CH_ALL_VALUES)
858
+ .then(function (res) {
859
+ var JS_UACH = new UAParserDataCH(res, false);
860
+ return new UAParserItem(itemType, ua, rgxMap, JS_UACH).parseCH().get();
861
+ });
862
+ };
863
+
864
+ if (itemType != UA_RESULT) {
865
+ UAParserData.prototype.is = function (strToCheck) {
866
+ var is = false;
867
+ for (var i in this) {
868
+ if (this.hasOwnProperty(i) && !has(is_ignoreProps, i) && lowerize(is_ignoreRgx ? strip(is_ignoreRgx, this[i]) : this[i]) == lowerize(is_ignoreRgx ? strip(is_ignoreRgx, strToCheck) : strToCheck)) {
869
+ is = true;
870
+ if (strToCheck != UNDEF_TYPE) break;
871
+ } else if (strToCheck == UNDEF_TYPE && is) {
872
+ is = !is;
873
+ break;
874
+ }
875
+ }
876
+ return is;
877
+ };
878
+ UAParserData.prototype.toString = function () {
879
+ var str = EMPTY;
880
+ for (var i in toString_props) {
881
+ if (typeof(this[toString_props[i]]) !== UNDEF_TYPE) {
882
+ str += (str ? ' ' : EMPTY) + this[toString_props[i]];
883
+ }
884
+ }
885
+ return str || UNDEF_TYPE;
886
+ };
887
+ }
888
+
889
+ if (!NAVIGATOR_UADATA) {
890
+ UAParserData.prototype.then = function (cb) {
891
+ cb(this);
892
+ return this;
893
+ };
894
+ }
895
+
896
+ return new UAParserData();
897
+ };
898
+
762
899
  /////////////////
763
900
  // Constructor
764
901
  ////////////////
765
902
 
766
- var UAParser = function (ua, extensions) {
903
+ function UAParserDataCH (uach, isHTTP_UACH) {
904
+ uach = uach || {};
905
+ assignFromEntries.call(this, CH_ALL_VALUES);
906
+ if (isHTTP_UACH) {
907
+ assignFromEntries.call(this, [
908
+ [BRANDS, itemListToArray(uach[CH_HEADER])],
909
+ [FULLVERLIST, itemListToArray(uach[CH_HEADER_FULL_VER_LIST])],
910
+ [BRANDS, itemListToArray(uach[CH_HEADER])],
911
+ [MOBILE, /\?1/.test(uach[CH_HEADER_MOBILE])],
912
+ [MODEL, stripQuotes(uach[CH_HEADER_MODEL])],
913
+ [PLATFORM, stripQuotes(uach[CH_HEADER_PLATFORM])],
914
+ [PLATFORMVER, stripQuotes(uach[CH_HEADER_PLATFORM_VER])],
915
+ [ARCHITECTURE, stripQuotes(uach[CH_HEADER_ARCH])],
916
+ [BITNESS, stripQuotes(uach[CH_HEADER_BITNESS])]
917
+ ]);
918
+ } else {
919
+ for (var prop in uach) {
920
+ if(this.hasOwnProperty(prop) && typeof uach[prop] !== UNDEF_TYPE) this[prop] = uach[prop];
921
+ }
922
+ }
923
+ return this;
924
+ }
925
+
926
+ function UAParserItem (itemType, ua, rgxMap, uaCH) {
927
+ assignFromEntries.call(this, [
928
+ ['itemType', itemType],
929
+ ['ua', ua],
930
+ ['uaCH', uaCH],
931
+ ['rgxMap', rgxMap],
932
+ ['data', createUAParserData(itemType, ua, rgxMap, uaCH)]
933
+ ]);
934
+ this.parse();
935
+ switch(this.itemType) {
936
+ case UA_BROWSER:
937
+ // Brave-specific detection
938
+ if (NAVIGATOR && NAVIGATOR.userAgent == ua && NAVIGATOR.brave && typeof NAVIGATOR.brave.isBrave == FUNC_TYPE) {
939
+ this.set(NAME, 'Brave');
940
+ }
941
+ this.set(MAJOR, majorize(this.get(VERSION)));
942
+ break;
943
+ case UA_DEVICE:
944
+ if (!this.get(TYPE) && NAVIGATOR_UADATA && NAVIGATOR_UADATA[MOBILE]) {
945
+ this.set(TYPE, MOBILE);
946
+ }
947
+ // iPadOS-specific detection: identified as Mac, but has some iOS-only properties
948
+ if (this.get(MODEL) == 'Macintosh' && NAVIGATOR && typeof NAVIGATOR.standalone !== UNDEF_TYPE && NAVIGATOR.maxTouchPoints && NAVIGATOR.maxTouchPoints > 2) {
949
+ this.set(MODEL, 'iPad')
950
+ .set(TYPE, TABLET);
951
+ }
952
+ break;
953
+ case UA_OS:
954
+ if (!this.get(NAME) && NAVIGATOR_UADATA && NAVIGATOR_UADATA[PLATFORM] && NAVIGATOR_UADATA[PLATFORM] != 'Unknown') {
955
+ this.set(NAME, NAVIGATOR_UADATA[PLATFORM]);
956
+ }
957
+ break;
958
+ case UA_RESULT:
959
+ var createUAParserItem = function (itemType) {
960
+ return new UAParserItem(itemType, ua, rgxMap[itemType], uaCH).get();
961
+ };
962
+ this.set('ua', ua)
963
+ .set(UA_BROWSER, createUAParserItem(UA_BROWSER))
964
+ .set(UA_CPU, createUAParserItem(UA_CPU))
965
+ .set(UA_DEVICE, createUAParserItem(UA_DEVICE))
966
+ .set(UA_ENGINE, createUAParserItem(UA_ENGINE))
967
+ .set(UA_OS, createUAParserItem(UA_OS))
968
+ .get();
969
+ }
970
+ return this;
971
+ }
972
+ UAParserItem.prototype.get = function (prop) {
973
+ if (!prop) return this.data;
974
+ return this.data.hasOwnProperty(prop) ? this.data[prop] : undefined;
975
+ };
976
+ UAParserItem.prototype.parse = function () {
977
+ if (this.itemType != UA_RESULT) {
978
+ rgxMapper.call(this.data, this.ua, this.rgxMap);
979
+ }
980
+ return this;
981
+ };
982
+ UAParserItem.prototype.parseCH = function () {
983
+ var ua = this.ua,
984
+ uaCH = this.uaCH,
985
+ rgxMap = this.rgxMap;
986
+
987
+ switch (this.itemType) {
988
+ case UA_BROWSER:
989
+ var brands = uaCH[FULLVERLIST] || uaCH[BRANDS];
990
+ if (brands) {
991
+ for (var i in brands) {
992
+ var brandName = brands[i].brand,
993
+ brandVersion = brands[i].version;
994
+ if (!/not.a.brand/i.test(brandName) || /chromi/i.test(this.get(NAME))) {
995
+ this.set(NAME, strip(GOOGLE+' ', brandName))
996
+ .set(VERSION, brandVersion)
997
+ .set(MAJOR, majorize(brandVersion));
998
+ }
999
+ }
1000
+ }
1001
+ break;
1002
+ case UA_CPU:
1003
+ var archName = uaCH[ARCHITECTURE];
1004
+ if (archName) {
1005
+ if (archName && uaCH[BITNESS] == '64') archName += '64';
1006
+ rgxMapper.call(this.data, archName + ';', rgxMap);
1007
+ }
1008
+ break;
1009
+ case UA_DEVICE:
1010
+ if (uaCH[MOBILE]) {
1011
+ this.set(TYPE, MOBILE);
1012
+ }
1013
+ if (uaCH[MODEL]) {
1014
+ this.set(MODEL, uaCH[MODEL]);
1015
+ }
1016
+ break;
1017
+ case UA_OS:
1018
+ var osName = uaCH[PLATFORM];
1019
+ if(osName) {
1020
+ var osVersion = uaCH[PLATFORMVER];
1021
+ if (osName == WINDOWS) osVersion = (parseInt(majorize(osVersion), 10) >= 13 ? '11' : '10');
1022
+ this.set(NAME, osName)
1023
+ .set(VERSION, osVersion);
1024
+ }
1025
+ break;
1026
+ case UA_RESULT:
1027
+ var createUAParserItemWithCH = function (itemType) {
1028
+ return new UAParserItem(itemType, ua, rgxMap[itemType], uaCH).parseCH().get();
1029
+ };
1030
+ this.set('ua', ua)
1031
+ .set(UA_BROWSER, createUAParserItemWithCH(UA_BROWSER))
1032
+ .set(UA_CPU, createUAParserItemWithCH(UA_CPU))
1033
+ .set(UA_DEVICE, createUAParserItemWithCH(UA_DEVICE))
1034
+ .set(UA_ENGINE, createUAParserItemWithCH(UA_ENGINE))
1035
+ .set(UA_OS, createUAParserItemWithCH(UA_OS));
1036
+ }
1037
+ return this;
1038
+ };
1039
+ UAParserItem.prototype.set = function (prop, val) {
1040
+ this.data[prop] = val;
1041
+ return this;
1042
+ };
1043
+
1044
+ function UAParser (ua, extensions, headers) {
767
1045
 
768
1046
  if (typeof ua === OBJ_TYPE) {
769
- extensions = ua;
1047
+ if (isExtensions(ua)) {
1048
+ if (typeof extensions === OBJ_TYPE) {
1049
+ headers = extensions; // case UAParser(extensions, headers)
1050
+ }
1051
+ extensions = ua; // case UAParser(extensions)
1052
+ } else {
1053
+ headers = ua; // case UAParser(headers)
1054
+ extensions = undefined;
1055
+ }
770
1056
  ua = undefined;
1057
+ } else if (typeof ua === STR_TYPE && !isExtensions(extensions)) {
1058
+ headers = extensions; // case UAParser(ua, headers)
1059
+ extensions = undefined;
771
1060
  }
772
-
1061
+
773
1062
  if (!(this instanceof UAParser)) {
774
- return new UAParser(ua, extensions).getResult();
1063
+ return new UAParser(ua, extensions, headers).getResult();
775
1064
  }
776
1065
 
777
- var _ua = ua || ((typeof window !== UNDEF_TYPE && window.navigator && window.navigator.userAgent) ? window.navigator.userAgent : EMPTY);
778
- var _rgxmap = extensions ? extend(regexes, extensions) : regexes;
1066
+ var userAgent = ua ||
1067
+ ((NAVIGATOR && NAVIGATOR.userAgent) ?
1068
+ NAVIGATOR.userAgent :
1069
+ (headers && headers[USER_AGENT] ?
1070
+ headers[USER_AGENT] :
1071
+ EMPTY)),
1072
+
1073
+ HTTP_UACH = new UAParserDataCH(headers, true),
779
1074
 
780
- this.getBrowser = function () {
781
- var _browser = {};
782
- _browser[NAME] = undefined;
783
- _browser[VERSION] = undefined;
784
- rgxMapper.call(_browser, _ua, _rgxmap.browser);
785
- _browser.major = majorize(_browser.version);
786
- return _browser;
787
- };
788
- this.getCPU = function () {
789
- var _cpu = {};
790
- _cpu[ARCHITECTURE] = undefined;
791
- rgxMapper.call(_cpu, _ua, _rgxmap.cpu);
792
- return _cpu;
793
- };
794
- this.getDevice = function () {
795
- var _device = {};
796
- _device[VENDOR] = undefined;
797
- _device[MODEL] = undefined;
798
- _device[TYPE] = undefined;
799
- rgxMapper.call(_device, _ua, _rgxmap.device);
800
- return _device;
801
- };
802
- this.getEngine = function () {
803
- var _engine = {};
804
- _engine[NAME] = undefined;
805
- _engine[VERSION] = undefined;
806
- rgxMapper.call(_engine, _ua, _rgxmap.engine);
807
- return _engine;
808
- };
809
- this.getOS = function () {
810
- var _os = {};
811
- _os[NAME] = undefined;
812
- _os[VERSION] = undefined;
813
- rgxMapper.call(_os, _ua, _rgxmap.os);
814
- return _os;
815
- };
816
- this.getResult = function () {
817
- return {
818
- ua : this.getUA(),
819
- browser : this.getBrowser(),
820
- engine : this.getEngine(),
821
- os : this.getOS(),
822
- device : this.getDevice(),
823
- cpu : this.getCPU()
1075
+ regexMap = extensions ?
1076
+ extend(defaultRegexes, extensions) :
1077
+ defaultRegexes,
1078
+
1079
+ createUAParserItemFunc = function (itemType) {
1080
+ return function () {
1081
+ return new UAParserItem(itemType, userAgent, itemType == UA_RESULT ? regexMap : regexMap[itemType], HTTP_UACH).get();
1082
+ };
824
1083
  };
825
- };
826
- this.getUA = function () {
827
- return _ua;
828
- };
829
- this.setUA = function (ua) {
830
- _ua = (typeof ua === STR_TYPE && ua.length > UA_MAX_LENGTH) ? trim(ua, UA_MAX_LENGTH) : ua;
831
- return this;
832
- };
833
- this.setUA(_ua);
1084
+
1085
+ // public methods
1086
+ assignFromEntries.call(this, [
1087
+ ['getBrowser', createUAParserItemFunc(UA_BROWSER)],
1088
+ ['getCPU', createUAParserItemFunc(UA_CPU)],
1089
+ ['getDevice', createUAParserItemFunc(UA_DEVICE)],
1090
+ ['getEngine', createUAParserItemFunc(UA_ENGINE)],
1091
+ ['getOS', createUAParserItemFunc(UA_OS)],
1092
+ ['getResult', createUAParserItemFunc(UA_RESULT)],
1093
+ ['getUA', function () { return userAgent; }],
1094
+ ['setUA', function (ua) {
1095
+ userAgent = (typeof ua === STR_TYPE && ua.length > UA_MAX_LENGTH) ? trim(ua, UA_MAX_LENGTH) : ua;
1096
+ return this;
1097
+ }]
1098
+ ]).setUA(userAgent);
834
1099
  return this;
835
- };
1100
+ }
836
1101
 
837
1102
  UAParser.VERSION = LIBVERSION;
838
1103
  UAParser.BROWSER = enumerize([NAME, VERSION, MAJOR]);