Commit a7812ea26dc2399d2a69759df98a4e7e8c8ff9e1

Authored by Adelmo Freitas
1 parent b3b1b287

ios changes

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