ua-parser-js 2.0.0-beta.1 → 2.0.0-beta.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,6 +1,6 @@
1
1
  /////////////////////////////////////////////////////////////////////////////////
2
- /* UAParser.js v2.0.0-beta.1
3
- Copyright © 2012-2023 Faisal Salman <f@faisalman.com>
2
+ /* UAParser.js v2.0.0-beta.3
3
+ Copyright © 2012-2024 Faisal Salman <f@faisalman.com>
4
4
  AGPLv3 License *//*
5
5
  Detect Browser, Engine, OS, CPU, and Device type/model from User-Agent data.
6
6
  Supports browser & node.js environment.
@@ -19,8 +19,7 @@
19
19
  // Constants
20
20
  /////////////
21
21
 
22
-
23
- var LIBVERSION = '2.0.0-beta.1',
22
+ var LIBVERSION = '2.0.0-beta.3',
24
23
  EMPTY = '',
25
24
  UNKNOWN = '?',
26
25
  FUNC_TYPE = 'function',
@@ -39,11 +38,12 @@
39
38
  TABLET = 'tablet',
40
39
  SMARTTV = 'smarttv',
41
40
  WEARABLE = 'wearable',
41
+ XR = 'xr',
42
42
  EMBEDDED = 'embedded',
43
43
  USER_AGENT = 'user-agent',
44
- UA_MAX_LENGTH = 350,
44
+ UA_MAX_LENGTH = 500,
45
45
  BRANDS = 'brands',
46
- FORMFACTOR = 'formFactor',
46
+ FORMFACTORS = 'formFactors',
47
47
  FULLVERLIST = 'fullVersionList',
48
48
  PLATFORM = 'platform',
49
49
  PLATFORMVER = 'platformVersion',
@@ -52,12 +52,12 @@
52
52
  CH_HEADER_FULL_VER_LIST = CH_HEADER + '-full-version-list',
53
53
  CH_HEADER_ARCH = CH_HEADER + '-arch',
54
54
  CH_HEADER_BITNESS = CH_HEADER + '-' + BITNESS,
55
- CH_HEADER_FORM_FACTOR = CH_HEADER + '-form-factor',
55
+ CH_HEADER_FORM_FACTORS = CH_HEADER + '-form-factors',
56
56
  CH_HEADER_MOBILE = CH_HEADER + '-' + MOBILE,
57
57
  CH_HEADER_MODEL = CH_HEADER + '-' + MODEL,
58
58
  CH_HEADER_PLATFORM = CH_HEADER + '-' + PLATFORM,
59
59
  CH_HEADER_PLATFORM_VER = CH_HEADER_PLATFORM + '-version',
60
- CH_ALL_VALUES = [BRANDS, FULLVERLIST, MOBILE, MODEL, PLATFORM, PLATFORMVER, ARCHITECTURE, FORMFACTOR, BITNESS],
60
+ CH_ALL_VALUES = [BRANDS, FULLVERLIST, MOBILE, MODEL, PLATFORM, PLATFORMVER, ARCHITECTURE, FORMFACTORS, BITNESS],
61
61
  UA_BROWSER = 'browser',
62
62
  UA_CPU = 'cpu',
63
63
  UA_DEVICE = 'device',
@@ -70,6 +70,7 @@
70
70
  BLACKBERRY = 'BlackBerry',
71
71
  GOOGLE = 'Google',
72
72
  HUAWEI = 'Huawei',
73
+ LENOVO = 'Lenovo',
73
74
  LG = 'LG',
74
75
  MICROSOFT = 'Microsoft',
75
76
  MOTOROLA = 'Motorola',
@@ -85,9 +86,11 @@
85
86
  FIREFOX = 'Firefox',
86
87
  OPERA = 'Opera',
87
88
  FACEBOOK = 'Facebook',
89
+ SOGOU = 'Sogou',
88
90
  WINDOWS = 'Windows';
89
91
 
90
- var NAVIGATOR = (typeof window !== UNDEF_TYPE && window.navigator) ?
92
+ var isWindow = typeof window !== UNDEF_TYPE,
93
+ NAVIGATOR = (isWindow && window.navigator) ?
91
94
  window.navigator :
92
95
  undefined,
93
96
  NAVIGATOR_UADATA = (NAVIGATOR && NAVIGATOR.userAgentData) ?
@@ -98,12 +101,21 @@
98
101
  // Helper
99
102
  //////////
100
103
 
101
- var extend = function (regexes, extensions) {
102
- var mergedRegexes = {};
103
- for (var i in regexes) {
104
- mergedRegexes[i] = extensions[i] && extensions[i].length % 2 === 0 ? extensions[i].concat(regexes[i]) : regexes[i];
104
+ var extend = function (defaultRgx, extensions) {
105
+ var mergedRgx = {};
106
+ var extraRgx = extensions;
107
+ if (!isExtensions(extensions)) {
108
+ extraRgx = {};
109
+ for (var i in extensions) {
110
+ for (var j in extensions[i]) {
111
+ extraRgx[j] = extensions[i][j].concat(extraRgx[j] ? extraRgx[j] : []);
112
+ }
113
+ }
114
+ }
115
+ for (var k in defaultRgx) {
116
+ mergedRgx[k] = extraRgx[k] && extraRgx[k].length % 2 === 0 ? extraRgx[k].concat(defaultRgx[k]) : defaultRgx[k];
105
117
  }
106
- return mergedRegexes;
118
+ return mergedRgx;
107
119
  },
108
120
  enumerize = function (arr) {
109
121
  var enums = {};
@@ -119,13 +131,16 @@
119
131
  }
120
132
  return false;
121
133
  }
122
- return typeof str1 === STR_TYPE ? lowerize(str2).indexOf(lowerize(str1)) !== -1 : false;
134
+ return isString(str1) ? lowerize(str2).indexOf(lowerize(str1)) !== -1 : false;
123
135
  },
124
- isExtensions = function (obj) {
136
+ isExtensions = function (obj, deep) {
125
137
  for (var prop in obj) {
126
- return /^(browser|cpu|device|engine|os)$/.test(prop);
138
+ return /^(browser|cpu|device|engine|os)$/.test(prop) || (deep ? isExtensions(obj[prop]) : false);
127
139
  }
128
140
  },
141
+ isString = function (val) {
142
+ return typeof val === STR_TYPE;
143
+ },
129
144
  itemListToArray = function (header) {
130
145
  if (!header) return undefined;
131
146
  var arr = [];
@@ -135,16 +150,16 @@
135
150
  var token = trim(tokens[i]).split(';v=');
136
151
  arr[i] = { brand : token[0], version : token[1] };
137
152
  } else {
138
- arr[i] = tokens[i];
153
+ arr[i] = trim(tokens[i]);
139
154
  }
140
155
  }
141
156
  return arr;
142
157
  },
143
158
  lowerize = function (str) {
144
- return typeof(str) === STR_TYPE ? str.toLowerCase() : str;
159
+ return isString(str) ? str.toLowerCase() : str;
145
160
  },
146
161
  majorize = function (version) {
147
- return typeof(version) === STR_TYPE ? strip(/[^\d\.]/g, version).split('.')[0] : undefined;
162
+ return isString(version) ? strip(/[^\d\.]/g, version).split('.')[0] : undefined;
148
163
  },
149
164
  setProps = function (arr) {
150
165
  for (var i in arr) {
@@ -158,15 +173,15 @@
158
173
  return this;
159
174
  },
160
175
  strip = function (pattern, str) {
161
- return str.replace(pattern, EMPTY);
176
+ return isString(str) ? str.replace(pattern, EMPTY) : str;
162
177
  },
163
- stripQuotes = function (val) {
164
- return typeof val === STR_TYPE ? strip(/\\?\"/g, val) : val;
178
+ stripQuotes = function (str) {
179
+ return strip(/\\?\"/g, str);
165
180
  },
166
181
  trim = function (str, len) {
167
- if (typeof(str) === STR_TYPE) {
182
+ if (isString(str)) {
168
183
  str = strip(/^\s\s*/, str);
