ua-parser-js 2.0.3 → 2.0.6

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,5 +1,5 @@
1
1
  /////////////////////////////////////////////////////////////////////////////////
2
- /* UAParser.js v2.0.3
2
+ /* UAParser.js v2.0.6
3
3
  Copyright © 2012-2025 Faisal Salman <f@faisalman.com>
4
4
  AGPLv3 License *//*
5
5
  Detect Browser, Engine, OS, CPU, and Device type/model from User-Agent data.
@@ -19,26 +19,26 @@
19
19
  // Constants
20
20
  /////////////
21
21
 
22
- var LIBVERSION = '2.0.3',
22
+ var LIBVERSION = '2.0.6',
23
23
  UA_MAX_LENGTH = 500,
24
24
  USER_AGENT = 'user-agent',
25
25
  EMPTY = '',
26
26
  UNKNOWN = '?',
27
-
28
- // typeof
29
- FUNC_TYPE = 'function',
30
- UNDEF_TYPE = 'undefined',
31
- OBJ_TYPE = 'object',
32
- STR_TYPE = 'string',
27
+ TYPEOF = {
28
+ FUNCTION : 'function',
29
+ OBJECT : 'object',
30
+ STRING : 'string',
31
+ UNDEFINED : 'undefined'
32
+ },
33
33
 
34
34
  // properties
35
- UA_BROWSER = 'browser',
36
- UA_CPU = 'cpu',
37
- UA_DEVICE = 'device',
38
- UA_ENGINE = 'engine',
39
- UA_OS = 'os',
40
- UA_RESULT = 'result',
41
-
35
+ BROWSER = 'browser',
36
+ CPU = 'cpu',
37
+ DEVICE = 'device',
38
+ ENGINE = 'engine',
39
+ OS = 'os',
40
+ RESULT = 'result',
41
+
42
42
  NAME = 'name',
43
43
  TYPE = 'type',
44
44
  VENDOR = 'vendor',
@@ -66,16 +66,16 @@
66
66
  PLATFORM = 'platform',
67
67
  PLATFORMVER = 'platformVersion',
68
68
  BITNESS = 'bitness',
69
- CH_HEADER = 'sec-ch-ua',
70
- CH_HEADER_FULL_VER_LIST = CH_HEADER + '-full-version-list',
71
- CH_HEADER_ARCH = CH_HEADER + '-arch',
72
- CH_HEADER_BITNESS = CH_HEADER + '-' + BITNESS,
73
- CH_HEADER_FORM_FACTORS = CH_HEADER + '-form-factors',
74
- CH_HEADER_MOBILE = CH_HEADER + '-' + MOBILE,
75
- CH_HEADER_MODEL = CH_HEADER + '-' + MODEL,
76
- CH_HEADER_PLATFORM = CH_HEADER + '-' + PLATFORM,
77
- CH_HEADER_PLATFORM_VER = CH_HEADER_PLATFORM + '-version',
78
- CH_ALL_VALUES = [BRANDS, FULLVERLIST, MOBILE, MODEL, PLATFORM, PLATFORMVER, ARCHITECTURE, FORMFACTORS, BITNESS],
69
+ CH = 'sec-ch-ua',
70
+ CH_FULL_VER_LIST= CH + '-full-version-list',
71
+ CH_ARCH = CH + '-arch',
72
+ CH_BITNESS = CH + '-' + BITNESS,
73
+ CH_FORM_FACTORS = CH + '-form-factors',
74
+ CH_MOBILE = CH + '-' + MOBILE,
75
+ CH_MODEL = CH + '-' + MODEL,
76
+ CH_PLATFORM = CH + '-' + PLATFORM,
77
+ CH_PLATFORM_VER = CH_PLATFORM + '-version',
78
+ CH_ALL_VALUES = [BRANDS, FULLVERLIST, MOBILE, MODEL, PLATFORM, PLATFORMVER, ARCHITECTURE, FORMFACTORS, BITNESS],
79
79
 
80
80
  // device vendors
81
81
  AMAZON = 'Amazon',
@@ -114,7 +114,7 @@
114
114
  // os
115
115
  WINDOWS = 'Windows';
116
116
 
117
- var isWindow = typeof window !== UNDEF_TYPE,
117
+ var isWindow = typeof window !== TYPEOF.UNDEFINED,
118
118
  NAVIGATOR = (isWindow && window.navigator) ?
119
119
  window.navigator :
120
120
  undefined,
@@ -150,13 +150,13 @@
150
150
  return enums;
151
151
  },
152
152
  has = function (str1, str2) {
153
- if (typeof str1 === OBJ_TYPE && str1.length > 0) {
153
+ if (typeof str1 === TYPEOF.OBJECT && str1.length > 0) {
154
154
  for (var i in str1) {
155
- if (lowerize(str1[i]) == lowerize(str2)) return true;
155
+ if (lowerize(str2) == lowerize(str1[i])) return true;
156
156
  }
157
157
  return false;
158
158
  }
159
- return isString(str1) ? lowerize(str2).indexOf(lowerize(str1)) !== -1 : false;
159
+ return isString(str1) ? lowerize(str2) == lowerize(str1) : false;
160
160
  },
161
161
  isExtensions = function (obj, deep) {
162
162
  for (var prop in obj) {
@@ -164,7 +164,7 @@
164
164
  }
165
165
  },
166
166
  isString = function (val) {
167
- return typeof val === STR_TYPE;
167
+ return typeof val === TYPEOF.STRING;
168
168
  },
169
169
  itemListToArray = function (header) {
170
170
  if (!header) return undefined;
@@ -188,8 +188,10 @@
188
188
  },
189
189
  setProps = function (arr) {
190
190
  for (var i in arr) {
191
+ if (!arr.hasOwnProperty(i)) continue;
192
+
191
193
  var propName = arr[i];
192
- if (typeof propName == OBJ_TYPE && propName.length == 2) {
194
+ if (typeof propName == TYPEOF.OBJECT && propName.length == 2) {
193
195
  this[propName[0]] = propName[1];
194
196
  } else {
195
197
  this[propName] = undefined;
@@ -204,10 +206,8 @@
204
206
  return strip(/\\?\"/g, str);
205
207
  },
206
208
  trim = function (str, len) {
207
- if (isString(str)) {
208
- str = strip(/^\s\s*/, str);
209
- return typeof len === UNDEF_TYPE ? str : str.substring(0, UA_MAX_LENGTH);
210
- }
209
+ str = strip(/^\s\s*/, String(str));
210
+ return typeof len === TYPEOF.UNDEFINED ? str : str.substring(0, len);
211
211
  };
212
212
 
213
213
  ///////////////
@@ -238,26 +238,34 @@
238
238
  match = matches[++k];
239
239
  q = props[p];
240
240
  // check if given property is actually array
