1/*! 2 * Bowser - a browser detector 3 * https://github.com/ded/bowser 4 * MIT License | (c) Dustin Diaz 2015 5 */ 6 7!function (root, name, definition) { 8 if (typeof module != 'undefined' && module.exports) module.exports = definition() 9 else if (typeof define == 'function' && define.amd) define(name, definition) 10 else root[name] = definition() 11}(this, 'bowser', function () { 12 /** 13 * See useragents.js for examples of navigator.userAgent 14 */ 15 16 var t = true 17 18 function detect(ua) { 19 20 function getFirstMatch(regex) { 21 var match = ua.match(regex); 22 return (match && match.length > 1 && match[1]) || ''; 23 } 24 25 function getSecondMatch(regex) { 26 var match = ua.match(regex); 27 return (match && match.length > 1 && match[2]) || ''; 28 } 29 30 var iosdevice = getFirstMatch(/(ipod|iphone|ipad)/i).toLowerCase() 31 , likeAndroid = /like android/i.test(ua) 32 , android = !likeAndroid && /android/i.test(ua) 33 , nexusMobile = /nexus\s*[0-6]\s*/i.test(ua) 34 , nexusTablet = !nexusMobile && /nexus\s*[0-9]+/i.test(ua) 35 , chromeos = /CrOS/.test(ua) 36 , silk = /silk/i.test(ua) 37 , sailfish = /sailfish/i.test(ua) 38 , tizen = /tizen/i.test(ua) 39 , webos = /(web|hpw)os/i.test(ua) 40 , windowsphone = /windows phone/i.test(ua) 41 , samsungBrowser = /SamsungBrowser/i.test(ua) 42 , windows = !windowsphone && /windows/i.test(ua) 43 , mac = !iosdevice && !silk && /macintosh/i.test(ua) 44 , linux = !android && !sailfish && !tizen && !webos && /linux/i.test(ua) 45 , edgeVersion = getFirstMatch(/edge\/(\d+(\.\d+)?)/i) 46 , versionIdentifier = getFirstMatch(/version\/(\d+(\.\d+)?)/i) 47 , tablet = /tablet/i.test(ua) && !/tablet pc/i.test(ua) 48 , mobile = !tablet && /[^-]mobi/i.test(ua) 49 , xbox = /xbox/i.test(ua) 50 , result 51 52 if (/opera/i.test(ua)) { 53 // an old Opera 54 result = { 55 name: 'Opera' 56 , opera: t 57 , version: versionIdentifier || getFirstMatch(/(?:opera|opr|opios)[\s\/](\d+(\.\d+)?)/i) 58 } 59 } else if (/opr|opios/i.test(ua)) { 60 // a new Opera 61 result = { 62 name: 'Opera' 63 , opera: t 64 , version: getFirstMatch(/(?:opr|opios)[\s\/](\d+(\.\d+)?)/i) || versionIdentifier 65 } 66 } 67 else if (/SamsungBrowser/i.test(ua)) { 68 result = { 69 name: 'Samsung Internet for Android' 70 , samsungBrowser: t 71 , version: versionIdentifier || getFirstMatch(/(?:SamsungBrowser)[\s\/](\d+(\.\d+)?)/i) 72 } 73 } 74 else if (/coast/i.test(ua)) { 75 result = { 76 name: 'Opera Coast' 77 , coast: t 78 , version: versionIdentifier || getFirstMatch(/(?:coast)[\s\/](\d+(\.\d+)?)/i) 79 } 80 } 81 else if (/yabrowser/i.test(ua)) { 82 result = { 83 name: 'Yandex Browser' 84 , yandexbrowser: t 85 , version: versionIdentifier || getFirstMatch(/(?:yabrowser)[\s\/](\d+(\.\d+)?)/i) 86 } 87 } 88 else if (/ucbrowser/i.test(ua)) { 89 result = { 90 name: 'UC Browser' 91 , ucbrowser: t 92 , version: getFirstMatch(/(?:ucbrowser)[\s\/](\d+(?:\.\d+)+)/i) 93 } 94 } 95 else if (/mxios/i.test(ua)) { 96 result = { 97 name: 'Maxthon' 98 , maxthon: t 99 , version: getFirstMatch(/(?:mxios)[\s\/](\d+(?:\.\d+)+)/i) 100 } 101 } 102 else if (/epiphany/i.test(ua)) { 103 result = { 104 name: 'Epiphany' 105 , epiphany: t 106 , version: getFirstMatch(/(?:epiphany)[\s\/](\d+(?:\.\d+)+)/i) 107 } 108 } 109 else if (/puffin/i.test(ua)) { 110 result = { 111 name: 'Puffin' 112 , puffin: t 113 , version: getFirstMatch(/(?:puffin)[\s\/](\d+(?:\.\d+)?)/i) 114 } 115 } 116 else if (/sleipnir/i.test(ua)) { 117 result = { 118 name: 'Sleipnir' 119 , sleipnir: t 120 , version: getFirstMatch(/(?:sleipnir)[\s\/](\d+(?:\.\d+)+)/i) 121 } 122 } 123 else if (/k-meleon/i.test(ua)) { 124 result = { 125 name: 'K-Meleon' 126 , kMeleon: t 127 , version: getFirstMatch(/(?:k-meleon)[\s\/](\d+(?:\.\d+)+)/i) 128 } 129 } 130 else if (windowsphone) { 131 result = { 132 name: 'Windows Phone' 133 , windowsphone: t 134 } 135 if (edgeVersion) { 136 result.msedge = t 137 result.version = edgeVersion 138 } 139 else { 140 result.msie = t 141 result.version = getFirstMatch(/iemobile\/(\d+(\.\d+)?)/i) 142 } 143 } 144 else if (/msie|trident/i.test(ua)) { 145 result = { 146 name: 'Internet Explorer' 147 , msie: t 148 , version: getFirstMatch(/(?:msie |rv:)(\d+(\.\d+)?)/i) 149 } 150 } else if (chromeos) { 151 result = { 152 name: 'Chrome' 153 , chromeos: t 154 , chromeBook: t 155 , chrome: t 156 , version: getFirstMatch(/(?:chrome|crios|crmo)\/(\d+(\.\d+)?)/i) 157 } 158 } else if (/chrome.+? edge/i.test(ua)) { 159 result = { 160 name: 'Microsoft Edge' 161 , msedge: t 162 , version: edgeVersion 163 } 164 } 165 else if (/vivaldi/i.test(ua)) { 166 result = { 167 name: 'Vivaldi' 168 , vivaldi: t 169 , version: getFirstMatch(/vivaldi\/(\d+(\.\d+)?)/i) || versionIdentifier 170 } 171 } 172 else if (sailfish) { 173 result = { 174 name: 'Sailfish' 175 , sailfish: t 176 , version: getFirstMatch(/sailfish\s?browser\/(\d+(\.\d+)?)/i) 177 } 178 } 179 else if (/seamonkey\//i.test(ua)) { 180 result = { 181 name: 'SeaMonkey' 182 , seamonkey: t 183 , version: getFirstMatch(/seamonkey\/(\d+(\.\d+)?)/i) 184 } 185 } 186 else if (/firefox|iceweasel|fxios/i.test(ua)) { 187 result = { 188 name: 'Firefox' 189 , firefox: t 190 , version: getFirstMatch(/(?:firefox|iceweasel|fxios)[ \/](\d+(\.\d+)?)/i) 191 } 192 if (/\((mobile|tablet);[^\)]*rv:[\d\.]+\)/i.test(ua)) { 193 result.firefoxos = t 194 } 195 } 196 else if (silk) { 197 result = { 198 name: 'Amazon Silk' 199 , silk: t 200 , version : getFirstMatch(/silk\/(\d+(\.\d+)?)/i) 201 } 202 } 203 else if (/phantom/i.test(ua)) { 204 result = { 205 name: 'PhantomJS' 206 , phantom: t 207 , version: getFirstMatch(/phantomjs\/(\d+(\.\d+)?)/i) 208 } 209 } 210 else if (/slimerjs/i.test(ua)) { 211 result = { 212 name: 'SlimerJS' 213 , slimer: t 214 , version: getFirstMatch(/slimerjs\/(\d+(\.\d+)?)/i) 215 } 216 } 217 else if (/blackberry|\bbb\d+/i.test(ua) || /rim\stablet/i.test(ua)) { 218 result = { 219 name: 'BlackBerry' 220 , blackberry: t 221 , version: versionIdentifier || getFirstMatch(/blackberry[\d]+\/(\d+(\.\d+)?)/i) 222 } 223 } 224 else if (webos) { 225 result = { 226 name: 'WebOS' 227 , webos: t 228 , version: versionIdentifier || getFirstMatch(/w(?:eb)?osbrowser\/(\d+(\.\d+)?)/i) 229 }; 230 /touchpad\//i.test(ua) && (result.touchpad = t) 231 } 232 else if (/bada/i.test(ua)) { 233 result = { 234 name: 'Bada' 235 , bada: t 236 , version: getFirstMatch(/dolfin\/(\d+(\.\d+)?)/i) 237 }; 238 } 239 else if (tizen) { 240 result = { 241 name: 'Tizen' 242 , tizen: t 243 , version: getFirstMatch(/(?:tizen\s?)?browser\/(\d+(\.\d+)?)/i) || versionIdentifier 244 }; 245 } 246 else if (/qupzilla/i.test(ua)) { 247 result = { 248 name: 'QupZilla' 249 , qupzilla: t 250 , version: getFirstMatch(/(?:qupzilla)[\s\/](\d+(?:\.\d+)+)/i) || versionIdentifier 251 } 252 } 253 else if (/chromium/i.test(ua)) { 254 result = { 255 name: 'Chromium' 256 , chromium: t 257 , version: getFirstMatch(/(?:chromium)[\s\/](\d+(?:\.\d+)?)/i) || versionIdentifier 258 } 259 } 260 else if (/chrome|crios|crmo/i.test(ua)) { 261 result = { 262 name: 'Chrome' 263 , chrome: t 264 , version: getFirstMatch(/(?:chrome|crios|crmo)\/(\d+(\.\d+)?)/i) 265 } 266 } 267 else if (android) { 268 result = { 269 name: 'Android' 270 , version: versionIdentifier 271 } 272 } 273 else if (/safari|applewebkit/i.test(ua)) { 274 result = { 275 name: 'Safari' 276 , safari: t 277 } 278 if (versionIdentifier) { 279 result.version = versionIdentifier 280 } 281 } 282 else if (iosdevice) { 283 result = { 284 name : iosdevice == 'iphone' ? 'iPhone' : iosdevice == 'ipad' ? 'iPad' : 'iPod' 285 } 286 // WTF: version is not part of user agent in web apps 287 if (versionIdentifier) { 288 result.version = versionIdentifier 289 } 290 } 291 else if(/googlebot/i.test(ua)) { 292 result = { 293 name: 'Googlebot' 294 , googlebot: t 295 , version: getFirstMatch(/googlebot\/(\d+(\.\d+))/i) || versionIdentifier 296 } 297 } 298 else { 299 result = { 300 name: getFirstMatch(/^(.*)\/(.*) /), 301 version: getSecondMatch(/^(.*)\/(.*) /) 302 }; 303 } 304 305 // set webkit or gecko flag for browsers based on these engines 306 if (!result.msedge && /(apple)?webkit/i.test(ua)) { 307 if (/(apple)?webkit\/537\.36/i.test(ua)) { 308 result.name = result.name || "Blink" 309 result.blink = t 310 } else { 311 result.name = result.name || "Webkit" 312 result.webkit = t 313 } 314 if (!result.version && versionIdentifier) { 315 result.version = versionIdentifier 316 } 317 } else if (!result.opera && /gecko\//i.test(ua)) { 318 result.name = result.name || "Gecko" 319 result.gecko = t 320 result.version = result.version || getFirstMatch(/gecko\/(\d+(\.\d+)?)/i) 321 } 322 323 // set OS flags for platforms that have multiple browsers 324 if (!result.windowsphone && !result.msedge && (android || result.silk)) { 325 result.android = t 326 } else if (!result.windowsphone && !result.msedge && iosdevice) { 327 result[iosdevice] = t 328 result.ios = t 329 } else if (mac) { 330 result.mac = t 331 } else if (xbox) { 332 result.xbox = t 333 } else if (windows) { 334 result.windows = t 335 } else if (linux) { 336 result.linux = t 337 } 338 339 function getWindowsVersion (s) { 340 switch (s) { 341 case 'NT': return 'NT' 342 case 'XP': return 'XP' 343 case 'NT 5.0': return '2000' 344 case 'NT 5.1': return 'XP' 345 case 'NT 5.2': return '2003' 346 case 'NT 6.0': return 'Vista' 347 case 'NT 6.1': return '7' 348 case 'NT 6.2': return '8' 349 case 'NT 6.3': return '8.1' 350 case 'NT 10.0': return '10' 351 default: return undefined 352 } 353 } 354 355 // OS version extraction 356 var osVersion = ''; 357 if (result.windows) { 358 osVersion = getWindowsVersion(getFirstMatch(/Windows ((NT|XP)( \d\d?.\d)?)/i)) 359 } else if (result.windowsphone) { 360 osVersion = getFirstMatch(/windows phone (?:os)?\s?(\d+(\.\d+)*)/i); 361 } else if (result.mac) { 362 osVersion = getFirstMatch(/Mac OS X (\d+([_\.\s]\d+)*)/i); 363 osVersion = osVersion.replace(/[_\s]/g, '.'); 364 } else if (iosdevice) { 365 osVersion = getFirstMatch(/os (\d+([_\s]\d+)*) like mac os x/i); 366 osVersion = osVersion.replace(/[_\s]/g, '.'); 367 } else if (android) { 368 osVersion = getFirstMatch(/android[ \/-](\d+(\.\d+)*)/i); 369 } else if (result.webos) { 370 osVersion = getFirstMatch(/(?:web|hpw)os\/(\d+(\.\d+)*)/i); 371 } else if (result.blackberry) { 372 osVersion = getFirstMatch(/rim\stablet\sos\s(\d+(\.\d+)*)/i); 373 } else if (result.bada) { 374 osVersion = getFirstMatch(/bada\/(\d+(\.\d+)*)/i); 375 } else if (result.tizen) { 376 osVersion = getFirstMatch(/tizen[\/\s](\d+(\.\d+)*)/i); 377 } 378 if (osVersion) { 379 result.osversion = osVersion; 380 } 381 382 // device type extraction 383 var osMajorVersion = !result.windows && osVersion.split('.')[0]; 384 if ( 385 tablet 386 || nexusTablet 387 || iosdevice == 'ipad' 388 || (android && (osMajorVersion == 3 || (osMajorVersion >= 4 && !mobile))) 389 || result.silk 390 ) { 391 result.tablet = t 392 } else if ( 393 mobile 394 || iosdevice == 'iphone' 395 || iosdevice == 'ipod' 396 || android 397 || nexusMobile 398 || result.blackberry 399 || result.webos 400 || result.bada 401 ) { 402 result.mobile = t 403 } 404 405 // Graded Browser Support
406 // http://developer.yahoo.com/yui/articles/gbs 407 if (result.msedge || 408 (result.msie && result.version >= 10) || 409 (result.yandexbrowser && result.version >= 15) || 410 (result.vivaldi && result.version >= 1.0) || 411 (result.chrome && result.version >= 20) || 412 (result.samsungBrowser && result.version >= 4) || 413 (result.firefox && result.version >= 20.0) || 414 (result.safari && result.version >= 6) || 415 (result.opera && result.version >= 10.0) || 416 (result.ios && result.osversion && result.osversion.split(".")[0] >= 6) || 417 (result.blackberry && result.version >= 10.1) 418 || (result.chromium && result.version >= 20) 419 ) { 420 result.a = t; 421 } 422 else if ((result.msie && result.version < 10) || 423 (result.chrome && result.version < 20) || 424 (result.firefox && result.version < 20.0) || 425 (result.safari && result.version < 6) || 426 (result.opera && result.version < 10.0) || 427 (result.ios && result.osversion && result.osversion.split(".")[0] < 6) 428 || (result.chromium && result.version < 20) 429 ) { 430 result.c = t 431 } else result.x = t 432 433 return result 434 } 435 436 var bowser = detect(typeof navigator !== 'undefined' ? navigator.userAgent || '' : '') 437 438 bowser.test = function (browserList) { 439 for (var i = 0; i < browserList.length; ++i) { 440 var browserItem = browserList[i]; 441 if (typeof browserItem=== 'string') { 442 if (browserItem in bowser) { 443 return true; 444 } 445 } 446 } 447 return false; 448 } 449 450 /** 451 * Get version precisions count 452 * 453 * @example 454 * getVersionPrecision("1.10.3") // 3 455 * 456 * @param {string} version 457 * @return {number} 458 */ 459 function getVersionPrecision(version) { 460 return version.split(".").length; 461 } 462 463 /** 464 * Array::map polyfill 465 * 466 * @param {Array} arr 467 * @param {Function} iterator 468 * @return {Array} 469 */ 470 function map(arr, iterator) { 471 var result = [], i; 472 if (Array.prototype.map) { 473 return Array.prototype.map.call(arr, iterator); 474 } 475 for (i = 0; i < arr.length; i++) { 476 result.push(iterator(arr[i])); 477 } 478 return result; 479 } 480 481 /** 482 * Calculate browser version weight 483 * 484 * @example 485 * compareVersions(['1.10.2.1', '1.8.2.1.90']) // 1 486 * compareVersions(['1.010.2.1', '1.09.2.1.90']); // 1 487 * compareVersions(['1.10.2.1', '1.10.2.1']); // 0 488 * compareVersions(['1.10.2.1', '1.0800.2']); // -1 489 * 490 * @param {Array<String>} versions versions to compare 491 * @return {Number} comparison result 492 */ 493 function compareVersions(versions) { 494 // 1) get common precision for both versions, for example for "10.0" and "9" it should be 2 495 var precision = Math.max(getVersionPrecision(versions[0]), getVersionPrecision(versions[1])); 496 var chunks = map(versions, function (version) { 497 var delta = precision - getVersionPrecision(version); 498 499 // 2) "9" -> "9.0" (for precision = 2) 500 version = version + new Array(delta + 1).join(".0"); 501 502 // 3) "9.0" -> ["000000000"", "000000009"] 503 return map(version.split("."), function (chunk) { 504 return new Array(20 - chunk.length).join("0") + chunk; 505 }).reverse(); 506 }); 507 508 // iterate in reverse order by reversed chunks array 509 while (--precision >= 0) { 510 // 4) compare: "000000009" > "000000010" = false (but "9" > "10" = true) 511 if (chunks[0][precision] > chunks[1][precision]) { 512 return 1; 513 } 514 else if (chunks[0][precision] === chunks[1][precision]) { 515 if (precision === 0) { 516 // all version chunks are same 517 return 0; 518 } 519 } 520 else { 521 return -1; 522 } 523 } 524 } 525 526 /** 527 * Check if browser is unsupported 528 * 529 * @example 530 * bowser.isUnsupportedBrowser({ 531 * msie: "10", 532 * firefox: "23", 533 * chrome: "29", 534 * safari: "5.1", 535 * opera: "16", 536 * phantom: "534" 537 * }); 538 * 539 * @param {Object} minVersions map of minimal version to browser 540 * @param {Boolean} [strictMode = false] flag to return false if browser wasn't found in map 541 * @param {String} [ua] user agent string 542 * @return {Boolean} 543 */ 544 function isUnsupportedBrowser(minVersions, strictMode, ua) { 545 var _bowser = bowser; 546 547 // make strictMode param optional with ua param usage 548 if (typeof strictMode === 'string') { 549 ua = strictMode;
550 strictMode = void(0); 551 } 552 553 if (strictMode === void(0)) { 554 strictMode = false; 555 } 556 if (ua) { 557 _bowser = detect(ua); 558 } 559 560 var version = "" + _bowser.version; 561 for (var browser in minVersions) { 562 if (minVersions.hasOwnProperty(browser)) { 563 if (_bowser[browser]) { 564 if (typeof minVersions[browser] !== 'string') { 565 throw new Error('Browser version in the minVersion map should be a string: ' + browser + ': ' + String(minVersions)); 566 } 567 568 // browser version and min supported version. 569 return compareVersions([version, minVersions[browser]]) < 0; 570 } 571 } 572 } 573 574 return strictMode; // not found 575 } 576 577 /** 578 * Check if browser is supported 579 * 580 * @param {Object} minVersions map of minimal version to browser 581 * @param {Boolean} [strictMode = false] flag to return false if browser wasn't found in map 582 * @param {String} [ua] user agent string 583 * @return {Boolean} 584 */ 585 function check(minVersions, strictMode, ua) { 586 return !isUnsupportedBrowser(minVersions, strictMode, ua); 587 } 588 589 bowser.isUnsupportedBrowser = isUnsupportedBrowser; 590 bowser.compareVersions = compareVersions; 591 bowser.check = check; 592 593 /* 594 * Set our detect method to the main bowser object so we can 595 * reuse it to test other user agents. 596 * This is needed to implement future tests. 597 */ 598 bowser._detect = detect; 599 600 return bowser 601});
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.