169
- return typeof(len) === UNDEF_TYPE ? str : str.substring(0, UA_MAX_LENGTH);
184
+ return typeof len === UNDEF_TYPE ? str : str.substring(0, UA_MAX_LENGTH);
170
185
  }
171
186
  };
172
187
 
@@ -264,12 +279,13 @@
264
279
  'RT' : 'ARM'
265
280
  },
266
281
 
267
- formFactorMap = {
282
+ formFactorsMap = {
268
283
  'embedded' : 'Automotive',
269
284
  'mobile' : 'Mobile',
270
285
  'tablet' : ['Tablet', 'EInk'],
271
286
  'smarttv' : 'TV',
272
- 'wearable' : ['VR', 'XR', 'Watch'],
287
+ 'wearable' : 'Watch',
288
+ 'xr' : ['VR', 'XR'],
273
289
  '?' : ['Desktop', 'Unknown'],
274
290
  '*' : undefined
275
291
  };
@@ -295,28 +311,33 @@
295
311
  ], [NAME, VERSION], [
296
312
  /opios[\/ ]+([\w\.]+)/i // Opera mini on iphone >= 8.0
297
313
  ], [VERSION, [NAME, OPERA+' Mini']], [
314
+ /\bop(?:rg)?x\/([\w\.]+)/i // Opera GX
315
+ ], [VERSION, [NAME, OPERA+' GX']], [
298
316
  /\bopr\/([\w\.]+)/i // Opera Webkit
299
317
  ], [VERSION, [NAME, OPERA]], [
300
318
 
301
319
  // Mixed
320
+ /\bb[ai]*d(?:uhd|[ub]*[aekoprswx]{5,6})[\/ ]?([\w\.]+)/i // Baidu
321
+ ], [VERSION, [NAME, 'Baidu']], [
302
322
  /(kindle)\/([\w\.]+)/i, // Kindle
303
- /(lunascape|maxthon|netfront|jasmine|blazer)[\/ ]?([\w\.]*)/i, // Lunascape/Maxthon/Netfront/Jasmine/Blazer
323
+ /(lunascape|maxthon|netfront|jasmine|blazer|sleipnir)[\/ ]?([\w\.]*)/i,
324
+ // Lunascape/Maxthon/Netfront/Jasmine/Blazer/Sleipnir
304
325
  // Trident based
305
- /(avant |iemobile|slim)(?:browser)?[\/ ]?([\w\.]*)/i, // Avant/IEMobile/SlimBrowser
306
- /(ba?idubrowser)[\/ ]?([\w\.]+)/i, // Baidu Browser
326
+ /(avant|iemobile|slim)\s?(?:browser)?[\/ ]?([\w\.]*)/i, // Avant/IEMobile/SlimBrowser
307
327
  /(?:ms|\()(ie) ([\w\.]+)/i, // Internet Explorer
308
328
 
309
329
  // Webkit/KHTML based // Flock/RockMelt/Midori/Epiphany/Silk/Skyfire/Bolt/Iron/Iridium/PhantomJS/Bowser/QupZilla/Falkon
310
- /(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,
311
- // Rekonq/Puffin/Brave/Whale/QQBrowserLite/QQ//Vivaldi/DuckDuckGo
330
+ /(flock|rockmelt|midori|epiphany|silk|skyfire|ovibrowser|bolt|iron|vivaldi|iridium|phantomjs|bowser|quark|qupzilla|falkon|rekonq|puffin|brave|whale(?!.+naver)|qqbrowserlite|duckduckgo|klar)\/([-\w\.]+)/i,
331
+ // Rekonq/Puffin/Brave/Whale/QQBrowserLite/QQ//Vivaldi/DuckDuckGo/Klar
312
332
  /(heytap|ovi)browser\/([\d\.]+)/i, // HeyTap/Ovi
313
333
  /(weibo)__([\d\.]+)/i // Weibo
314
334
  ], [NAME, VERSION], [
335
+ /\bddg\/([\w\.]+)/i // DuckDuckGo
336
+ ], [VERSION, [NAME, 'DuckDuckGo']], [
315
337
  /(?:\buc? ?browser|(?:juc.+)ucweb)[\/ ]?([\w\.]+)/i // UCBrowser
316
338
  ], [VERSION, [NAME, 'UCBrowser']], [
317
339
  /microm.+\bqbcore\/([\w\.]+)/i, // WeChat Desktop for Windows Built-in Browser
318
- /\bqbcore\/([\w\.]+).+microm/i
319
- ], [VERSION, [NAME, 'WeChat(Win) Desktop']], [
340
+ /\bqbcore\/([\w\.]+).+microm/i,
320
341
  /micromessenger\/([\w\.]+)/i // WeChat
321
342
  ], [VERSION, [NAME, 'WeChat']], [
322
343
  /konqueror\/([\w\.]+)/i // Konqueror
@@ -325,6 +346,8 @@
325
346
  ], [VERSION, [NAME, 'IE']], [
326
347
  /ya(?:search)?browser\/([\w\.]+)/i // Yandex
327
348
  ], [VERSION, [NAME, 'Yandex']], [
349
+ /slbrowser\/([\w\.]+)/i // Smart Lenovo Browser
350
+ ], [VERSION, [NAME, 'Smart ' + LENOVO + SUFFIX_BROWSER]], [
328
351
  /(avast|avg)\/([\w\.]+)/i // Avast/AVG Secure Browser
329
352
  ], [[NAME, /(.+)/, '$1 Secure' + SUFFIX_BROWSER], VERSION], [
330
353
  /\bfocus\/([\w\.]+)/i // Firefox Focus
@@ -343,26 +366,36 @@
343
366
  ], [VERSION, [NAME, PREFIX_MOBILE + FIREFOX]], [
344
367
  /\bqihu|(qi?ho?o?|360)browser/i // 360
345
368
  ], [[NAME, '360' + SUFFIX_BROWSER]], [
346
- /(oculus|samsung|sailfish|huawei)browser\/([\w\.]+)/i
347
- ], [[NAME, /(.+)/, '$1' + SUFFIX_BROWSER], VERSION], [ // Oculus/Samsung/Sailfish/Huawei Browser
369
+ /\b(qq)\/([\w\.]+)/i // QQ
370
+ ], [[NAME, /(.+)/, '$1Browser'], VERSION], [
371
+ /(oculus|sailfish|huawei|vivo|pico)browser\/([\w\.]+)/i
372
+ ], [[NAME, /(.+)/, '$1' + SUFFIX_BROWSER], VERSION], [ // Oculus/Sailfish/HuaweiBrowser/VivoBrowser/PicoBrowser
373
+ /samsungbrowser\/([\w\.]+)/i // Samsung Internet
374
+ ], [VERSION, [NAME, SAMSUNG + ' Internet']], [
348
375
  /(comodo_dragon)\/([\w\.]+)/i // Comodo Dragon
349
376
  ], [[NAME, /_/g, ' '], VERSION], [
377
+ /metasr[\/ ]?([\d\.]+)/i // Sogou Explorer
378
+ ], [VERSION, [NAME, SOGOU + ' Explorer']], [
379
+ /(sogou)mo\w+\/([\d\.]+)/i // Sogou Mobile
380
+ ], [[NAME, SOGOU + ' Mobile'], VERSION], [
350
381
  /(electron)\/([\w\.]+) safari/i, // Electron-based App
351
382
  /(tesla)(?: qtcarbrowser|\/(20\d\d\.[-\w\.]+))/i, // Tesla
352
- /m?(qqbrowser|baiduboxapp|2345Explorer)[\/ ]?([\w\.]+)/i // QQBrowser/Baidu App/2345 Browser
383
+ /m?(qqbrowser|2345Explorer)[\/ ]?([\w\.]+)/i // QQBrowser/2345 Browser
353
384
  ], [NAME, VERSION], [
354
- /(metasr)[\/ ]?([\w\.]+)/i, // SouGouBrowser
355
- /(lbbrowser)/i, // LieBao Browser
385
+ /(lbbrowser|rekonq)/i, // LieBao Browser/Rekonq
356
386
  /\[(linkedin)app\]/i // LinkedIn App for iOS & Android
357
387
  ], [NAME], [
358
388
 
359
389
  // WebView
360
390
  /((?:fban\/fbios|fb_iab\/fb4a)(?!.+fbav)|;fbav\/([\w\.]+);)/i // Facebook App for iOS & Android
361
391
  ], [[NAME, FACEBOOK], VERSION], [
392
+ /(Klarna)\/([\w\.]+)/i, // Klarna Shopping Browser for iOS & Android
362
393
  /(kakao(?:talk|story))[\/ ]([\w\.]+)/i, // Kakao App
363
394
  /(naver)\(.*?(\d+\.[\w\.]+).*\)/i, // Naver InApp
364
395
  /safari (line)\/([\w\.]+)/i, // Line App for iOS
365
396
  /\b(line)\/([\w\.]+)\/iab/i, // Line App for Android
397
+ /(alipay)client\/([\w\.]+)/i, // Alipay
398
+ /(twitter)(?:and| f.+e\/([\w\.]+))/i, // Twitter
366
399
  /(chromium|instagram|snapchat)[\/ ]([-\w\.]+)/i // Chromium/Instagram/Snapchat
367
400
  ], [NAME, VERSION], [
368
401
  /\bgsa\/([\w\.]+) .*safari\//i // Google Search Appliance on iOS
@@ -402,23 +435,24 @@
402
435
  ], [[NAME, PREFIX_MOBILE + FIREFOX], VERSION], [
403
436
  /(navigator|netscape\d?)\/([-\w\.]+)/i // Netscape
404
437
  ], [[NAME, 'Netscape'], VERSION], [
438
+ /(wolvic)\/([\w\.]+)/i // Wolvic
439
+ ], [NAME, VERSION], [
405
440
  /mobile vr; rv:([\w\.]+)\).+firefox/i // Firefox Reality
406
441
  ], [VERSION, [NAME, FIREFOX+' Reality']], [
407
442
  /ekiohf.+(flow)\/([\w\.]+)/i, // Flow
408
443
  /(swiftfox)/i, // Swiftfox
409
- /(icedragon|iceweasel|camino|chimera|fennec|maemo browser|minimo|conkeror|klar)[\/ ]?([\w\.\+]+)/i,
410
- // IceDragon/Iceweasel/Camino/Chimera/Fennec/Maemo/Minimo/Conkeror/Klar
444
+ /(icedragon|iceweasel|camino|chimera|fennec|maemo browser|minimo|conkeror)[\/ ]?([\w\.\+]+)/i,
445
+ // IceDragon/Iceweasel/Camino/Chimera/Fennec/Maemo/Minimo/Conkeror
411
446
  /(seamonkey|k-meleon|icecat|iceape|firebird|phoenix|palemoon|basilisk|waterfox)\/([-\w\.]+)$/i,
412
447
  // Firefox/SeaMonkey/K-Meleon/IceCat/IceApe/Firebird/Phoenix
413
448
  /(firefox)\/([\w\.]+)/i, // Other Firefox-based
414
449
  /(mozilla)\/([\w\.]+) .+rv\:.+gecko\/\d+/i, // Mozilla
415
450
 
416
451
  // Other
417
- /(polaris|lynx|dillo|icab|doris|amaya|w3m|netsurf|sleipnir|obigo|mosaic|(?:go|ice|up)[\. ]?browser)[-\/ ]?v?([\w\.]+)/i,
418
- // Polaris/Lynx/Dillo/iCab/Doris/Amaya/w3m/NetSurf/Sleipnir/Obigo/Mosaic/Go/ICE/UP.Browser
419
- /(links) \(([\w\.]+)/i, // Links
420
- /panasonic;(viera)/i // Panasonic Viera
421
- ], [NAME, VERSION], [
452
+ /(polaris|lynx|dillo|icab|doris|amaya|w3m|netsurf|obigo|mosaic|(?:go|ice|up)[\. ]?browser)[-\/ ]?v?([\w\.]+)/i,
453
+ // Polaris/Lynx/Dillo/iCab/Doris/Amaya/w3m/NetSurf/Obigo/Mosaic/Go/ICE/UP.Browser
454
+ /(links) \(([\w\.]+)/i // Links
455
+ ], [NAME, [VERSION, /_/g, '.']], [
422
456
 
423
457
  /(cobalt)\/([\w\.]+)/i // Cobalt
424
458
  ], [NAME, [VERSION, /[^\d\.]+./, EMPTY]]
@@ -494,7 +528,7 @@
494
528
  /\b; (\w+) build\/hm\1/i, // Xiaomi Hongmi 'numeric' models
495
529
  /\b(hm[-_ ]?note?[_ ]?(?:\d\w)?) bui/i, // Xiaomi Hongmi
496
530
  /\b(redmi[\-_ ]?(?:note|k)?[\w_ ]+)(?: bui|\))/i, // Xiaomi Redmi
497
- /oid[^\)]+; (m?[12][0-389][01]\w{3,6}[c-y])( bui|\))/i, // Xiaomi Redmi 'numeric' models
531
+ /oid[^\)]+; (m?[12][0-389][01]\w{3,6}[c-y])( bui|; wv|\))/i, // Xiaomi Redmi 'numeric' models
498
532
  /\b(mi[-_ ]?(?:a\d|one|one[_ ]plus|note lte|max|cc)?[_ ]?(?:\d?\w?)[_ ]?(?:plus|se|lite)?)(?: bui|\))/i // Xiaomi Mi