241
- if (typeof q === OBJ_TYPE && q.length > 0) {
241
+ if (typeof q === TYPEOF.OBJECT && q.length > 0) {
242
242
  if (q.length === 2) {
243
- if (typeof q[1] == FUNC_TYPE) {
243
+ if (typeof q[1] == TYPEOF.FUNCTION) {
244
244
  // assign modified match
245
245
  this[q[0]] = q[1].call(this, match);
246
246
  } else {
247
247
  // assign given value, ignore regex match
248
248
  this[q[0]] = q[1];
249
249
  }
250
- } else if (q.length === 3) {
251
- // check whether function or regex
252
- if (typeof q[1] === FUNC_TYPE && !(q[1].exec && q[1].test)) {
253
- // call function (usually string mapper)
254
- this[q[0]] = match ? q[1].call(this, match, q[2]) : undefined;
250
+ } else if (q.length >= 3) {
251
+ // Check whether q[1] FUNCTION or REGEX
252
+ if (typeof q[1] === TYPEOF.FUNCTION && !(q[1].exec && q[1].test)) {
253
+ if (q.length > 3) {
254
+ this[q[0]] = match ? q[1].apply(this, q.slice(2)) : undefined;
255
+ } else {
256
+ // call function (usually string mapper)
257
+ this[q[0]] = match ? q[1].call(this, match, q[2]) : undefined;
258
+ }
255
259
  } else {
256
- // sanitize match using given regex
257
- this[q[0]] = match ? match.replace(q[1], q[2]) : undefined;
260
+ if (q.length == 3) {
261
+ // sanitize match using given regex
262
+ this[q[0]] = match ? match.replace(q[1], q[2]) : undefined;
263
+ } else if (q.length == 4) {
264
+ this[q[0]] = match ? q[3].call(this, match.replace(q[1], q[2])) : undefined;
265
+ } else if (q.length > 4) {
266
+ this[q[0]] = match ? q[3].apply(this, [match.replace(q[1], q[2])].concat(q.slice(4))) : undefined;
267
+ }
258
268
  }
259
- } else if (q.length === 4) {
260
- this[q[0]] = match ? q[3].call(this, match.replace(q[1], q[2])) : undefined;
261
269
  }
262
270
  } else {
263
271
  this[q] = match ? match : undefined;
@@ -273,7 +281,7 @@
273
281
 
274
282
  for (var i in map) {
275
283
  // check if current value is array
276
- if (typeof map[i] === OBJ_TYPE && map[i].length > 0) {
284
+ if (typeof map[i] === TYPEOF.OBJECT && map[i].length > 0) {
277
285
  for (var j = 0; j < map[i].length; j++) {
278
286
  if (has(map[i][j], str)) {
279
287
  return (i === UNKNOWN) ? undefined : i;
@@ -291,17 +299,17 @@
291
299
  //////////////
292
300
 
293
301
  var windowsVersionMap = {
294
- 'ME' : '4.90',
295
- 'NT 3.11' : 'NT3.51',
296
- 'NT 4.0' : 'NT4.0',
297
- '2000' : 'NT 5.0',
298
- 'XP' : ['NT 5.1', 'NT 5.2'],
299
- 'Vista' : 'NT 6.0',
300
- '7' : 'NT 6.1',
301
- '8' : 'NT 6.2',
302
- '8.1' : 'NT 6.3',
303
- '10' : ['NT 6.4', 'NT 10.0'],
304
- 'RT' : 'ARM'
302
+ 'ME' : '4.90',
303
+ 'NT 3.51': '3.51',
304
+ 'NT 4.0': '4.0',
305
+ '2000' : ['5.0', '5.01'],
306
+ 'XP' : ['5.1', '5.2'],
307
+ 'Vista' : '6.0',
308
+ '7' : '6.1',
309
+ '8' : '6.2',
310
+ '8.1' : '6.3',
311
+ '10' : ['6.4', '10.0'],
312
+ 'NT' : ''
305
313
  },
306
314
 
307
315
  formFactorsMap = {
@@ -313,6 +321,18 @@
313
321
  'xr' : ['VR', 'XR'],
314
322
  '?' : ['Desktop', 'Unknown'],
315
323
  '*' : undefined
324
+ },
325
+
326
+ browserHintsMap = {
327
+ 'Chrome' : 'Google Chrome',
328
+ 'Edge' : 'Microsoft Edge',
329
+ 'Edge WebView2' : 'Microsoft Edge WebView2',
330
+ 'Chrome WebView': 'Android WebView',
331
+ 'Chrome Headless':'HeadlessChrome',
332
+ 'Huawei Browser': 'HuaweiBrowser',
333
+ 'MIUI Browser' : 'Miui Browser',
334
+ 'Opera Mobi' : 'OperaMobile',
335
+ 'Yandex' : 'YaBrowser'
316
336
  };
317
337
 
318
338
  //////////////
@@ -326,7 +346,9 @@
326
346
  // Most common regardless engine
327
347
  /\b(?:crmo|crios)\/([\w\.]+)/i // Chrome for Android/iOS
328
348
  ], [VERSION, [NAME, PREFIX_MOBILE + 'Chrome']], [
329
- /edg(?:e|ios|a)?\/([\w\.]+)/i // Microsoft Edge
349
+ /webview.+edge\/([\w\.]+)/i // Microsoft Edge
350
+ ], [VERSION, [NAME, EDGE+' WebView']], [
351
+ /edg(?:e|ios|a)?\/([\w\.]+)/i
330
352
  ], [VERSION, [NAME, 'Edge']], [
331
353
 
332
354
  // Presto based
@@ -353,10 +375,11 @@
353
375
  /(avant|iemobile|slim(?:browser|boat|jet))[\/ ]?([\d\.]*)/i, // Avant/IEMobile/SlimBrowser/SlimBoat/Slimjet
354
376
  /(?:ms|\()(ie) ([\w\.]+)/i, // Internet Explorer
355
377
 
356
- // Blink/Webkit/KHTML based // Flock/RockMelt/Midori/Epiphany/Silk/Skyfire/Bolt/Iron/Iridium/PhantomJS/Bowser/QupZilla/Falkon/LG Browser/Otter/qutebrowser/Dooble
357
- /(flock|rockmelt|midori|epiphany|silk|skyfire|ovibrowser|bolt|iron|vivaldi|iridium|phantomjs|bowser|qupzilla|falkon|rekonq|puffin|brave|whale(?!.+naver)|qqbrowserlite|duckduckgo|klar|helio|(?=comodo_)?dragon|otter|dooble|(?:lg |qute)browser)\/([-\w\.]+)/i,
378
+ // Blink/Webkit/KHTML based // Flock/RockMelt/Midori/Epiphany/Silk/Skyfire/Bolt/Iron/Iridium/PhantomJS/Bowser/QupZilla/Falkon/LG Browser/Otter/qutebrowser/Dooble/Palemoon
379
+ /(flock|rockmelt|midori|epiphany|silk|skyfire|ovibrowser|bolt|iron|vivaldi|iridium|phantomjs|bowser|qupzilla|falkon|rekonq|puffin|brave|whale(?!.+naver)|qqbrowserlite|duckduckgo|klar|helio|(?=comodo_)?dragon|otter|dooble|(?:lg |qute)browser|palemoon)\/([-\w\.]+)/i,
358
380
  // Rekonq/Puffin/Brave/Whale/QQBrowserLite/QQ//Vivaldi/DuckDuckGo/Klar/Helio/Dragon
359
- /(heytap|ovi|115|surf)browser\/([\d\.]+)/i, // HeyTap/Ovi/115/Surf
381
+ /(heytap|ovi|115|surf|qwant)browser\/([\d\.]+)/i, // HeyTap/Ovi/115/Surf
382
+ /(qwant)(?:ios|mobile)\/([\d\.]+)/i, // Qwant
360
383
  /(ecosia|weibo)(?:__| \w+@)([\d\.]+)/i // Ecosia/Weibo
361
384
  ], [NAME, VERSION], [
362
385
  /quark(?:pc)?\/([-\w\.]+)/i // Quark
@@ -418,7 +441,6 @@
418
441
  // WebView
419
442
  /((?:fban\/fbios|fb_iab\/fb4a)(?!.+fbav)|;fbav\/([\w\.]+);)/i // Facebook App for iOS & Android
420
443
  ], [[NAME, FACEBOOK], VERSION, [TYPE, INAPP]], [
421
- /(Klarna)\/([\w\.]+)/i, // Klarna Shopping Browser for iOS & Android
422
444
  /(kakao(?:talk|story))[\/ ]([\w\.]+)/i, // Kakao App
423
445
  /(naver)\(.*?(\d+\.[\w\.]+).*\)/i, // Naver InApp
424
446
  /(daum)apps[\/ ]([\w\.]+)/i, // Daum App
@@ -426,7 +448,8 @@
426
448
  /\b(line)\/([\w\.]+)\/iab/i, // Line App for Android
427
449
  /(alipay)client\/([\w\.]+)/i, // Alipay
428
450
  /(twitter)(?:and| f.+e\/([\w\.]+))/i, // Twitter
429
- /(instagram|snapchat)[\/ ]([-\w\.]+)/i // Instagram/Snapchat
451
+ /(bing)(?:web|sapphire)\/([\w\.]+)/i, // Bing
452
+ /(instagram|snapchat|klarna)[\/ ]([-\w\.]+)/i // Instagram/Snapchat/Klarna
430
453
  ], [NAME, VERSION, [TYPE, INAPP]], [
431
454
  /\bgsa\/([\w\.]+) .*safari\//i // Google Search Appliance on iOS
432
455
  ], [VERSION, [NAME, 'GSA'], [TYPE, INAPP]], [
@@ -434,6 +457,8 @@
434
457
  ], [VERSION, [NAME, 'TikTok'], [TYPE, INAPP]], [
435
458
  /\[(linkedin)app\]/i // LinkedIn App for iOS & Android
436
459
  ], [NAME, [TYPE, INAPP]], [
460
+ /(zalo(?:app)?)[\/\sa-z]*([\w\.-]+)/i // Zalo
461
+ ], [[NAME, /(.+)/, 'Zalo'], VERSION, [TYPE, INAPP]], [
437
462
 
438
463
  /(chromium)[\/ ]([-\w\.]+)/i // Chromium
439
464
  ], [NAME, VERSION], [
@@ -441,6 +466,9 @@
441
466
  /headlesschrome(?:\/([\w\.]+)| )/i // Chrome Headless
442
467
  ], [VERSION, [NAME, CHROME+' Headless']], [
443
468
 
469
+ /wv\).+chrome\/([\w\.]+).+edgw\//i // Edge WebView2
470
+ ], [VERSION, [NAME, EDGE+' WebView2']], [
471
+
444
472
  / wv\).+(chrome)\/([\w\.]+)/i // Chrome WebView
445
473
  ], [[NAME, CHROME+' WebView'], VERSION], [
446
474
 
@@ -478,10 +506,10 @@
478
506
  /(swiftfox)/i, // Swiftfox
479
507
  /(icedragon|iceweasel|camino|chimera|fennec|maemo browser|minimo|conkeror)[\/ ]?([\w\.\+]+)/i,
480
508
  // IceDragon/Iceweasel/Camino/Chimera/Fennec/Maemo/Minimo/Conkeror
481
- /(seamonkey|k-meleon|icecat|iceape|firebird|phoenix|palemoon|basilisk|waterfox)\/([-\w\.]+)$/i,
509
+ /(seamonkey|k-meleon|icecat|iceape|firebird|phoenix|basilisk|waterfox)\/([-\w\.]+)$/i,
482
510
  // Firefox/SeaMonkey/K-Meleon/IceCat/IceApe/Firebird/Phoenix
483
511
  /(firefox)\/([\w\.]+)/i, // Other Firefox-based
484
- /(mozilla)\/([\w\.]+) .+rv\:.+gecko\/\d+/i, // Mozilla
512
+ /(mozilla)\/([\w\.]+(?= .+rv\:.+gecko\/\d+)|[0-4][\w\.]+(?!.+compatible))/i, // Mozilla
485
513
 
486
514
  // Other
487
515
  /(amaya|dillo|doris|icab|ladybird|lynx|mosaic|netsurf|obigo|polaris|w3m|(?:go|ice|up)[\. ]?browser)[-\/ ]?v?([\w\.]+)/i,
@@ -512,15 +540,17 @@
512
540
  /( (ce|mobile); ppc;|\/[\w\.]+arm\b)/i
513
541
  ], [[ARCHITECTURE, 'arm']], [
514
542
 
515
- /((ppc|powerpc)(64)?)( mac|;|\))/i // PowerPC
516
- ], [[ARCHITECTURE, /ower/, EMPTY, lowerize]], [
517
-
518
543
  / sun4\w[;\)]/i // SPARC
519
544
  ], [[ARCHITECTURE, 'sparc']], [
520
-
521
- /\b(avr32|ia64(?=;)|68k(?=\))|\barm(?=v([1-7]|[5-7]1)l?|;|eabi)|(irix|mips|sparc)(64)?\b|pa-risc)/i
522
545
  // IA64, 68K, ARM/64, AVR/32, IRIX/64, MIPS/64, SPARC/64, PA-RISC
523
- ], [[ARCHITECTURE, lowerize]]
546
+ /\b(avr32|ia64(?=;)|68k(?=\))|\barm(?=v([1-7]|[5-7]1)l?|;|eabi)|(irix|mips|sparc)(64)?\b|pa-risc)/i,
547
+ /((ppc|powerpc)(64)?)( mac|;|\))/i, // PowerPC
548
+ /(?:osf1|[freopnt]{3,4}bsd) (alpha)/i // Alpha
549
+ ], [[ARCHITECTURE, /ower/, EMPTY, lowerize]], [
550
+ /mc680.0/i
551
+ ], [[ARCHITECTURE, '68k']], [
552
+ /winnt.+\[axp/i
553
+ ], [[ARCHITECTURE, 'alpha']]
524
554
  ],
525
555
 
526
556
  device : [[
@@ -533,16 +563,15 @@
533
563
  /\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
534
564
  ], [MODEL, [VENDOR, SAMSUNG], [TYPE, TABLET]], [
535
565
  /\b((?:s[cgp]h|gt|sm)-(?![lr])\w+|sc[g-]?[\d]+a?|galaxy nexus)/i,
536
- /samsung[- ]((?!sm-[lr])[-\w]+)/i,
566
+ /samsung[- ]((?!sm-[lr]|browser)[-\w]+)/i,
537
567
  /sec-(sgh\w+)/i
538
568
  ], [MODEL, [VENDOR, SAMSUNG], [TYPE, MOBILE]], [
539
569
 
540
570
  // Apple
541
- /(?:\/|\()(ip(?:hone|od)[\w, ]*)(?:\/|;)/i // iPod/iPhone
571
+ /(?:\/|\()(ip(?:hone|od)[\w, ]*)[\/\);]/i // iPod/iPhone
542
572
  ], [MODEL, [VENDOR, APPLE], [TYPE, MOBILE]], [
543
- /\((ipad);[-\w\),; ]+apple/i, // iPad
544
- /applecoremedia\/[\w\.]+ \((ipad)/i,
545
- /\b(ipad)\d\d?,\d\d?[;\]].+ios/i
573
+ /\b(?:ios|apple\w+)\/.+[\(\/](ipad)/i, // iPad
574
+ /\b(ipad)[\d,]*[;\] ].+(mac |i(pad)?)os/i
546
575
  ], [MODEL, [VENDOR, APPLE], [TYPE, TABLET]], [
547
576
  /(macintosh);/i
548
577
  ], [MODEL, [VENDOR, APPLE]], [
@@ -560,13 +589,13 @@
560
589
  // Huawei
561
590
  /\b((?:ag[rs][2356]?k?|bah[234]?|bg[2o]|bt[kv]|cmr|cpn|db[ry]2?|jdn2|got|kob2?k?|mon|pce|scm|sht?|[tw]gr|vrd)-[ad]?[lw][0125][09]b?|605hw|bg2-u03|(?:gem|fdr|m2|ple|t1)-[7a]0[1-4][lu]|t1-a2[13][lw]|mediapad[\w\. ]*(?= bui|\)))\b(?!.+d\/s)/i
562
591
  ], [MODEL, [VENDOR, HUAWEI], [TYPE, TABLET]], [
563
- /(?:huawei)([-\w ]+)[;\)]/i,
564
- /\b(nexus 6p|\w{2,4}e?-[atu]?[ln][\dx][012359c][adn]?)\b(?!.+d\/s)/i
592
+ /(?:huawei) ?([-\w ]+)[;\)]/i,
593
+ /\b(nexus 6p|\w{2,4}e?-[atu]?[ln][\dx][\dc][adnt]?)\b(?!.+d\/s)/i
565
594
  ], [MODEL, [VENDOR, HUAWEI], [TYPE, MOBILE]], [
566
595
 
567
596
  // Xiaomi
568
597
  /oid[^\)]+; (2[\dbc]{4}(182|283|rp\w{2})[cgl]|m2105k81a?c)(?: bui|\))/i,
