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