499
533
  ], [[MODEL, /_/g, ' '], [VENDOR, XIAOMI], [TYPE, MOBILE]], [
500
534
  /oid[^\)]+; (2\d{4}(283|rpbf)[cgl])( bui|\))/i, // Redmi Pad
@@ -505,6 +539,8 @@
505
539
  /; (\w+) bui.+ oppo/i,
506
540
  /\b(cph[12]\d{3}|p(?:af|c[al]|d\w|e[ar])[mt]\d0|x9007|a101op)\b/i
507
541
  ], [MODEL, [VENDOR, 'OPPO'], [TYPE, MOBILE]], [
542
+ /\b(opd2\d{3}a?) bui/i
543
+ ], [MODEL, [VENDOR, 'OPPO'], [TYPE, TABLET]], [
508
544
 
509
545
  // Vivo
510
546
  /vivo (\w+)(?: bui|\))/i,
@@ -534,7 +570,7 @@
534
570
  // Lenovo
535
571
  /(ideatab[-\w ]+)/i,
536
572
  /lenovo ?(s[56]000[-\w]+|tab(?:[\w ]+)|yt[-\d\w]{6}|tb[-\d\w]{6})/i
537
- ], [MODEL, [VENDOR, 'Lenovo'], [TYPE, TABLET]], [
573
+ ], [MODEL, [VENDOR, LENOVO], [TYPE, TABLET]], [
538
574
 
539
575
  // Nokia
540
576
  /(?:maemo|nokia).*(n900|lumia \d+)/i,
@@ -688,12 +724,17 @@
688
724
  ], [VENDOR, MODEL, [TYPE, WEARABLE]], [
689
725
  /(watch)(?: ?os[,\/]|\d,\d\/)[\d\.]+/i // Apple Watch
690
726
  ], [MODEL, [VENDOR, APPLE], [TYPE, WEARABLE]], [
691
- /droid.+; (glass) \d/i // Google Glass
692
- ], [MODEL, [VENDOR, GOOGLE], [TYPE, WEARABLE]], [
693
727
  /droid.+; (wt63?0{2,3})\)/i