569
- /\b((?:red)?mi[-_ ]?pad[\w- ]*)(?: bui|\))/i // Mi Pad tablets
598
+ /\b(?:xiao)?((?:red)?mi[-_ ]?pad[\w- ]*)(?: bui|\))/i // Mi Pad tablets
570
599
  ],[[MODEL, /_/g, ' '], [VENDOR, XIAOMI], [TYPE, TABLET]], [
571
600
 
572
601
  /\b(poco[\w ]+|m2\d{3}j\d\d[a-z]{2})(?: bui|\))/i, // Xiaomi POCO
@@ -574,20 +603,26 @@
574
603
  /\b(hm[-_ ]?note?[_ ]?(?:\d\w)?) bui/i, // Xiaomi Hongmi
575
604
  /\b(redmi[\-_ ]?(?:note|k)?[\w_ ]+)(?: bui|\))/i, // Xiaomi Redmi
576
605
  /oid[^\)]+; (m?[12][0-389][01]\w{3,6}[c-y])( bui|; wv|\))/i, // Xiaomi Redmi 'numeric' models
577
- /\b(mi[-_ ]?(?:a\d|one|one[_ ]plus|note lte|max|cc)?[_ ]?(?:\d?\w?)[_ ]?(?:plus|se|lite|pro)?)(?: bui|\))/i, // Xiaomi Mi
606
+ /\b(mi[-_ ]?(?:a\d|one|one[_ ]plus|note|max|cc)?[_ ]?(?:\d{0,2}\w?)[_ ]?(?:plus|se|lite|pro)?( 5g|lte)?)(?: bui|\))/i, // Xiaomi Mi
578
607
  / ([\w ]+) miui\/v?\d/i
579
608
  ], [[MODEL, /_/g, ' '], [VENDOR, XIAOMI], [TYPE, MOBILE]], [
580
609
 
610
+ // OnePlus
611
+ /droid.+; (cph2[3-6]\d[13579]|((gm|hd)19|(ac|be|in|kb)20|(d[en]|eb|le|mt)21|ne22)[0-2]\d|p[g-k]\w[1m]10)\b/i,
612
+ /(?:one)?(?:plus)? (a\d0\d\d)(?: b|\))/i
613
+ ], [MODEL, [VENDOR, ONEPLUS], [TYPE, MOBILE]], [
614
+
581
615
  // OPPO
582
616
  /; (\w+) bui.+ oppo/i,
583
617
  /\b(cph[12]\d{3}|p(?:af|c[al]|d\w|e[ar])[mt]\d0|x9007|a101op)\b/i
584
618
  ], [MODEL, [VENDOR, OPPO], [TYPE, MOBILE]], [
585
619
  /\b(opd2(\d{3}a?))(?: bui|\))/i
586
- ], [MODEL, [VENDOR, strMapper, { 'OnePlus' : ['304', '403', '203'], '*' : OPPO }], [TYPE, TABLET]], [
620
+ ], [MODEL, [VENDOR, strMapper, { 'OnePlus' : ['203', '304', '403', '404', '413', '415'], '*' : OPPO }], [TYPE, TABLET]], [
621
+
622
+ // BLU
623
+ /(vivo (5r?|6|8l?|go|one|s|x[il]?[2-4]?)[\w\+ ]*)(?: bui|\))/i // Vivo series
624
+ ], [MODEL, [VENDOR, 'BLU'], [TYPE, MOBILE]], [
587
625
 
588
- // BLU Vivo Series
589
- /(vivo (5r?|6|8l?|go|one|s|x[il]?[2-4]?)[\w\+ ]*)(?: bui|\))/i
590
- ], [MODEL, [VENDOR, 'BLU'], [TYPE, MOBILE]], [
591
626
  // Vivo
592
627
  /; vivo (\w+)(?: bui|\))/i,
593
628
  /\b(v[12]\d{3}\w?[at])(?: bui|;)/i
@@ -597,10 +632,17 @@
597
632
  /\b(rmx[1-3]\d{3})(?: bui|;|\))/i
