ua-parser-js 2.0.0-rc.2 → 2.0.0

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
- /* Helpers for UAParser.js v2.0.0-rc.2
2
+ /* Helpers for UAParser.js v2.0.0
3
3
  https://github.com/faisalman/ua-parser-js
4
4
  Author: Faisal Salman <f@faisalman.com>
5
5
  AGPLv3 License */
@@ -9,35 +9,117 @@
9
9
 
10
10
  const { UAParser } = require('../main/ua-parser');
11
11
  const { CPU, OS, Engine } = require('../enums/ua-parser-enums');
12
+ const { Bots } = require('../extensions/ua-parser-extensions');
12
13
  const { isFromEU } = require('detect-europe-js');
13
14
  const { isFrozenUA } = require('ua-is-frozen');
14
15
  const { isStandalonePWA } = require('is-standalone-pwa');
15
16
 
17
+ const toResult = (value, head, ext) => typeof value === 'string' ? UAParser(value, head, ext) : value;
18
+
16
19
  const getDeviceVendor = (model) => UAParser(`Mozilla/5.0 (Linux; Android 10; ${model}) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/100.0.0.0 Safari/537.36`).device.vendor;
17
20
 
18
- const isAppleSilicon = (res) => {
21
+ const isAppleSilicon = (resultOrUA) => {
22
+ const res = toResult(resultOrUA);
19
23
  if (res.os.is(OS.MACOS)) {
20
24
  if (res.cpu.is(CPU.ARM)) {
21
25
  return true;
22
26
  }
23
- try {
24
- const canvas = document.createElement('canvas');
25
- const webgl = canvas.getContext('webgl2') || canvas.getContext('webgl') || canvas.getContext('experimental-webgl');
26
- const debug = webgl.getExtension('WEBGL_debug_renderer_info');
27
- const renderer = webgl.getParameter(debug.UNMASKED_RENDERER_WEBGL);
28
- if (renderer.match(/apple m\d/i)) {
29
- return true;
27
+ if (typeof resultOrUA !== 'string' && typeof window !== 'undefined') {
28
+ try {
29
+ const canvas = document.createElement('canvas');
30
+ const webgl = canvas.getContext('webgl2') || canvas.getContext('webgl') || canvas.getContext('experimental-webgl');
31
+ const debug = webgl.getExtension('WEBGL_debug_renderer_info');
32
+ const renderer = webgl.getParameter(debug.UNMASKED_RENDERER_WEBGL);
33
+ if (renderer.match(/apple m\d/i)) {
34
+ return true;
35
+ }
36
+ } catch {
37
+ return false;
30
38
  }
31
- } catch {
32
- return false;
33
39
  }
34
40
  }
35
41
  return false;
36
42
  }
37
43
 
38
- const isBot = (res) => ['cli', 'crawler', 'fetcher', 'module'].includes(res.browser.type);
44
+ const isAIBot = (resultOrUA) => [
45
+
46
+ // AI2
47
+ 'ai2bot',
48
+
49
+ // Amazon
50
+ 'amazonbot',
51
+
52
+ // Anthropic
53
+ 'anthropic-ai',
54
+ 'claude-web',
55
+ 'claudebot',
56
+
57
+ // Apple
58
+ 'applebot',
59
+ 'applebot-extended',
60
+
61
+ // ByteDance
62
+ 'bytespider',
63
+
64
+ // Common Crawl
65
+ 'ccbot',
66
+
67
+ // DataForSeo
68
+ 'dataforseobot',
69
+
70
+ // Diffbot
71
+ 'diffbot',
72
+
73
+ // Google
74
+ 'googleother',
75
+ 'googleother-image',
76
+ 'googleother-video',
77
+ 'google-extended',
78
+
79
+ // Hive AI
80
+ 'imagesiftbot',
81
+
82
+ // Huawei
83
+ 'petalbot',
84
+
85
+ // Meta
86
+ 'facebookbot',
87
+ 'meta-externalagent',
88
+
89
+ // OpenAI
90
+ 'gptbot',
91
+ 'oai-searchbot',
92
+
93
+ // Perplexity
94
+ 'perplexitybot',
95
+
96
+ // Timpi
97
+ 'timpibot',
98
+
99
+ // Velen.io
100
+ 'velenpublicwebcrawler',
101
+
102
+ // Webz.io
103
+ 'omgili',
104
+ 'omgilibot',
105
+ 'webzio-extended',
106
+
107
+ // You.com
108
+ 'youbot',
109
+
110
+ // Zyte
111
+ 'scrapy'
112
+
113
+ ].includes(String(toResult(resultOrUA, Bots).browser.name).toLowerCase());
114
+
115
+ const isBot = (resultOrUA) => [
116
+ 'cli',
117
+ 'crawler',
118
+ 'fetcher',
119
+ 'library'
120
+ ].includes(toResult(resultOrUA, Bots).browser.type);
39
121
 
40
- const isChromeFamily = (res) => res.engine.is(Engine.BLINK);
122
+ const isChromeFamily = (resultOrUA) => toResult(resultOrUA).engine.is(Engine.BLINK);
41
123
 
42
124
  const isElectron = () => !!(process?.versions?.hasOwnProperty('electron') || // node.js
43
125
  / electron\//i.test(navigator?.userAgent)); // browser
@@ -45,6 +127,7 @@ const isElectron = () => !!(process?.versions?.hasOwnProperty('electron') ||
45
127
  module.exports = {
46
128
  getDeviceVendor,
47
129
  isAppleSilicon,
130
+ isAIBot,
48
131
  isBot,
49
132
  isChromeFamily,
50
133
  isElectron,
@@ -3,7 +3,7 @@
3
3
  // Source: /src/helpers/ua-parser-helpers.js
4
4
 
5
5
  ///////////////////////////////////////////////
6
- /* Helpers for UAParser.js v2.0.0-rc.2
6
+ /* Helpers for UAParser.js v2.0.0
7
7
  https://github.com/faisalman/ua-parser-js
8
8
  Author: Faisal Salman <f@faisalman.com>
9
9
  AGPLv3 License */
@@ -13,35 +13,117 @@
13
13
 
14
14
  import { UAParser } from '../main/ua-parser.mjs';
15
15
  import { CPU, OS, Engine } from '../enums/ua-parser-enums.mjs';
16
+ import { Bots } from '../extensions/ua-parser-extensions.mjs';
16
17
  import { isFromEU } from 'detect-europe-js';
17
18
  import { isFrozenUA } from 'ua-is-frozen';
18
19
  import { isStandalonePWA } from 'is-standalone-pwa';
19
20
 
21
+ const toResult = (value, head, ext) => typeof value === 'string' ? UAParser(value, head, ext) : value;
22
+
20
23
  const getDeviceVendor = (model) => UAParser(`Mozilla/5.0 (Linux; Android 10; ${model}) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/100.0.0.0 Safari/537.36`).device.vendor;
21
24
 
22
- const isAppleSilicon = (res) => {
25
+ const isAppleSilicon = (resultOrUA) => {
26
+ const res = toResult(resultOrUA);
23
27
  if (res.os.is(OS.MACOS)) {
24
28
  if (res.cpu.is(CPU.ARM)) {
25
29
  return true;
26
30
  }
27
- try {
28
- const canvas = document.createElement('canvas');
29
- const webgl = canvas.getContext('webgl2') || canvas.getContext('webgl') || canvas.getContext('experimental-webgl');
30
- const debug = webgl.getExtension('WEBGL_debug_renderer_info');
31
- const renderer = webgl.getParameter(debug.UNMASKED_RENDERER_WEBGL);
32
- if (renderer.match(/apple m\d/i)) {
33
- return true;
31
+ if (typeof resultOrUA !== 'string' && typeof window !== 'undefined') {
32
+ try {
33
+ const canvas = document.createElement('canvas');
34
+ const webgl = canvas.getContext('webgl2') || canvas.getContext('webgl') || canvas.getContext('experimental-webgl');
35
+ const debug = webgl.getExtension('WEBGL_debug_renderer_info');
36
+ const renderer = webgl.getParameter(debug.UNMASKED_RENDERER_WEBGL);
37
+ if (renderer.match(/apple m\d/i)) {
38
+ return true;
39
+ }
40
+ } catch {
41
+ return false;
34
42
  }
35
- } catch {
36
- return false;
37
43
  }
38
44
  }
39
45
  return false;
40
46
  }
41
47
 
42
- const isBot = (res) => ['cli', 'crawler', 'fetcher', 'module'].includes(res.browser.type);
48
+ const isAIBot = (resultOrUA) => [
49
+
50
+ // AI2
51
+ 'ai2bot',
52
+
53
+ // Amazon
54
+ 'amazonbot',
55
+
56
+ // Anthropic
57
+ 'anthropic-ai',
58
+ 'claude-web',
59
+ 'claudebot',
60
+
61
+ // Apple
62
+ 'applebot',
63
+ 'applebot-extended',
64
+
65
+ // ByteDance
66
+ 'bytespider',
67
+
68
+ // Common Crawl
69
+ 'ccbot',
70
+
71
+ // DataForSeo
72
+ 'dataforseobot',
73
+
74
+ // Diffbot
75
+ 'diffbot',
76
+
77
+ // Google
78
+ 'googleother',
79
+ 'googleother-image',
80
+ 'googleother-video',
81
+ 'google-extended',
82
+
83
+ // Hive AI
84
+ 'imagesiftbot',
85
+
86
+ // Huawei
87
+ 'petalbot',
88
+
89
+ // Meta
90
+ 'facebookbot',
91
+ 'meta-externalagent',
92
+
93
+ // OpenAI
94
+ 'gptbot',
95
+ 'oai-searchbot',
96
+
97
+ // Perplexity
98
+ 'perplexitybot',
99
+
100
+ // Timpi
101
+ 'timpibot',
102
+
103
+ // Velen.io
104
+ 'velenpublicwebcrawler',
105
+
106
+ // Webz.io
107
+ 'omgili',
108
+ 'omgilibot',
109
+ 'webzio-extended',
110
+
111
+ // You.com
112
+ 'youbot',
113
+
114
+ // Zyte
115
+ 'scrapy'
116
+
117
+ ].includes(String(toResult(resultOrUA, Bots).browser.name).toLowerCase());
118
+
119
+ const isBot = (resultOrUA) => [
120
+ 'cli',
121
+ 'crawler',
122
+ 'fetcher',
123
+ 'library'
124
+ ].includes(toResult(resultOrUA, Bots).browser.type);
43
125
 
44
- const isChromeFamily = (res) => res.engine.is(Engine.BLINK);
126
+ const isChromeFamily = (resultOrUA) => toResult(resultOrUA).engine.is(Engine.BLINK);
45
127
 
46
128
  const isElectron = () => !!(process?.versions?.hasOwnProperty('electron') || // node.js
47
129
  / electron\//i.test(navigator?.userAgent)); // browser
@@ -49,6 +131,7 @@ const isElectron = () => !!(process?.versions?.hasOwnProperty('electron') ||
49
131
  export {
50
132
  getDeviceVendor,
51
133
  isAppleSilicon,
134
+ isAIBot,
52
135
  isBot,
53
136
  isChromeFamily,
54
137
  isElectron,
@@ -1,4 +1,4 @@
1
- // Type definitions for UAParser.js v2.0.0-rc.2
1
+ // Type definitions for UAParser.js v2.0.0
2
2
  // Project: https://github.com/faisalman/ua-parser-js
3
3
  // Definitions by: Faisal Salman <https://github.com/faisalman>
4
4
 
@@ -15,11 +15,11 @@ declare namespace UAParser {
15
15
  name?: string;
16
16
  version?: string;
17
17
  major?: string;
18
- type?: 'crawler' | 'cli' | 'email' | 'fetcher' | 'inapp' | 'mediaplayer' | 'module';
18
+ type?: 'crawler' | 'cli' | 'email' | 'fetcher' | 'inapp' | 'mediaplayer' | 'library';
19
19
  }
20
20
 
21
21
  interface ICPU extends IData<ICPU> {
22
- architecture?: 'ia32' | 'ia64' | 'amd64' | 'arm' | 'arm64' | 'armhf' | 'avr' | 'irix' | 'irix64' | 'mips' | 'mips64' | '68k' | 'ppc' | 'sparc' | 'sparc64';
22
+ architecture?: 'ia32' | 'ia64' | 'amd64' | 'arm' | 'arm64' | 'armhf' | 'avr' | 'avr32' | 'irix' | 'irix64' | 'mips' | 'mips64' | '68k' | 'pa-risc' | 'ppc' | 'sparc' | 'sparc64';
23
23
  }
24
24
 
25
25
  interface IDevice extends IData<IDevice> {
@@ -29,7 +29,7 @@ declare namespace UAParser {
29
29
  }
30
30
 
31
31
  interface IEngine extends IData<IEngine> {
32
- name?: 'Amaya' | 'Blink' | 'EdgeHTML' | 'Flow' | 'Gecko' | 'Goanna' | 'iCab' | 'KHTML' | 'LibWeb' | 'Links' | 'Lynx' | 'NetFront' | 'NetSurf' | 'Presto' | 'Tasman' | 'Trident' | 'w3m' | 'WebKit';
32
+ name?: 'Amaya' | 'ArkWeb' | 'Blink' | 'EdgeHTML' | 'Flow' | 'Gecko' | 'Goanna' | 'iCab' | 'KHTML' | 'LibWeb' | 'Links' | 'Lynx' | 'NetFront' | 'NetSurf' | 'Presto' | 'Servo' | 'Tasman' | 'Trident' | 'w3m' | 'WebKit';
33
33
  version?: string;
34
34
  }
35
35
 
@@ -1,5 +1,5 @@
1
1
  /////////////////////////////////////////////////////////////////////////////////
2
- /* UAParser.js v2.0.0-rc.2
2
+ /* UAParser.js v2.0.0
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.
@@ -19,7 +19,7 @@
19
19
  // Constants
20
20
  /////////////
21
21
 
22
- var LIBVERSION = '2.0.0-rc.2',
22
+ var LIBVERSION = '2.0.0',
23
23
  EMPTY = '',
24
24
  UNKNOWN = '?',
25
25
  FUNC_TYPE = 'function',
@@ -72,6 +72,7 @@
72
72
  GOOGLE = 'Google',
73
73
  HUAWEI = 'Huawei',
74
74
  LENOVO = 'Lenovo',
75
+ HONOR = 'Honor',
75
76
  LG = 'LG',
76
77
  MICROSOFT = 'Microsoft',
77
78
  MOTOROLA = 'Motorola',
@@ -462,7 +463,7 @@
462
463
  // Other
463
464
  /(polaris|lynx|dillo|icab|doris|amaya|w3m|netsurf|obigo|mosaic|(?:go|ice|up)[\. ]?browser)[-\/ ]?v?([\w\.]+)/i,
464
465
  // Polaris/Lynx/Dillo/iCab/Doris/Amaya/w3m/NetSurf/Obigo/Mosaic/Go/ICE/UP.Browser
465
- /(links) \(([\w\.]+)/i // Links
466
+ /\b(links) \(([\w\.]+)/i // Links
466
467
  ], [NAME, [VERSION, /_/g, '.']], [
467
468
 
468
469
  /(cobalt)\/([\w\.]+)/i // Cobalt
@@ -527,10 +528,14 @@
527
528
  /\b(sh-?[altvz]?\d\d[a-ekm]?)/i
528
529
  ], [MODEL, [VENDOR, SHARP], [TYPE, MOBILE]], [
529
530
 
531
+ // Honor
532
+ /(?:honor)([-\w ]+)[;\)]/i
533
+ ], [MODEL, [VENDOR, HONOR], [TYPE, MOBILE]], [
534
+
530
535
  // Huawei
531
536
  /\b((?:ag[rs][23]?|bah2?|sht?|btv)-a?[lw]\d{2})\b(?!.+d\/s)/i
532
537
  ], [MODEL, [VENDOR, HUAWEI], [TYPE, TABLET]], [
533
- /(?:huawei|honor)([-\w ]+)[;\)]/i,
538
+ /(?:huawei)([-\w ]+)[;\)]/i,
534
539
  /\b(nexus 6p|\w{2,4}e?-[atu]?[ln][\dx][012359c][adn]?)\b(?!.+d\/s)/i
535
540
  ], [MODEL, [VENDOR, HUAWEI], [TYPE, MOBILE]], [
536
541
 
@@ -595,7 +600,7 @@
595
600
  ], [MODEL, [VENDOR, GOOGLE], [TYPE, MOBILE]], [
596
601
 
597
602
  // Sony
598
- /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
603
+ /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
599
604
  ], [MODEL, [VENDOR, SONY], [TYPE, MOBILE]], [
600
605
  /sony tablet [ps]/i,
601
606
  /\b(?:sony)?sgp\w+(?: bui|\))/i
@@ -661,13 +666,28 @@
661
666
  /; ((?:power )?armor(?:[\w ]{0,8}))(?: bui|\))/i
662
667
  ], [MODEL, [VENDOR, 'Ulefone'], [TYPE, MOBILE]], [
663
668
 
669
+ // Energizer
670
+ /; (energy ?\w+)(?: bui|\))/i,
671
+ /; energizer ([\w ]+)(?: bui|\))/i
672
+ ], [MODEL, [VENDOR, 'Energizer'], [TYPE, MOBILE]], [
673
+
674
+ // Cat
675
+ /; cat (b35);/i,
676
+ /; (b15q?|s22 flip|s48c|s62 pro)(?: bui|\))/i
677
+ ], [MODEL, [VENDOR, 'Cat'], [TYPE, MOBILE]], [
678
+
679
+ // Smartfren
680
+ /((?:new )?andromax[\w- ]+)(?: bui|\))/i
681
+ ], [MODEL, [VENDOR, 'Smartfren'], [TYPE, MOBILE]], [
682
+
664
683
  // Nothing
665
684
  /droid.+; (a(?:015|06[35]|142p?))/i
666
685
  ], [MODEL, [VENDOR, 'Nothing'], [TYPE, MOBILE]], [
667
686
 
668
687
  // MIXED
669
- /(blackberry|benq|palm(?=\-)|sonyericsson|acer|asus|dell|meizu|motorola|polytron|infinix|tecno)[-_ ]?([-\w]*)/i,
670
- // BlackBerry/BenQ/Palm/Sony-Ericsson/Acer/Asus/Dell/Meizu/Motorola/Polytron
688
+ /(blackberry|benq|palm(?=\-)|sonyericsson|acer|asus|dell|meizu|motorola|polytron|infinix|tecno|micromax|advan)[-_ ]?([-\w]*)/i,
689
+ // BlackBerry/BenQ/Palm/Sony-Ericsson/Acer/Asus/Dell/Meizu/Motorola/Polytron/Infinix/Tecno/Micromax/Advan
690
+ /; (imo) ((?!tab)[\w ]+?)(?: bui|\))/i, // IMO
671
691
  /(hp) ([\w ]+\w)/i, // HP iPAQ
672
692
  /(asus)-?(\w+)/i, // Asus
673
693
  /(microsoft); (lumia[\w ]+)/i, // Microsoft Lumia
@@ -676,6 +696,7 @@
676
696
  /(oppo) ?([\w ]+) bui/i // OPPO
677
697
  ], [VENDOR, MODEL, [TYPE, MOBILE]], [
678
698
 
699
+ /(imo) (tab \w+)/i, // IMO
679
700
  /(kobo)\s(ereader|touch)/i, // Kobo
680
701
  /(archos) (gamepad2?)/i, // Archos
681
702
  /(hp).+(touchpad(?!.+tablet)|tablet)/i, // HP TouchPad
@@ -809,7 +830,7 @@
809
830
  ], [VERSION, [NAME, 'Blink']], [
810
831
 
811
832
  /(presto)\/([\w\.]+)/i, // Presto
812
- /(webkit|trident|netfront|netsurf|amaya|lynx|w3m|goanna)\/([\w\.]+)/i, // WebKit/Trident/NetFront/NetSurf/Amaya/Lynx/w3m/Goanna
833
+ /(webkit|trident|netfront|netsurf|amaya|lynx|w3m|goanna|servo)\/([\w\.]+)/i, // WebKit/Trident/NetFront/NetSurf/Amaya/Lynx/w3m/Goanna/Servo
813
834
  /ekioh(flow)\/([\w\.]+)/i, // Flow
814
835
  /(khtml|tasman|links)[\/ ]\(?([\w\.]+)/i, // KHTML/Tasman/Links
815
836
  /(icab)[\/ ]([23]\.[\d\.]+)/i, // iCab
@@ -1236,14 +1257,21 @@
1236
1257
  headers = extensions; // case UAParser(ua, headers)
1237
1258
  extensions = undefined;
1238
1259
  }
1260
+
1261
+ // Convert Headers object into a plain object
1262
+ if (headers && typeof headers.append === FUNC_TYPE) {
1263
+ var kv = {};
1264
+ headers.forEach(function (v, k) { kv[k] = v; });
1265
+ headers = kv;
1266
+ }
1239
1267
 
1240
1268
  if (!(this instanceof UAParser)) {
1241
1269
  return new UAParser(ua, extensions, headers).getResult();
1242
1270
  }
1243
1271
 
1244
1272
  var userAgent = typeof ua === STR_TYPE ? ua : // Passed user-agent string
1245
- ((NAVIGATOR && NAVIGATOR.userAgent) ? NAVIGATOR.userAgent : // navigator.userAgent
1246
1273
  (headers && headers[USER_AGENT] ? headers[USER_AGENT] : // User-Agent from passed headers
1274
+ ((NAVIGATOR && NAVIGATOR.userAgent) ? NAVIGATOR.userAgent : // navigator.userAgent
1247
1275
  EMPTY)), // empty string
1248
1276
 
1249
1277
  httpUACH = new UACHData(headers, true),
@@ -3,7 +3,7 @@
3
3
  // Source: /src/main/ua-parser.js
4
4
 
5
5
  /////////////////////////////////////////////////////////////////////////////////
6
- /* UAParser.js v2.0.0-rc.2
6
+ /* UAParser.js v2.0.0
7
7
  Copyright © 2012-2024 Faisal Salman <f@faisalman.com>
8
8
  AGPLv3 License *//*
9
9
  Detect Browser, Engine, OS, CPU, and Device type/model from User-Agent data.
@@ -21,7 +21,7 @@
21
21
  // Constants
22
22
  /////////////
23
23
 
24
- var LIBVERSION = '2.0.0-rc.2',
24
+ var LIBVERSION = '2.0.0',
25
25
  EMPTY = '',
26
26
  UNKNOWN = '?',
27
27
  FUNC_TYPE = 'function',
@@ -74,6 +74,7 @@
74
74
  GOOGLE = 'Google',
75
75
  HUAWEI = 'Huawei',
76
76
  LENOVO = 'Lenovo',
77
+ HONOR = 'Honor',
77
78
  LG = 'LG',
78
79
  MICROSOFT = 'Microsoft',
79
80
  MOTOROLA = 'Motorola',
@@ -464,7 +465,7 @@
464
465
  // Other
465
466
  /(polaris|lynx|dillo|icab|doris|amaya|w3m|netsurf|obigo|mosaic|(?:go|ice|up)[\. ]?browser)[-\/ ]?v?([\w\.]+)/i,
466
467
  // Polaris/Lynx/Dillo/iCab/Doris/Amaya/w3m/NetSurf/Obigo/Mosaic/Go/ICE/UP.Browser
467
- /(links) \(([\w\.]+)/i // Links
468
+ /\b(links) \(([\w\.]+)/i // Links
468
469
  ], [NAME, [VERSION, /_/g, '.']], [
469
470
 
470
471
  /(cobalt)\/([\w\.]+)/i // Cobalt
@@ -529,10 +530,14 @@
529
530
  /\b(sh-?[altvz]?\d\d[a-ekm]?)/i
530
531
  ], [MODEL, [VENDOR, SHARP], [TYPE, MOBILE]], [
531
532
 
533
+ // Honor
534
+ /(?:honor)([-\w ]+)[;\)]/i
535
+ ], [MODEL, [VENDOR, HONOR], [TYPE, MOBILE]], [
536
+
532
537
  // Huawei
533
538
  /\b((?:ag[rs][23]?|bah2?|sht?|btv)-a?[lw]\d{2})\b(?!.+d\/s)/i
534
539
  ], [MODEL, [VENDOR, HUAWEI], [TYPE, TABLET]], [
535
- /(?:huawei|honor)([-\w ]+)[;\)]/i,
540
+ /(?:huawei)([-\w ]+)[;\)]/i,
536
541
  /\b(nexus 6p|\w{2,4}e?-[atu]?[ln][\dx][012359c][adn]?)\b(?!.+d\/s)/i
537
542
  ], [MODEL, [VENDOR, HUAWEI], [TYPE, MOBILE]], [
538
543
 
@@ -597,7 +602,7 @@
597
602
  ], [MODEL, [VENDOR, GOOGLE], [TYPE, MOBILE]], [
598
603
 
599
604
  // Sony
600
- /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
605
+ /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
601
606
  ], [MODEL, [VENDOR, SONY], [TYPE, MOBILE]], [
602
607
  /sony tablet [ps]/i,
603
608
  /\b(?:sony)?sgp\w+(?: bui|\))/i
@@ -663,13 +668,28 @@
663
668
  /; ((?:power )?armor(?:[\w ]{0,8}))(?: bui|\))/i
664
669
  ], [MODEL, [VENDOR, 'Ulefone'], [TYPE, MOBILE]], [
665
670
 
671
+ // Energizer
672
+ /; (energy ?\w+)(?: bui|\))/i,
673
+ /; energizer ([\w ]+)(?: bui|\))/i
674
+ ], [MODEL, [VENDOR, 'Energizer'], [TYPE, MOBILE]], [
675
+
676
+ // Cat
677
+ /; cat (b35);/i,
678
+ /; (b15q?|s22 flip|s48c|s62 pro)(?: bui|\))/i
679
+ ], [MODEL, [VENDOR, 'Cat'], [TYPE, MOBILE]], [
680
+
681
+ // Smartfren
682
+ /((?:new )?andromax[\w- ]+)(?: bui|\))/i
683
+ ], [MODEL, [VENDOR, 'Smartfren'], [TYPE, MOBILE]], [
684
+
666
685
  // Nothing
667
686
  /droid.+; (a(?:015|06[35]|142p?))/i
668
687
  ], [MODEL, [VENDOR, 'Nothing'], [TYPE, MOBILE]], [
669
688
 
670
689
  // MIXED
671
- /(blackberry|benq|palm(?=\-)|sonyericsson|acer|asus|dell|meizu|motorola|polytron|infinix|tecno)[-_ ]?([-\w]*)/i,
672
- // BlackBerry/BenQ/Palm/Sony-Ericsson/Acer/Asus/Dell/Meizu/Motorola/Polytron
690
+ /(blackberry|benq|palm(?=\-)|sonyericsson|acer|asus|dell|meizu|motorola|polytron|infinix|tecno|micromax|advan)[-_ ]?([-\w]*)/i,
691
+ // BlackBerry/BenQ/Palm/Sony-Ericsson/Acer/Asus/Dell/Meizu/Motorola/Polytron/Infinix/Tecno/Micromax/Advan
692
+ /; (imo) ((?!tab)[\w ]+?)(?: bui|\))/i, // IMO
673
693
  /(hp) ([\w ]+\w)/i, // HP iPAQ
674
694
  /(asus)-?(\w+)/i, // Asus
675
695
  /(microsoft); (lumia[\w ]+)/i, // Microsoft Lumia
@@ -678,6 +698,7 @@
678
698
  /(oppo) ?([\w ]+) bui/i // OPPO
679
699
  ], [VENDOR, MODEL, [TYPE, MOBILE]], [
680
700
 
701
+ /(imo) (tab \w+)/i, // IMO
681
702
  /(kobo)\s(ereader|touch)/i, // Kobo
682
703
  /(archos) (gamepad2?)/i, // Archos
683
704
  /(hp).+(touchpad(?!.+tablet)|tablet)/i, // HP TouchPad
@@ -811,7 +832,7 @@
811
832
  ], [VERSION, [NAME, 'Blink']], [
812
833
 
813
834
  /(presto)\/([\w\.]+)/i, // Presto
814
- /(webkit|trident|netfront|netsurf|amaya|lynx|w3m|goanna)\/([\w\.]+)/i, // WebKit/Trident/NetFront/NetSurf/Amaya/Lynx/w3m/Goanna
835
+ /(webkit|trident|netfront|netsurf|amaya|lynx|w3m|goanna|servo)\/([\w\.]+)/i, // WebKit/Trident/NetFront/NetSurf/Amaya/Lynx/w3m/Goanna/Servo
815
836
  /ekioh(flow)\/([\w\.]+)/i, // Flow
816
837
  /(khtml|tasman|links)[\/ ]\(?([\w\.]+)/i, // KHTML/Tasman/Links
817
838
  /(icab)[\/ ]([23]\.[\d\.]+)/i, // iCab
@@ -1238,14 +1259,21 @@
1238
1259
  headers = extensions; // case UAParser(ua, headers)
1239
1260
  extensions = undefined;
1240
1261
  }
1262
+
1263
+ // Convert Headers object into a plain object
1264
+ if (headers && typeof headers.append === FUNC_TYPE) {
1265
+ var kv = {};
1266
+ headers.forEach(function (v, k) { kv[k] = v; });
1267
+ headers = kv;
1268
+ }
1241
1269
 
1242
1270
  if (!(this instanceof UAParser)) {
1243
1271
  return new UAParser(ua, extensions, headers).getResult();
1244
1272
  }
1245
1273
 
1246
1274
  var userAgent = typeof ua === STR_TYPE ? ua : // Passed user-agent string
1247
- ((NAVIGATOR && NAVIGATOR.userAgent) ? NAVIGATOR.userAgent : // navigator.userAgent
1248
1275
  (headers && headers[USER_AGENT] ? headers[USER_AGENT] : // User-Agent from passed headers
1276
+ ((NAVIGATOR && NAVIGATOR.userAgent) ? NAVIGATOR.userAgent : // navigator.userAgent
1249
1277
  EMPTY)), // empty string
1250
1278
 
1251
1279
  httpUACH = new UACHData(headers, true),