694
728
  ], [MODEL, [VENDOR, ZEBRA], [TYPE, WEARABLE]], [
695
- /(quest( 2| pro)?)/i // Oculus Quest
696
- ], [MODEL, [VENDOR, FACEBOOK], [TYPE, WEARABLE]], [
729
+
730
+ ///////////////////
731
+ // XR
732
+ ///////////////////
733
+
734
+ /droid.+; (glass) \d/i // Google Glass
735
+ ], [MODEL, [VENDOR, GOOGLE], [TYPE, XR]], [
736
+ /(quest( \d| pro)?)/i // Oculus Quest
737
+ ], [MODEL, [VENDOR, FACEBOOK], [TYPE, XR]], [
697
738
 
698
739
  ///////////////////
699
740
  // EMBEDDED
@@ -708,7 +749,7 @@
708
749
  // MIXED (GENERIC)
709
750
  ///////////////////
710
751
 
711
- /droid .+?; ([^;]+?)(?: bui|\) applew).+? mobile safari/i // Android Phones from Unidentified Vendors
752
+ /droid .+?; ([^;]+?)(?: bui|; wv\)|\) applew).+? mobile safari/i // Android Phones from Unidentified Vendors
712
753
  ], [MODEL, [TYPE, MOBILE]], [
713
754
  /droid .+?; ([^;]+?)(?: bui|\) applew).+?(?! mobile) safari/i // Android Tablets from Unidentified Vendors