598
633
  ], [MODEL, [VENDOR, 'Realme'], [TYPE, MOBILE]], [
599
634
 
635
+ // Lenovo
636
+ /(ideatab[-\w ]+|602lv|d-42a|a101lv|a2109a|a3500-hv|s[56]000|pb-6505[my]|tb-?x?\d{3,4}(?:f[cu]|xu|[av])|yt\d?-[jx]?\d+[lfmx])( bui|;|\)|\/)/i,
637
+ /lenovo ?(b[68]0[08]0-?[hf]?|tab(?:[\w- ]+?)|tb[\w-]{6,7})( bui|;|\)|\/)/i
638
+ ], [MODEL, [VENDOR, LENOVO], [TYPE, TABLET]], [
639
+ /lenovo[-_ ]?([-\w ]+?)(?: bui|\)|\/)/i
640
+ ], [MODEL, [VENDOR, LENOVO], [TYPE, MOBILE]], [
641
+
600
642
  // Motorola
601
643
  /\b(milestone|droid(?:[2-4x]| (?:bionic|x2|pro|razr))?:?( 4g)?)\b[\w ]+build\//i,
602
- /\bmot(?:orola)?[- ](\w*)/i,
603
- /((?:moto(?! 360)[\w\(\) ]+|xt\d{3,4}|nexus 6)(?= bui|\)))/i
644
+ /\bmot(?:orola)?[- ]([\w\s]+)(\)| bui)/i,
645
+ /((?:moto(?! 360)[-\w\(\) ]+|xt\d{3,4}[cgkosw\+]?[-\d]*|nexus 6)(?= bui|\)))/i
604
646
  ], [MODEL, [VENDOR, MOTOROLA], [TYPE, MOBILE]], [
605
647
  /\b(mz60\d|xoom[2 ]{0,2}) build\//i
606
648
  ], [MODEL, [VENDOR, MOTOROLA], [TYPE, TABLET]], [
@@ -609,40 +651,33 @@
609
651
  /((?=lg)?[vl]k\-?\d{3}) bui| 3\.[-\w; ]{10}lg?-([06cv9]{3,4})/i
610
652
  ], [MODEL, [VENDOR, LG], [TYPE, TABLET]], [
611
653
  /(lm(?:-?f100[nv]?|-[\w\.]+)(?= bui|\))|nexus [45])/i,
612
- /\blg[-e;\/ ]+(?!.*(?:browser|netcast|android tv|watch))(\w+)/i,
654
+ /\blg[-e;\/ ]+(?!.*(?:browser|netcast|android tv|watch|webos))(\w+)/i,
613
655
  /\blg-?([\d\w]+) bui/i
614
656
  ], [MODEL, [VENDOR, LG], [TYPE, MOBILE]], [
615
657
 
616
- // Lenovo
617
- /(ideatab[-\w ]+|602lv|d-42a|a101lv|a2109a|a3500-hv|s[56]000|pb-6505[my]|tb-?x?\d{3,4}(?:f[cu]|xu|[av])|yt\d?-[jx]?\d+[lfmx])( bui|;|\)|\/)/i,
618
- /lenovo ?(b[68]0[08]0-?[hf]?|tab(?:[\w- ]+?)|tb[\w-]{6,7})( bui|;|\)|\/)/i
619
- ], [MODEL, [VENDOR, LENOVO], [TYPE, TABLET]], [
620
-
621
658
  // Nokia
622
659
  /(nokia) (t[12][01])/i
623
660
  ], [VENDOR, MODEL, [TYPE, TABLET]], [
624
661
  /(?:maemo|nokia).*(n900|lumia \d+|rm-\d+)/i,
625
- /nokia[-_ ]?(([-\w\. ]*))/i
662
+ /nokia[-_ ]?(([-\w\. ]*?))( bui|\)|;|\/)/i
626
663
  ], [[MODEL, /_/g, ' '], [TYPE, MOBILE], [VENDOR, 'Nokia']], [
627
664
 
628
665
  // Google
629
666
  /(pixel (c|tablet))\b/i // Google Pixel C/Tablet
630
667
  ], [MODEL, [VENDOR, GOOGLE], [TYPE, TABLET]], [
631
- /droid.+; (pixel[\daxl ]{0,6})(?: bui|\))/i // Google Pixel
668
+ // Google Pixel
669
+ /droid.+;(?: google)? (g(01[13]a|020[aem]|025[jn]|1b60|1f8f|2ybb|4s1m|576d|5nz6|8hhn|8vou|a02099|c15s|d1yq|e2ae|ec77|gh2x|kv4x|p4bc|pj41|r83y|tt9q|ur25|wvk6)|pixel[\d ]*a?( pro)?( xl)?( fold)?( \(5g\))?)( bui|\))/i
632
670
  ], [MODEL, [VENDOR, GOOGLE], [TYPE, MOBILE]], [
671
+ /(google) (pixelbook( go)?)/i
672
+ ], [VENDOR, MODEL], [
633
673
 
634
674
  // Sony
635
- /droid.+; (a?\d[0-2]{2}so|[c-g]\d{4}|so[-gl]\w+|xq-a\w[4-7][12])(?= bui|\).+chrome\/(?![1-6]{0,1}\d\.))/i
675
+ /droid.+; (a?\d[0-2]{2}so|[c-g]\d{4}|so[-gl]\w+|xq-\w\w\d\d)(?= bui|\).+chrome\/(?![1-6]{0,1}\d\.))/i
636
676
  ], [MODEL, [VENDOR, SONY], [TYPE, MOBILE]], [
637
677
  /sony tablet [ps]/i,
638
678
  /\b(?:sony)?sgp\w+(?: bui|\))/i
639
679
  ], [[MODEL, 'Xperia Tablet'], [VENDOR, SONY], [TYPE, TABLET]], [
640
680
 
641
- // OnePlus
642
- / (kb2005|in20[12]5|be20[12][59])\b/i,
643
- /(?:one)?(?:plus)? (a\d0\d\d)(?: b|\))/i
644
- ], [MODEL, [VENDOR, ONEPLUS], [TYPE, MOBILE]], [
645
-
646
681
  // Amazon
647
682
  /(alexa)webm/i,
648
683
  /(kf[a-z]{2}wi|aeo(?!bc)\w\w)( bui|\))/i, // Kindle Fire without Silk / Echo Show
@@ -655,7 +690,7 @@
655
690
  /(playbook);[-\w\),; ]+(rim)/i // BlackBerry PlayBook
656
691
  ], [MODEL, VENDOR, [TYPE, TABLET]], [
657
692
  /\b((?:bb[a-f]|st[hv])100-\d)/i,
658
- /\(bb10; (\w+)/i // BlackBerry 10
693
+ /(?:blackberry|\(bb10;) (\w+)/i
659
694
  ], [MODEL, [VENDOR, BLACKBERRY], [TYPE, MOBILE]], [
660
695
 
661
696
  // Asus
@@ -713,7 +748,7 @@
713
748
  ], [MODEL, [VENDOR, 'Smartfren'], [TYPE, MOBILE]], [
714
749
 
715
750
  // Nothing
716
- /droid.+; (a(?:015|06[35]|142p?))/i
751
+ /droid.+; (a(in)?(0(15|59|6[35])|142)p?)/i
717
752
  ], [MODEL, [VENDOR, 'Nothing'], [TYPE, MOBILE]], [
718
753
 
719
754
  // Archos
@@ -724,18 +759,24 @@
724
759
  /; (ac[3-6]\d\w{2,8})( b|\))/i
725
760
  ], [MODEL, [VENDOR, 'Archos'], [TYPE, MOBILE]], [
726
761
 
762
+ // HMD
763
+ /; (n159v)/i
764
+ ], [MODEL, [VENDOR, 'HMD'], [TYPE, MOBILE]], [
765
+
727
766
  // MIXED
728
767
  /(imo) (tab \w+)/i, // IMO
729
- /(infinix) (x1101b?)/i // Infinix XPad
768
+ /(infinix|tecno) (x1101b?|p904|dp(7c|8d|10a)( pro)?|p70[1-3]a?|p904|t1101)/i // Infinix XPad / Tecno
730
769
  ], [VENDOR, MODEL, [TYPE, TABLET]], [
731
770
 
732
- /(blackberry|benq|palm(?=\-)|sonyericsson|acer|asus(?! zenw)|dell|jolla|meizu|motorola|polytron|infinix|tecno|micromax|advan)[-_ ]?([-\w]*)/i,
733
- // BlackBerry/BenQ/Palm/Sony-Ericsson/Acer/Asus/Dell/Meizu/Motorola/Polytron/Infinix/Tecno/Micromax/Advan
734
- /; (blu|hmd|imo|tcl)[_ ]([\w\+ ]+?)(?: bui|\)|; r)/i, // BLU/HMD/IMO/TCL
771
+ /(blackberry|benq|palm(?=\-)|sonyericsson|acer|asus(?! zenw)|dell|jolla|meizu|motorola|polytron|tecno|micromax|advan)[-_ ]?([-\w]*)/i,
772
+ // BlackBerry/BenQ/Palm/Sony-Ericsson/Acer/Asus/Dell/Meizu/Motorola/Polytron/Tecno/Micromax/Advan
773
+ // BLU/HMD/IMO/Infinix/Lava/OnePlus/TCL/Wiko
774
+ /; (blu|hmd|imo|infinix|lava|oneplus|tcl|wiko)[_ ]([\w\+ ]+?)(?: bui|\)|; r)/i,
735
775
  /(hp) ([\w ]+\w)/i, // HP iPAQ
736
776
  /(microsoft); (lumia[\w ]+)/i, // Microsoft Lumia
