vendor: 11,880 bytes, lines 1-346
1/*! 2 * Platform.js 3 * Copyright 2014-2018 Benjamin Tan 4 * Copyright 2011-2013 John-David Dalton 5 * Available under MIT license 6 */ 7; (function () { 8 'use strict'; 9 10 /** Used to determine if values are of the language type `Object`. */ 11 var objectTypes = { 12 'function': true, 13 'object': true 14 }; 15 16 /** Used as a reference to the global object. */ 17 var root = (objectTypes[typeof window] && window) || this; 18 19 /** Backup possible global object. */ 20 var oldRoot = root; 21 22 /** Detect free variable `exports`. */ 23 var freeExports = objectTypes[typeof exports] && exports; 24 25 /** Detect free variable `module`. */ 26 var freeModule = objectTypes[typeof module] && module && !module.nodeType && module; 27 28 /** Detect free variable `global` from Node.js or Browserified code and use it as `root`. */ 29 var freeGlobal = freeExports && freeModule && typeof global == 'object' && global; 30 if (freeGlobal && (freeGlobal.global === freeGlobal || freeGlobal.window === freeGlobal || freeGlobal.self === freeGlobal)) { 31 root = freeGlobal; 32 } 33 34 /** 35 * Used as the maximum length of an array-like object. 36 * See the [ES6 spec](http://people.mozilla.org/~jorendorff/es6-draft.html#sec-tolength) 37 * for more details. 38 */ 39 var maxSafeInteger = Math.pow(2, 53) - 1; 40 41 /** Regular expression to detect Opera. */ 42 var reOpera = /\bOpera/; 43 44 /** Possible global object. */ 45 var thisBinding = this; 46 47 /** Used for native method references. */ 48 var objectProto = Object.prototype; 49 50 /** Used to check for own properties of an object. */ 51 var hasOwnProperty = objectProto.hasOwnProperty; 52 53 /** Used to resolve the internal `[[Class]]` of values. */ 54 var toString = objectProto.toString; 55 56 /*--------------------------------------------------------------------------*/ 57 58 /** 59 * Capitalizes a string value. 60 * 61 * @private 62 * @param {string} string The string to capitalize. 63 * @returns {string} The capitalized string. 64 */ 65 function capitalize(string) { 66 string = String(string); 67 return string.charAt(0).toUpperCase() + string.slice(1); 68 } 69 70 /** 71 * A utility function to clean up the OS name. 72 * 73 * @private 74 * @param {string} os The OS name to clean up. 75 * @param {string} [pattern] A `RegExp` pattern matching the OS name. 76 * @param {string} [label] A label for the OS. 77 */ 78 function cleanupOS(os, pattern, label) { 79 // Platform tokens are defined at: 80 // http://msdn.microsoft.com/en-us/library/ms537503(VS.85).aspx 81 // http://web.archive.org/web/20081122053950/http://msdn.microsoft.com/en-us/library/ms537503(VS.85).aspx 82 var data = { 83 '10.0': '10', 84 '6.4': '10 Technical Preview', 85 '6.3': '8.1', 86 '6.2': '8', 87 '6.1': 'Server 2008 R2 / 7', 88 '6.0': 'Server 2008 / Vista', 89 '5.2': 'Server 2003 / XP 64-bit', 90 '5.1': 'XP', 91 '5.01': '2000 SP1', 92 '5.0': '2000', 93 '4.0': 'NT', 94 '4.90': 'ME' 95 }; 96 // Detect Windows version from platform tokens. 97 if (pattern && label && /^Win/i.test(os) && !/^Windows Phone /i.test(os) && 98 (data = data[/[\d.]+$/.exec(os)])) { 99 os = 'Windows ' + data; 100 } 101 // Correct character case and cleanup string. 102 os = String(os); 103 104 if (pattern && label) { 105 os = os.replace(RegExp(pattern, 'i'), label); 106 } 107 108 os = format( 109 os.replace(/ ce$/i, ' CE') 110 .replace(/\bhpw/i, 'web') 111 .replace(/\bMacintosh\b/, 'Mac OS') 112 .replace(/_PowerPC\b/i, ' OS') 113 .replace(/\b(OS X) [^ \d]+/i, '$1') 114 .replace(/\bMac (OS X)\b/, '$1') 115 .replace(/\/(\d)/, ' $1') 116 .replace(/_/g, '.') 117 .replace(/(?: BePC|[ .]*fc[ \d.]+)$/i, '') 118 .replace(/\bx86\.64\b/gi, 'x86_64') 119 .replace(/\b(Windows Phone) OS\b/, '$1') 120 .replace(/\b(Chrome OS \w+) [\d.]+\b/, '$1') 121 .split(' on ')[0] 122 ); 123 124 return os; 125 } 126 127 /** 128 * An iteration utility for arrays and objects. 129 * 130 * @private 131 * @param {Array|Object} object The object to iterate over. 132 * @param {Function} callback The function called per iteration. 133 */ 134 function each(object, callback) { 135 var index = -1, 136 length = object ? object.length : 0; 137 138 if (typeof length == 'number' && length > -1 && length <= maxSafeInteger) { 139 while (++index < length) { 140 callback(object[index], index, object); 141 } 142 } else { 143 forOwn(object, callback); 144 } 145 } 146 147 /** 148 * Trim and conditionally capitalize string values. 149 * 150 * @private 151 * @param {string} string The string to format. 152 * @returns {string} The formatted string. 153 */ 154 function format(string) { 155 string = trim(string); 156 return /^(?:webOS|i(?:OS|P))/.test(string) 157 ? string 158 : capitalize(string); 159 } 160 161 /** 162 * Iterates over an object's own properties, executing the `callback` for each. 163 * 164 * @private 165 * @param {Object} object The object to iterate over. 166 * @param {Function} callback The function executed per own property. 167 */ 168 function forOwn(object, callback) { 169 for (var key in object) { 170 if (hasOwnProperty.call(object, key)) { 171 callback(object[key], key, object); 172 } 173 } 174 } 175 176 /** 177 * Gets the internal `[[Class]]` of a value. 178 * 179 * @private 180 * @param {*} value The value. 181 * @returns {string} The `[[Class]]`. 182 */ 183 function getClassOf(value) { 184 return value == null 185 ? capitalize(value) 186 : toString.call(value).slice(8, -1); 187 } 188 189 /** 190 * Host objects can return type values that are different from their actual 191 * data type. The objects we are concerned with usually return non-primitive 192 * types of "object", "function", or "unknown". 193 * 194 * @private 195 * @param {*} object The owner of the property. 196 * @param {string} property The property to check. 197 * @returns {boolean} Returns `true` if the property value is a non-primitive, else `false`. 198 */ 199 function isHostType(object, property) { 200 var type = object != null ? typeof object[property] : 'number'; 201 return !/^(?:boolean|number|string|undefined)$/.test(type) && 202 (type == 'object' ? !!object[property] : true); 203 } 204 205 /** 206 * Prepares a string for use in a `RegExp` by making hyphens and spaces optional. 207 * 208 * @private 209 * @param {string} string The string to qualify. 210 * @returns {string} The qualified string. 211 */ 212 function qualify(string) { 213 return String(string).replace(/([ -])(?!$)/g, '$1?'); 214 } 215 216 /** 217 * A bare-bones `Array#reduce` like utility function. 218 * 219 * @private 220 * @param {Array} array The array to iterate over. 221 * @param {Function} callback The function called per iteration. 222 * @returns {*} The accumulated result. 223 */ 224 function reduce(array, callback) { 225 var accumulator = null; 226 each(array, function (value, index) { 227 accumulator = callback(accumulator, value, index, array); 228 }); 229 return accumulator; 230 } 231 232 /** 233 * Removes leading and trailing whitespace from a string. 234 * 235 * @private 236 * @param {string} string The string to trim. 237 * @returns {string} The trimmed string. 238 */ 239 function trim(string) { 240 return String(string).replace(/^ +| +$/g, ''); 241 } 242 243 /*--------------------------------------------------------------------------*/ 244 245 /** 246 * Creates a new platform object. 247 * 248 * @memberOf platform 249 * @param {Object|string} [ua=navigator.userAgent] The user agent string or 250 * context object. 251 * @returns {Object} A platform object. 252 */ 253 function parse(ua) { 254 255 /** The environment context object. */ 256 var context = root; 257 258 /** Used to flag when a custom context is provided. */ 259 var isCustomContext = ua && typeof ua == 'object' && getClassOf(ua) != 'String'; 260 261 // Juggle arguments. 262 if (isCustomContext) { 263 context = ua; 264 ua = null; 265 } 266 267 /** Browser navigator object. */ 268 var nav = context.navigator || {}; 269 270 /** Browser user agent string. */ 271 var userAgent = nav.userAgent || ''; 272 273 ua || (ua = userAgent); 274 275 /** Used to flag when `thisBinding` is the [ModuleScope]. */ 276 var isModuleScope = isCustomContext || thisBinding == oldRoot; 277 278 /** Used to detect if browser is like Chrome. */ 279 var likeChrome = isCustomContext 280 ? !!nav.likeChrome 281 : /\bChrome\b/.test(ua) && !/internal|\n/i.test(toString.toString()); 282 283 /** Internal `[[Class]]` value shortcuts. */ 284 var objectClass = 'Object', 285 airRuntimeClass = isCustomContext ? objectClass : 'ScriptBridgingProxyObject', 286 enviroClass = isCustomContext ? objectClass : 'Environment', 287 javaClass = (isCustomContext && context.java) ? 'JavaPackage' : getClassOf(context.java), 288 phantomClass = isCustomContext ? objectClass : 'RuntimeObject'; 289 290 /** Detect Java environments. */ 291 var java = /\bJava/.test(javaClass) && context.java; 292 293 /** Detect Rhino. */ 294 var rhino = java && getClassOf(context.environment) == enviroClass; 295 296 /** A character to represent alpha. */ 297 var alpha = java ? 'a' : '\u03b1'; 298 299 /** A character to represent beta. */ 300 var beta = java ? 'b' : '\u03b2'; 301 302 /** Browser document object. */ 303 var doc = context.document || {}; 304 305 /** 306 * Detect Opera browser (Presto-based). 307 * http://www.howtocreate.co.uk/operaStuff/operaObject.html 308 * http://dev.opera.com/articles/view/opera-mini-web-content-authoring-guidelines/#operamini 309 */ 310 var opera = context.operamini || context.opera; 311 312 /** Opera `[[Class]]`. */ 313 var operaClass = reOpera.test(operaClass = (isCustomContext && opera) ? opera['[[Class]]'] : getClassOf(opera)) 314 ? operaClass 315 : (opera = null); 316 317 /*------------------------------------------------------------------------*/ 318 319 /** Temporary variable used over the script's lifetime. */ 320 var data; 321 322 /** The CPU architecture. */ 323 var arch = ua; 324 325 /** Platform description array. */ 326 var description = []; 327 328 /** Platform alpha/beta indicator. */ 329 var prerelease = null; 330 331 /** A flag to indicate that environment features should be used to resolve the platform. */ 332 var useFeatures = ua == userAgent; 333 334 /** The browser/environment version. */ 335 var version = useFeatures && opera && typeof opera.version == 'function' && opera.version(); 336 337 /** A flag to indicate if the OS ends with "/ Version" */ 338 var isSpecialCasedOS; 339 340 /* Detectable layout engines (order is important). */ 341 var layout = getLayout([ 342 { 'label': 'EdgeHTML', 'pattern': '(?:Edge|EdgA|EdgiOS)' }, 343 'Trident', 344 { 'label': 'WebKit', 'pattern': 'AppleWebKit' }, 345 'iCab', 346 'Presto',
vendor: 12,546 bytes, lines 347-674
347 'NetFront', 348 'Tasman', 349 'KHTML', 350 'Gecko' 351 ]); 352 353 /* Detectable browser names (order is important). */ 354 var name = getName([ 355 'Adobe AIR', 356 'Arora', 357 'Avant Browser', 358 'Breach', 359 'Camino', 360 'Electron', 361 'Epiphany', 362 'Fennec', 363 'Flock', 364 'Galeon', 365 'GreenBrowser', 366 'iCab', 367 'Iceweasel', 368 'K-Meleon', 369 'Konqueror', 370 'Lunascape', 371 'Maxthon', 372 { 'label': 'Microsoft Edge', 'pattern': '(?:Edge|Edg|EdgA|EdgiOS)' }, 373 'Midori', 374 'Nook Browser', 375 'PaleMoon', 376 'PhantomJS', 377 'Raven', 378 'Rekonq', 379 'RockMelt', 380 { 'label': 'Samsung Internet', 'pattern': 'SamsungBrowser' }, 381 'SeaMonkey', 382 { 'label': 'Silk', 'pattern': '(?:Cloud9|Silk-Accelerated)' }, 383 'Sleipnir', 384 'SlimBrowser', 385 { 'label': 'SRWare Iron', 'pattern': 'Iron' }, 386 'Sunrise', 387 'Swiftfox', 388 'Waterfox', 389 'WebPositive', 390 'Opera Mini', 391 { 'label': 'Opera Mini', 'pattern': 'OPiOS' }, 392 'Opera', 393 { 'label': 'Opera', 'pattern': 'OPR' }, 394 'Chrome', 395 { 'label': 'Chrome Mobile', 'pattern': '(?:CriOS|CrMo)' }, 396 { 'label': 'Firefox', 'pattern': '(?:Firefox|Minefield)' }, 397 { 'label': 'Firefox for iOS', 'pattern': 'FxiOS' }, 398 { 'label': 'IE', 'pattern': 'IEMobile' }, 399 { 'label': 'IE', 'pattern': 'MSIE' }, 400 'Safari' 401 ]); 402 403 /* Detectable products (order is important). */ 404 var product = getProduct([ 405 { 'label': 'BlackBerry', 'pattern': 'BB10' }, 406 'BlackBerry', 407 { 'label': 'Galaxy S', 'pattern': 'GT-I9000' }, 408 { 'label': 'Galaxy S2', 'pattern': 'GT-I9100' }, 409 { 'label': 'Galaxy S3', 'pattern': 'GT-I9300' }, 410 { 'label': 'Galaxy S4', 'pattern': 'GT-I9500' }, 411 { 'label': 'Galaxy S5', 'pattern': 'SM-G900' }, 412 { 'label': 'Galaxy S6', 'pattern': 'SM-G920' }, 413 { 'label': 'Galaxy S6 Edge', 'pattern': 'SM-G925' }, 414 { 'label': 'Galaxy S7', 'pattern': 'SM-G930' }, 415 { 'label': 'Galaxy S7 Edge', 'pattern': 'SM-G935' }, 416 'Google TV', 417 'Lumia', 418 'iPad', 419 'iPod', 420 'iPhone', 421 'Kindle', 422 { 'label': 'Kindle Fire', 'pattern': '(?:Cloud9|Silk-Accelerated)' }, 423 'Nexus', 424 'Nook', 425 'PlayBook', 426 'PlayStation Vita', 427 'PlayStation', 428 'TouchPad', 429 'Transformer', 430 { 'label': 'Wii U', 'pattern': 'WiiU' }, 431 'Wii', 432 'Xbox One', 433 { 'label': 'Xbox 360', 'pattern': 'Xbox' }, 434 'Xoom' 435 ]); 436 437 /* Detectable manufacturers. */ 438 var manufacturer = getManufacturer({ 439 'Apple': { 'iPad': 1, 'iPhone': 1, 'iPod': 1 }, 440 'Archos': {}, 441 'Amazon': { 'Kindle': 1, 'Kindle Fire': 1 }, 442 'Asus': { 'Transformer': 1 }, 443 'Barnes & Noble': { 'Nook': 1 }, 444 'BlackBerry': { 'PlayBook': 1 }, 445 'Google': { 'Google TV': 1, 'Nexus': 1 }, 446 'HP': { 'TouchPad': 1 }, 447 'HTC': {}, 448 'LG': {}, 449 'Microsoft': { 'Xbox': 1, 'Xbox One': 1 }, 450 'Motorola': { 'Xoom': 1 }, 451 'Nintendo': { 'Wii U': 1, 'Wii': 1 }, 452 'Nokia': { 'Lumia': 1 }, 453 'Samsung': { 'Galaxy S': 1, 'Galaxy S2': 1, 'Galaxy S3': 1, 'Galaxy S4': 1 }, 454 'Sony': { 'PlayStation': 1, 'PlayStation Vita': 1 } 455 }); 456 457 /* Detectable operating systems (order is important). */ 458 var os = getOS([ 459 'Windows Phone', 460 'Android', 461 'CentOS', 462 { 'label': 'Chrome OS', 'pattern': 'CrOS' }, 463 'Debian', 464 'Fedora', 465 'FreeBSD', 466 'Gentoo', 467 'Haiku', 468 'Kubuntu', 469 'Linux Mint', 470 'OpenBSD', 471 'Red Hat', 472 'SuSE', 473 'Ubuntu', 474 'Xubuntu', 475 'Cygwin', 476 'Symbian OS', 477 'hpwOS', 478 'webOS ', 479 'webOS', 480 'Tablet OS', 481 'Tizen', 482 'Linux', 483 'Mac OS X', 484 'Macintosh', 485 'Mac', 486 'Windows 98;', 487 'Windows ' 488 ]); 489 490 /*------------------------------------------------------------------------*/ 491 492 /** 493 * Picks the layout engine from an array of guesses. 494 * 495 * @private 496 * @param {Array} guesses An array of guesses. 497 * @returns {null|string} The detected layout engine. 498 */ 499 function getLayout(guesses) { 500 return reduce(guesses, function (result, guess) { 501 return result || RegExp('\\b' + ( 502 guess.pattern || qualify(guess) 503 ) + '\\b', 'i').exec(ua) && (guess.label || guess); 504 }); 505 } 506 507 /** 508 * Picks the manufacturer from an array of guesses. 509 * 510 * @private 511 * @param {Array} guesses An object of guesses. 512 * @returns {null|string} The detected manufacturer. 513 */ 514 function getManufacturer(guesses) { 515 return reduce(guesses, function (result, value, key) { 516 // Lookup the manufacturer by product or scan the UA for the manufacturer. 517 return result || ( 518 value[product] || 519 value[/^[a-z]+(?: +[a-z]+\b)*/i.exec(product)] || 520 RegExp('\\b' + qualify(key) + '(?:\\b|\\w*\\d)', 'i').exec(ua) 521 ) && key; 522 }); 523 } 524 525 /** 526 * Picks the browser name from an array of guesses. 527 * 528 * @private 529 * @param {Array} guesses An array of guesses. 530 * @returns {null|string} The detected browser name. 531 */ 532 function getName(guesses) { 533 return reduce(guesses, function (result, guess) { 534 return result || RegExp('\\b' + ( 535 guess.pattern || qualify(guess) 536 ) + '\\b', 'i').exec(ua) && (guess.label || guess); 537 }); 538 } 539 540 /** 541 * Picks the OS name from an array of guesses. 542 * 543 * @private 544 * @param {Array} guesses An array of guesses. 545 * @returns {null|string} The detected OS name. 546 */ 547 function getOS(guesses) { 548 return reduce(guesses, function (result, guess) { 549 var pattern = guess.pattern || qualify(guess); 550 if (!result && (result = 551 RegExp('\\b' + pattern + '(?:/[\\d.]+|[ \\w.]*)', 'i').exec(ua) 552 )) { 553 result = cleanupOS(result, pattern, guess.label || guess); 554 } 555 return result; 556 }); 557 } 558 559 /** 560 * Picks the product name from an array of guesses. 561 * 562 * @private 563 * @param {Array} guesses An array of guesses. 564 * @returns {null|string} The detected product name. 565 */ 566 function getProduct(guesses) { 567 return reduce(guesses, function (result, guess) { 568 var pattern = guess.pattern || qualify(guess); 569 if (!result && (result = 570 RegExp('\\b' + pattern + ' *\\d+[.\\w_]*', 'i').exec(ua) || 571 RegExp('\\b' + pattern + ' *\\w+-[\\w]*', 'i').exec(ua) || 572 RegExp('\\b' + pattern + '(?:; *(?:[a-z]+[_-])?[a-z]+\\d+|[^ ();-]*)', 'i').exec(ua) 573 )) { 574 // Split by forward slash and append product version if needed. 575 if ((result = String((guess.label && !RegExp(pattern, 'i').test(guess.label)) ? guess.label : result).split('/'))[1] && !/[\d.]+/.test(result[0])) { 576 result[0] += ' ' + result[1]; 577 } 578 // Correct character case and cleanup string. 579 guess = guess.label || guess; 580 result = format(result[0] 581 .replace(RegExp(pattern, 'i'), guess) 582 .replace(RegExp('; *(?:' + guess + '[_-])?', 'i'), ' ') 583 .replace(RegExp('(' + guess + ')[-_.]?(\\w)', 'i'), '$1 $2')); 584 } 585 return result; 586 }); 587 } 588 589 /** 590 * Resolves the version using an array of UA patterns. 591 * 592 * @private 593 * @param {Array} patterns An array of UA patterns. 594 * @returns {null|string} The detected version. 595 */ 596 function getVersion(patterns) { 597 return reduce(patterns, function (result, pattern) { 598 return result || (RegExp(pattern + 599 '(?:-[\\d.]+/|(?: for [\\w-]+)?[ /-])([\\d.]+[^ ();/_-]*)', 'i').exec(ua) || 0)[1] || null; 600 }); 601 } 602 603 /** 604 * Returns `platform.description` when the platform object is coerced to a string. 605 * 606 * @name toString 607 * @memberOf platform 608 * @returns {string} Returns `platform.description` if available, else an empty string. 609 */ 610 function toStringPlatform() { 611 return this.description || ''; 612 } 613 614 /*------------------------------------------------------------------------*/ 615 616 // Convert layout to an array so we can add extra details. 617 layout && (layout = [layout]); 618 619 // Detect product names that contain their manufacturer's name. 620 if (manufacturer && !product) { 621 product = getProduct([manufacturer]); 622 } 623 // Clean up Google TV. 624 if ((data = /\bGoogle TV\b/.exec(product))) { 625 product = data[0]; 626 } 627 // Detect simulators. 628 if (/\bSimulator\b/i.test(ua)) { 629 product = (product ? product + ' ' : '') + 'Simulator'; 630 } 631 // Detect Opera Mini 8+ running in Turbo/Uncompressed mode on iOS. 632 if (name == 'Opera Mini' && /\bOPiOS\b/.test(ua)) { 633 description.push('running in Turbo/Uncompressed mode'); 634 } 635 // Detect IE Mobile 11. 636 if (name == 'IE' && /\blike iPhone OS\b/.test(ua)) { 637 data = parse(ua.replace(/like iPhone OS/, '')); 638 manufacturer = data.manufacturer; 639 product = data.product; 640 } 641 // Detect iOS. 642 else if (/^iP/.test(product)) { 643 name || (name = 'Safari'); 644 os = 'iOS' + ((data = / OS ([\d_]+)/i.exec(ua)) 645 ? ' ' + data[1].replace(/_/g, '.') 646 : ''); 647 } 648 // Detect Kubuntu. 649 else if (name == 'Konqueror' && !/buntu/i.test(os)) { 650 os = 'Kubuntu'; 651 } 652 // Detect Android browsers. 653 else if ((manufacturer && manufacturer != 'Google' && 654 ((/Chrome/.test(name) && !/\bMobile Safari\b/i.test(ua)) || /\bVita\b/.test(product))) || 655 (/\bAndroid\b/.test(os) && /^Chrome/.test(name) && /\bVersion\//i.test(ua))) { 656 name = 'Android Browser'; 657 os = /\bAndroid\b/.test(os) ? os : 'Android'; 658 } 659 // Detect Silk desktop/accelerated modes. 660 else if (name == 'Silk') { 661 if (!/\bMobi/i.test(ua)) { 662 os = 'Android'; 663 description.unshift('desktop mode'); 664 } 665 if (/Accelerated *= *true/i.test(ua)) { 666 description.unshift('accelerated'); 667 } 668 } 669 // Detect PaleMoon identifying as Firefox. 670 else if (name == 'PaleMoon' && (data = /\bFirefox\/([\d.]+)\b/.exec(ua))) { 671 description.push('identifying as Firefox ' + data[1]); 672 } 673 // Detect Firefox OS and products running Firefox. 674 else if (name == 'Firefox' && (data = /\b(Mobile|Tablet|TV)\b/i.exec(ua))) {
vendor: 13,010 bytes, lines 675-934
675 os || (os = 'Firefox OS'); 676 product || (product = data[1]); 677 } 678 // Detect false positives for Firefox/Safari. 679 else if (!name || (data = !/\bMinefield\b/i.test(ua) && /\b(?:Firefox|Safari)\b/.exec(name))) { 680 // Escape the `/` for Firefox 1. 681 if (name && !product && /[\/,]|^[^(]+?\)/.test(ua.slice(ua.indexOf(data + '/') + 8))) { 682 // Clear name of false positives. 683 name = null; 684 } 685 // Reassign a generic name. 686 if ((data = product || manufacturer || os) && 687 (product || manufacturer || /\b(?:Android|Symbian OS|Tablet OS|webOS)\b/.test(os))) { 688 name = /[a-z]+(?: Hat)?/i.exec(/\bAndroid\b/.test(os) ? os : data) + ' Browser'; 689 } 690 } 691 // Add Chrome version to description for Electron. 692 else if (name == 'Electron' && (data = (/\bChrome\/([\d.]+)\b/.exec(ua) || 0)[1])) { 693 description.push('Chromium ' + data); 694 } 695 // Detect non-Opera (Presto-based) versions (order is important). 696 if (!version) { 697 version = getVersion([ 698 '(?:Cloud9|CriOS|CrMo|Edge|Edg|EdgA|EdgiOS|FxiOS|IEMobile|Iron|Opera ?Mini|OPiOS|OPR|Raven|SamsungBrowser|Silk(?!/[\\d.]+$))', 699 'Version', 700 qualify(name), 701 '(?:Firefox|Minefield|NetFront)' 702 ]); 703 } 704 // Detect stubborn layout engines. 705 if ((data = 706 layout == 'iCab' && parseFloat(version) > 3 && 'WebKit' || 707 /\bOpera\b/.test(name) && (/\bOPR\b/.test(ua) ? 'Blink' : 'Presto') || 708 /\b(?:Midori|Nook|Safari)\b/i.test(ua) && !/^(?:Trident|EdgeHTML)$/.test(layout) && 'WebKit' || 709 !layout && /\bMSIE\b/i.test(ua) && (os == 'Mac OS' ? 'Tasman' : 'Trident') || 710 layout == 'WebKit' && /\bPlayStation\b(?! Vita\b)/i.test(name) && 'NetFront' 711 )) { 712 layout = [data]; 713 } 714 // Detect Windows Phone 7 desktop mode. 715 if (name == 'IE' && (data = (/; *(?:XBLWP|ZuneWP)(\d+)/i.exec(ua) || 0)[1])) { 716 name += ' Mobile'; 717 os = 'Windows Phone ' + (/\+$/.test(data) ? data : data + '.x'); 718 description.unshift('desktop mode'); 719 } 720 // Detect Windows Phone 8.x desktop mode. 721 else if (/\bWPDesktop\b/i.test(ua)) { 722 name = 'IE Mobile'; 723 os = 'Windows Phone 8.x'; 724 description.unshift('desktop mode'); 725 version || (version = (/\brv:([\d.]+)/.exec(ua) || 0)[1]); 726 } 727 // Detect IE 11 identifying as other browsers. 728 else if (name != 'IE' && layout == 'Trident' && (data = /\brv:([\d.]+)/.exec(ua))) { 729 if (name) { 730 description.push('identifying as ' + name + (version ? ' ' + version : '')); 731 } 732 name = 'IE'; 733 version = data[1]; 734 } 735 // Leverage environment features. 736 if (useFeatures) { 737 // Detect server-side environments. 738 // Rhino has a global function while others have a global object. 739 if (isHostType(context, 'global')) { 740 if (java) { 741 data = java.lang.System; 742 arch = data.getProperty('os.arch'); 743 os = os || data.getProperty('os.name') + ' ' + data.getProperty('os.version'); 744 } 745 if (rhino) { 746 try { 747 version = context.require('ringo/engine').version.join('.'); 748 name = 'RingoJS'; 749 } catch (e) { 750 if ((data = context.system) && data.global.system == context.system) { 751 name = 'Narwhal'; 752 os || (os = data[0].os || null); 753 } 754 } 755 if (!name) { 756 name = 'Rhino'; 757 } 758 } 759 else if ( 760 typeof context.process == 'object' && !context.process.browser && 761 (data = context.process) 762 ) { 763 if (typeof data.versions == 'object') { 764 if (typeof data.versions.electron == 'string') { 765 description.push('Node ' + data.versions.node); 766 name = 'Electron'; 767 version = data.versions.electron; 768 } else if (typeof data.versions.nw == 'string') { 769 description.push('Chromium ' + version, 'Node ' + data.versions.node); 770 name = 'NW.js'; 771 version = data.versions.nw; 772 } 773 } 774 if (!name) { 775 name = 'Node.js'; 776 arch = data.arch; 777 os = data.platform; 778 version = /[\d.]+/.exec(data.version); 779 version = version ? version[0] : null; 780 } 781 } 782 } 783 // Detect Adobe AIR. 784 else if (getClassOf((data = context.runtime)) == airRuntimeClass) { 785 name = 'Adobe AIR'; 786 os = data.flash.system.Capabilities.os; 787 } 788 // Detect PhantomJS. 789 else if (getClassOf((data = context.phantom)) == phantomClass) { 790 name = 'PhantomJS'; 791 version = (data = data.version || null) && (data.major + '.' + data.minor + '.' + data.patch); 792 } 793 // Detect IE compatibility modes. 794 else if (typeof doc.documentMode == 'number' && (data = /\bTrident\/(\d+)/i.exec(ua))) { 795 // We're in compatibility mode when the Trident version + 4 doesn't 796 // equal the document mode. 797 version = [version, doc.documentMode]; 798 if ((data = +data[1] + 4) != version[1]) { 799 description.push('IE ' + version[1] + ' mode'); 800 layout && (layout[1] = ''); 801 version[1] = data; 802 } 803 version = name == 'IE' ? String(version[1].toFixed(1)) : version[0]; 804 } 805 // Detect IE 11 masking as other browsers. 806 else if (typeof doc.documentMode == 'number' && /^(?:Chrome|Firefox)\b/.test(name)) { 807 description.push('masking as ' + name + ' ' + version); 808 name = 'IE'; 809 version = '11.0'; 810 layout = ['Trident']; 811 os = 'Windows'; 812 } 813 os = os && format(os); 814 } 815 // Detect prerelease phases. 816 if (version && (data = 817 /(?:[ab]|dp|pre|[ab]\d+pre)(?:\d+\+?)?$/i.exec(version) || 818 /(?:alpha|beta)(?: ?\d)?/i.exec(ua + ';' + (useFeatures && nav.appMinorVersion)) || 819 /\bMinefield\b/i.test(ua) && 'a' 820 )) { 821 prerelease = /b/i.test(data) ? 'beta' : 'alpha'; 822 version = version.replace(RegExp(data + '\\+?$'), '') + 823 (prerelease == 'beta' ? beta : alpha) + (/\d+\+?/.exec(data) || ''); 824 } 825 // Detect Firefox Mobile. 826 if (name == 'Fennec' || name == 'Firefox' && /\b(?:Android|Firefox OS)\b/.test(os)) { 827 name = 'Firefox Mobile'; 828 } 829 // Obscure Maxthon's unreliable version. 830 else if (name == 'Maxthon' && version) { 831 version = version.replace(/\.[\d.]+/, '.x'); 832 } 833 // Detect Xbox 360 and Xbox One. 834 else if (/\bXbox\b/i.test(product)) { 835 if (product == 'Xbox 360') { 836 os = null; 837 } 838 if (product == 'Xbox 360' && /\bIEMobile\b/.test(ua)) { 839 description.unshift('mobile mode'); 840 } 841 } 842 // Add mobile postfix. 843 else if ((/^(?:Chrome|IE|Opera)$/.test(name) || name && !product && !/Browser|Mobi/.test(name)) && 844 (os == 'Windows CE' || /Mobi/i.test(ua))) { 845 name += ' Mobile'; 846 } 847 // Detect IE platform preview. 848 else if (name == 'IE' && useFeatures) { 849 try { 850 if (context.external === null) { 851 description.unshift('platform preview'); 852 } 853 } catch (e) { 854 description.unshift('embedded'); 855 } 856 } 857 // Detect BlackBerry OS version. 858 // http://docs.blackberry.com/en/developers/deliverables/18169/HTTP_headers_sent_by_BB_Browser_1234911_11.jsp 859 else if ((/\bBlackBerry\b/.test(product) || /\bBB10\b/.test(ua)) && (data = 860 (RegExp(product.replace(/ +/g, ' *') + '/([.\\d]+)', 'i').exec(ua) || 0)[1] || 861 version 862 )) { 863 data = [data, /BB10/.test(ua)]; 864 os = (data[1] ? (product = null, manufacturer = 'BlackBerry') : 'Device Software') + ' ' + data[0]; 865 version = null; 866 } 867 // Detect Opera identifying/masking itself as another browser. 868 // http://www.opera.com/support/kb/view/843/ 869 else if (this != forOwn && product != 'Wii' && ( 870 (useFeatures && opera) || 871 (/Opera/.test(name) && /\b(?:MSIE|Firefox)\b/i.test(ua)) || 872 (name == 'Firefox' && /\bOS X (?:\d+\.){2,}/.test(os)) || 873 (name == 'IE' && ( 874 (os && !/^Win/.test(os) && version > 5.5) || 875 /\bWindows XP\b/.test(os) && version > 8 || 876 version == 8 && !/\bTrident\b/.test(ua) 877 )) 878 ) && !reOpera.test((data = parse.call(forOwn, ua.replace(reOpera, '') + ';'))) && data.name) { 879 // When "identifying", the UA contains both Opera and the other browser's name. 880 data = 'ing as ' + data.name + ((data = data.version) ? ' ' + data : ''); 881 if (reOpera.test(name)) { 882 if (/\bIE\b/.test(data) && os == 'Mac OS') { 883 os = null; 884 } 885 data = 'identify' + data; 886 } 887 // When "masking", the UA contains only the other browser's name. 888 else { 889 data = 'mask' + data; 890 if (operaClass) { 891 name = format(operaClass.replace(/([a-z])([A-Z])/g, '$1 $2')); 892 } else { 893 name = 'Opera'; 894 } 895 if (/\bIE\b/.test(data)) { 896 os = null; 897 } 898 if (!useFeatures) { 899 version = null; 900 } 901 } 902 layout = ['Presto']; 903 description.push(data); 904 } 905 // Detect WebKit Nightly and approximate Chrome/Safari versions. 906 if ((data = (/\bAppleWebKit\/([\d.]+\+?)/i.exec(ua) || 0)[1])) { 907 // Correct build number for numeric comparison. 908 // (e.g. "532.5" becomes "532.05") 909 data = [parseFloat(data.replace(/\.(\d)$/, '.0$1')), data]; 910 // Nightly builds are postfixed with a "+". 911 if (name == 'Safari' && data[1].slice(-1) == '+') { 912 name = 'WebKit Nightly'; 913 prerelease = 'alpha'; 914 version = data[1].slice(0, -1); 915 } 916 // Clear incorrect browser versions. 917 else if (version == data[1] || 918 version == (data[2] = (/\bSafari\/([\d.]+\+?)/i.exec(ua) || 0)[1])) { 919 version = null; 920 } 921 // Use the full Chrome version when available. 922 data[1] = (/\bChrome\/([\d.]+)/i.exec(ua) || 0)[1]; 923 // Detect Blink layout engine. 924 if (data[0] == 537.36 && data[2] == 537.36 && parseFloat(data[1]) >= 28 && layout == 'WebKit') { 925 layout = ['Blink']; 926 } 927 // Detect JavaScriptCore. 928 // http://stackoverflow.com/questions/6768474/how-can-i-detect-which-javascript-engine-v8-or-jsc-is-used-at-runtime-in-androi 929 if (!useFeatures || (!likeChrome && !data[1])) { 930 layout && (layout[1] = 'like Safari'); 931 data = (data = data[0], data < 400 ? 1 : data < 500 ? 2 : data < 526 ? 3 : data < 533 ? 4 : data < 534 ? '4+' : data < 535 ? 5 : data < 537 ? 6 : data < 538 ? 7 : data < 601 ? 8 : '8'); 932 } else { 933 layout && (layout[1] = 'like Chrome'); 934 data = data[1] || (data = data[0], data < 530 ? 1 : data < 532 ? 2 : data < 532.05 ? 3 : data < 533 ? 4 : data < 534.03 ? 5 : data < 534.07 ? 6 : data < 534.10 ? 7 : data < 534.13 ? 8 : data < 534.16 ? 9 : data < 534.24 ? 10 : data < 534.30 ? 11 : data < 535.01 ? 12 : data < 535.02 ? '13+' : data < 535.07 ? 15 : data < 535.11 ? 16
vendor: 7,036 bytes, lines 934-1122
934: data < 535.19 ? 17 : data < 536.05 ? 18 : data < 536.10 ? 19 : data < 537.01 ? 20 : data < 537.11 ? '21+' : data < 537.13 ? 23 : data < 537.18 ? 24 : data < 537.24 ? 25 : data < 537.36 ? 26 : layout != 'Blink' ? '27' : '28'); 935 } 936 // Add the postfix of ".x" or "+" for approximate versions. 937 layout && (layout[1] += ' ' + (data += typeof data == 'number' ? '.x' : /[.+]/.test(data) ? '' : '+')); 938 // Obscure version for some Safari 1-2 releases. 939 if (name == 'Safari' && (!version || parseInt(version) > 45)) { 940 version = data; 941 } 942 } 943 // Detect Opera desktop modes. 944 if (name == 'Opera' && (data = /\bzbov|zvav$/.exec(os))) { 945 name += ' '; 946 description.unshift('desktop mode'); 947 if (data == 'zvav') { 948 name += 'Mini'; 949 version = null; 950 } else { 951 name += 'Mobile'; 952 } 953 os = os.replace(RegExp(' *' + data + '$'), ''); 954 } 955 // Detect Chrome desktop mode. 956 else if (name == 'Safari' && /\bChrome\b/.exec(layout && layout[1])) { 957 description.unshift('desktop mode'); 958 name = 'Chrome Mobile'; 959 version = null; 960 961 if (/\bOS X\b/.test(os)) { 962 manufacturer = 'Apple'; 963 os = 'iOS 4.3+'; 964 } else { 965 os = null; 966 } 967 } 968 // Strip incorrect OS versions. 969 if (version && version.indexOf((data = /[\d.]+$/.exec(os))) == 0 && 970 ua.indexOf('/' + data + '-') > -1) { 971 os = trim(os.replace(data, '')); 972 } 973 // Add layout engine. 974 if (layout && !/\b(?:Avant|Nook)\b/.test(name) && ( 975 /Browser|Lunascape|Maxthon/.test(name) || 976 name != 'Safari' && /^iOS/.test(os) && /\bSafari\b/.test(layout[1]) || 977 /^(?:Adobe|Arora|Breach|Midori|Opera|Phantom|Rekonq|Rock|Samsung Internet|Sleipnir|Web)/.test(name) && layout[1])) { 978 // Don't add layout details to description if they are falsey. 979 (data = layout[layout.length - 1]) && description.push(data); 980 } 981 // Combine contextual information. 982 if (description.length) { 983 description = ['(' + description.join('; ') + ')']; 984 } 985 // Append manufacturer to description. 986 if (manufacturer && product && product.indexOf(manufacturer) < 0) { 987 description.push('on ' + manufacturer); 988 } 989 // Append product to description. 990 if (product) { 991 description.push((/^on /.test(description[description.length - 1]) ? '' : 'on ') + product); 992 } 993 // Parse the OS into an object. 994 if (os) { 995 data = / ([\d.+]+)$/.exec(os); 996 isSpecialCasedOS = data && os.charAt(os.length - data[0].length - 1) == '/'; 997 os = { 998 'architecture': 32, 999 'family': (data && !isSpecialCasedOS) ? os.replace(data[0], '') : os, 1000 'version': data ? data[1] : null, 1001 'toString': function () { 1002 var version = this.version; 1003 return this.family + ((version && !isSpecialCasedOS) ? ' ' + version : '') + (this.architecture == 64 ? ' 64-bit' : ''); 1004 } 1005 }; 1006 } 1007 // Add browser/OS architecture. 1008 if ((data = /\b(?:AMD|IA|Win|WOW|x86_|x)64\b/i.exec(arch)) && !/\bi686\b/i.test(arch)) { 1009 if (os) { 1010 os.architecture = 64; 1011 os.family = os.family.replace(RegExp(' *' + data), ''); 1012 } 1013 if ( 1014 name && (/\bWOW64\b/i.test(ua) || 1015 (useFeatures && /\w(?:86|32)$/.test(nav.cpuClass || nav.platform) && !/\bWin64; x64\b/i.test(ua))) 1016 ) { 1017 description.unshift('32-bit'); 1018 } 1019 } 1020 // Chrome 39 and above on OS X is always 64-bit. 1021 else if ( 1022 os && /^OS X/.test(os.family) && 1023 name == 'Chrome' && parseFloat(version) >= 39 1024 ) { 1025 os.architecture = 64; 1026 } 1027 1028 ua || (ua = null); 1029 1030 /*------------------------------------------------------------------------*/ 1031 1032 /** 1033 * The platform object. 1034 * 1035 * @name platform 1036 * @type Object 1037 */ 1038 var platform = {}; 1039 1040 /** 1041 * The platform description. 1042 * 1043 * @memberOf platform 1044 * @type string|null 1045 */ 1046 platform.description = ua; 1047 1048 /** 1049 * The name of the browser's layout engine. 1050 * 1051 * The list of common layout engines include: 1052 * "Blink", "EdgeHTML", "Gecko", "Trident" and "WebKit" 1053 * 1054 * @memberOf platform 1055 * @type string|null 1056 */ 1057 platform.layout = layout && layout[0]; 1058 1059 /** 1060 * The name of the product's manufacturer. 1061 * 1062 * The list of manufacturers include: 1063 * "Apple", "Archos", "Amazon", "Asus", "Barnes & Noble", "BlackBerry", 1064 * "Google", "HP", "HTC", "LG", "Microsoft", "Motorola", "Nintendo", 1065 * "Nokia", "Samsung" and "Sony" 1066 * 1067 * @memberOf platform 1068 * @type string|null 1069 */ 1070 platform.manufacturer = manufacturer; 1071 1072 /** 1073 * The name of the browser/environment. 1074 * 1075 * The list of common browser names include: 1076 * "Chrome", "Electron", "Firefox", "Firefox for iOS", "IE", 1077 * "Microsoft Edge", "PhantomJS", "Safari", "SeaMonkey", "Silk", 1078 * "Opera Mini" and "Opera" 1079 * 1080 * Mobile versions of some browsers have "Mobile" appended to their name: 1081 * eg. "Chrome Mobile", "Firefox Mobile", "IE Mobile" and "Opera Mobile" 1082 * 1083 * @memberOf platform 1084 * @type string|null 1085 */ 1086 platform.name = name; 1087 1088 /** 1089 * The alpha/beta release indicator. 1090 * 1091 * @memberOf platform 1092 * @type string|null 1093 */ 1094 platform.prerelease = prerelease; 1095 1096 /** 1097 * The name of the product hosting the browser. 1098 * 1099 * The list of common products include: 1100 * 1101 * "BlackBerry", "Galaxy S4", "Lumia", "iPad", "iPod", "iPhone", "Kindle", 1102 * "Kindle Fire", "Nexus", "Nook", "PlayBook", "TouchPad" and "Transformer" 1103 * 1104 * @memberOf platform 1105 * @type string|null 1106 */ 1107 platform.product = product; 1108 1109 /** 1110 * The browser's user agent string. 1111 * 1112 * @memberOf platform 1113 * @type string|null 1114 */ 1115 platform.ua = ua; 1116 1117 /** 1118 * The browser/environment version. 1119 * 1120 * @memberOf platform 1121 * @type string|null 1122 */
vendor: 3,089 bytes, lines 1123-1217
1123 platform.version = name && version; 1124 1125 /** 1126 * The name of the operating system. 1127 * 1128 * @memberOf platform 1129 * @type Object 1130 */ 1131 platform.os = os || { 1132 1133 /** 1134 * The CPU architecture the OS is built for. 1135 * 1136 * @memberOf platform.os 1137 * @type number|null 1138 */ 1139 'architecture': null, 1140 1141 /** 1142 * The family of the OS. 1143 * 1144 * Common values include: 1145 * "Windows", "Windows Server 2008 R2 / 7", "Windows Server 2008 / Vista", 1146 * "Windows XP", "OS X", "Ubuntu", "Debian", "Fedora", "Red Hat", "SuSE", 1147 * "Android", "iOS" and "Windows Phone" 1148 * 1149 * @memberOf platform.os 1150 * @type string|null 1151 */ 1152 'family': null, 1153 1154 /** 1155 * The version of the OS. 1156 * 1157 * @memberOf platform.os 1158 * @type string|null 1159 */ 1160 'version': null, 1161 1162 /** 1163 * Returns the OS string. 1164 * 1165 * @memberOf platform.os 1166 * @returns {string} The OS string. 1167 */ 1168 'toString': function () { return 'null'; } 1169 }; 1170 1171 platform.parse = parse; 1172 platform.toString = toStringPlatform; 1173 1174 if (platform.version) { 1175 description.unshift(version); 1176 } 1177 if (platform.name) { 1178 description.unshift(name); 1179 } 1180 if (os && name && !(os == String(os).split(' ')[0] && (os == name.split(' ')[0] || product))) { 1181 description.push(product ? '(' + os + ')' : 'on ' + os); 1182 } 1183 if (description.length) { 1184 platform.description = description.join(' '); 1185 } 1186 return platform; 1187 } 1188 1189 /*--------------------------------------------------------------------------*/ 1190 1191 // Export platform. 1192 var platform = parse(); 1193 1194 // Some AMD build optimizers, like r.js, check for condition patterns like the following: 1195 if (typeof define == 'function' && typeof define.amd == 'object' && define.amd) { 1196 // Expose platform on the global object to prevent errors when platform is 1197 // loaded by a script tag in the presence of an AMD loader. 1198 // See http://requirejs.org/docs/errors.html#mismatch for more details. 1199 root.platform = platform; 1200 1201 // Define as an anonymous module so platform can be aliased through path mapping. 1202 define(function () { 1203 return platform; 1204 }); 1205 } 1206 // Check for `exports` after `define` in case a build optimizer adds an `exports` object. 1207 else if (freeExports && freeModule) { 1208 // Export for CommonJS support. 1209 forOwn(platform, function (value, key) { 1210 freeExports[key] = value; 1211 }); 1212 } 1213 else { 1214 // Export to the global object. 1215 root.platform = platform; 1216 } 1217}.call(this));
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.