714
755
  ], [MODEL, [TYPE, TABLET]], [
@@ -745,12 +786,12 @@
745
786
  // Windows
746
787
  /microsoft (windows) (vista|xp)/i // Windows (iTunes)
747
788
  ], [NAME, VERSION], [
748
- /(windows) nt 6\.2; (arm)/i, // Windows RT
749
- /(windows (?:phone(?: os)?|mobile))[\/ ]?([\d\.\w ]*)/i, // Windows Phone
750
- /(windows)[\/ ]?([ntce\d\. ]+\w)(?!.+xbox)/i
789
+ /(windows (?:phone(?: os)?|mobile))[\/ ]?([\d\.\w ]*)/i // Windows Phone
751
790
  ], [NAME, [VERSION, strMapper, windowsVersionMap]], [
752
- /(win(?=3|9|n)|win 9x )([nt\d\.]+)/i
753
- ], [[NAME, WINDOWS], [VERSION, strMapper, windowsVersionMap]], [
791
+ /windows nt 6\.2; (arm)/i, // Windows RT
792
+ /windows[\/ ]?([ntce\d\. ]+\w)(?!.+xbox)/i,
793
+ /(?:win(?=3|9|n)|win 9x )([nt\d\.]+)/i
794
+ ], [[VERSION, strMapper, windowsVersionMap], [NAME, WINDOWS]], [
754
795
 
755
796
  // iOS/macOS
756
797
  /ip[honead]{2,4}\b(?:.*os ([\w]+) like mac|; opera)/i, // iOS
@@ -824,7 +865,7 @@
824
865
  var defaultProps = (function () {
825
866
  var props = { init : {}, isIgnore : {}, isIgnoreRgx : {}, toString : {}};
826
867
  setProps.call(props.init, [
827
- [UA_BROWSER, [NAME, VERSION, MAJOR]],
868
+ [UA_BROWSER, [NAME, VERSION, MAJOR, TYPE]],
828
869
  [UA_CPU, [ARCHITECTURE]],
829
870
  [UA_DEVICE, [TYPE, MODEL, VENDOR]],
830
871
  [UA_ENGINE, [NAME, VERSION]],
@@ -952,7 +993,7 @@
952
993
  [PLATFORM, stripQuotes(uach[CH_HEADER_PLATFORM])],
953
994
  [PLATFORMVER, stripQuotes(uach[CH_HEADER_PLATFORM_VER])],
954
995
  [ARCHITECTURE, stripQuotes(uach[CH_HEADER_ARCH])],
955
- [FORMFACTOR, itemListToArray(uach[CH_HEADER_FORM_FACTOR])],
996
+ [FORMFACTORS, itemListToArray(uach[CH_HEADER_FORM_FACTORS])],
956
997
  [BITNESS, stripQuotes(uach[CH_HEADER_BITNESS])]
957
998
  ]);
958
999
  } else {
@@ -1039,15 +1080,16 @@
1039
1080
 
1040
1081
  switch (this.itemType) {
1041
1082
  case UA_BROWSER:
1042
- var brands = uaCH[FULLVERLIST] || uaCH[BRANDS];
1083
+ var brands = uaCH[FULLVERLIST] || uaCH[BRANDS], prevName;
1043
1084
  if (brands) {
1044
1085
  for (var i in brands) {
1045
- var brandName = brands[i].brand,
1086
+ var brandName = strip(/(Google|Microsoft) /, brands[i].brand || brands[i]),
1046
1087
  brandVersion = brands[i].version;
1047
- if (!/not.a.brand/i.test(brandName) && (i < 1 || /chromi/i.test(this.get(NAME)))) {
1048
- this.set(NAME, strip(GOOGLE+' ', brandName))
1088
+ if (!/not.a.brand/i.test(brandName) && (!prevName || (/chrom/i.test(prevName) && !/chromi/i.test(brandName)))) {
1089
+ this.set(NAME, brandName)
1049
1090
  .set(VERSION, brandVersion)
1050
1091
  .set(MAJOR, majorize(brandVersion));
1092
+ prevName = brandName;
1051
1093
  }
1052
1094
  }
1053
1095
  }
@@ -1066,15 +1108,20 @@
1066
1108
  if (uaCH[MODEL]) {
1067
1109
  this.set(MODEL, uaCH[MODEL]);
1068
1110
  }
1069
- if (uaCH[FORMFACTOR]) {
1111
+ // Xbox-Specific Detection
1112
+ if (uaCH[MODEL] == 'Xbox') {
1113
+ this.set(TYPE, CONSOLE)
1114
+ .set(VENDOR, MICROSOFT);
1115
+ }
1116
+ if (uaCH[FORMFACTORS]) {
1070
1117
  var ff;
1071
- if (typeof uaCH[FORMFACTOR] !== 'string') {
1118
+ if (typeof uaCH[FORMFACTORS] !== 'string') {
1072
1119
  var idx = 0;
1073
- while (!ff && idx < uaCH[FORMFACTOR].length) {
1074
- ff = strMapper(uaCH[FORMFACTOR][idx++], formFactorMap);
1120
+ while (!ff && idx < uaCH[FORMFACTORS].length) {
1121
+ ff = strMapper(uaCH[FORMFACTORS][idx++], formFactorsMap);
1075
1122
  }
1076
1123
  } else {
1077
- ff = strMapper(uaCH[FORMFACTOR], formFactorMap);
1124
+ ff = strMapper(uaCH[FORMFACTORS], formFactorsMap);
1078
1125
  }
1079
1126
  this.set(TYPE, ff);
1080
1127
  }
@@ -1087,6 +1134,11 @@
1087
1134
  this.set(NAME, osName)
1088
1135
  .set(VERSION, osVersion);
1089
1136
  }
1137
+ // Xbox-Specific Detection
1138
+ if (this.get(NAME) == WINDOWS && uaCH[MODEL] == 'Xbox') {
1139
+ this.set(NAME, 'Xbox')
1140
+ .set(VERSION, undefined);
1141
+ }
1090
1142
  break;
1091
1143
  case UA_RESULT:
1092
1144
  var data = this.data;
@@ -1120,7 +1172,7 @@
1120
1172
  function UAParser (ua, extensions, headers) {
1121
1173
 
1122
1174
  if (typeof ua === OBJ_TYPE) {
1123
- if (isExtensions(ua)) {
1175
+ if (isExtensions(ua, true)) {
1124
1176
  if (typeof extensions === OBJ_TYPE) {
1125
1177
  headers = extensions; // case UAParser(extensions, headers)
1126
1178
  }
@@ -1130,7 +1182,7 @@
1130
1182
  extensions = undefined;
1131
1183
  }
1132
1184
  ua = undefined;
1133
- } else if (typeof ua === STR_TYPE && !isExtensions(extensions)) {
1185
+ } else if (typeof ua === STR_TYPE && !isExtensions(extensions, true)) {
1134
1186
  headers = extensions; // case UAParser(ua, headers)
1135
1187
  extensions = undefined;
1136
1188
  }
@@ -1180,7 +1232,7 @@
1180
1232
  ['getResult', createItemFunc(UA_RESULT)],
1181
1233
  ['getUA', function () { return userAgent; }],
1182
1234
  ['setUA', function (ua) {
1183
- if (typeof ua === STR_TYPE)
1235
+ if (isString(ua))
1184
1236
  userAgent = ua.length > UA_MAX_LENGTH ? trim(ua, UA_MAX_LENGTH) : ua;
1185
1237
  return this;
1186
1238
  }]
@@ -1191,7 +1243,7 @@
1191
1243
  }
1192
1244
 
1193
1245
  UAParser.VERSION = LIBVERSION;
1194
- UAParser.BROWSER = enumerize([NAME, VERSION, MAJOR]);
1246
+ UAParser.BROWSER = enumerize([NAME, VERSION, MAJOR, TYPE]);
1195
1247
  UAParser.CPU = enumerize([ARCHITECTURE]);
1196
1248
  UAParser.DEVICE = enumerize([MODEL, VENDOR, TYPE, CONSOLE, MOBILE, SMARTTV, TABLET, WEARABLE, EMBEDDED]);
1197
1249
  UAParser.ENGINE = UAParser.OS = enumerize([NAME, VERSION]);
@@ -1201,7 +1253,7 @@
1201
1253
  //////////
1202
1254
 
1203
1255
  // check js environment
1204
- if (typeof(exports) !== UNDEF_TYPE) {
1256
+ if (typeof exports !== UNDEF_TYPE) {
1205
1257
  // nodejs env
1206
1258
  if (typeof module !== UNDEF_TYPE && module.exports) {
1207
1259
  exports = module.exports = UAParser;
@@ -1209,11 +1261,11 @@
1209
1261
  exports.UAParser = UAParser;
1210
1262
  } else {
1211
1263
  // requirejs env (optional)
1212
- if (typeof(define) === FUNC_TYPE && define.amd) {
1264
+ if (typeof define === FUNC_TYPE && define.amd) {
1213
1265
  define(function () {
1214
1266
  return UAParser;
1215
1267
  });
1216
- } else if (typeof window !== UNDEF_TYPE) {
1268
+ } else if (isWindow) {
1217
1269
  // browser env
1218
1270
  window.UAParser = UAParser;
1219
1271
  }
@@ -1224,7 +1276,7 @@
1224
1276
  // In AMD env the global scope should be kept clean, but jQuery is an exception.
1225
1277
  // jQuery always exports to global scope, unless jQuery.noConflict(true) is used,
1226
1278
  // and we should catch that.
1227
- var $ = typeof window !== UNDEF_TYPE && (window.jQuery || window.Zepto);
1279
+ var $ = isWindow && (window.jQuery || window.Zepto);
1228
1280
  if ($ && !$.ua) {
1229
1281
  var parser = new UAParser();
1230
1282
  $.ua = parser.getResult();