737
- /(lenovo)[-_ ]?([-\w ]+?)(?: bui|\)|\/)/i, // Lenovo
738
- /(oppo) ?([\w ]+) bui/i // OPPO
777
+ /(oppo) ?([\w ]+) bui/i, // OPPO
778
+ /(hisense) ([ehv][\w ]+)\)/i, // Hisense
779
+ /droid[^;]+; (philips)[_ ]([sv-x][\d]{3,4}[xz]?)/i // Philips
739
780
  ], [VENDOR, MODEL, [TYPE, MOBILE]], [
740
781
 
741
782
  /(kobo)\s(ereader|touch)/i, // Kobo
@@ -762,10 +803,12 @@
762
803
  // SMARTTVS
763
804
  ///////////////////
764
805
 
806
+ /(philips)[\w ]+tv/i, // Philips
765
807
  /smart-tv.+(samsung)/i // Samsung
766
808
  ], [VENDOR, [TYPE, SMARTTV]], [
767
809
  /hbbtv.+maple;(\d+)/i
768
810
  ], [[MODEL, /^/, 'SmartTV'], [VENDOR, SAMSUNG], [TYPE, SMARTTV]], [
811
+ /(vizio)(?: |.+model\/)(\w+-\w+)/i, // Vizio
769
812
  /tcast.+(lg)e?. ([-\w]+)/i // LG SmartTV
770
813
  ], [VENDOR, MODEL, [TYPE, SMARTTV]], [
771
814
  /(nux; netcast.+smarttv|lg (netcast\.tv-201\d|android tv))/i
@@ -797,26 +840,22 @@
797
840
  ], [VENDOR, MODEL, [TYPE, SMARTTV]], [
798
841
  /\b(roku)[\dx]*[\)\/]((?:dvp-)?[\d\.]*)/i, // Roku
799
842
  /hbbtv\/\d+\.\d+\.\d+ +\([\w\+ ]*; *([\w\d][^;]*);([^;]*)/i // HbbTV devices
800
- ], [[VENDOR, trim], [MODEL, trim], [TYPE, SMARTTV]], [
801
- // SmartTV from Unidentified Vendors
802
- /droid.+; ([\w- ]+) (?:android tv|smart[- ]?tv)/i
803
- ], [MODEL, [TYPE, SMARTTV]], [
804
- /\b(android tv|smart[- ]?tv|opera tv|tv; rv:)\b/i
805
- ], [[TYPE, SMARTTV]], [
843
+ ], [[VENDOR, /.+\/(\w+)/, '$1', strMapper, {'LG':'lge'}], [MODEL, trim], [TYPE, SMARTTV]], [
806
844
 
807
845
  ///////////////////
808
846
  // CONSOLES
809
847
  ///////////////////
810
848
 
811
- /(ouya)/i, // Ouya
812
- /(nintendo) (\w+)/i // Nintendo
813
- ], [VENDOR, MODEL, [TYPE, CONSOLE]], [
814
- /droid.+; (shield)( bui|\))/i // Nvidia Portable
815
- ], [MODEL, [VENDOR, NVIDIA], [TYPE, CONSOLE]], [
816
849
  /(playstation \w+)/i // Playstation
817
850
  ], [MODEL, [VENDOR, SONY], [TYPE, CONSOLE]], [
818
851
  /\b(xbox(?: one)?(?!; xbox))[\); ]/i // Microsoft Xbox
