ua-parser-js 0.7.37 → 0.8.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.

Potentially problematic release.


This version of ua-parser-js might be problematic. Click here for more details.

package/src/ua-parser.js CHANGED
@@ -1,12 +1,11 @@
1
- /////////////////////////////////////////////////////////////////////////////////
2
- /* UAParser.js v0.7.37
3
- Copyright © 2012-2021 Faisal Salman <f@faisalman.com>
4
- MIT License *//*
5
- Detect Browser, Engine, OS, CPU, and Device type/model from User-Agent data.
6
- Supports browser & node.js environment.
7
- Demo : https://faisalman.github.io/ua-parser-js
8
- Source : https://github.com/faisalman/ua-parser-js */
9
- /////////////////////////////////////////////////////////////////////////////////
1
+ /*!@license
2
+ * UAParser.js v0.7.28
3
+ * Lightweight JavaScript-based User-Agent string parser
4
+ * https://github.com/faisalman/ua-parser-js
5
+ *
6
+ * Copyright © 2012-2021 Faisal Salman <f@faisalman.com>
7
+ * Licensed under MIT License
8
+ */
10
9
 
11
10
  (function (window, undefined) {
12
11
 
@@ -17,14 +16,14 @@
17
16
  /////////////
18
17
 
19
18
 
20
- var LIBVERSION = '0.7.37',
19
+ var LIBVERSION = '0.7.28',
21
20
  EMPTY = '',
22
21
  UNKNOWN = '?',
23
22
  FUNC_TYPE = 'function',
24
23
  UNDEF_TYPE = 'undefined',
25
24
  OBJ_TYPE = 'object',
26
25
  STR_TYPE = 'string',
27
- MAJOR = 'major',
26
+ MAJOR = 'major', // deprecated
28
27
  MODEL = 'model',
29
28
  NAME = 'name',
30
29
  TYPE = 'type',
@@ -37,36 +36,16 @@
37
36
  SMARTTV = 'smarttv',
38
37
  WEARABLE = 'wearable',
39
38
  EMBEDDED = 'embedded',
40
- UA_MAX_LENGTH = 500;
41
-
42
- var AMAZON = 'Amazon',
43
- APPLE = 'Apple',
44
- ASUS = 'ASUS',
45
- BLACKBERRY = 'BlackBerry',
46
- BROWSER = 'Browser',
47
- CHROME = 'Chrome',
48
- EDGE = 'Edge',
49
- FIREFOX = 'Firefox',
50
- GOOGLE = 'Google',
51
- HUAWEI = 'Huawei',
52
- LG = 'LG',
53
- MICROSOFT = 'Microsoft',
54
- MOTOROLA = 'Motorola',
55
- OPERA = 'Opera',
56
- SAMSUNG = 'Samsung',
57
- SHARP = 'Sharp',
58
- SONY = 'Sony',
59
- XIAOMI = 'Xiaomi',
60
- ZEBRA = 'Zebra',
61
- FACEBOOK = 'Facebook',
62
- CHROMIUM_OS = 'Chromium OS',
63
- MAC_OS = 'Mac OS';
39
+ UA_MAX_LENGTH = 255;
40
+
64
41
 
65
42
  ///////////
66
43
  // Helper
67
44
  //////////
68
45
 
69
- var extend = function (regexes, extensions) {
46
+
47
+ var util = {
48
+ extend : function (regexes, extensions) {
70
49
  var mergedRegexes = {};
71
50
  for (var i in regexes) {
72
51
  if (extensions[i] && extensions[i].length % 2 === 0) {
@@ -77,34 +56,30 @@
77
56
  }
78
57
  return mergedRegexes;
79
58
  },
80
- enumerize = function (arr) {
81
- var enums = {};
82
- for (var i=0; i<arr.length; i++) {
83
- enums[arr[i].toUpperCase()] = arr[i];
84
- }
85
- return enums;
86
- },
87
- has = function (str1, str2) {
88
- return typeof str1 === STR_TYPE ? lowerize(str2).indexOf(lowerize(str1)) !== -1 : false;
59
+ has : function (str1, str2) {
60
+ return typeof str1 === STR_TYPE ? str2.toLowerCase().indexOf(str1.toLowerCase()) !== -1 : false;
89
61
  },
90
- lowerize = function (str) {
62
+ lowerize : function (str) {
91
63
  return str.toLowerCase();
92
64
  },
93
- majorize = function (version) {
94
- return typeof(version) === STR_TYPE ? version.replace(/[^\d\.]/g, EMPTY).split('.')[0] : undefined;
65
+ major : function (version) {
66
+ return typeof(version) === STR_TYPE ? version.replace(/[^\d\.]/g,'').split(".")[0] : undefined;
95
67
  },
96
- trim = function (str, len) {
97
- if (typeof(str) === STR_TYPE) {
98
- str = str.replace(/^\s\s*/, EMPTY);
99
- return typeof(len) === UNDEF_TYPE ? str : str.substring(0, UA_MAX_LENGTH);
100
- }
68
+ trim : function (str, len) {
69
+ str = str.replace(/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g, '');
70
+ return typeof(len) === UNDEF_TYPE ? str : str.substring(0, UA_MAX_LENGTH);
71
+ }
101
72
  };
102
73
 
74
+
103
75
  ///////////////
104
76
  // Map helper
105
77
  //////////////
106
78
 
107
- var rgxMapper = function (ua, arrays) {
79
+
80
+ var mapper = {
81
+
82
+ rgx : function (ua, arrays) {
108
83
 
109
84
  var i = 0, j, k, p, q, matches, match;
110
85
 
@@ -118,7 +93,6 @@
118
93
  // try matching uastring with regexes
119
94
  while (j < regex.length && !matches) {
120
95
 
121
- if (!regex[j]) { break; }
122
96
  matches = regex[j++].exec(ua);
123
97
 
124
98
  if (!!matches) {
@@ -127,7 +101,7 @@
127
101
  q = props[p];
128
102
  // check if given property is actually array
129
103
  if (typeof q === OBJ_TYPE && q.length > 0) {
130
- if (q.length === 2) {
104
+ if (q.length == 2) {
131
105
  if (typeof q[1] == FUNC_TYPE) {
132
106
  // assign modified match
133
107
  this[q[0]] = q[1].call(this, match);
@@ -135,7 +109,7 @@
135
109
  // assign given value, ignore regex match
136
110
  this[q[0]] = q[1];
137
111
  }
138
- } else if (q.length === 3) {
112
+ } else if (q.length == 3) {
139
113
  // check whether function or regex
140
114
  if (typeof q[1] === FUNC_TYPE && !(q[1].exec && q[1].test)) {
141
115
  // call function (usually string mapper)
@@ -144,7 +118,7 @@
144
118
  // sanitize match using given regex
145
119
  this[q[0]] = match ? match.replace(q[1], q[2]) : undefined;
146
120
  }
147
- } else if (q.length === 4) {
121
+ } else if (q.length == 4) {
148
122
  this[q[0]] = match ? q[3].call(this, match.replace(q[1], q[2])) : undefined;
149
123
  }
150
124
  } else {
@@ -157,56 +131,84 @@
157
131
  }
158
132
  },
159
133
 
160
- strMapper = function (str, map) {
134
+ str : function (str, map) {
161
135
 
162
136
  for (var i in map) {
163
- // check if current value is array
137
+ // check if array
164
138
  if (typeof map[i] === OBJ_TYPE && map[i].length > 0) {
165
139
  for (var j = 0; j < map[i].length; j++) {
166
- if (has(map[i][j], str)) {
140
+ if (util.has(map[i][j], str)) {
167
141
  return (i === UNKNOWN) ? undefined : i;
168
142
  }
169
143
  }
170
- } else if (has(map[i], str)) {
144
+ } else if (util.has(map[i], str)) {
171
145
  return (i === UNKNOWN) ? undefined : i;
172
146
  }
173
147
  }
174
148
  return str;
149
+ }
175
150
  };
176
151
 
152
+
177
153
  ///////////////
178
154
  // String map
179
155
  //////////////
180
156
 
181
- // Safari < 3.0
182
- var oldSafariMap = {
183
- '1.0' : '/8',
184
- '1.2' : '/1',
185
- '1.3' : '/3',
186
- '2.0' : '/412',
187
- '2.0.2' : '/416',
188
- '2.0.3' : '/417',
189
- '2.0.4' : '/419',
190
- '?' : '/'
157
+
158
+ var maps = {
159
+
160
+ browser : {
161
+ // Safari < 3.0
162
+ oldSafari : {
163
+ version : {
164
+ '1.0' : '/8',
165
+ '1.2' : '/1',
166
+ '1.3' : '/3',
167
+ '2.0' : '/412',
168
+ '2.0.2' : '/416',
169
+ '2.0.3' : '/417',
170
+ '2.0.4' : '/419',
171
+ '?' : '/'
172
+ }
173
+ },
174
+ oldEdge : {
175
+ version : {
176
+ '0.1' : '12.',
177
+ '21' : '13.',
178
+ '31' : '14.',
179
+ '39' : '15.',
180
+ '41' : '16.',
181
+ '42' : '17.',
182
+ '44' : '18.'
183
+ }
184
+ }
191
185
  },
192
- windowsVersionMap = {
193
- 'ME' : '4.90',
194
- 'NT 3.11' : 'NT3.51',
195
- 'NT 4.0' : 'NT4.0',
196
- '2000' : 'NT 5.0',
197
- 'XP' : ['NT 5.1', 'NT 5.2'],
198
- 'Vista' : 'NT 6.0',
199
- '7' : 'NT 6.1',
200
- '8' : 'NT 6.2',
201
- '8.1' : 'NT 6.3',
202
- '10' : ['NT 6.4', 'NT 10.0'],
203
- 'RT' : 'ARM'
186
+
187
+ os : {
188
+ windows : {
189
+ version : {
190
+ 'ME' : '4.90',
191
+ 'NT 3.11' : 'NT3.51',
192
+ 'NT 4.0' : 'NT4.0',
193
+ '2000' : 'NT 5.0',
194
+ 'XP' : ['NT 5.1', 'NT 5.2'],
195
+ 'Vista' : 'NT 6.0',
196
+ '7' : 'NT 6.1',
197
+ '8' : 'NT 6.2',
198
+ '8.1' : 'NT 6.3',
199
+ '10' : ['NT 6.4', 'NT 10.0'],
200
+ 'RT' : 'ARM'
201
+ }
202
+ }
203
+ }
204
204
  };
205
205
 
206
+
206
207
  //////////////
207
208
  // Regex map
208
209
  /////////////
209
210
 
211
+
210
212
  var regexes = {
211
213
 
212
214
  browser : [[
@@ -215,406 +217,399 @@
215
217
  ], [VERSION, [NAME, 'Chrome']], [
216
218
  /edg(?:e|ios|a)?\/([\w\.]+)/i // Microsoft Edge
217
219
  ], [VERSION, [NAME, 'Edge']], [
220
+ // breaking change (reserved for next major release):
221
+ ///edge\/([\w\.]+)/i // Old Edge (Trident)
222
+ //], [[VERSION, mapper.str, maps.browser.oldEdge.version], [NAME, 'Edge']], [
218
223
 
219
224
  // Presto based
220
- /(opera mini)\/([-\w\.]+)/i, // Opera Mini
221
- /(opera [mobiletab]{3,6})\b.+version\/([-\w\.]+)/i, // Opera Mobi/Tablet
222
- /(opera)(?:.+version\/|[\/ ]+)([\w\.]+)/i // Opera
225
+ /(opera\smini)\/([\w\.-]+)/i, // Opera Mini
226
+ /(opera\s[mobiletab]{3,6})\b.+version\/([\w\.-]+)/i, // Opera Mobi/Tablet
227
+ /(opera)(?:.+version\/|[\/\s]+)([\w\.]+)/i, // Opera
223
228
  ], [NAME, VERSION], [
224
- /opios[\/ ]+([\w\.]+)/i // Opera mini on iphone >= 8.0
225
- ], [VERSION, [NAME, OPERA+' Mini']], [
226
- /\bopr\/([\w\.]+)/i // Opera Webkit
227
- ], [VERSION, [NAME, OPERA]], [
229
+ /opios[\/\s]+([\w\.]+)/i // Opera mini on iphone >= 8.0
230
+ ], [VERSION, [NAME, 'Opera Mini']], [
231
+ /\sopr\/([\w\.]+)/i // Opera Webkit
232
+ ], [VERSION, [NAME, 'Opera']], [
228
233
 
229
234
  // Mixed
230
- /\bb[ai]*d(?:uhd|[ub]*[aekoprswx]{5,6})[\/ ]?([\w\.]+)/i // Baidu
231
- ], [VERSION, [NAME, 'Baidu']], [
232
235
  /(kindle)\/([\w\.]+)/i, // Kindle
233
- /(lunascape|maxthon|netfront|jasmine|blazer)[\/ ]?([\w\.]*)/i, // Lunascape/Maxthon/Netfront/Jasmine/Blazer
236
+ /(lunascape|maxthon|netfront|jasmine|blazer)[\/\s]?([\w\.]*)/i, // Lunascape/Maxthon/Netfront/Jasmine/Blazer
234
237
  // Trident based
235
- /(avant|iemobile|slim)\s?(?:browser)?[\/ ]?([\w\.]*)/i, // Avant/IEMobile/SlimBrowser
236
- /(?:ms|\()(ie) ([\w\.]+)/i, // Internet Explorer
237
-
238
- // Webkit/KHTML based // Flock/RockMelt/Midori/Epiphany/Silk/Skyfire/Bolt/Iron/Iridium/PhantomJS/Bowser/QupZilla/Falkon
239
- /(flock|rockmelt|midori|epiphany|silk|skyfire|bolt|iron|vivaldi|iridium|phantomjs|bowser|quark|qupzilla|falkon|rekonq|puffin|brave|whale(?!.+naver)|qqbrowserlite|qq|duckduckgo)\/([-\w\.]+)/i,
240
- // Rekonq/Puffin/Brave/Whale/QQBrowserLite/QQ, aka ShouQ
241
- /(heytap|ovi)browser\/([\d\.]+)/i, // Heytap/Ovi
238
+ /(avant\s|iemobile|slim)(?:browser)?[\/\s]?([\w\.]*)/i, // Avant/IEMobile/SlimBrowser
239
+ /(ba?idubrowser)[\/\s]?([\w\.]+)/i, // Baidu Browser
240
+ /(?:ms|\()(ie)\s([\w\.]+)/i, // Internet Explorer
241
+
242
+ // Webkit/KHTML based
243
+ /(flock|rockmelt|midori|epiphany|silk|skyfire|ovibrowser|bolt|iron|vivaldi|iridium|phantomjs|bowser|quark|qupzilla|falkon)\/([\w\.-]+)/i,
244
+ // Flock/RockMelt/Midori/Epiphany/Silk/Skyfire/Bolt/Iron/Iridium/PhantomJS/Bowser/QupZilla/Falkon
245
+ /(rekonq|puffin|brave|whale|qqbrowserlite|qq)\/([\w\.]+)/i, // Rekonq/Puffin/Brave/Whale/QQBrowserLite/QQ, aka ShouQ
242
246
  /(weibo)__([\d\.]+)/i // Weibo
243
247
  ], [NAME, VERSION], [
244
- /(?:\buc? ?browser|(?:juc.+)ucweb)[\/ ]?([\w\.]+)/i // UCBrowser
245
- ], [VERSION, [NAME, 'UC'+BROWSER]], [
246
- /microm.+\bqbcore\/([\w\.]+)/i, // WeChat Desktop for Windows Built-in Browser
247
- /\bqbcore\/([\w\.]+).+microm/i,
248
+ /(?:[\s\/]uc?\s?browser|(?:juc.+)ucweb)[\/\s]?([\w\.]+)/i // UCBrowser
249
+ ], [VERSION, [NAME, 'UCBrowser']], [
250
+ /(?:windowswechat)?\sqbcore\/([\w\.]+)\b.*(?:windowswechat)?/i // WeChat Desktop for Windows Built-in Browser
251
+ ], [VERSION, [NAME, 'WeChat(Win) Desktop']], [
248
252
  /micromessenger\/([\w\.]+)/i // WeChat
249
253
  ], [VERSION, [NAME, 'WeChat']], [
250
254
  /konqueror\/([\w\.]+)/i // Konqueror
251
255
  ], [VERSION, [NAME, 'Konqueror']], [
252
- /trident.+rv[: ]([\w\.]{1,9})\b.+like gecko/i // IE11
256
+ /trident.+rv[:\s]([\w\.]{1,9})\b.+like\sgecko/i // IE11
253
257
  ], [VERSION, [NAME, 'IE']], [
254
- /ya(?:search)?browser\/([\w\.]+)/i // Yandex
258
+ /yabrowser\/([\w\.]+)/i // Yandex
255
259
  ], [VERSION, [NAME, 'Yandex']], [
256
- /slbrowser\/([\w\.]+)/i // Smart Lenovo Browser
257
- ], [VERSION, [NAME, 'Smart Lenovo '+BROWSER]], [
258
260
  /(avast|avg)\/([\w\.]+)/i // Avast/AVG Secure Browser
259
- ], [[NAME, /(.+)/, '$1 Secure '+BROWSER], VERSION], [
260
- /\bfocus\/([\w\.]+)/i // Firefox Focus
261
- ], [VERSION, [NAME, FIREFOX+' Focus']], [
262
- /\bopt\/([\w\.]+)/i // Opera Touch
263
- ], [VERSION, [NAME, OPERA+' Touch']], [
264
- /coc_coc\w+\/([\w\.]+)/i // Coc Coc Browser
261
+ ], [[NAME, /(.+)/, '$1 Secure Browser'], VERSION], [
262
+ /focus\/([\w\.]+)/i // Firefox Focus
263
+ ], [VERSION, [NAME, 'Firefox Focus']], [
264
+ /opt\/([\w\.]+)/i // Opera Touch
265
+ ], [VERSION, [NAME, 'Opera Touch']], [
266
+ /coc_coc_browser\/([\w\.]+)/i // Coc Coc Browser
265
267
  ], [VERSION, [NAME, 'Coc Coc']], [
266
268
  /dolfin\/([\w\.]+)/i // Dolphin
267
269
  ], [VERSION, [NAME, 'Dolphin']], [
268
270
  /coast\/([\w\.]+)/i // Opera Coast
269
- ], [VERSION, [NAME, OPERA+' Coast']], [
270
- /miuibrowser\/([\w\.]+)/i // MIUI Browser
271
- ], [VERSION, [NAME, 'MIUI '+BROWSER]], [
272
- /fxios\/([-\w\.]+)/i // Firefox for iOS
273
- ], [VERSION, [NAME, FIREFOX]], [
274
- /\bqihu|(qi?ho?o?|360)browser/i // 360
275
- ], [[NAME, '360 ' + BROWSER]], [
276
- /(oculus|sailfish|huawei|vivo)browser\/([\w\.]+)/i
277
- ], [[NAME, /(.+)/, '$1 ' + BROWSER], VERSION], [ // Oculus/Sailfish/HuaweiBrowser/VivoBrowser
278
- /samsungbrowser\/([\w\.]+)/i // Samsung Internet
279
- ], [VERSION, [NAME, SAMSUNG + ' Internet']], [
271
+ ], [VERSION, [NAME, 'Opera Coast']],
272
+ [/xiaomi\/miuibrowser\/([\w\.]+)/i // MIUI Browser
273
+ ], [VERSION, [NAME, 'MIUI Browser']], [
274
+ /fxios\/([\w\.-]+)/i // Firefox for iOS
275
+ ], [VERSION, [NAME, 'Firefox']], [
276
+ /(qihu|qhbrowser|qihoobrowser|360browser)/i // 360
277
+ ], [[NAME, '360 Browser']], [
278
+ /(oculus|samsung|sailfish)browser\/([\w\.]+)/i
279
+ ], [[NAME, /(.+)/, '$1 Browser'], VERSION], [ // Oculus/Samsung/Sailfish Browser
280
280
  /(comodo_dragon)\/([\w\.]+)/i // Comodo Dragon
281
281
  ], [[NAME, /_/g, ' '], VERSION], [
282
- /metasr[\/ ]?([\d\.]+)/i // Sogou Explorer
283
- ], [VERSION, [NAME, 'Sogou Explorer']], [
284
- /(sogou)mo\w+\/([\d\.]+)/i // Sogou Mobile
285
- ], [[NAME, 'Sogou Mobile'], VERSION], [
286
- /(electron)\/([\w\.]+) safari/i, // Electron-based App
287
- /(tesla)(?: qtcarbrowser|\/(20\d\d\.[-\w\.]+))/i, // Tesla
288
- /m?(qqbrowser|2345Explorer)[\/ ]?([\w\.]+)/i // QQBrowser/2345 Browser
282
+ /\s(electron)\/([\w\.]+)\ssafari/i, // Electron-based App
283
+ /(tesla)(?:\sqtcarbrowser|\/(20[12]\d\.[\w\.-]+))/i, // Tesla
284
+ /m?(qqbrowser|baiduboxapp|2345Explorer)[\/\s]?([\w\.]+)/i // QQBrowser/Baidu App/2345 Browser
289
285
  ], [NAME, VERSION], [
290
- /(lbbrowser)/i, // LieBao Browser
291
- /\[(linkedin)app\]/i // LinkedIn App for iOS & Android
286
+ /(MetaSr)[\/\s]?([\w\.]+)/i, // SouGouBrowser
287
+ /(LBBROWSER)/i // LieBao Browser
292
288
  ], [NAME], [
293
289
 
294
290
  // WebView
295
- /((?:fban\/fbios|fb_iab\/fb4a)(?!.+fbav)|;fbav\/([\w\.]+);)/i // Facebook App for iOS & Android
296
- ], [[NAME, FACEBOOK], VERSION], [
297
- /(Klarna)\/([\w\.]+)/i, // Klarna Shopping Browser for iOS & Android
298
- /(kakao(?:talk|story))[\/ ]([\w\.]+)/i, // Kakao App
299
- /(naver)\(.*?(\d+\.[\w\.]+).*\)/i, // Naver InApp
300
- /safari (line)\/([\w\.]+)/i, // Line App for iOS
291
+ /;fbav\/([\w\.]+);/i // Facebook App for iOS & Android with version
292
+ ], [VERSION, [NAME, 'Facebook']], [
293
+ /FBAN\/FBIOS|FB_IAB\/FB4A/i // Facebook App for iOS & Android without version
294
+ ], [[NAME, 'Facebook']], [
295
+ /safari\s(line)\/([\w\.]+)/i, // Line App for iOS
301
296
  /\b(line)\/([\w\.]+)\/iab/i, // Line App for Android
302
- /(alipay)client\/([\w\.]+)/i, // Alipay
303
- /(chromium|instagram|snapchat)[\/ ]([-\w\.]+)/i // Chromium/Instagram/Snapchat
297
+ /(chromium|instagram)[\/\s]([\w\.-]+)/i // Chromium/Instagram
304
298
  ], [NAME, VERSION], [
305
- /\bgsa\/([\w\.]+) .*safari\//i // Google Search Appliance on iOS
299
+ /\bgsa\/([\w\.]+)\s.*safari\//i // Google Search Appliance on iOS
306
300
  ], [VERSION, [NAME, 'GSA']], [
307
- /musical_ly(?:.+app_?version\/|_)([\w\.]+)/i // TikTok
308
- ], [VERSION, [NAME, 'TikTok']], [
309
301
 
310
- /headlesschrome(?:\/([\w\.]+)| )/i // Chrome Headless
311
- ], [VERSION, [NAME, CHROME+' Headless']], [
302
+ /headlesschrome(?:\/([\w\.]+)|\s)/i // Chrome Headless
303
+ ], [VERSION, [NAME, 'Chrome Headless']], [
312
304
 
313
- / wv\).+(chrome)\/([\w\.]+)/i // Chrome WebView
314
- ], [[NAME, CHROME+' WebView'], VERSION], [
305
+ /\swv\).+(chrome)\/([\w\.]+)/i // Chrome WebView
306
+ ], [[NAME, 'Chrome WebView'], VERSION], [
315
307
 
316
- /droid.+ version\/([\w\.]+)\b.+(?:mobile safari|safari)/i // Android Browser
317
- ], [VERSION, [NAME, 'Android '+BROWSER]], [
308
+ /droid.+\sversion\/([\w\.]+)\b.+(?:mobile\ssafari|safari)/i // Android Browser
309
+ ], [VERSION, [NAME, 'Android Browser']], [
318
310
 
319
- /(chrome|omniweb|arora|[tizenoka]{5} ?browser)\/v?([\w\.]+)/i // Chrome/OmniWeb/Arora/Tizen/Nokia
311
+ /(chrome|omniweb|arora|[tizenoka]{5}\s?browser)\/v?([\w\.]+)/i // Chrome/OmniWeb/Arora/Tizen/Nokia
320
312
  ], [NAME, VERSION], [
321
313
 
322
- /version\/([\w\.\,]+) .*mobile\/\w+ (safari)/i // Mobile Safari
314
+ /version\/([\w\.]+)\s.*mobile\/\w+\s(safari)/i // Mobile Safari
323
315
  ], [VERSION, [NAME, 'Mobile Safari']], [
324
- /version\/([\w(\.|\,)]+) .*(mobile ?safari|safari)/i // Safari & Safari Mobile
316
+ /version\/([\w\.]+)\s.*(mobile\s?safari|safari)/i // Safari & Safari Mobile
325
317
  ], [VERSION, NAME], [
326
- /webkit.+?(mobile ?safari|safari)(\/[\w\.]+)/i // Safari < 3.0
327
- ], [NAME, [VERSION, strMapper, oldSafariMap]], [
318
+ /webkit.+?(mobile\s?safari|safari)(\/[\w\.]+)/i // Safari < 3.0
319
+ ], [NAME, [VERSION, mapper.str, maps.browser.oldSafari.version]], [
328
320
 
329
321
  /(webkit|khtml)\/([\w\.]+)/i
330
322
  ], [NAME, VERSION], [
331
323
 
332
324
  // Gecko based
333
- /(navigator|netscape\d?)\/([-\w\.]+)/i // Netscape
325
+ /(navigator|netscape)\/([\w\.-]+)/i // Netscape
334
326
  ], [[NAME, 'Netscape'], VERSION], [
335
- /mobile vr; rv:([\w\.]+)\).+firefox/i // Firefox Reality
336
- ], [VERSION, [NAME, FIREFOX+' Reality']], [
327
+ /ile\svr;\srv:([\w\.]+)\).+firefox/i // Firefox Reality
328
+ ], [VERSION, [NAME, 'Firefox Reality']], [
337
329
  /ekiohf.+(flow)\/([\w\.]+)/i, // Flow
338
330
  /(swiftfox)/i, // Swiftfox
339
- /(icedragon|iceweasel|camino|chimera|fennec|maemo browser|minimo|conkeror|klar)[\/ ]?([\w\.\+]+)/i,
340
- // IceDragon/Iceweasel/Camino/Chimera/Fennec/Maemo/Minimo/Conkeror/Klar
341
- /(seamonkey|k-meleon|icecat|iceape|firebird|phoenix|palemoon|basilisk|waterfox)\/([-\w\.]+)$/i,
331
+ /(icedragon|iceweasel|camino|chimera|fennec|maemo\sbrowser|minimo|conkeror)[\/\s]?([\w\.\+]+)/i,
332
+ // IceDragon/Iceweasel/Camino/Chimera/Fennec/Maemo/Minimo/Conkeror
333
+ /(firefox|seamonkey|k-meleon|icecat|iceape|firebird|phoenix|palemoon|basilisk|waterfox)\/([\w\.-]+)$/i,
342
334
  // Firefox/SeaMonkey/K-Meleon/IceCat/IceApe/Firebird/Phoenix
343
- /(firefox)\/([\w\.]+)/i, // Other Firefox-based
344
- /(mozilla)\/([\w\.]+) .+rv\:.+gecko\/\d+/i, // Mozilla
335
+ /(firefox)\/([\w\.]+)\s[\w\s\-]+\/[\w\.]+$/i, // Other Firefox-based
336
+ /(mozilla)\/([\w\.]+)\s.+rv\:.+gecko\/\d+/i, // Mozilla
345
337
 
346
338
  // Other
347
- /(polaris|lynx|dillo|icab|doris|amaya|w3m|netsurf|sleipnir|obigo|mosaic|(?:go|ice|up)[\. ]?browser)[-\/ ]?v?([\w\.]+)/i,
348
- // Polaris/Lynx/Dillo/iCab/Doris/Amaya/w3m/NetSurf/Sleipnir/Obigo/Mosaic/Go/ICE/UP.Browser
349
- /(links) \(([\w\.]+)/i, // Links
350
- /panasonic;(viera)/i // Panasonic Viera
351
- ], [NAME, VERSION], [
352
-
353
- /(cobalt)\/([\w\.]+)/i // Cobalt
354
- ], [NAME, [VERSION, /master.|lts./, ""]]
339
+ /(polaris|lynx|dillo|icab|doris|amaya|w3m|netsurf|sleipnir)[\/\s]?([\w\.]+)/i,
340
+ // Polaris/Lynx/Dillo/iCab/Doris/Amaya/w3m/NetSurf/Sleipnir
341
+ /(links)\s\(([\w\.]+)/i, // Links
342
+ /(gobrowser)\/?([\w\.]*)/i, // GoBrowser
343
+ /(ice\s?browser)\/v?([\w\._]+)/i, // ICE Browser
344
+ /(mosaic)[\/\s]([\w\.]+)/i // Mosaic
345
+ ], [NAME, VERSION]
355
346
  ],
356
347
 
357
348
  cpu : [[
358
349
 
359
- /(?:(amd|x(?:(?:86|64)[-_])?|wow|win)64)[;\)]/i // AMD64 (x64)
350
+ /(?:(amd|x(?:(?:86|64)[_-])?|wow|win)64)[;\)]/i // AMD64 (x64)
360
351
  ], [[ARCHITECTURE, 'amd64']], [
361
352
 
362
353
  /(ia32(?=;))/i // IA32 (quicktime)
363
- ], [[ARCHITECTURE, lowerize]], [
354
+ ], [[ARCHITECTURE, util.lowerize]], [
364
355
 
365
356
  /((?:i[346]|x)86)[;\)]/i // IA32 (x86)
366
357
  ], [[ARCHITECTURE, 'ia32']], [
367
358
 
368
- /\b(aarch64|arm(v?8e?l?|_?64))\b/i // ARM64
359
+ /\b(aarch64|armv?8e?l?)\b/i // ARM64
369
360
  ], [[ARCHITECTURE, 'arm64']], [
370
361
 
371
362
  /\b(arm(?:v[67])?ht?n?[fl]p?)\b/i // ARMHF
372
363
  ], [[ARCHITECTURE, 'armhf']], [
373
364
 
374
365
  // PocketPC mistakenly identified as PowerPC
375
- /windows (ce|mobile); ppc;/i
366
+ /windows\s(ce|mobile);\sppc;/i
376
367
  ], [[ARCHITECTURE, 'arm']], [
377
368
 
378
- /((?:ppc|powerpc)(?:64)?)(?: mac|;|\))/i // PowerPC
379
- ], [[ARCHITECTURE, /ower/, EMPTY, lowerize]], [
369
+ /((?:ppc|powerpc)(?:64)?)(?:\smac|;|\))/i // PowerPC
370
+ ], [[ARCHITECTURE, /ower/, '', util.lowerize]], [
380
371
 
381
372
  /(sun4\w)[;\)]/i // SPARC
382
373
  ], [[ARCHITECTURE, 'sparc']], [
383
374
 
384
- /((?:avr32|ia64(?=;))|68k(?=\))|\barm(?=v(?:[1-7]|[5-7]1)l?|;|eabi)|(?=atmel )avr|(?:irix|mips|sparc)(?:64)?\b|pa-risc)/i
375
+ /((?:avr32|ia64(?=;))|68k(?=\))|\barm(?:64|(?=v(?:[1-7]|[5-7]1)l?|;|eabi))|(?=atmel\s)avr|(?:irix|mips|sparc)(?:64)?\b|pa-risc)/i
385
376
  // IA64, 68K, ARM/64, AVR/32, IRIX/64, MIPS/64, SPARC/64, PA-RISC
386
- ], [[ARCHITECTURE, lowerize]]
377
+ ], [[ARCHITECTURE, util.lowerize]]
387
378
  ],
388
379
 
389
380
  device : [[
390
381
 
391
382
  //////////////////////////
392
383
  // MOBILES & TABLETS
384
+ // Ordered by popularity
393
385
  /////////////////////////
394
386
 
395
387
  // Samsung
396
- /\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
397
- ], [MODEL, [VENDOR, SAMSUNG], [TYPE, TABLET]], [
398
- /\b((?:s[cgp]h|gt|sm)-\w+|sc[g-]?[\d]+a?|galaxy nexus)/i,
399
- /samsung[- ]([-\w]+)/i,
388
+ /\b(sch-i[89]0\d|shw-m380s|sm-[pt]\w{2,4}|gt-[pn]\d{2,4}|sgh-t8[56]9|nexus\s10)/i
389
+ ], [MODEL, [VENDOR, 'Samsung'], [TYPE, TABLET]], [
390
+ /\b((?:s[cgp]h|gt|sm)-\w+|galaxy\snexus)/i,
391
+ /\ssamsung[\s-]([\w-]+)/i,
400
392
  /sec-(sgh\w+)/i
401
- ], [MODEL, [VENDOR, SAMSUNG], [TYPE, MOBILE]], [
393
+ ], [MODEL, [VENDOR, 'Samsung'], [TYPE, MOBILE]], [
402
394
 
403
395
  // Apple
404
- /(?:\/|\()(ip(?:hone|od)[\w, ]*)(?:\/|;)/i // iPod/iPhone
405
- ], [MODEL, [VENDOR, APPLE], [TYPE, MOBILE]], [
406
- /\((ipad);[-\w\),; ]+apple/i, // iPad
407
- /applecoremedia\/[\w\.]+ \((ipad)/i,
396
+ /\((ip(?:hone|od)[\s\w]*);/i // iPod/iPhone
397
+ ], [MODEL, [VENDOR, 'Apple'], [TYPE, MOBILE]], [
398
+ /\((ipad);[\w\s\),;-]+apple/i, // iPad
399
+ /applecoremedia\/[\w\.]+\s\((ipad)/i,
408
400
  /\b(ipad)\d\d?,\d\d?[;\]].+ios/i
409
- ], [MODEL, [VENDOR, APPLE], [TYPE, TABLET]], [
410
- /(macintosh);/i
411
- ], [MODEL, [VENDOR, APPLE]], [
412
-
413
- // Sharp
414
- /\b(sh-?[altvz]?\d\d[a-ekm]?)/i
415
- ], [MODEL, [VENDOR, SHARP], [TYPE, MOBILE]], [
401
+ ], [MODEL, [VENDOR, 'Apple'], [TYPE, TABLET]], [
416
402
 
417
403
  // Huawei
418
- /\b((?:ag[rs][23]?|bah2?|sht?|btv)-a?[lw]\d{2})\b(?!.+d\/s)/i
419
- ], [MODEL, [VENDOR, HUAWEI], [TYPE, TABLET]], [
420
- /(?:huawei|honor)([-\w ]+)[;\)]/i,
421
- /\b(nexus 6p|\w{2,4}e?-[atu]?[ln][\dx][012359c][adn]?)\b(?!.+d\/s)/i
422
- ], [MODEL, [VENDOR, HUAWEI], [TYPE, MOBILE]], [
404
+ /\b((?:agr|ags[23]|bah2?|sht?)-a?[lw]\d{2})/i,
405
+ ], [MODEL, [VENDOR, 'Huawei'], [TYPE, TABLET]], [
406
+ /d\/huawei([\w\s-]+)[;\)]/i,
407
+ /\b(nexus\s6p|vog-[at]?l\d\d|ane-[at]?l[x\d]\d|eml-a?l\d\da?|lya-[at]?l\d[\dc]|clt-a?l\d\di?|ele-l\d\d)/i,
408
+ /\b(\w{2,4}-[atu][ln][01259][019])[;\)\s]/i
409
+ ], [MODEL, [VENDOR, 'Huawei'], [TYPE, MOBILE]], [
423
410
 
424
411
  // Xiaomi
425
- /\b(poco[\w ]+|m2\d{3}j\d\d[a-z]{2})(?: bui|\))/i, // Xiaomi POCO
426
- /\b; (\w+) build\/hm\1/i, // Xiaomi Hongmi 'numeric' models
427
- /\b(hm[-_ ]?note?[_ ]?(?:\d\w)?) bui/i, // Xiaomi Hongmi
428
- /\b(redmi[\-_ ]?(?:note|k)?[\w_ ]+)(?: bui|\))/i, // Xiaomi Redmi
429
- /oid[^\)]+; (m?[12][0-389][01]\w{3,6}[c-y])( bui|; wv|\))/i, // Xiaomi Redmi 'numeric' models
430
- /\b(mi[-_ ]?(?:a\d|one|one[_ ]plus|note lte|max|cc)?[_ ]?(?:\d?\w?)[_ ]?(?:plus|se|lite)?)(?: bui|\))/i // Xiaomi Mi
431
- ], [[MODEL, /_/g, ' '], [VENDOR, XIAOMI], [TYPE, MOBILE]], [
432
- /oid[^\)]+; (2\d{4}(283|rpbf)[cgl])( bui|\))/i, // Redmi Pad
433
- /\b(mi[-_ ]?(?:pad)(?:[\w_ ]+))(?: bui|\))/i // Mi Pad tablets
434
- ],[[MODEL, /_/g, ' '], [VENDOR, XIAOMI], [TYPE, TABLET]], [
412
+ /\b(poco[\s\w]+)(?:\sbuild|\))/i, // Xiaomi POCO
413
+ /\b;\s(\w+)\sbuild\/hm\1/i, // Xiaomi Hongmi 'numeric' models
414
+ /\b(hm[\s\-_]?note?[\s_]?(?:\d\w)?)\sbuild/i, // Xiaomi Hongmi
415
+ /\b(redmi[\s\-_]?(?:note|k)?[\w\s_]+)(?:\sbuild|\))/i, // Xiaomi Redmi
416
+ /\b(mi[\s\-_]?(?:a\d|one|one[\s_]plus|note lte)?[\s_]?(?:\d?\w?)[\s_]?(?:plus)?)\sbuild/i // Xiaomi Mi
417
+ ], [[MODEL, /_/g, ' '], [VENDOR, 'Xiaomi'], [TYPE, MOBILE]], [
418
+ /\b(mi[\s\-_]?(?:pad)(?:[\w\s_]+))(?:\sbuild|\))/i // Mi Pad tablets
419
+ ],[[MODEL, /_/g, ' '], [VENDOR, 'Xiaomi'], [TYPE, TABLET]], [
435
420
 
436
421
  // OPPO
437
- /; (\w+) bui.+ oppo/i,
438
- /\b(cph[12]\d{3}|p(?:af|c[al]|d\w|e[ar])[mt]\d0|x9007|a101op)\b/i
422
+ /;\s(\w+)\sbuild.+\soppo/i,
423
+ /\s(cph[12]\d{3}|p(?:af|c[al]|d\w|e[ar])[mt]\d0|x9007)\b/i
439
424
  ], [MODEL, [VENDOR, 'OPPO'], [TYPE, MOBILE]], [
440
425
 
441
426
  // Vivo
442
- /vivo (\w+)(?: bui|\))/i,
443
- /\b(v[12]\d{3}\w?[at])(?: bui|;)/i
427
+ /\svivo\s(\w+)(?:\sbuild|\))/i,
428
+ /\s(v[12]\d{3}\w?[at])(?:\sbuild|;)/i
444
429
  ], [MODEL, [VENDOR, 'Vivo'], [TYPE, MOBILE]], [
445
430
 
446
431
  // Realme
447
- /\b(rmx[1-3]\d{3})(?: bui|;|\))/i
432
+ /\s(rmx[12]\d{3})(?:\sbuild|;)/i
448
433
  ], [MODEL, [VENDOR, 'Realme'], [TYPE, MOBILE]], [
449
434
 
450
435
  // Motorola
451
- /\b(milestone|droid(?:[2-4x]| (?:bionic|x2|pro|razr))?:?( 4g)?)\b[\w ]+build\//i,
452
- /\bmot(?:orola)?[- ](\w*)/i,
453
- /((?:moto[\w\(\) ]+|xt\d{3,4}|nexus 6)(?= bui|\)))/i
454
- ], [MODEL, [VENDOR, MOTOROLA], [TYPE, MOBILE]], [
455
- /\b(mz60\d|xoom[2 ]{0,2}) build\//i
456
- ], [MODEL, [VENDOR, MOTOROLA], [TYPE, TABLET]], [
436
+ /\s(milestone|droid(?:[2-4x]|\s(?:bionic|x2|pro|razr))?:?(\s4g)?)\b[\w\s]+build\//i,
437
+ /\smot(?:orola)?[\s-](\w*)/i,
438
+ /((?:moto[\s\w\(\)]+|xt\d{3,4}|nexus\s6)(?=\sbuild|\)))/i
439
+ ], [MODEL, [VENDOR, 'Motorola'], [TYPE, MOBILE]], [
440
+ /\s(mz60\d|xoom[\s2]{0,2})\sbuild\//i
441
+ ], [MODEL, [VENDOR, 'Motorola'], [TYPE, TABLET]], [
457
442
 
458
443
  // LG
459
- /((?=lg)?[vl]k\-?\d{3}) bui| 3\.[-\w; ]{10}lg?-([06cv9]{3,4})/i
460
- ], [MODEL, [VENDOR, LG], [TYPE, TABLET]], [
461
- /(lm(?:-?f100[nv]?|-[\w\.]+)(?= bui|\))|nexus [45])/i,
462
- /\blg[-e;\/ ]+((?!browser|netcast|android tv)\w+)/i,
463
- /\blg-?([\d\w]+) bui/i
464
- ], [MODEL, [VENDOR, LG], [TYPE, MOBILE]], [
444
+ /((?=lg)?[vl]k\-?\d{3})\sbuild|\s3\.[\s\w;-]{10}lg?-([06cv9]{3,4})/i
445
+ ], [MODEL, [VENDOR, 'LG'], [TYPE, TABLET]], [
446
+ /(lm-?f100[nv]?|nexus\s[45])/i,
447
+ /lg[e;\s\/-]+((?!browser|netcast)\w+)/i,
448
+ /\blg(\-?[\d\w]+)\sbuild/i
449
+ ], [MODEL, [VENDOR, 'LG'], [TYPE, MOBILE]], [
465
450
 
466
451
  // Lenovo
467
- /(ideatab[-\w ]+)/i,
468
- /lenovo ?(s[56]000[-\w]+|tab(?:[\w ]+)|yt[-\d\w]{6}|tb[-\d\w]{6})/i
452
+ /(ideatab[\w\-\s]+)/i,
453
+ /lenovo\s?(s(?:5000|6000)(?:[\w-]+)|tab(?:[\s\w]+)|yt[\d\w-]{6}|tb[\d\w-]{6})/i // Lenovo tablets
469
454
  ], [MODEL, [VENDOR, 'Lenovo'], [TYPE, TABLET]], [
470
455
 
471
456
  // Nokia
472
- /(?:maemo|nokia).*(n900|lumia \d+)/i,
473
- /nokia[-_ ]?([-\w\.]*)/i
457
+ /(?:maemo|nokia).*(n900|lumia\s\d+)/i,
458
+ /nokia[\s_-]?([\w\.-]*)/i
474
459
  ], [[MODEL, /_/g, ' '], [VENDOR, 'Nokia'], [TYPE, MOBILE]], [
475
460
 
476
461
  // Google
477
- /(pixel c)\b/i // Google Pixel C
478
- ], [MODEL, [VENDOR, GOOGLE], [TYPE, TABLET]], [
479
- /droid.+; (pixel[\daxl ]{0,6})(?: bui|\))/i // Google Pixel
480
- ], [MODEL, [VENDOR, GOOGLE], [TYPE, MOBILE]], [
462
+ /droid.+;\s(pixel\sc)[\s)]/i // Google Pixel C
463
+ ], [MODEL, [VENDOR, 'Google'], [TYPE, TABLET]], [
464
+ /droid.+;\s(pixel[\s\daxl]{0,6})(?:\sbuild|\))/i // Google Pixel
465
+ ], [MODEL, [VENDOR, 'Google'], [TYPE, MOBILE]], [
481
466
 
482
467
  // Sony
483
- /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
484
- ], [MODEL, [VENDOR, SONY], [TYPE, MOBILE]], [
485
- /sony tablet [ps]/i,
486
- /\b(?:sony)?sgp\w+(?: bui|\))/i
487
- ], [[MODEL, 'Xperia Tablet'], [VENDOR, SONY], [TYPE, TABLET]], [
468
+ /droid.+\s([c-g]\d{4}|so[-l]\w+|xq-a\w[4-7][12])(?=\sbuild\/|\).+chrome\/(?![1-6]{0,1}\d\.))/i
469
+ ], [MODEL, [VENDOR, 'Sony'], [TYPE, MOBILE]], [
470
+ /sony\stablet\s[ps]\sbuild\//i,
471
+ /(?:sony)?sgp\w+(?:\sbuild\/|\))/i
472
+ ], [[MODEL, 'Xperia Tablet'], [VENDOR, 'Sony'], [TYPE, TABLET]], [
488
473
 
489
474
  // OnePlus
490
- / (kb2005|in20[12]5|be20[12][59])\b/i,
491
- /(?:one)?(?:plus)? (a\d0\d\d)(?: b|\))/i
475
+ /\s(kb2005|in20[12]5|be20[12][59])\b/i,
476
+ /\ba000(1)\sbuild/i, // OnePlus
477
+ /\boneplus\s(a\d{4})[\s)]/i
492
478
  ], [MODEL, [VENDOR, 'OnePlus'], [TYPE, MOBILE]], [
493
479
 
494
480
  // Amazon
495
481
  /(alexa)webm/i,
496
- /(kf[a-z]{2}wi|aeo[c-r]{2})( bui|\))/i, // Kindle Fire without Silk / Echo Show
497
- /(kf[a-z]+)( bui|\)).+silk\//i // Kindle Fire HD
498
- ], [MODEL, [VENDOR, AMAZON], [TYPE, TABLET]], [
499
- /((?:sd|kf)[0349hijorstuw]+)( bui|\)).+silk\//i // Fire Phone
500
- ], [[MODEL, /(.+)/g, 'Fire Phone $1'], [VENDOR, AMAZON], [TYPE, MOBILE]], [
482
+ /(kf[a-z]{2}wi)(\sbuild\/|\))/i, // Kindle Fire without Silk
483
+ /(kf[a-z]+)(\sbuild\/|\)).+silk\//i // Kindle Fire HD
484
+ ], [MODEL, [VENDOR, 'Amazon'], [TYPE, TABLET]], [
485
+ /(sd|kf)[0349hijorstuw]+(\sbuild\/|\)).+silk\//i // Fire Phone
486
+ ], [[MODEL, 'Fire Phone'], [VENDOR, 'Amazon'], [TYPE, MOBILE]], [
501
487
 
502
488
  // BlackBerry
503
- /(playbook);[-\w\),; ]+(rim)/i // BlackBerry PlayBook
489
+ /\((playbook);[\w\s\),;-]+(rim)/i // BlackBerry PlayBook
504
490
  ], [MODEL, VENDOR, [TYPE, TABLET]], [
505
- /\b((?:bb[a-f]|st[hv])100-\d)/i,
506
- /\(bb10; (\w+)/i // BlackBerry 10
507
- ], [MODEL, [VENDOR, BLACKBERRY], [TYPE, MOBILE]], [
491
+ /((?:bb[a-f]|st[hv])100-\d)/i,
492
+ /\(bb10;\s(\w+)/i // BlackBerry 10
493
+ ], [MODEL, [VENDOR, 'BlackBerry'], [TYPE, MOBILE]], [
508
494
 
509
495
  // Asus
510
- /(?:\b|asus_)(transfo[prime ]{4,10} \w+|eeepc|slider \w+|nexus 7|padfone|p00[cj])/i
511
- ], [MODEL, [VENDOR, ASUS], [TYPE, TABLET]], [
512
- / (z[bes]6[027][012][km][ls]|zenfone \d\w?)\b/i
513
- ], [MODEL, [VENDOR, ASUS], [TYPE, MOBILE]], [
496
+ /(?:\b|asus_)(transfo[prime\s]{4,10}\s\w+|eeepc|slider\s\w+|nexus\s7|padfone|p00[cj])/i
497
+ ], [MODEL, [VENDOR, 'ASUS'], [TYPE, TABLET]], [
498
+ /\s(z[es]6[027][01][km][ls]|zenfone\s\d\w?)\b/i
499
+ ], [MODEL, [VENDOR, 'ASUS'], [TYPE, MOBILE]], [
514
500
 
515
501
  // HTC
516
- /(nexus 9)/i // HTC Nexus 9
502
+ /(nexus\s9)/i // HTC Nexus 9
517
503
  ], [MODEL, [VENDOR, 'HTC'], [TYPE, TABLET]], [
518
- /(htc)[-;_ ]{1,2}([\w ]+(?=\)| bui)|\w+)/i, // HTC
504
+ /(htc)[;_\s-]{1,2}([\w\s]+(?=\)|\sbuild)|\w+)/i, // HTC
519
505
 
520
506
  // ZTE
521
- /(zte)[- ]([\w ]+?)(?: bui|\/|\))/i,
522
- /(alcatel|geeksphone|nexian|panasonic(?!(?:;|\.))|sony(?!-bra))[-_ ]?([-\w]*)/i // Alcatel/GeeksPhone/Nexian/Panasonic/Sony
507
+ /(zte)-(\w*)/i,
508
+ /(alcatel|geeksphone|nexian|panasonic|(?=;\s)sony)[_\s-]?([\w-]*)/i // Alcatel/GeeksPhone/Nexian/Panasonic/Sony
523
509
  ], [VENDOR, [MODEL, /_/g, ' '], [TYPE, MOBILE]], [
524
510
 
525
511
  // Acer
526
- /droid.+; ([ab][1-7]-?[0178a]\d\d?)/i
512
+ /droid[x\d\.\s;]+\s([ab][1-7]\-?[0178a]\d\d?)/i
527
513
  ], [MODEL, [VENDOR, 'Acer'], [TYPE, TABLET]], [
528
514
 
529
515
  // Meizu
530
- /droid.+; (m[1-5] note) bui/i,
531
- /\bmz-([-\w]{2,})/i
516
+ /droid.+;\s(m[1-5]\snote)\sbuild/i,
517
+ /\bmz-([\w-]{2,})/i
532
518
  ], [MODEL, [VENDOR, 'Meizu'], [TYPE, MOBILE]], [
533
-
534
- // Ulefone
535
- /; ((?:power )?armor(?:[\w ]{0,8}))(?: bui|\))/i
536
- ], [MODEL, [VENDOR, 'Ulefone'], [TYPE, MOBILE]], [
537
519
 
538
520
  // MIXED
539
- /(blackberry|benq|palm(?=\-)|sonyericsson|acer|asus|dell|meizu|motorola|polytron|infinix|tecno)[-_ ]?([-\w]*)/i,
521
+ /(blackberry|benq|palm(?=\-)|sonyericsson|acer|asus|dell|meizu|motorola|polytron)[\s_-]?([\w-]*)/i,
540
522
  // BlackBerry/BenQ/Palm/Sony-Ericsson/Acer/Asus/Dell/Meizu/Motorola/Polytron
541
- /(hp) ([\w ]+\w)/i, // HP iPAQ
523
+ /(hp)\s([\w\s]+\w)/i, // HP iPAQ
542
524
  /(asus)-?(\w+)/i, // Asus
543
- /(microsoft); (lumia[\w ]+)/i, // Microsoft Lumia
544
- /(lenovo)[-_ ]?([-\w]+)/i, // Lenovo
545
- /(jolla)/i, // Jolla
546
- /(oppo) ?([\w ]+) bui/i // OPPO
525
+ /(microsoft);\s(lumia[\s\w]+)/i, // Microsoft Lumia
526
+ /(lenovo)[_\s-]?([\w-]+)/i, // Lenovo
527
+ /linux;.+(jolla);/i, // Jolla
528
+ /droid.+;\s(oppo)\s?([\w\s]+)\sbuild/i // OPPO
547
529
  ], [VENDOR, MODEL, [TYPE, MOBILE]], [
548
530
 
549
- /(kobo)\s(ereader|touch)/i, // Kobo
550
- /(archos) (gamepad2?)/i, // Archos
531
+ /(archos)\s(gamepad2?)/i, // Archos
551
532
  /(hp).+(touchpad(?!.+tablet)|tablet)/i, // HP TouchPad
552
533
  /(kindle)\/([\w\.]+)/i, // Kindle
553
- /(nook)[\w ]+build\/(\w+)/i, // Nook
554
- /(dell) (strea[kpr\d ]*[\dko])/i, // Dell Streak
555
- /(le[- ]+pan)[- ]+(\w{1,9}) bui/i, // Le Pan Tablets
556
- /(trinity)[- ]*(t\d{3}) bui/i, // Trinity Tablets
557
- /(gigaset)[- ]+(q\w{1,9}) bui/i, // Gigaset Tablets
558
- /(vodafone) ([\w ]+)(?:\)| bui)/i // Vodafone
534
+ /\s(nook)[\w\s]+build\/(\w+)/i, // Nook
535
+ /(dell)\s(strea[kpr\s\d]*[\dko])/i, // Dell Streak
536
+ /[;\/]\s?(le[\s\-]+pan)[\s\-]+(\w{1,9})\sbuild/i, // Le Pan Tablets
537
+ /[;\/]\s?(trinity)[\-\s]*(t\d{3})\sbuild/i, // Trinity Tablets
538
+ /\b(gigaset)[\s\-]+(q\w{1,9})\sbuild/i, // Gigaset Tablets
539
+ /\b(vodafone)\s([\w\s]+)(?:\)|\sbuild)/i // Vodafone
559
540
  ], [VENDOR, MODEL, [TYPE, TABLET]], [
560
541
 
561
- /(surface duo)/i // Surface Duo
562
- ], [MODEL, [VENDOR, MICROSOFT], [TYPE, TABLET]], [
563
- /droid [\d\.]+; (fp\du?)(?: b|\))/i // Fairphone
542
+ /\s(surface\sduo)\s/i // Surface Duo
543
+ ], [MODEL, [VENDOR, 'Microsoft'], [TYPE, TABLET]], [
544
+ /droid\s[\d\.]+;\s(fp\du?)\sbuild/i
564
545
  ], [MODEL, [VENDOR, 'Fairphone'], [TYPE, MOBILE]], [
565
- /(u304aa)/i // AT&T
546
+ /\s(u304aa)\sbuild/i // AT&T
566
547
  ], [MODEL, [VENDOR, 'AT&T'], [TYPE, MOBILE]], [
567
- /\bsie-(\w*)/i // Siemens
548
+ /sie-(\w*)/i // Siemens
568
549
  ], [MODEL, [VENDOR, 'Siemens'], [TYPE, MOBILE]], [
569
- /\b(rct\w+) b/i // RCA Tablets
550
+ /[;\/]\s?(rct\w+)\sbuild/i // RCA Tablets
570
551
  ], [MODEL, [VENDOR, 'RCA'], [TYPE, TABLET]], [
571
- /\b(venue[\d ]{2,7}) b/i // Dell Venue Tablets
552
+ /[;\/\s](venue[\d\s]{2,7})\sbuild/i // Dell Venue Tablets
572
553
  ], [MODEL, [VENDOR, 'Dell'], [TYPE, TABLET]], [
573
- /\b(q(?:mv|ta)\w+) b/i // Verizon Tablet
554
+ /[;\/]\s?(q(?:mv|ta)\w+)\sbuild/i // Verizon Tablet
574
555
  ], [MODEL, [VENDOR, 'Verizon'], [TYPE, TABLET]], [
575
- /\b(?:barnes[& ]+noble |bn[rt])([\w\+ ]*) b/i // Barnes & Noble Tablet
556
+ /[;\/]\s(?:barnes[&\s]+noble\s|bn[rt])([\w\s\+]*)\sbuild/i // Barnes & Noble Tablet
576
557
  ], [MODEL, [VENDOR, 'Barnes & Noble'], [TYPE, TABLET]], [
577
- /\b(tm\d{3}\w+) b/i
558
+ /[;\/]\s(tm\d{3}\w+)\sbuild/i
578
559
  ], [MODEL, [VENDOR, 'NuVision'], [TYPE, TABLET]], [
579
- /\b(k88) b/i // ZTE K Series Tablet
560
+ /;\s(k88)\sbuild/i // ZTE K Series Tablet
580
561
  ], [MODEL, [VENDOR, 'ZTE'], [TYPE, TABLET]], [
581
- /\b(nx\d{3}j) b/i // ZTE Nubia
562
+ /;\s(nx\d{3}j)\sbuild/i // ZTE Nubia
582
563
  ], [MODEL, [VENDOR, 'ZTE'], [TYPE, MOBILE]], [
583
- /\b(gen\d{3}) b.+49h/i // Swiss GEN Mobile
564
+ /[;\/]\s?(gen\d{3})\sbuild.*49h/i // Swiss GEN Mobile
584
565
  ], [MODEL, [VENDOR, 'Swiss'], [TYPE, MOBILE]], [
585
- /\b(zur\d{3}) b/i // Swiss ZUR Tablet
566
+ /[;\/]\s?(zur\d{3})\sbuild/i // Swiss ZUR Tablet
586
567
  ], [MODEL, [VENDOR, 'Swiss'], [TYPE, TABLET]], [
587
- /\b((zeki)?tb.*\b) b/i // Zeki Tablets
568
+ /[;\/]\s?((zeki)?tb.*\b)\sbuild/i // Zeki Tablets
588
569
  ], [MODEL, [VENDOR, 'Zeki'], [TYPE, TABLET]], [
589
- /\b([yr]\d{2}) b/i,
590
- /\b(dragon[- ]+touch |dt)(\w{5}) b/i // Dragon Touch Tablet
570
+ /[;\/]\s([yr]\d{2})\sbuild/i,
571
+ /[;\/]\s(dragon[\-\s]+touch\s|dt)(\w{5})\sbuild/i // Dragon Touch Tablet
591
572
  ], [[VENDOR, 'Dragon Touch'], MODEL, [TYPE, TABLET]], [
592
- /\b(ns-?\w{0,9}) b/i // Insignia Tablets
573
+ /[;\/]\s?(ns-?\w{0,9})\sbuild/i // Insignia Tablets
593
574
  ], [MODEL, [VENDOR, 'Insignia'], [TYPE, TABLET]], [
594
- /\b((nxa|next)-?\w{0,9}) b/i // NextBook Tablets
575
+ /[;\/]\s?((nxa|Next)-?\w{0,9})\sbuild/i // NextBook Tablets
595
576
  ], [MODEL, [VENDOR, 'NextBook'], [TYPE, TABLET]], [
596
- /\b(xtreme\_)?(v(1[045]|2[015]|[3469]0|7[05])) b/i // Voice Xtreme Phones
597
- ], [[VENDOR, 'Voice'], MODEL, [TYPE, MOBILE]], [
598
- /\b(lvtel\-)?(v1[12]) b/i // LvTel Phones
577
+ /[;\/]\s?(xtreme\_)?(v(1[045]|2[015]|[3469]0|7[05]))\sbuild/i
578
+ ], [[VENDOR, 'Voice'], MODEL, [TYPE, MOBILE]], [ // Voice Xtreme Phones
579
+ /[;\/]\s?(lvtel\-)?(v1[12])\sbuild/i // LvTel Phones
599
580
  ], [[VENDOR, 'LvTel'], MODEL, [TYPE, MOBILE]], [
600
- /\b(ph-1) /i // Essential PH-1
601
- ], [MODEL, [VENDOR, 'Essential'], [TYPE, MOBILE]], [
602
- /\b(v(100md|700na|7011|917g).*\b) b/i // Envizen Tablets
581
+ /;\s(ph-1)\s/i
582
+ ], [MODEL, [VENDOR, 'Essential'], [TYPE, MOBILE]], [ // Essential PH-1
583
+ /[;\/]\s?(v(100md|700na|7011|917g).*\b)\sbuild/i // Envizen Tablets
603
584
  ], [MODEL, [VENDOR, 'Envizen'], [TYPE, TABLET]], [
604
- /\b(trio[-\w\. ]+) b/i // MachSpeed Tablets
585
+ /[;\/]\s?(trio[\s\w\-\.]+)\sbuild/i // MachSpeed Tablets
605
586
  ], [MODEL, [VENDOR, 'MachSpeed'], [TYPE, TABLET]], [
606
- /\btu_(1491) b/i // Rotor Tablets
587
+ /[;\/]\s?tu_(1491)\sbuild/i // Rotor Tablets
607
588
  ], [MODEL, [VENDOR, 'Rotor'], [TYPE, TABLET]], [
608
- /(shield[\w ]+) b/i // Nvidia Shield Tablets
589
+ /(shield[\w\s]+)\sbuild/i // Nvidia Shield Tablets
609
590
  ], [MODEL, [VENDOR, 'Nvidia'], [TYPE, TABLET]], [
610
- /(sprint) (\w+)/i // Sprint Phones
591
+ /(sprint)\s(\w+)/i // Sprint Phones
611
592
  ], [VENDOR, MODEL, [TYPE, MOBILE]], [
612
593
  /(kin\.[onetw]{3})/i // Microsoft Kin
613
- ], [[MODEL, /\./g, ' '], [VENDOR, MICROSOFT], [TYPE, MOBILE]], [
614
- /droid.+; (cc6666?|et5[16]|mc[239][23]x?|vc8[03]x?)\)/i // Zebra
615
- ], [MODEL, [VENDOR, ZEBRA], [TYPE, TABLET]], [
616
- /droid.+; (ec30|ps20|tc[2-8]\d[kx])\)/i
617
- ], [MODEL, [VENDOR, ZEBRA], [TYPE, MOBILE]], [
594
+ ], [[MODEL, /\./g, ' '], [VENDOR, 'Microsoft'], [TYPE, MOBILE]], [
595
+ /droid\s[\d\.]+;\s(cc6666?|et5[16]|mc[239][23]x?|vc8[03]x?)\)/i // Zebra
596
+ ], [MODEL, [VENDOR, 'Zebra'], [TYPE, TABLET]], [
597
+ /droid\s[\d\.]+;\s(ec30|ps20|tc[2-8]\d[kx])\)/i
598
+ ], [MODEL, [VENDOR, 'Zebra'], [TYPE, MOBILE]], [
599
+
600
+ ///////////////////
601
+ // CONSOLES
602
+ ///////////////////
603
+
604
+ /\s(ouya)\s/i, // Ouya
605
+ /(nintendo)\s([wids3utch]+)/i // Nintendo
606
+ ], [VENDOR, MODEL, [TYPE, CONSOLE]], [
607
+ /droid.+;\s(shield)\sbuild/i // Nvidia
608
+ ], [MODEL, [VENDOR, 'Nvidia'], [TYPE, CONSOLE]], [
609
+ /(playstation\s[345portablevi]+)/i // Playstation
610
+ ], [MODEL, [VENDOR, 'Sony'], [TYPE, CONSOLE]], [
611
+ /[\s\(;](xbox(?:\sone)?(?!;\sxbox))[\s\);]/i // Microsoft Xbox
612
+ ], [MODEL, [VENDOR, 'Microsoft'], [TYPE, CONSOLE]], [
618
613
 
619
614
  ///////////////////
620
615
  // SMARTTVS
@@ -623,88 +618,61 @@
623
618
  /smart-tv.+(samsung)/i // Samsung
624
619
  ], [VENDOR, [TYPE, SMARTTV]], [
625
620
  /hbbtv.+maple;(\d+)/i
626
- ], [[MODEL, /^/, 'SmartTV'], [VENDOR, SAMSUNG], [TYPE, SMARTTV]], [
627
- /(nux; netcast.+smarttv|lg (netcast\.tv-201\d|android tv))/i // LG SmartTV
628
- ], [[VENDOR, LG], [TYPE, SMARTTV]], [
629
- /(apple) ?tv/i // Apple TV
630
- ], [VENDOR, [MODEL, APPLE+' TV'], [TYPE, SMARTTV]], [
621
+ ], [[MODEL, /^/, 'SmartTV'], [VENDOR, 'Samsung'], [TYPE, SMARTTV]], [
622
+ /(?:linux;\snetcast.+smarttv|lg\snetcast\.tv-201\d)/i, // LG SmartTV
623
+ ], [[VENDOR, 'LG'], [TYPE, SMARTTV]], [
624
+ /(apple)\s?tv/i // Apple TV
625
+ ], [VENDOR, [MODEL, 'Apple TV'], [TYPE, SMARTTV]], [
631
626
  /crkey/i // Google Chromecast
632
- ], [[MODEL, CHROME+'cast'], [VENDOR, GOOGLE], [TYPE, SMARTTV]], [
633
- /droid.+aft(\w+)( bui|\))/i // Fire TV
634
- ], [MODEL, [VENDOR, AMAZON], [TYPE, SMARTTV]], [
635
- /\(dtv[\);].+(aquos)/i,
636
- /(aquos-tv[\w ]+)\)/i // Sharp
637
- ], [MODEL, [VENDOR, SHARP], [TYPE, SMARTTV]],[
638
- /(bravia[\w ]+)( bui|\))/i // Sony
639
- ], [MODEL, [VENDOR, SONY], [TYPE, SMARTTV]], [
640
- /(mitv-\w{5}) bui/i // Xiaomi
641
- ], [MODEL, [VENDOR, XIAOMI], [TYPE, SMARTTV]], [
642
- /Hbbtv.*(technisat) (.*);/i // TechniSAT
643
- ], [VENDOR, MODEL, [TYPE, SMARTTV]], [
644
- /\b(roku)[\dx]*[\)\/]((?:dvp-)?[\d\.]*)/i, // Roku
645
- /hbbtv\/\d+\.\d+\.\d+ +\([\w\+ ]*; *([\w\d][^;]*);([^;]*)/i // HbbTV devices
646
- ], [[VENDOR, trim], [MODEL, trim], [TYPE, SMARTTV]], [
647
- /\b(android tv|smart[- ]?tv|opera tv|tv; rv:)\b/i // SmartTV from Unidentified Vendors
627
+ ], [[MODEL, 'Chromecast'], [VENDOR, 'Google'], [TYPE, SMARTTV]], [
628
+ /droid.+aft([\w])(\sbuild\/|\))/i // Fire TV
629
+ ], [MODEL, [VENDOR, 'Amazon'], [TYPE, SMARTTV]], [
630
+ /\(dtv[\);].+(aquos)/i // Sharp
631
+ ], [MODEL, [VENDOR, 'Sharp'], [TYPE, SMARTTV]], [
632
+ /hbbtv\/\d+\.\d+\.\d+\s+\([\w\s]*;\s*(\w[^;]*);([^;]*)/i // HbbTV devices
633
+ ], [[VENDOR, util.trim], [MODEL, util.trim], [TYPE, SMARTTV]], [
634
+ /[\s\/\(](android\s|smart[-\s]?|opera\s)tv[;\)\s]/i // SmartTV from Unidentified Vendors
648
635
  ], [[TYPE, SMARTTV]], [
649
636
 
650
- ///////////////////
651
- // CONSOLES
652
- ///////////////////
653
-
654
- /(ouya)/i, // Ouya
655
- /(nintendo) ([wids3utch]+)/i // Nintendo
656
- ], [VENDOR, MODEL, [TYPE, CONSOLE]], [
657
- /droid.+; (shield) bui/i // Nvidia
658
- ], [MODEL, [VENDOR, 'Nvidia'], [TYPE, CONSOLE]], [
659
- /(playstation [345portablevi]+)/i // Playstation
660
- ], [MODEL, [VENDOR, SONY], [TYPE, CONSOLE]], [
661
- /\b(xbox(?: one)?(?!; xbox))[\); ]/i // Microsoft Xbox
662
- ], [MODEL, [VENDOR, MICROSOFT], [TYPE, CONSOLE]], [
663
-
664
637
  ///////////////////
665
638
  // WEARABLES
666
639
  ///////////////////
667
640
 
668
- /((pebble))app/i // Pebble
641
+ /((pebble))app\/[\d\.]+\s/i // Pebble
669
642
  ], [VENDOR, MODEL, [TYPE, WEARABLE]], [
670
- /(watch)(?: ?os[,\/]|\d,\d\/)[\d\.]+/i // Apple Watch
671
- ], [MODEL, [VENDOR, APPLE], [TYPE, WEARABLE]], [
672
- /droid.+; (glass) \d/i // Google Glass
673
- ], [MODEL, [VENDOR, GOOGLE], [TYPE, WEARABLE]], [
674
- /droid.+; (wt63?0{2,3})\)/i
675
- ], [MODEL, [VENDOR, ZEBRA], [TYPE, WEARABLE]], [
676
- /(quest( 2| pro)?)/i // Oculus Quest
677
- ], [MODEL, [VENDOR, FACEBOOK], [TYPE, WEARABLE]], [
643
+ /droid.+;\s(glass)\s\d/i // Google Glass
644
+ ], [MODEL, [VENDOR, 'Google'], [TYPE, WEARABLE]], [
645
+ /droid\s[\d\.]+;\s(wt63?0{2,3})\)/i
646
+ ], [MODEL, [VENDOR, 'Zebra'], [TYPE, WEARABLE]], [
678
647
 
679
648
  ///////////////////
680
649
  // EMBEDDED
681
650
  ///////////////////
682
651
 
683
- /(tesla)(?: qtcarbrowser|\/[-\w\.]+)/i // Tesla
652
+ /(tesla)(?:\sqtcarbrowser|\/20[12]\d\.[\w\.-]+)/i // Tesla
684
653
  ], [VENDOR, [TYPE, EMBEDDED]], [
685
- /(aeobc)\b/i // Echo Dot
686
- ], [MODEL, [VENDOR, AMAZON], [TYPE, EMBEDDED]], [
687
654
 
688
655
  ////////////////////
689
656
  // MIXED (GENERIC)
690
657
  ///////////////////
691
658
 
692
- /droid .+?; ([^;]+?)(?: bui|; wv\)|\) applew).+? mobile safari/i // Android Phones from Unidentified Vendors
659
+ /droid .+?; ([^;]+?)(?: build|\) applewebkit).+? mobile safari/i // Android Phones from Unidentified Vendors
693
660
  ], [MODEL, [TYPE, MOBILE]], [
694
- /droid .+?; ([^;]+?)(?: bui|\) applew).+?(?! mobile) safari/i // Android Tablets from Unidentified Vendors
661
+ /droid .+?;\s([^;]+?)(?: build|\) applewebkit).+?(?! mobile) safari/i // Android Tablets from Unidentified Vendors
695
662
  ], [MODEL, [TYPE, TABLET]], [
696
- /\b((tablet|tab)[;\/]|focus\/\d(?!.+mobile))/i // Unidentifiable Tablet
697
- ], [[TYPE, TABLET]], [
698
- /(phone|mobile(?:[;\/]| [ \w\/\.]*safari)|pda(?=.+windows ce))/i // Unidentifiable Mobile
699
- ], [[TYPE, MOBILE]], [
700
- /(android[-\w\. ]{0,9});.+buil/i // Generic Android Device
701
- ], [MODEL, [VENDOR, 'Generic']]
663
+ /\s(tablet|tab)[;\/]/i, // Unidentifiable Tablet
664
+ /\s(mobile)(?:[;\/]|\ssafari)/i // Unidentifiable Mobile
665
+ ], [[TYPE, util.lowerize]], [
666
+ /(android[\w\.\s\-]{0,9});.+build/i // Generic Android Device
667
+ ], [MODEL, [VENDOR, 'Generic']], [
668
+ /(phone)/i
669
+ ], [[TYPE, MOBILE]]
702
670
  ],
