ua-parser-js 0.7.28 → 0.7.33

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