819
852
  ], [MODEL, [VENDOR, MICROSOFT], [TYPE, CONSOLE]], [
853
+ /(ouya)/i, // Ouya
854
+ /(nintendo) (\w+)/i, // Nintendo
855
+ /(retroid) (pocket ([^\)]+))/i // Retroid Pocket
856
+ ], [VENDOR, MODEL, [TYPE, CONSOLE]], [
857
+ /droid.+; (shield)( bui|\))/i // Nvidia Portable
858
+ ], [MODEL, [VENDOR, NVIDIA], [TYPE, CONSOLE]], [
820
859
 
821
860
  ///////////////////
822
861
  // WEARABLES
@@ -848,10 +887,12 @@
848
887
 
849
888
  /droid.+; (glass) \d/i // Google Glass
850
889
  ], [MODEL, [VENDOR, GOOGLE], [TYPE, XR]], [
851
- /(pico) (4|neo3(?: link|pro)?)/i // Pico
890
+ /(pico) ([\w ]+) os\d/i // Pico
852
891
  ], [VENDOR, MODEL, [TYPE, XR]], [
853
892
  /(quest( \d| pro)?s?).+vr/i // Meta Quest
854
893
  ], [MODEL, [VENDOR, FACEBOOK], [TYPE, XR]], [
894
+ /mobile vr; rv.+firefox/i // Unidentifiable VR device using Firefox Reality / Wolvic
895
+ ], [[TYPE, XR]], [
855
896
 
856
897
  ///////////////////
857
898
  // EMBEDDED
@@ -863,14 +904,18 @@
863
904
  ], [MODEL, [VENDOR, AMAZON], [TYPE, EMBEDDED]], [
864
905
  /(homepod).+mac os/i // Apple HomePod
865
906
  ], [MODEL, [VENDOR, APPLE], [TYPE, EMBEDDED]], [
866
- /windows iot/i
907
+ /windows iot/i // Unidentifiable embedded device using Windows IoT
867
908
  ], [[TYPE, EMBEDDED]], [
868
909
 
869
910
  ////////////////////
870
911
  // MIXED (GENERIC)
871
912
  ///////////////////
872
913
 
873
- /droid .+?; ([^;]+?)(?: bui|; wv\)|\) applew).+?(mobile|vr|\d) safari/i
914
+ /droid.+; ([\w- ]+) (4k|android|smart|google)[- ]?tv/i // Unidentifiable SmartTV
915
+ ], [MODEL, [TYPE, SMARTTV]], [
916
+ /\b((4k|android|smart|opera)[- ]?tv|tv; rv:|large screen[\w ]+safari)\b/i
917
+ ], [[TYPE, SMARTTV]], [
918
+ /droid .+?; ([^;]+?)(?: bui|; wv\)|\) applew|; hmsc).+?(mobile|vr|\d) safari/i
874
919
  ], [MODEL, [TYPE, strMapper, { 'mobile' : 'Mobile', 'xr' : 'VR', '*' : TABLET }]], [
875
920
  /\b((tablet|tab)[;\/]|focus\/\d(?!.+mobile))/i // Unidentifiable Tablet
876
921
  ], [[TYPE, TABLET]], [
@@ -909,22 +954,25 @@
909
954
  os : [[
910
955
 
911
956
  // Windows
912
- /microsoft (windows) (vista|xp)/i // Windows (iTunes)
957
+ /(windows nt) (6\.[23]); arm/i // Windows RT
958
+ ], [[NAME, /N/, 'R'], [VERSION, strMapper, windowsVersionMap]], [
959
+ /(windows (?:phone|mobile|iot))(?: os)?[\/ ]?([\d\.]*( se)?)/i, // Windows IoT/Mobile/Phone
960
+ // Windows NT/3.1/95/98/ME/2000/XP/Vista/7/8/8.1/10/11
961
+ /(windows)[\/ ](1[01]|2000|3\.1|7|8(\.1)?|9[58]|me|server 20\d\d( r2)?|vista|xp)/i
962
+ ], [NAME, VERSION], [
963
+ /windows nt ?([\d\.\)]*)(?!.+xbox)/i,
964
+ /\bwin(?=3| ?9|n)(?:nt| 9x )?([\d\.;]*)/i
965
+ ], [[VERSION, /(;|\))/g, '', strMapper, windowsVersionMap], [NAME, WINDOWS]], [
966
+ /(windows ce)\/?([\d\.]*)/i // Windows CE
913
967
  ], [NAME, VERSION], [
914
- /(windows (?:phone(?: os)?|mobile|iot))[\/ ]?([\d\.\w ]*)/i // Windows Phone
915
- ], [NAME, [VERSION, strMapper, windowsVersionMap]], [
916
- /windows nt 6\.2; (arm)/i, // Windows RT
917
- /windows[\/ ]([ntce\d\. ]+\w)(?!.+xbox)/i,
918
- /(?:win(?=3|9|n)|win 9x )([nt\d\.]+)/i
919
- ], [[VERSION, strMapper, windowsVersionMap], [NAME, WINDOWS]], [
920
968
 
921
969
  // iOS/macOS
922
970
  /[adehimnop]{4,7}\b(?:.*os ([\w]+) like mac|; opera)/i, // iOS
923
- /(?:ios;fbsv\/|iphone.+ios[\/ ])([\d\.]+)/i,
971
+ /(?:ios;fbsv|ios(?=.+ip(?:ad|hone))|ip(?:ad|hone)(?: |.+i(?:pad)?)os)[\/ ]([\w\.]+)/i,
924
972
  /cfnetwork\/.+darwin/i
925
973
  ], [[VERSION, /_/g, '.'], [NAME, 'iOS']], [
926
974
  /(mac os x) ?([\w\. ]*)/i,
927
- /(macintosh|mac_powerpc\b)(?!.+haiku)/i // Mac OS
975
+ /(macintosh|mac_powerpc\b)(?!.+(haiku|morphos))/i // Mac OS
928
976
  ], [[NAME, 'macOS'], [VERSION, /_/g, '.']], [
929
977
 
930
978
  // Google Chromecast
@@ -940,12 +988,13 @@
940
988
  ], [VERSION, [NAME, CHROMECAST]], [
941
989
 
942
990
  // Mobile OSes
943
- /droid ([\w\.]+)\b.+(android[- ]x86|harmonyos)/i // Android-x86/HarmonyOS
991
+ /droid ([\w\.]+)\b.+(android[- ]x86)/i // Android-x86
944
992
  ], [VERSION, NAME], [
945
993
  /(ubuntu) ([\w\.]+) like android/i // Ubuntu Touch
946
994
  ], [[NAME, /(.+)/, '$1 Touch'], VERSION], [
995
+ /(harmonyos)[\/ ]?([\d\.]*)/i, // HarmonyOS
947
996
  // Android/Blackberry/WebOS/QNX/Bada/RIM/KaiOS/Maemo/MeeGo/S40/Sailfish OS/OpenHarmony/Tizen
948
- /(android|bada|blackberry|kaios|maemo|meego|openharmony|qnx|rim tablet os|sailfish|series40|symbian|tizen|webos)\w*[-\/\.; ]?([\d\.]*)/i
997
+ /(android|bada|blackberry|kaios|maemo|meego|openharmony|qnx|rim tablet os|sailfish|series40|symbian|tizen)\w*[-\/\.; ]?([\d\.]*)/i
949
998
  ], [NAME, VERSION], [
950
999
  /\(bb(10);/i // BlackBerry 10
951
1000
  ], [VERSION, [NAME, BLACKBERRY]], [
@@ -953,9 +1002,12 @@
953
1002
  ], [VERSION, [NAME, 'Symbian']], [
954
1003
  /mozilla\/[\d\.]+ \((?:mobile|tablet|tv|mobile; [\w ]+); rv:.+ gecko\/([\w\.]+)/i // Firefox OS
955
1004
  ], [VERSION, [NAME, FIREFOX+' OS']], [
956
- /web0s;.+rt(tv)/i,
957
- /\b(?:hp)?wos(?:browser)?\/([\w\.]+)/i // WebOS
1005
+ /\b(?:hp)?wos(?:browser)?\/([\w\.]+)/i, // WebOS
1006
+ /webos(?:[ \/]?|\.tv-20(?=2[2-9]))(\d[\d\.]*)/i
958
1007
  ], [VERSION, [NAME, 'webOS']], [
1008
+ /web0s;.+?(?:chr[o0]me|safari)\/(\d+)/i
1009
+ // https://webostv.developer.lge.com/develop/specifications/web-api-and-web-engine
1010
+ ], [[VERSION, strMapper, {'25':'120','24':'108','23':'94','22':'87','6':'79','5':'68','4':'53','3':'38','2':'538','1':'537','*':'TV'}], [NAME, 'webOS']], [
959
1011
  /watch(?: ?os[,\/]|\d,\d\/)([\d\.]+)/i // watchOS
960
1012
  ], [VERSION, [NAME, 'watchOS']], [
961
1013
 
@@ -975,20 +1027,20 @@
975
1027
 
976
1028
  // Other
977
1029
  /\b(joli|palm)\b ?(?:os)?\/?([\w\.]*)/i, // Joli/Palm
978
- /(mint)[\/\(\) ]?(\w*)/i, // Mint
979
- /(mageia|vectorlinux)[; ]/i, // Mageia/VectorLinux
980
- /([kxln]?ubuntu|debian|suse|opensuse|gentoo|arch(?= linux)|slackware|fedora|mandriva|centos|pclinuxos|red ?hat|zenwalk|linpus|raspbian|plan 9|minix|risc os|contiki|deepin|manjaro|elementary os|sabayon|linspire)(?: gnu\/linux)?(?: enterprise)?(?:[- ]linux)?(?:-gnu)?[-\/ ]?(?!chrom|package)([-\w\.]*)/i,
981
- // Ubuntu/Debian/SUSE/Gentoo/Arch/Slackware/Fedora/Mandriva/CentOS/PCLinuxOS/RedHat/Zenwalk/Linpus/Raspbian/Plan9/Minix/RISCOS/Contiki/Deepin/Manjaro/elementary/Sabayon/Linspire
982
- /(hurd|linux)(?: arm\w*| x86\w*| ?)([\w\.]*)/i, // Hurd/Linux
1030
+ /linux.+(mint)[\/\(\) ]?([\w\.]*)/i, // Mint
1031
+ /(mageia|vectorlinux|fuchsia|arcaos|arch(?= ?linux))[;l ]([\d\.]*)/i, // Mageia/VectorLinux/Fuchsia/ArcaOS/Arch
1032
+ /([kxln]?ubuntu|debian|suse|opensuse|gentoo|slackware|fedora|mandriva|centos|pclinuxos|red ?hat|zenwalk|linpus|raspbian|plan 9|minix|risc os|contiki|deepin|manjaro|elementary os|sabayon|linspire|knoppix)(?: gnu[\/ ]linux)?(?: enterprise)?(?:[- ]linux)?(?:-gnu)?[-\/ ]?(?!chrom|package)([-\w\.]*)/i,
1033
+ // Ubuntu/Debian/SUSE/Gentoo/Slackware/Fedora/Mandriva/CentOS/PCLinuxOS/RedHat/Zenwalk/Linpus/Raspbian/Plan9/Minix/RISCOS/Contiki/Deepin/Manjaro/elementary/Sabayon/Linspire/Knoppix
1034
+ /((?:open)?solaris)[-\/ ]?([\w\.]*)/i, // Solaris
1035
+ /\b(aix)[; ]([1-9\.]{0,4})/i, // AIX
1036
+ /(hurd|linux|morphos)(?: (?:arm|x86|ppc)\w*| ?)([\w\.]*)/i, // Hurd/Linux/MorphOS
983
1037
  /(gnu) ?([\w\.]*)/i, // GNU
984
1038
  /\b([-frentopcghs]{0,5}bsd|dragonfly)[\/ ]?(?!amd|[ix346]{1,2}86)([\w\.]*)/i, // FreeBSD/NetBSD/OpenBSD/PC-BSD/GhostBSD/DragonFly
985
- /(haiku) (\w+)/i // Haiku
1039
+ /(haiku) ?(r\d)?/i // Haiku
986
1040
  ], [NAME, VERSION], [
987
- /(sunos) ?([\w\.\d]*)/i // Solaris
1041
+ /(sunos) ?([\d\.]*)/i // Solaris
988
1042
  ], [[NAME, 'Solaris'], VERSION], [
989
- /((?:open)?solaris)[-\/ ]?([\w\.]*)/i, // Solaris
990
- /(aix) ((\d)(?=\.|\)| )[\w\.])*/i, // AIX
991
- /\b(beos|os\/2|amigaos|morphos|openvms|fuchsia|hp-ux|serenityos)/i, // BeOS/OS2/AmigaOS/MorphOS/OpenVMS/Fuchsia/HP-UX/SerenityOS
1043
+ /\b(beos|os\/2|amigaos|openvms|hp-ux|serenityos)/i, // BeOS/OS2/AmigaOS/OpenVMS/HP-UX/SerenityOS
992
1044
  /(unix) ?([\w\.]*)/i // UNIX
993
1045
  ], [NAME, VERSION]
994
1046
  ]
@@ -1001,27 +1053,27 @@
1001
1053
  var defaultProps = (function () {
1002
1054
  var props = { init : {}, isIgnore : {}, isIgnoreRgx : {}, toString : {}};
1003
1055
  setProps.call(props.init, [
1004
- [UA_BROWSER, [NAME, VERSION, MAJOR, TYPE]],
1005
- [UA_CPU, [ARCHITECTURE]],
1006
- [UA_DEVICE, [TYPE, MODEL, VENDOR]],
1007
- [UA_ENGINE, [NAME, VERSION]],
1008
- [UA_OS, [NAME, VERSION]]
1056
+ [BROWSER, [NAME, VERSION, MAJOR, TYPE]],
1057
+ [CPU, [ARCHITECTURE]],
1058
+ [DEVICE, [TYPE, MODEL, VENDOR]],
1059
+ [ENGINE, [NAME, VERSION]],
1060
+ [OS, [NAME, VERSION]]
1009
1061
  ]);
1010
1062
  setProps.call(props.isIgnore, [
1011
- [UA_BROWSER, [VERSION, MAJOR]],
1012
- [UA_ENGINE, [VERSION]],
1013
- [UA_OS, [VERSION]]
1063
+ [BROWSER, [VERSION, MAJOR]],
1064
+ [ENGINE, [VERSION]],
1065
+ [OS, [VERSION]]
1014
1066
  ]);
1015
1067
  setProps.call(props.isIgnoreRgx, [
1016
- [UA_BROWSER, / ?browser$/i],
1017
- [UA_OS, / ?os$/i]
1068
+ [BROWSER, / ?browser$/i],
1069
+ [OS, / ?os$/i]
1018
1070
  ]);
1019
1071
  setProps.call(props.toString, [
1020
- [UA_BROWSER, [NAME, VERSION]],
1021
- [UA_CPU, [ARCHITECTURE]],
1022
- [UA_DEVICE, [VENDOR, MODEL]],
1023
- [UA_ENGINE, [NAME, VERSION]],
1024
- [UA_OS, [NAME, VERSION]]
1072
+ [BROWSER, [NAME, VERSION]],
1073
+ [CPU, [ARCHITECTURE]],
1074
+ [DEVICE, [VENDOR, MODEL]],
1075
+ [ENGINE, [NAME, VERSION]],
1076
+ [OS, [NAME, VERSION]]
1025
1077
  ]);
1026
1078
  return props;
1027
1079
  })();
@@ -1065,14 +1117,14 @@
1065
1117
  return item.detectFeature().get();
1066
1118
  };
1067
1119
 