703
671
 
704
672
  engine : [[
705
673
 
706
- /windows.+ edge\/([\w\.]+)/i // EdgeHTML
707
- ], [VERSION, [NAME, EDGE+'HTML']], [
674
+ /windows.+\sedge\/([\w\.]+)/i // EdgeHTML
675
+ ], [VERSION, [NAME, 'EdgeHTML']], [
708
676
 
709
677
  /webkit\/537\.36.+chrome\/(?!27)([\w\.]+)/i // Blink
710
678
  ], [VERSION, [NAME, 'Blink']], [
@@ -712,9 +680,8 @@
712
680
  /(presto)\/([\w\.]+)/i, // Presto
713
681
  /(webkit|trident|netfront|netsurf|amaya|lynx|w3m|goanna)\/([\w\.]+)/i, // WebKit/Trident/NetFront/NetSurf/Amaya/Lynx/w3m/Goanna
714
682
  /ekioh(flow)\/([\w\.]+)/i, // Flow
715
- /(khtml|tasman|links)[\/ ]\(?([\w\.]+)/i, // KHTML/Tasman/Links
716
- /(icab)[\/ ]([23]\.[\d\.]+)/i, // iCab
717
- /\b(libweb)/i
683
+ /(khtml|tasman|links)[\/\s]\(?([\w\.]+)/i, // KHTML/Tasman/Links
684
+ /(icab)[\/\s]([23]\.[\d\.]+)/i // iCab
718
685
  ], [NAME, VERSION], [
719
686
 
720
687
  /rv\:([\w\.]{1,9})\b.+(gecko)/i // Gecko
@@ -724,87 +691,81 @@
724
691
  os : [[
725
692
 
726
693
  // Windows
727
- /microsoft (windows) (vista|xp)/i // Windows (iTunes)
694
+ /microsoft\s(windows)\s(vista|xp)/i // Windows (iTunes)
728
695
  ], [NAME, VERSION], [
729
- /(windows (?:phone(?: os)?|mobile))[\/ ]?([\d\.\w ]*)/i // Windows Phone
730
- ], [NAME, [VERSION, strMapper, windowsVersionMap]], [
731
- /windows nt 6\.2; (arm)/i, // Windows RT
732
- /windows[\/ ]?([ntce\d\. ]+\w)(?!.+xbox)/i,
733
- /(?:win(?=3|9|n)|win 9x )([nt\d\.]+)/i
734
- ], [[VERSION, strMapper, windowsVersionMap], [NAME, 'Windows']], [
696
+ /(windows)\snt\s6\.2;\s(arm)/i, // Windows RT
697
+ /(windows\sphone(?:\sos)*)[\s\/]?([\d\.\s\w]*)/i, // Windows Phone
698
+ /(windows\smobile|windows)[\s\/]?([ntce\d\.\s]+\w)(?!.+xbox)/i
699
+ ], [NAME, [VERSION, mapper.str, maps.os.windows.version]], [
700
+ /(win(?=3|9|n)|win\s9x\s)([nt\d\.]+)/i
701
+ ], [[NAME, 'Windows'], [VERSION, mapper.str, maps.os.windows.version]], [
735
702
 
736
703
  // iOS/macOS
737
- /ip[honead]{2,4}\b(?:.*os ([\w]+) like mac|; opera)/i, // iOS
738
- /(?:ios;fbsv\/|iphone.+ios[\/ ])([\d\.]+)/i,
704
+ /ip[honead]{2,4}\b(?:.*os\s([\w]+)\slike\smac|;\sopera)/i, // iOS
739
705
  /cfnetwork\/.+darwin/i
740
706
  ], [[VERSION, /_/g, '.'], [NAME, 'iOS']], [
741
- /(mac os x) ?([\w\. ]*)/i,
742
- /(macintosh|mac_powerpc\b)(?!.+haiku)/i // Mac OS
743
- ], [[NAME, MAC_OS], [VERSION, /_/g, '.']], [
744
-
745
- // Mobile OSes
746
- /droid ([\w\.]+)\b.+(android[- ]x86|harmonyos)/i // Android-x86/HarmonyOS
747
- ], [VERSION, NAME], [ // Android/WebOS/QNX/Bada/RIM/Maemo/MeeGo/Sailfish OS
748
- /(android|webos|qnx|bada|rim tablet os|maemo|meego|sailfish)[-\/ ]?([\w\.]*)/i,
707
+ /(mac\sos\sx)\s?([\w\s\.]*)/i,
708
+ /(macintosh|mac(?=_powerpc)\s)(?!.+haiku)/i // Mac OS
709
+ ], [[NAME, 'Mac OS'], [VERSION, /_/g, '.']], [
710
+
711
+ // Mobile OSes // Android/WebOS/Palm/QNX/Bada/RIM/MeeGo/Contiki/Sailfish OS
712
+ /(android|webos|palm\sos|qnx|bada|rim\stablet\sos|meego|sailfish|contiki)[\/\s-]?([\w\.]*)/i,
749
713
  /(blackberry)\w*\/([\w\.]*)/i, // Blackberry
750
- /(tizen|kaios)[\/ ]([\w\.]+)/i, // Tizen/KaiOS
714
+ /(tizen|kaios)[\/\s]([\w\.]+)/i, // Tizen/KaiOS
751
715
  /\((series40);/i // Series 40
752
716
  ], [NAME, VERSION], [
753
717
  /\(bb(10);/i // BlackBerry 10
754
- ], [VERSION, [NAME, BLACKBERRY]], [
755
- /(?:symbian ?os|symbos|s60(?=;)|series60)[-\/ ]?([\w\.]*)/i // Symbian
718
+ ], [VERSION, [NAME, 'BlackBerry']], [
719
+ /(?:symbian\s?os|symbos|s60(?=;)|series60)[\/\s-]?([\w\.]*)/i // Symbian
756
720
  ], [VERSION, [NAME, 'Symbian']], [
757
- /mozilla\/[\d\.]+ \((?:mobile|tablet|tv|mobile; [\w ]+); rv:.+ gecko\/([\w\.]+)/i // Firefox OS
758
- ], [VERSION, [NAME, FIREFOX+' OS']], [
721
+ /mozilla.+\(mobile;.+gecko.+firefox/i // Firefox OS
722
+ ], [[NAME, 'Firefox OS']], [
759
723
  /web0s;.+rt(tv)/i,
760
724
  /\b(?:hp)?wos(?:browser)?\/([\w\.]+)/i // WebOS
761
725
  ], [VERSION, [NAME, 'webOS']], [
762
- /watch(?: ?os[,\/]|\d,\d\/)([\d\.]+)/i // watchOS
763
- ], [VERSION, [NAME, 'watchOS']], [
764
726
 
765
727
  // Google Chromecast
766
728
  /crkey\/([\d\.]+)/i // Google Chromecast
767
- ], [VERSION, [NAME, CHROME+'cast']], [
768
- /(cros) [\w]+(?:\)| ([\w\.]+)\b)/i // Chromium OS
769
- ], [[NAME, CHROMIUM_OS], VERSION],[
770
-
771
- // Smart TVs
772
- /panasonic;(viera)/i, // Panasonic Viera
773
- /(netrange)mmh/i, // Netrange
774
- /(nettv)\/(\d+\.[\w\.]+)/i, // NetTV
729
+ ], [VERSION, [NAME, 'Chromecast']], [
730
+ /(cros)\s[\w]+\s([\w\.]+\w)/i // Chromium OS
731
+ ], [[NAME, 'Chromium OS'], VERSION],[
775
732
 
776
733
  // Console
777
- /(nintendo|playstation) ([wids345portablevuch]+)/i, // Nintendo/Playstation
778
- /(xbox); +xbox ([^\);]+)/i, // Microsoft Xbox (360, One, X, S, Series X, Series S)
734
+ /(nintendo|playstation)\s([wids345portablevuch]+)/i, // Nintendo/Playstation
735
+ /(xbox);\s+xbox\s([^\);]+)/i, // Microsoft Xbox (360, One, X, S, Series X, Series S)
736
+
737
+ // GNU/Linux based
738
+ /(mint)[\/\s\(\)]?(\w*)/i, // Mint
739
+ /(mageia|vectorlinux)[;\s]/i, // Mageia/VectorLinux
740
+ /(joli|[kxln]?ubuntu|debian|suse|opensuse|gentoo|arch(?=\slinux)|slackware|fedora|mandriva|centos|pclinuxos|redhat|zenwalk|linpus|raspbian)(?:\sgnu\/linux)?(?:\slinux)?[\/\s-]?(?!chrom|package)([\w\.-]*)/i,
741
+ // Joli/Ubuntu/Debian/SUSE/Gentoo/Arch/Slackware
742
+ // Fedora/Mandriva/CentOS/PCLinuxOS/RedHat/Zenwalk/Linpus
743
+ /(hurd|linux)\s?([\w\.]*)/i, // Hurd/Linux
744
+ /(gnu)\s?([\w\.]*)/i, // GNU
745
+
746
+ // BSD based
747
+ /\s([frentopc-]{0,4}bsd|dragonfly)\s?(?!amd|[ix346]{1,2}86)([\w\.]*)/i, // FreeBSD/NetBSD/OpenBSD/PC-BSD/DragonFly
748
+ /(haiku)\s(\w+)/i // Haiku
749
+ ], [NAME, VERSION], [
779
750
 
780
751
  // Other
781
- /\b(joli|palm)\b ?(?:os)?\/?([\w\.]*)/i, // Joli/Palm
782
- /(mint)[\/\(\) ]?(\w*)/i, // Mint
783
- /(mageia|vectorlinux)[; ]/i, // Mageia/VectorLinux
784
- /([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,
785
- // Ubuntu/Debian/SUSE/Gentoo/Arch/Slackware/Fedora/Mandriva/CentOS/PCLinuxOS/RedHat/Zenwalk/Linpus/Raspbian/Plan9/Minix/RISCOS/Contiki/Deepin/Manjaro/elementary/Sabayon/Linspire
786
- /(hurd|linux) ?([\w\.]*)/i, // Hurd/Linux
787
- /(gnu) ?([\w\.]*)/i, // GNU
788
- /\b([-frentopcghs]{0,5}bsd|dragonfly)[\/ ]?(?!amd|[ix346]{1,2}86)([\w\.]*)/i, // FreeBSD/NetBSD/OpenBSD/PC-BSD/GhostBSD/DragonFly
789
- /(haiku) (\w+)/i // Haiku
790
- ], [NAME, VERSION], [
791
- /(sunos) ?([\w\.\d]*)/i // Solaris
752
+ /(sunos)\s?([\w\.\d]*)/i // Solaris
792
753
  ], [[NAME, 'Solaris'], VERSION], [
793
- /((?:open)?solaris)[-\/ ]?([\w\.]*)/i, // Solaris
794
- /(aix) ((\d)(?=\.|\)| )[\w\.])*/i, // AIX
795
- /\b(beos|os\/2|amigaos|morphos|openvms|fuchsia|hp-ux|serenityos)/i, // BeOS/OS2/AmigaOS/MorphOS/OpenVMS/Fuchsia/HP-UX/SerenityOS
796
- /(unix) ?([\w\.]*)/i // UNIX
754
+ /((?:open)?solaris)[\/\s-]?([\w\.]*)/i, // Solaris
755
+ /(aix)\s((\d)(?=\.|\)|\s)[\w\.])*/i, // AIX
756
+ /(plan\s9|minix|beos|os\/2|amigaos|morphos|risc\sos|openvms|fuchsia)/i, // Plan9/Minix/BeOS/OS2/AmigaOS/MorphOS/RISCOS/OpenVMS/Fuchsia
757
+ /(unix)\s?([\w\.]*)/i // UNIX
797
758
  ], [NAME, VERSION]
798
759
  ]
799
760
  };
800
761
 
762
+
801
763
  /////////////////
802
764
  // Constructor
803
765
  ////////////////
804
-
805
766
  var UAParser = function (ua, extensions) {
806
767
 
807
- if (typeof ua === OBJ_TYPE) {
768
+ if (typeof ua === 'object') {
808
769
  extensions = ua;
809
770
  ua = undefined;
810
771
  }
@@ -813,63 +774,33 @@
813
774
  return new UAParser(ua, extensions).getResult();
814
775
  }
815
776
 
816
- var _navigator = (typeof window !== UNDEF_TYPE && window.navigator) ? window.navigator : undefined;
817
- var _ua = ua || ((_navigator && _navigator.userAgent) ? _navigator.userAgent : EMPTY);
818
- var _uach = (_navigator && _navigator.userAgentData) ? _navigator.userAgentData : undefined;
819
- var _rgxmap = extensions ? extend(regexes, extensions) : regexes;
820
- var _isSelfNav = _navigator && _navigator.userAgent == _ua;
777
+ var _ua = ua || ((typeof window !== 'undefined' && window.navigator && window.navigator.userAgent) ? window.navigator.userAgent : EMPTY);
778
+ var _rgxmap = extensions ? util.extend(regexes, extensions) : regexes;
821
779
 
822
780
  this.getBrowser = function () {
823
- var _browser = {};
824
- _browser[NAME] = undefined;
825
- _browser[VERSION] = undefined;
826
- rgxMapper.call(_browser, _ua, _rgxmap.browser);
827
- _browser[MAJOR] = majorize(_browser[VERSION]);
828
- // Brave-specific detection
829
- if (_isSelfNav && _navigator && _navigator.brave && typeof _navigator.brave.isBrave == FUNC_TYPE) {
830
- _browser[NAME] = 'Brave';
831
- }
781
+ var _browser = { name: undefined, version: undefined };
782
+ mapper.rgx.call(_browser, _ua, _rgxmap.browser);
783
+ _browser.major = util.major(_browser.version); // deprecated
832
784
  return _browser;
833
785
  };
834
786
  this.getCPU = function () {
835
- var _cpu = {};
836
- _cpu[ARCHITECTURE] = undefined;
837
- rgxMapper.call(_cpu, _ua, _rgxmap.cpu);
787
+ var _cpu = { architecture: undefined };
788
+ mapper.rgx.call(_cpu, _ua, _rgxmap.cpu);
838
789
  return _cpu;
839
790
  };
840
791
  this.getDevice = function () {
841
- var _device = {};
842
- _device[VENDOR] = undefined;
843
- _device[MODEL] = undefined;
844
- _device[TYPE] = undefined;
845
- rgxMapper.call(_device, _ua, _rgxmap.device);
846
- if (_isSelfNav && !_device[TYPE] && _uach && _uach.mobile) {
847
- _device[TYPE] = MOBILE;
848
- }
849
- // iPadOS-specific detection: identified as Mac, but has some iOS-only properties
850
- if (_isSelfNav && _device[MODEL] == 'Macintosh' && _navigator && typeof _navigator.standalone !== UNDEF_TYPE && _navigator.maxTouchPoints && _navigator.maxTouchPoints > 2) {
851
- _device[MODEL] = 'iPad';
852
- _device[TYPE] = TABLET;
853
- }
792
+ var _device = { vendor: undefined, model: undefined, type: undefined };
793
+ mapper.rgx.call(_device, _ua, _rgxmap.device);
854
794
  return _device;
855
795
  };
856
796
  this.getEngine = function () {
857
- var _engine = {};
858
- _engine[NAME] = undefined;
859
- _engine[VERSION] = undefined;
860
- rgxMapper.call(_engine, _ua, _rgxmap.engine);
797
+ var _engine = { name: undefined, version: undefined };
798
+ mapper.rgx.call(_engine, _ua, _rgxmap.engine);
861
799
  return _engine;
862
800
  };
863
801
  this.getOS = function () {
864
- var _os = {};
865
- _os[NAME] = undefined;
866
- _os[VERSION] = undefined;
867
- rgxMapper.call(_os, _ua, _rgxmap.os);
868
- if (_isSelfNav && !_os[NAME] && _uach && _uach.platform != 'Unknown') {
869
- _os[NAME] = _uach.platform
870
- .replace(/chrome os/i, CHROMIUM_OS)
871
- .replace(/macos/i, MAC_OS); // backward compatibility
872
- }
802
+ var _os = { name: undefined, version: undefined };
803
+ mapper.rgx.call(_os, _ua, _rgxmap.os);
873
804
  return _os;
874
805
  };
875
806
  this.getResult = function () {
@@ -886,7 +817,7 @@
886
817
  return _ua;
887
818
  };
888
819
  this.setUA = function (ua) {
889
- _ua = (typeof ua === STR_TYPE && ua.length > UA_MAX_LENGTH) ? trim(ua, UA_MAX_LENGTH) : ua;
820
+ _ua = (typeof ua === STR_TYPE && ua.length > UA_MAX_LENGTH) ? util.trim(ua, UA_MAX_LENGTH) : ua;
890
821
  return this;
891
822
  };
892
823
  this.setUA(_ua);
@@ -894,15 +825,39 @@
894
825
  };
895
826
 
896
827
  UAParser.VERSION = LIBVERSION;
897
- UAParser.BROWSER = enumerize([NAME, VERSION, MAJOR]);
898
- UAParser.CPU = enumerize([ARCHITECTURE]);
899
- UAParser.DEVICE = enumerize([MODEL, VENDOR, TYPE, CONSOLE, MOBILE, SMARTTV, TABLET, WEARABLE, EMBEDDED]);
900
- UAParser.ENGINE = UAParser.OS = enumerize([NAME, VERSION]);
828
+ UAParser.BROWSER = {
829
+ NAME : NAME,
830
+ MAJOR : MAJOR, // deprecated
831
+ VERSION : VERSION
832
+ };
833
+ UAParser.CPU = {
834
+ ARCHITECTURE : ARCHITECTURE
835
+ };
836
+ UAParser.DEVICE = {
837
+ MODEL : MODEL,
838
+ VENDOR : VENDOR,
839
+ TYPE : TYPE,
840
+ CONSOLE : CONSOLE,
841
+ MOBILE : MOBILE,
842
+ SMARTTV : SMARTTV,
843
+ TABLET : TABLET,
844
+ WEARABLE: WEARABLE,
845
+ EMBEDDED: EMBEDDED
846
+ };
847
+ UAParser.ENGINE = {
848
+ NAME : NAME,
849
+ VERSION : VERSION
850
+ };
851
+ UAParser.OS = {
852
+ NAME : NAME,
853
+ VERSION : VERSION
854
+ };
901
855
 
902
856
  ///////////
903
857
  // Export
904
858
  //////////
905
859
 
860
+
906
861
  // check js environment
907
862
  if (typeof(exports) !== UNDEF_TYPE) {
908
863
  // nodejs env
@@ -912,11 +867,11 @@
912
867
  exports.UAParser = UAParser;
913
868
  } else {
914
869
  // requirejs env (optional)
915
- if (typeof(define) === FUNC_TYPE && define.amd) {
870
+ if (typeof(define) === 'function' && define.amd) {
916
871
  define(function () {
917
872
  return UAParser;
918
873
  });
919
- } else if (typeof window !== UNDEF_TYPE) {
874
+ } else if (typeof window !== 'undefined') {
920
875
  // browser env
921
876
  window.UAParser = UAParser;
922
877
  }
@@ -927,15 +882,15 @@
927
882
  // In AMD env the global scope should be kept clean, but jQuery is an exception.
928
883
  // jQuery always exports to global scope, unless jQuery.noConflict(true) is used,
929
884
  // and we should catch that.
930
- var $ = typeof window !== UNDEF_TYPE && (window.jQuery || window.Zepto);
885
+ var $ = typeof window !== 'undefined' && (window.jQuery || window.Zepto);
931
886
  if ($ && !$.ua) {
932
887
  var parser = new UAParser();
933
888
  $.ua = parser.getResult();
934
889
  $.ua.get = function () {
935
890
  return parser.getUA();
936
891
  };
937
- $.ua.set = function (ua) {
938
- parser.setUA(ua);
892
+ $.ua.set = function (uastring) {
893
+ parser.setUA(uastring);
939
894
  var result = parser.getResult();
940
895
  for (var prop in result) {
941
896
  $.ua[prop] = result[prop];