1068
- if (itemType != UA_RESULT) {
1120
+ if (itemType != RESULT) {
1069
1121
  IData.prototype.is = function (strToCheck) {
1070
1122
  var is = false;
1071
1123
  for (var i in this) {
1072
1124
  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)) {
1073
1125
  is = true;
1074
- if (strToCheck != UNDEF_TYPE) break;
1075
- } else if (strToCheck == UNDEF_TYPE && is) {
1126
+ if (strToCheck != TYPEOF.UNDEFINED) break;
1127
+ } else if (strToCheck == TYPEOF.UNDEFINED && is) {
1076
1128
  is = !is;
1077
1129
  break;
1078
1130
  }
@@ -1082,11 +1134,11 @@
1082
1134
  IData.prototype.toString = function () {
1083
1135
  var str = EMPTY;
1084
1136
  for (var i in toString_props) {
1085
- if (typeof(this[toString_props[i]]) !== UNDEF_TYPE) {
1137
+ if (typeof(this[toString_props[i]]) !== TYPEOF.UNDEFINED) {
1086
1138
  str += (str ? ' ' : EMPTY) + this[toString_props[i]];
1087
1139
  }
1088
1140
  }
1089
- return str || UNDEF_TYPE;
1141
+ return str || TYPEOF.UNDEFINED;
1090
1142
  };
1091
1143
  }
1092
1144
 
@@ -1122,19 +1174,19 @@
1122
1174
  setProps.call(this, CH_ALL_VALUES);
1123
1175
  if (isHttpUACH) {
1124
1176
  setProps.call(this, [
1125
- [BRANDS, itemListToArray(uach[CH_HEADER])],
1126
- [FULLVERLIST, itemListToArray(uach[CH_HEADER_FULL_VER_LIST])],
1127
- [MOBILE, /\?1/.test(uach[CH_HEADER_MOBILE])],
1128
- [MODEL, stripQuotes(uach[CH_HEADER_MODEL])],
1129
- [PLATFORM, stripQuotes(uach[CH_HEADER_PLATFORM])],
1130
- [PLATFORMVER, stripQuotes(uach[CH_HEADER_PLATFORM_VER])],
1131
- [ARCHITECTURE, stripQuotes(uach[CH_HEADER_ARCH])],
1132
- [FORMFACTORS, itemListToArray(uach[CH_HEADER_FORM_FACTORS])],
1133
- [BITNESS, stripQuotes(uach[CH_HEADER_BITNESS])]
1177
+ [BRANDS, itemListToArray(uach[CH])],
1178
+ [FULLVERLIST, itemListToArray(uach[CH_FULL_VER_LIST])],
1179
+ [MOBILE, /\?1/.test(uach[CH_MOBILE])],
1180
+ [MODEL, stripQuotes(uach[CH_MODEL])],
1181
+ [PLATFORM, stripQuotes(uach[CH_PLATFORM])],
1182
+ [PLATFORMVER, stripQuotes(uach[CH_PLATFORM_VER])],
1183
+ [ARCHITECTURE, stripQuotes(uach[CH_ARCH])],
1184
+ [FORMFACTORS, itemListToArray(uach[CH_FORM_FACTORS])],
1185
+ [BITNESS, stripQuotes(uach[CH_BITNESS])]
1134
1186
  ]);
1135
1187
  } else {
1136
1188
  for (var prop in uach) {
1137
- if(this.hasOwnProperty(prop) && typeof uach[prop] !== UNDEF_TYPE) this[prop] = uach[prop];
1189
+ if(this.hasOwnProperty(prop) && typeof uach[prop] !== TYPEOF.UNDEFINED) this[prop] = uach[prop];
1138
1190
  }
1139
1191
  }
1140
1192
  }
@@ -1159,30 +1211,30 @@
1159
1211
  this.detectFeature = function () {
1160
1212
  if (NAVIGATOR && NAVIGATOR.userAgent == this.ua) {
1161
1213
  switch (this.itemType) {
1162
- case UA_BROWSER:
1214
+ case BROWSER:
1163
1215
  // Brave-specific detection
1164
- if (NAVIGATOR.brave && typeof NAVIGATOR.brave.isBrave == FUNC_TYPE) {
1216
+ if (NAVIGATOR.brave && typeof NAVIGATOR.brave.isBrave == TYPEOF.FUNCTION) {
1165
1217
  this.set(NAME, 'Brave');
1166
1218
  }
1167
1219
  break;
1168
- case UA_DEVICE:
1220
+ case DEVICE:
1169
1221
  // Chrome-specific detection: check for 'mobile' value of navigator.userAgentData
1170
1222
  if (!this.get(TYPE) && NAVIGATOR_UADATA && NAVIGATOR_UADATA[MOBILE]) {
1171
1223
  this.set(TYPE, MOBILE);
1172
1224
  }
1173
1225
  // iPadOS-specific detection: identified as Mac, but has some iOS-only properties
1174
- if (this.get(MODEL) == 'Macintosh' && NAVIGATOR && typeof NAVIGATOR.standalone !== UNDEF_TYPE && NAVIGATOR.maxTouchPoints && NAVIGATOR.maxTouchPoints > 2) {
1226
+ if (this.get(MODEL) == 'Macintosh' && NAVIGATOR && typeof NAVIGATOR.standalone !== TYPEOF.UNDEFINED && NAVIGATOR.maxTouchPoints && NAVIGATOR.maxTouchPoints > 2) {
1175
1227
  this.set(MODEL, 'iPad')
1176
1228
  .set(TYPE, TABLET);
1177
1229
  }
1178
1230
  break;
1179
- case UA_OS:
1231
+ case OS:
1180
1232
  // Chrome-specific detection: check for 'platform' value of navigator.userAgentData
1181
1233
  if (!this.get(NAME) && NAVIGATOR_UADATA && NAVIGATOR_UADATA[PLATFORM]) {
1182
1234
  this.set(NAME, NAVIGATOR_UADATA[PLATFORM]);
1183
1235
  }
1184
1236
  break;
1185
- case UA_RESULT:
1237
+ case RESULT:
1186
1238
  var data = this.data;
1187
1239
  var detect = function (itemType) {
1188
1240
  return data[itemType]
@@ -1190,22 +1242,33 @@
1190
1242
  .detectFeature()
1191
1243
  .get();
1192
1244
  };
1193
- this.set(UA_BROWSER, detect(UA_BROWSER))
1194
- .set(UA_CPU, detect(UA_CPU))
1195
- .set(UA_DEVICE, detect(UA_DEVICE))
1196
- .set(UA_ENGINE, detect(UA_ENGINE))
1197
- .set(UA_OS, detect(UA_OS));
1245
+ this.set(BROWSER, detect(BROWSER))
1246
+ .set(CPU, detect(CPU))
1247
+ .set(DEVICE, detect(DEVICE))
1248
+ .set(ENGINE, detect(ENGINE))
1249
+ .set(OS, detect(OS));
1198
1250
  }
1199
1251
  }
1200
1252
  return this;
1201
1253
  };
1202
1254
 
1203
1255
  this.parseUA = function () {
1204
- if (this.itemType != UA_RESULT) {
1256
+ if (this.itemType != RESULT) {
1205
1257
  rgxMapper.call(this.data, this.ua, this.rgxMap);
1206
1258
  }
1207
- if (this.itemType == UA_BROWSER) {
1208
- this.set(MAJOR, majorize(this.get(VERSION)));
1259
+ switch (this.itemType) {
1260
+ case BROWSER:
1261
+ this.set(MAJOR, majorize(this.get(VERSION)));
1262
+ break;
1263
+ case OS:
1264
+ if (this.get(NAME) == 'iOS' && this.get(VERSION) == '18.6') {
1265
+ // Based on the assumption that iOS version is tightly coupled with Safari version
1266
+ var realVersion = /\) Version\/([\d\.]+)/.exec(this.ua); // Get Safari version
1267
+ if (realVersion && parseInt(realVersion[1].substring(0,2), 10) >= 26) {
1268
+ this.set(VERSION, realVersion[1]); // Set as iOS version
1269
+ }
1270
+ }
1271
+ break;
1209
1272
  }
1210
1273
  return this;
1211
1274
  };
@@ -1215,43 +1278,42 @@
1215
1278
  rgxMap = this.rgxMap;
1216
1279
 
1217
1280
  switch (this.itemType) {
1218
- case UA_BROWSER:
1219
- case UA_ENGINE:
1281
+ case BROWSER:
1282
+ case ENGINE:
1220
1283
  var brands = uaCH[FULLVERLIST] || uaCH[BRANDS], prevName;
1221
1284
  if (brands) {
1222
- for (var i in brands) {
1285
+ for (var i=0; i<brands.length; i++) {
1223
1286
  var brandName = brands[i].brand || brands[i],
1224
1287
  brandVersion = brands[i].version;
1225
- if (this.itemType == UA_BROWSER && !/not.a.brand/i.test(brandName) && (!prevName || (/chrom/i.test(prevName) && brandName != CHROMIUM))) {
1226
- brandName = strMapper(brandName, {
1227
- 'Chrome' : 'Google Chrome',
1228
- 'Edge' : 'Microsoft Edge',
1229
- 'Chrome WebView' : 'Android WebView',
1230
- 'Chrome Headless' : 'HeadlessChrome',
1231
- 'Huawei Browser' : 'HuaweiBrowser',
1232
- 'MIUI Browser' : 'Miui Browser',
1233
- 'Opera Mobi' : 'OperaMobile',
1234
- 'Yandex' : 'YaBrowser'
1235
- });
1236
- this.set(NAME, brandName)
1237
- .set(VERSION, brandVersion)
1238
- .set(MAJOR, majorize(brandVersion));
1239
- prevName = brandName;
1288
+ if (this.itemType == BROWSER &&
1289
+ !/not.a.brand/i.test(brandName) &&
1290
+ (!prevName ||
1291
+ (/Chrom/.test(prevName) && brandName != CHROMIUM) ||
1292
+ (prevName == EDGE && /WebView2/.test(brandName))
1293
+ )) {
1294
+ brandName = strMapper(brandName, browserHintsMap);
1295
+ prevName = this.get(NAME);
1296
+ if (!(prevName && !/Chrom/.test(prevName) && /Chrom/.test(brandName))) {
1297
+ this.set(NAME, brandName)
1298
+ .set(VERSION, brandVersion)
1299
+ .set(MAJOR, majorize(brandVersion));
1300
+ }
1301
+ prevName = brandName;
1240
1302
  }
1241
- if (this.itemType == UA_ENGINE && brandName == CHROMIUM) {
1303
+ if (this.itemType == ENGINE && brandName == CHROMIUM) {
1242
1304
  this.set(VERSION, brandVersion);
1243
1305
  }
1244
1306
  }
1245
1307
  }
1246
1308
  break;
1247
- case UA_CPU:
1309
+ case CPU:
1248
1310
  var archName = uaCH[ARCHITECTURE];
1249
1311
  if (archName) {
1250
1312
  if (archName && uaCH[BITNESS] == '64') archName += '64';
1251
1313
  rgxMapper.call(this.data, archName + ';', rgxMap);
1252
1314
  }
1253
1315
  break;
1254
- case UA_DEVICE:
1316
+ case DEVICE:
1255
1317
  if (uaCH[MOBILE]) {
1256
1318
  this.set(TYPE, MOBILE);
1257
1319
  }
@@ -1281,7 +1343,7 @@
1281
1343
  this.set(TYPE, ff);
1282
1344
  }
1283
1345
  break;
1284
- case UA_OS:
1346
+ case OS:
1285
1347
  var osName = uaCH[PLATFORM];
1286
1348
  if(osName) {
1287
1349
  var osVersion = uaCH[PLATFORMVER];
@@ -1295,7 +1357,7 @@
1295
1357
  .set(VERSION, undefined);
1296
1358
  }
1297
1359
  break;
1298
- case UA_RESULT:
1360
+ case RESULT:
1299
1361
  var data = this.data;
1300
1362
  var parse = function (itemType) {
1301
1363
  return data[itemType]
@@ -1304,11 +1366,11 @@
1304
1366
  .parseCH()
1305
1367
  .get();
1306
1368
  };
1307
- this.set(UA_BROWSER, parse(UA_BROWSER))
1308
- .set(UA_CPU, parse(UA_CPU))
1309
- .set(UA_DEVICE, parse(UA_DEVICE))
1310
- .set(UA_ENGINE, parse(UA_ENGINE))
1311
- .set(UA_OS, parse(UA_OS));
1369
+ this.set(BROWSER, parse(BROWSER))
1370
+ .set(CPU, parse(CPU))
1371
+ .set(DEVICE, parse(DEVICE))
1372
+ .set(ENGINE, parse(ENGINE))
1373
+ .set(OS, parse(OS));
1312
1374
  }
1313
1375
  return this;
1314
1376
  };
@@ -1326,9 +1388,9 @@
1326
1388
 
1327
1389
  function UAParser (ua, extensions, headers) {
1328
1390
 
1329
- if (typeof ua === OBJ_TYPE) {
1391
+ if (typeof ua === TYPEOF.OBJECT) {
1330
1392
  if (isExtensions(ua, true)) {
1331
- if (typeof extensions === OBJ_TYPE) {
1393
+ if (typeof extensions === TYPEOF.OBJECT) {
1332
1394
  headers = extensions; // case UAParser(extensions, headers)
1333
1395
  }
1334
1396
  extensions = ua; // case UAParser(extensions)
@@ -1337,23 +1399,34 @@
1337
1399
  extensions = undefined;
1338
1400
  }
1339
1401
  ua = undefined;
1340
- } else if (typeof ua === STR_TYPE && !isExtensions(extensions, true)) {
1402
+ } else if (typeof ua === TYPEOF.STRING && !isExtensions(extensions, true)) {
1341
1403
  headers = extensions; // case UAParser(ua, headers)
1342
1404
  extensions = undefined;
1343
1405
  }
1344
1406
 
1345
- // Convert Headers object into a plain object
1346
- if (headers && typeof headers.append === FUNC_TYPE) {
1347
- var kv = {};
1348
- headers.forEach(function (v, k) { kv[k] = v; });
1349
- headers = kv;
1407
+ if (headers) {
1408
+ if (typeof headers.append === TYPEOF.FUNCTION) {
1409
+ // Convert Headers object into a plain object
1410
+ var kv = {};
1411
+ headers.forEach(function (v, k) { kv[String(k).toLowerCase()] = v; });
1412
+ headers = kv;
1413
+ } else {
1414
+ // Normalize headers field name into lowercase
1415
+ var normalized = {};
1416
+ for (var header in headers) {
1417
+ if (headers.hasOwnProperty(header)) {
1418
+ normalized[String(header).toLowerCase()] = headers[header];
1419
+ }
1420
+ }
1421
+ headers = normalized;
1422
+ }
1350
1423
  }
1351
1424
 
1352
1425
  if (!(this instanceof UAParser)) {
1353
1426
  return new UAParser(ua, extensions, headers).getResult();
1354
1427
  }
1355
1428
 
1356
- var userAgent = typeof ua === STR_TYPE ? ua : // Passed user-agent string
1429
+ var userAgent = typeof ua === TYPEOF.STRING ? ua : // Passed user-agent string
1357
1430
  (headers && headers[USER_AGENT] ? headers[USER_AGENT] : // User-Agent from passed headers
1358
1431
  ((NAVIGATOR && NAVIGATOR.userAgent) ? NAVIGATOR.userAgent : // navigator.userAgent
1359
1432
  EMPTY)), // empty string
@@ -1364,15 +1437,15 @@
1364
1437
  defaultRegexes,
1365
1438
 
1366
1439
  createItemFunc = function (itemType) {
1367
- if (itemType == UA_RESULT) {
1440
+ if (itemType == RESULT) {
1368
1441
  return function () {
1369
1442
  return new UAItem(itemType, userAgent, regexMap, httpUACH)
1370
1443
  .set('ua', userAgent)
1371
- .set(UA_BROWSER, this.getBrowser())
1372
- .set(UA_CPU, this.getCPU())
1373
- .set(UA_DEVICE, this.getDevice())
1374
- .set(UA_ENGINE, this.getEngine())
1375
- .set(UA_OS, this.getOS())
1444
+ .set(BROWSER, this.getBrowser())
1445
+ .set(CPU, this.getCPU())
1446
+ .set(DEVICE, this.getDevice())
1447
+ .set(ENGINE, this.getEngine())
1448
+ .set(OS, this.getOS())
1376
1449
  .get();
1377
1450
  };
1378
1451
  } else {
@@ -1386,16 +1459,15 @@
1386
1459
 
1387
1460
  // public methods
1388
1461
  setProps.call(this, [
1389
- ['getBrowser', createItemFunc(UA_BROWSER)],
1390
- ['getCPU', createItemFunc(UA_CPU)],
1391
- ['getDevice', createItemFunc(UA_DEVICE)],
1392
- ['getEngine', createItemFunc(UA_ENGINE)],
1393
- ['getOS', createItemFunc(UA_OS)],
1394
- ['getResult', createItemFunc(UA_RESULT)],
1462
+ ['getBrowser', createItemFunc(BROWSER)],
1463
+ ['getCPU', createItemFunc(CPU)],
1464
+ ['getDevice', createItemFunc(DEVICE)],
1465
+ ['getEngine', createItemFunc(ENGINE)],
1466
+ ['getOS', createItemFunc(OS)],
1467
+ ['getResult', createItemFunc(RESULT)],
1395
1468
  ['getUA', function () { return userAgent; }],
1396
1469
  ['setUA', function (ua) {
1397
- if (isString(ua))
1398
- userAgent = ua.length > UA_MAX_LENGTH ? trim(ua, UA_MAX_LENGTH) : ua;
1470
+ if (isString(ua)) userAgent = trim(ua, UA_MAX_LENGTH);
1399
1471
  return this;
1400
1472
  }]
1401
1473
  ])
@@ -1415,15 +1487,15 @@
1415
1487
  //////////
1416
1488
 
1417
1489
  // check js environment
1418
- if (typeof exports !== UNDEF_TYPE) {
1490
+ if (typeof exports !== TYPEOF.UNDEFINED) {
1419
1491
  // nodejs env
1420
- if (typeof module !== UNDEF_TYPE && module.exports) {
1492
+ if (typeof module !== TYPEOF.UNDEFINED && module.exports) {
1421
1493
  exports = module.exports = UAParser;
1422
1494
  }
1423
1495
  exports.UAParser = UAParser;
1424
1496
  } else {
1425
1497
  // requirejs env (optional)
1426
- if (typeof define === FUNC_TYPE && define.amd) {
1498
+ if (typeof define === TYPEOF.FUNCTION && define.amd) {
1427
1499
  define(function () {
1428
1500
  return UAParser;
1429
1501
  });