[ Index ]

PHP Cross Reference of Unnamed Project

title

Body

[close]

/lib/yuilib/3.17.2/yui-core/ -> yui-core.js (source)

   1  /*
   2  YUI 3.17.2 (build 9c3c78e)
   3  Copyright 2014 Yahoo! Inc. All rights reserved.
   4  Licensed under the BSD License.
   5  http://yuilibrary.com/license/
   6  */
   7  
   8  /**
   9  The YUI module contains the components required for building the YUI seed file.
  10  This includes the script loading mechanism, a simple queue, and the core
  11  utilities for the library.
  12  
  13  @module yui
  14  @main yui
  15  @submodule yui-base
  16  **/
  17  
  18  /*jshint eqeqeq: false*/
  19  if (typeof YUI != 'undefined') {
  20      YUI._YUI = YUI;
  21  }
  22  
  23  /**
  24  The YUI global namespace object. This is the constructor for all YUI instances.
  25  
  26  This is a self-instantiable factory function, meaning you don't need to precede
  27  it with the `new` operator. You can invoke it directly like this:
  28  
  29      YUI().use('*', function (Y) {
  30          // Y is a new YUI instance.
  31      });
  32  
  33  But it also works like this:
  34  
  35      var Y = YUI();
  36  
  37  The `YUI` constructor accepts an optional config object, like this:
  38  
  39      YUI({
  40          debug: true,
  41          combine: false
  42      }).use('node', function (Y) {
  43          // Y.Node is ready to use.
  44      });
  45  
  46  See the API docs for the <a href="config.html">Config</a> class for the complete
  47  list of supported configuration properties accepted by the YUI constuctor.
  48  
  49  If a global `YUI` object is already defined, the existing YUI object will not be
  50  overwritten, to ensure that defined namespaces are preserved.
  51  
  52  Each YUI instance has full custom event support, but only if the event system is
  53  available.
  54  
  55  @class YUI
  56  @uses EventTarget
  57  @constructor
  58  @global
  59  @param {Object} [config]* Zero or more optional configuration objects. Config
  60      values are stored in the `Y.config` property. See the
  61      <a href="config.html">Config</a> docs for the list of supported properties.
  62  **/
  63  
  64      /*global YUI*/
  65      /*global YUI_config*/
  66      var YUI = function() {
  67          var i = 0,
  68              Y = this,
  69              args = arguments,
  70              l = args.length,
  71              instanceOf = function(o, type) {
  72                  return (o && o.hasOwnProperty && (o instanceof type));
  73              },
  74              gconf = (typeof YUI_config !== 'undefined') && YUI_config;
  75  
  76          if (!(instanceOf(Y, YUI))) {
  77              Y = new YUI();
  78          } else {
  79              // set up the core environment
  80              Y._init();
  81  
  82              /**
  83              Master configuration that might span multiple contexts in a non-
  84              browser environment. It is applied first to all instances in all
  85              contexts.
  86  
  87              @example
  88  
  89                  YUI.GlobalConfig = {
  90                      filter: 'debug'
  91                  };
  92  
  93                  YUI().use('node', function (Y) {
  94                      // debug files used here
  95                  });
  96  
  97                  YUI({
  98                      filter: 'min'
  99                  }).use('node', function (Y) {
 100                      // min files used here
 101                  });
 102  
 103              @property {Object} GlobalConfig
 104              @global
 105              @static
 106              **/
 107              if (YUI.GlobalConfig) {
 108                  Y.applyConfig(YUI.GlobalConfig);
 109              }
 110  
 111              /**
 112              Page-level config applied to all YUI instances created on the
 113              current page. This is applied after `YUI.GlobalConfig` and before
 114              any instance-level configuration.
 115  
 116              @example
 117  
 118                  // Single global var to include before YUI seed file
 119                  YUI_config = {
 120                      filter: 'debug'
 121                  };
 122  
 123                  YUI().use('node', function (Y) {
 124                      // debug files used here
 125                  });
 126  
 127                  YUI({
 128                      filter: 'min'
 129                  }).use('node', function (Y) {
 130                      // min files used here
 131                  });
 132  
 133              @property {Object} YUI_config
 134              @global
 135              **/
 136              if (gconf) {
 137                  Y.applyConfig(gconf);
 138              }
 139  
 140              // bind the specified additional modules for this instance
 141              if (!l) {
 142                  Y._setup();
 143              }
 144          }
 145  
 146          if (l) {
 147              // Each instance can accept one or more configuration objects.
 148              // These are applied after YUI.GlobalConfig and YUI_Config,
 149              // overriding values set in those config files if there is a
 150              // matching property.
 151              for (; i < l; i++) {
 152                  Y.applyConfig(args[i]);
 153              }
 154  
 155              Y._setup();
 156          }
 157  
 158          Y.instanceOf = instanceOf;
 159  
 160          return Y;
 161      };
 162  
 163  (function() {
 164  
 165      var proto, prop,
 166          VERSION = '3.17.2',
 167          PERIOD = '.',
 168          BASE = 'http://yui.yahooapis.com/',
 169          /*
 170              These CSS class names can't be generated by
 171              getClassName since it is not available at the
 172              time they are being used.
 173          */
 174          DOC_LABEL = 'yui3-js-enabled',
 175          CSS_STAMP_EL = 'yui3-css-stamp',
 176          NOOP = function() {},
 177          SLICE = Array.prototype.slice,
 178          APPLY_TO_AUTH = { 'io.xdrReady': 1,   // the functions applyTo
 179                            'io.xdrResponse': 1,   // can call. this should
 180                            'SWF.eventHandler': 1 }, // be done at build time
 181          hasWin = (typeof window != 'undefined'),
 182          win = (hasWin) ? window : null,
 183          doc = (hasWin) ? win.document : null,
 184          docEl = doc && doc.documentElement,
 185          docClass = docEl && docEl.className,
 186          instances = {},
 187          time = new Date().getTime(),
 188          add = function(el, type, fn, capture) {
 189              if (el && el.addEventListener) {
 190                  el.addEventListener(type, fn, capture);
 191              } else if (el && el.attachEvent) {
 192                  el.attachEvent('on' + type, fn);
 193              }
 194          },
 195          remove = function(el, type, fn, capture) {
 196              if (el && el.removeEventListener) {
 197                  // this can throw an uncaught exception in FF
 198                  try {
 199                      el.removeEventListener(type, fn, capture);
 200                  } catch (ex) {}
 201              } else if (el && el.detachEvent) {
 202                  el.detachEvent('on' + type, fn);
 203              }
 204          },
 205          handleReady = function() {
 206              YUI.Env.DOMReady = true;
 207              if (hasWin) {
 208                  remove(doc, 'DOMContentLoaded', handleReady);
 209              }        
 210          },
 211          handleLoad = function() {
 212              YUI.Env.windowLoaded = true;
 213              YUI.Env.DOMReady = true;
 214              if (hasWin) {
 215                  remove(window, 'load', handleLoad);
 216              }
 217          },
 218          getLoader = function(Y, o) {
 219              var loader = Y.Env._loader,
 220                  lCore = [ 'loader-base' ],
 221                  G_ENV = YUI.Env,
 222                  mods = G_ENV.mods;
 223  
 224              if (loader) {
 225                  //loader._config(Y.config);
 226                  loader.ignoreRegistered = false;
 227                  loader.onEnd = null;
 228                  loader.data = null;
 229                  loader.required = [];
 230                  loader.loadType = null;
 231              } else {
 232                  loader = new Y.Loader(Y.config);
 233                  Y.Env._loader = loader;
 234              }
 235              if (mods && mods.loader) {
 236                  lCore = [].concat(lCore, YUI.Env.loaderExtras);
 237              }
 238              YUI.Env.core = Y.Array.dedupe([].concat(YUI.Env.core, lCore));
 239  
 240              return loader;
 241          },
 242  
 243          clobber = function(r, s) {
 244              for (var i in s) {
 245                  if (s.hasOwnProperty(i)) {
 246                      r[i] = s[i];
 247                  }
 248              }
 249          },
 250  
 251          ALREADY_DONE = { success: true };
 252  
 253  //  Stamp the documentElement (HTML) with a class of "yui-loaded" to
 254  //  enable styles that need to key off of JS being enabled.
 255  if (docEl && docClass.indexOf(DOC_LABEL) == -1) {
 256      if (docClass) {
 257          docClass += ' ';
 258      }
 259      docClass += DOC_LABEL;
 260      docEl.className = docClass;
 261  }
 262  
 263  if (VERSION.indexOf('@') > -1) {
 264      VERSION = '3.5.0'; // dev time hack for cdn test
 265  }
 266  
 267  proto = {
 268      /**
 269      Applies a new configuration object to the config of this YUI instance. This
 270      will merge new group/module definitions, and will also update the loader
 271      cache if necessary. Updating `Y.config` directly will not update the cache.
 272  
 273      @method applyConfig
 274      @param {Object} o the configuration object.
 275      @since 3.2.0
 276      **/
 277      applyConfig: function(o) {
 278  
 279          o = o || NOOP;
 280  
 281          var attr,
 282              name,
 283              // detail,
 284              config = this.config,
 285              mods = config.modules,
 286              groups = config.groups,
 287              aliases = config.aliases,
 288              loader = this.Env._loader;
 289  
 290          for (name in o) {
 291              if (o.hasOwnProperty(name)) {
 292                  attr = o[name];
 293                  if (mods && name == 'modules') {
 294                      clobber(mods, attr);
 295                  } else if (aliases && name == 'aliases') {
 296                      clobber(aliases, attr);
 297                  } else if (groups && name == 'groups') {
 298                      clobber(groups, attr);
 299                  } else if (name == 'win') {
 300                      config[name] = (attr && attr.contentWindow) || attr;
 301                      config.doc = config[name] ? config[name].document : null;
 302                  } else if (name == '_yuid') {
 303                      // preserve the guid
 304                  } else {
 305                      config[name] = attr;
 306                  }
 307              }
 308          }
 309  
 310          if (loader) {
 311              loader._config(o);
 312          }
 313  
 314      },
 315  
 316      /**
 317      Old way to apply a config to this instance (calls `applyConfig` under the
 318      hood).
 319  
 320      @private
 321      @method _config
 322      @param {Object} o The config to apply
 323      **/
 324      _config: function(o) {
 325          this.applyConfig(o);
 326      },
 327  
 328      /**
 329      Initializes this YUI instance.
 330  
 331      @private
 332      @method _init
 333      **/
 334      _init: function() {
 335          var filter, el,
 336              Y = this,
 337              G_ENV = YUI.Env,
 338              Env = Y.Env,
 339              prop;
 340  
 341          /**
 342          The version number of this YUI instance.
 343  
 344          This value is typically updated by a script when a YUI release is built,
 345          so it may not reflect the correct version number when YUI is run from
 346          the development source tree.
 347  
 348          @property {String} version
 349          **/
 350          Y.version = VERSION;
 351  
 352          if (!Env) {
 353              Y.Env = {
 354                  core: ['intl-base'],
 355                  loaderExtras: ['loader-rollup', 'loader-yui3'],
 356                  mods: {}, // flat module map
 357                  versions: {}, // version module map
 358                  base: BASE,
 359                  cdn: BASE + VERSION + '/build/',
 360                  // bootstrapped: false,
 361                  _idx: 0,
 362                  _used: {},
 363                  _attached: {},
 364                  _exported: {},
 365                  _missed: [],
 366                  _yidx: 0,
 367                  _uidx: 0,
 368                  _guidp: 'y',
 369                  _loaded: {},
 370                  // serviced: {},
 371                  // Regex in English:
 372                  // I'll start at the \b(yui).
 373                  // 1. Look in the test string for "yui" or
 374                  //    "yui-base" or "yui-davglass" or "yui-foobar" that comes after a word break.  That is, it
 375                  //    can't match "foyui" or "i_heart_yui". This can be anywhere in the string.
 376                  // 2. After #1 must come a forward slash followed by the string matched in #1, so
 377                  //    "yui-base/yui-base" or "yui-pants/yui-pants".
 378                  // 3. The second occurence of the #1 token can optionally be followed by "-debug" or "-min",
 379                  //    so "yui/yui-min", "yui/yui-debug", "yui-base/yui-base-debug". NOT "yui/yui-tshirt".
 380                  // 4. This is followed by ".js", so "yui/yui.js".
 381                  // 0. Going back to the beginning, now. If all that stuff in 1-4 comes after a "?" in the string,
 382                  //    then capture the junk between the LAST "&" and the string in 1-4.  So
 383                  //    "blah?foo/yui/yui.js" will capture "foo/" and "blah?some/thing.js&3.3.0/build/yui-davglass/yui-davglass.js"
 384                  //    will capture "3.3.0/build/"
 385                  //
 386                  // Regex Exploded:
 387                  // (?:\?             Find a ?
 388                  //   (?:[^&]*&)      followed by 0..n characters followed by an &
 389                  //   *               in fact, find as many sets of characters followed by a & as you can
 390                  //   ([^&]*)         capture the stuff after the last & in \1
 391                  // )?                but it's ok if all this ?junk&more_junk stuff isn't even there
 392                  // \b(               after a word break find either the string
 393                  //    yui(?:-\w+)?   "yui" optionally followed by a -, then more characters
 394                  // )                 and store the yui-* string in \2
 395                  // \/\2              then comes a / followed by the yui-* string in \2
 396                  // (?:-(min|debug))? optionally followed by "-min" or "-debug"
 397                  // .js               and ending in ".js"
 398                  _BASE_RE: /(?:\?(?:[^&]*&)*([^&]*))?\b(yui(?:-\w+)?)\/\2(?:-(min|debug))?\.js/,
 399                  parseBasePath: function(src, pattern) {
 400                      var match = src.match(pattern),
 401                          path, filter;
 402  
 403                      if (match) {
 404                          path = RegExp.leftContext || src.slice(0, src.indexOf(match[0]));
 405  
 406                          // this is to set up the path to the loader.  The file
 407                          // filter for loader should match the yui include.
 408                          filter = match[3];
 409  
 410                          // extract correct path for mixed combo urls
 411                          // http://yuilibrary.com/projects/yui3/ticket/2528423
 412                          if (match[1]) {
 413                              path += '?' + match[1];
 414                          }
 415                          path = {
 416                              filter: filter,
 417                              path: path
 418                          };
 419                      }
 420                      return path;
 421                  },
 422                  getBase: G_ENV && G_ENV.getBase ||
 423                          function(pattern) {
 424                              var nodes = (doc && doc.getElementsByTagName('script')) || [],
 425                                  path = Env.cdn, parsed,
 426                                  i, len, src;
 427  
 428                              for (i = 0, len = nodes.length; i < len; ++i) {
 429                                  src = nodes[i].src;
 430                                  if (src) {
 431                                      parsed = Y.Env.parseBasePath(src, pattern);
 432                                      if (parsed) {
 433                                          filter = parsed.filter;
 434                                          path = parsed.path;
 435                                          break;
 436                                      }
 437                                  }
 438                              }
 439  
 440                              // use CDN default
 441                              return path;
 442                          }
 443  
 444              };
 445  
 446              Env = Y.Env;
 447  
 448              Env._loaded[VERSION] = {};
 449  
 450              if (G_ENV && Y !== YUI) {
 451                  Env._yidx = ++G_ENV._yidx;
 452                  Env._guidp = ('yui_' + VERSION + '_' +
 453                               Env._yidx + '_' + time).replace(/[^a-z0-9_]+/g, '_');
 454              } else if (YUI._YUI) {
 455  
 456                  G_ENV = YUI._YUI.Env;
 457                  Env._yidx += G_ENV._yidx;
 458                  Env._uidx += G_ENV._uidx;
 459  
 460                  for (prop in G_ENV) {
 461                      if (!(prop in Env)) {
 462                          Env[prop] = G_ENV[prop];
 463                      }
 464                  }
 465  
 466                  delete YUI._YUI;
 467              }
 468  
 469              Y.id = Y.stamp(Y);
 470              instances[Y.id] = Y;
 471  
 472          }
 473  
 474          Y.constructor = YUI;
 475  
 476          // configuration defaults
 477          Y.config = Y.config || {
 478              bootstrap: true,
 479              cacheUse: true,
 480              debug: true,
 481              doc: doc,
 482              fetchCSS: true,
 483              throwFail: true,
 484              useBrowserConsole: true,
 485              useNativeES5: true,
 486              win: win,
 487              global: Function('return this')()
 488          };
 489  
 490          //Register the CSS stamp element
 491          if (doc && !doc.getElementById(CSS_STAMP_EL)) {
 492              el = doc.createElement('div');
 493              el.innerHTML = '<div id="' + CSS_STAMP_EL + '" style="position: absolute !important; visibility: hidden !important"></div>';
 494              YUI.Env.cssStampEl = el.firstChild;
 495              if (doc.body) {
 496                  doc.body.appendChild(YUI.Env.cssStampEl);
 497              } else {
 498                  docEl.insertBefore(YUI.Env.cssStampEl, docEl.firstChild);
 499              }
 500          } else if (doc && doc.getElementById(CSS_STAMP_EL) && !YUI.Env.cssStampEl) {
 501              YUI.Env.cssStampEl = doc.getElementById(CSS_STAMP_EL);
 502          }
 503  
 504          Y.config.lang = Y.config.lang || 'en-US';
 505  
 506          Y.config.base = YUI.config.base || Y.Env.getBase(Y.Env._BASE_RE);
 507  
 508          if (!filter || (!('mindebug').indexOf(filter))) {
 509              filter = 'min';
 510          }
 511          filter = (filter) ? '-' + filter : filter;
 512          Y.config.loaderPath = YUI.config.loaderPath || 'loader/loader' + filter + '.js';
 513  
 514      },
 515  
 516      /**
 517      Finishes the instance setup. Attaches whatever YUI modules were defined
 518      at the time that this instance was created.
 519  
 520      @method _setup
 521      @private
 522      **/
 523      _setup: function() {
 524          var i, Y = this,
 525              core = [],
 526              mods = YUI.Env.mods,
 527              extras = Y.config.core || [].concat(YUI.Env.core); //Clone it..
 528  
 529          for (i = 0; i < extras.length; i++) {
 530              if (mods[extras[i]]) {
 531                  core.push(extras[i]);
 532              }
 533          }
 534  
 535          Y._attach(['yui-base']);
 536          Y._attach(core);
 537  
 538          if (Y.Loader) {
 539              getLoader(Y);
 540          }
 541  
 542      },
 543  
 544      /**
 545      Executes the named method on the specified YUI instance if that method is
 546      whitelisted.
 547  
 548      @method applyTo
 549      @param {String} id YUI instance id.
 550      @param {String} method Name of the method to execute. For example:
 551          'Object.keys'.
 552      @param {Array} args Arguments to apply to the method.
 553      @return {Mixed} Return value from the applied method, or `null` if the
 554          specified instance was not found or the method was not whitelisted.
 555      **/
 556      applyTo: function(id, method, args) {
 557          if (!(method in APPLY_TO_AUTH)) {
 558              this.log(method + ': applyTo not allowed', 'warn', 'yui');
 559              return null;
 560          }
 561  
 562          var instance = instances[id], nest, m, i;
 563          if (instance) {
 564              nest = method.split('.');
 565              m = instance;
 566              for (i = 0; i < nest.length; i = i + 1) {
 567                  m = m[nest[i]];
 568                  if (!m) {
 569                      this.log('applyTo not found: ' + method, 'warn', 'yui');
 570                  }
 571              }
 572              return m && m.apply(instance, args);
 573          }
 574  
 575          return null;
 576      },
 577  
 578  /**
 579  Registers a YUI module and makes it available for use in a `YUI().use()` call or
 580  as a dependency for other modules.
 581  
 582  The easiest way to create a first-class YUI module is to use
 583  <a href="http://yui.github.com/shifter/">Shifter</a>, the YUI component build
 584  tool.
 585  
 586  Shifter will automatically wrap your module code in a `YUI.add()` call along
 587  with any configuration info required for the module.
 588  
 589  @example
 590  
 591      YUI.add('davglass', function (Y) {
 592          Y.davglass = function () {
 593          };
 594      }, '3.4.0', {
 595          requires: ['harley-davidson', 'mt-dew']
 596      });
 597  
 598  @method add
 599  @param {String} name Module name.
 600  @param {Function} fn Function containing module code. This function will be
 601      executed whenever the module is attached to a specific YUI instance.
 602  
 603      @param {YUI} fn.Y The YUI instance to which this module is attached.
 604      @param {String} fn.name Name of the module
 605  
 606  @param {String} version Module version number. This is currently used only for
 607      informational purposes, and is not used internally by YUI.
 608  
 609  @param {Object} [details] Module config.
 610      @param {Array} [details.requires] Array of other module names that must be
 611          attached before this module can be attached.
 612      @param {Array} [details.optional] Array of optional module names that should
 613          be attached before this module is attached if they've already been
 614          loaded. If the `loadOptional` YUI option is `true`, optional modules
 615          that have not yet been loaded will be loaded just as if they were hard
 616          requirements.
 617      @param {Array} [details.use] Array of module names that are included within
 618          or otherwise provided by this module, and which should be attached
 619          automatically when this module is attached. This makes it possible to
 620          create "virtual rollup" modules that simply attach a collection of other
 621          modules or submodules.
 622  
 623  @return {YUI} This YUI instance.
 624  **/
 625      add: function(name, fn, version, details) {
 626          details = details || {};
 627          var env = YUI.Env,
 628              mod = {
 629                  name: name,
 630                  fn: fn,
 631                  version: version,
 632                  details: details
 633              },
 634              //Instance hash so we don't apply it to the same instance twice
 635              applied = {},
 636              loader, inst, modInfo,
 637              i, versions = env.versions;
 638  
 639          env.mods[name] = mod;
 640          versions[version] = versions[version] || {};
 641          versions[version][name] = mod;
 642  
 643          for (i in instances) {
 644              if (instances.hasOwnProperty(i)) {
 645                  inst = instances[i];
 646                  if (!applied[inst.id]) {
 647                      applied[inst.id] = true;
 648                      loader = inst.Env._loader;
 649                      if (loader) {
 650                          modInfo = loader.getModuleInfo(name);
 651                          if (!modInfo || modInfo.temp) {
 652                              loader.addModule(details, name);
 653                          }
 654                      }
 655                  }
 656              }
 657          }
 658  
 659          return this;
 660      },
 661  
 662      /**
 663      Executes the callback function associated with each required module,
 664      attaching the module to this YUI instance.
 665  
 666      @method _attach
 667      @param {Array} r The array of modules to attach
 668      @param {Boolean} [moot=false] If `true`, don't throw a warning if the module
 669          is not attached.
 670      @private
 671      **/
 672      _attach: function(r, moot) {
 673          var i, name, mod, details, req, use, after,
 674              mods = YUI.Env.mods,
 675              aliases = YUI.Env.aliases,
 676              Y = this, j,
 677              cache = YUI.Env._renderedMods,
 678              loader = Y.Env._loader,
 679              done = Y.Env._attached,
 680              exported = Y.Env._exported,
 681              len = r.length, loader, def, go,
 682              c = [],
 683              modArgs, esCompat, reqlen, modInfo,
 684              condition,
 685              __exports__, __imports__;
 686  
 687          //Check for conditional modules (in a second+ instance) and add their requirements
 688          //TODO I hate this entire method, it needs to be fixed ASAP (3.5.0) ^davglass
 689          for (i = 0; i < len; i++) {
 690              name = r[i];
 691              mod = mods[name];
 692              c.push(name);
 693              if (loader && loader.conditions[name]) {
 694                  for (j in loader.conditions[name]) {
 695                      if (loader.conditions[name].hasOwnProperty(j)) {
 696                          def = loader.conditions[name][j];
 697                          go = def && ((def.ua && Y.UA[def.ua]) || (def.test && def.test(Y)));
 698                          if (go) {
 699                              c.push(def.name);
 700                          }
 701                      }
 702                  }
 703              }
 704          }
 705          r = c;
 706          len = r.length;
 707  
 708          for (i = 0; i < len; i++) {
 709              if (!done[r[i]]) {
 710                  name = r[i];
 711                  mod = mods[name];
 712  
 713                  if (aliases && aliases[name] && !mod) {
 714                      Y._attach(aliases[name]);
 715                      continue;
 716                  }
 717                  if (!mod) {
 718                      modInfo = loader && loader.getModuleInfo(name);
 719                      if (modInfo) {
 720                          mod = modInfo;
 721                          moot = true;
 722                      }
 723  
 724  
 725                      //if (!loader || !loader.moduleInfo[name]) {
 726                      //if ((!loader || !loader.moduleInfo[name]) && !moot) {
 727                      if (!moot && name) {
 728                          if ((name.indexOf('skin-') === -1) && (name.indexOf('css') === -1)) {
 729                              Y.Env._missed.push(name);
 730                              Y.Env._missed = Y.Array.dedupe(Y.Env._missed);
 731                              Y.message('NOT loaded: ' + name, 'warn', 'yui');
 732                          }
 733                      }
 734                  } else {
 735                      done[name] = true;
 736                      //Don't like this, but in case a mod was asked for once, then we fetch it
 737                      //We need to remove it from the missed list ^davglass
 738                      for (j = 0; j < Y.Env._missed.length; j++) {
 739                          if (Y.Env._missed[j] === name) {
 740                              Y.message('Found: ' + name + ' (was reported as missing earlier)', 'warn', 'yui');
 741                              Y.Env._missed.splice(j, 1);
 742                          }
 743                      }
 744  
 745                      // Optional dependencies normally work by modifying the
 746                      // dependency list of a module. If the dependency's test
 747                      // passes it is added to the list. If not, it's not loaded.
 748                      // This following check ensures that optional dependencies
 749                      // are not attached when they were already loaded into the
 750                      // page (when bundling for example)
 751                      if (loader && !loader._canBeAttached(name)) {
 752                          return true;
 753                      }
 754  
 755                      /*
 756                          If it's a temp module, we need to redo it's requirements if it's already loaded
 757                          since it may have been loaded by another instance and it's dependencies might
 758                          have been redefined inside the fetched file.
 759                      */
 760                      if (loader && cache && cache[name] && cache[name].temp) {
 761                          loader.getRequires(cache[name]);
 762                          req = [];
 763                          modInfo = loader.getModuleInfo(name);
 764                          for (j in modInfo.expanded_map) {
 765                              if (modInfo.expanded_map.hasOwnProperty(j)) {
 766                                  req.push(j);
 767                              }
 768                          }
 769                          Y._attach(req);
 770                      }
 771  
 772                      details = mod.details;
 773                      req = details.requires;
 774                      esCompat = details.es;
 775                      use = details.use;
 776                      after = details.after;
 777                      //Force Intl load if there is a language (Loader logic) @todo fix this shit
 778                      if (details.lang) {
 779                          req = req || [];
 780                          req.unshift('intl');
 781                      }
 782  
 783                      if (req) {
 784                          reqlen = req.length;
 785                          for (j = 0; j < reqlen; j++) {
 786                              if (!done[req[j]]) {
 787                                  if (!Y._attach(req)) {
 788                                      return false;
 789                                  }
 790                                  break;
 791                              }
 792                          }
 793                      }
 794  
 795                      if (after) {
 796                          for (j = 0; j < after.length; j++) {
 797                              if (!done[after[j]]) {
 798                                  if (!Y._attach(after, true)) {
 799                                      return false;
 800                                  }
 801                                  break;
 802                              }
 803                          }
 804                      }
 805  
 806                      if (mod.fn) {
 807                          modArgs = [Y, name];
 808                          if (esCompat) {
 809                              __imports__ = {};
 810                              __exports__ = {};
 811                              // passing `exports` and `imports` onto the module function
 812                              modArgs.push(__imports__, __exports__);
 813                              if (req) {
 814                                  reqlen = req.length;
 815                                  for (j = 0; j < reqlen; j++) {
 816                                      __imports__[req[j]] = exported.hasOwnProperty(req[j]) ? exported[req[j]] : Y;
 817                                  }
 818                              }
 819                          }
 820                          if (Y.config.throwFail) {
 821                              __exports__ = mod.fn.apply(esCompat ? undefined : mod, modArgs);
 822                          } else {
 823                              try {
 824                                  __exports__ = mod.fn.apply(esCompat ? undefined : mod, modArgs);
 825                              } catch (e) {
 826                                  Y.error('Attach error: ' + name, e, name);
 827                                  return false;
 828                              }
 829                          }
 830                          if (esCompat) {
 831                              // store the `exports` in case others `es` modules requires it
 832                              exported[name] = __exports__;
 833  
 834                              // If an ES module is conditionally loaded and set
 835                              // to be used "instead" another module, replace the
 836                              // trigger module's content with the conditionally
 837                              // loaded one so the values returned by require()
 838                              // still makes sense
 839                              condition = mod.details.condition;
 840                              if (condition && condition.when === 'instead') {
 841                                  exported[condition.trigger] = __exports__;
 842                              }
 843                          }
 844                      }
 845  
 846                      if (use) {
 847                          for (j = 0; j < use.length; j++) {
 848                              if (!done[use[j]]) {
 849                                  if (!Y._attach(use)) {
 850                                      return false;
 851                                  }
 852                                  break;
 853                              }
 854                          }
 855                      }
 856  
 857  
 858  
 859                  }
 860              }
 861          }
 862  
 863          return true;
 864      },
 865  
 866      /**
 867      Delays the `use` callback until another event has taken place such as
 868      `window.onload`, `domready`, `contentready`, or `available`.
 869  
 870      @private
 871      @method _delayCallback
 872      @param {Function} cb The original `use` callback.
 873      @param {String|Object} until Either an event name ('load', 'domready', etc.)
 874          or an object containing event/args keys for contentready/available.
 875      @return {Function}
 876      **/
 877      _delayCallback: function(cb, until) {
 878  
 879          var Y = this,
 880              mod = ['event-base'];
 881  
 882          until = (Y.Lang.isObject(until) ? until : { event: until });
 883  
 884          if (until.event === 'load') {
 885              mod.push('event-synthetic');
 886          }
 887  
 888          return function() {
 889              var args = arguments;
 890              Y._use(mod, function() {
 891                  Y.on(until.event, function() {
 892                      args[1].delayUntil = until.event;
 893                      cb.apply(Y, args);
 894                  }, until.args);
 895              });
 896          };
 897      },
 898  
 899      /**
 900      Attaches one or more modules to this YUI instance. When this is executed,
 901      the requirements of the desired modules are analyzed, and one of several
 902      things can happen:
 903  
 904  
 905        * All required modules have already been loaded, and just need to be
 906          attached to this YUI instance. In this case, the `use()` callback will
 907          be executed synchronously after the modules are attached.
 908  
 909        * One or more modules have not yet been loaded, or the Get utility is not
 910          available, or the `bootstrap` config option is `false`. In this case,
 911          a warning is issued indicating that modules are missing, but all
 912          available modules will still be attached and the `use()` callback will
 913          be executed synchronously.
 914  
 915        * One or more modules are missing and the Loader is not available but the
 916          Get utility is, and `bootstrap` is not `false`. In this case, the Get
 917          utility will be used to load the Loader, and we will then proceed to
 918          the following state:
 919  
 920        * One or more modules are missing and the Loader is available. In this
 921          case, the Loader will be used to resolve the dependency tree for the
 922          missing modules and load them and their dependencies. When the Loader is
 923          finished loading modules, the `use()` callback will be executed
 924          asynchronously.
 925  
 926      @example
 927  
 928          // Loads and attaches dd and its dependencies.
 929          YUI().use('dd', function (Y) {
 930              // ...
 931          });
 932  
 933          // Loads and attaches dd and node as well as all of their dependencies.
 934          YUI().use(['dd', 'node'], function (Y) {
 935              // ...
 936          });
 937  
 938          // Attaches all modules that have already been loaded.
 939          YUI().use('*', function (Y) {
 940              // ...
 941          });
 942  
 943          // Attaches a gallery module.
 944          YUI().use('gallery-yql', function (Y) {
 945              // ...
 946          });
 947  
 948          // Attaches a YUI 2in3 module.
 949          YUI().use('yui2-datatable', function (Y) {
 950              // ...
 951          });
 952  
 953      @method use
 954      @param {String|Array} modules* One or more module names to attach.
 955      @param {Function} [callback] Callback function to be executed once all
 956          specified modules and their dependencies have been attached.
 957      @param {YUI} callback.Y The YUI instance created for this sandbox.
 958      @param {Object} callback.status Object containing `success`, `msg` and
 959          `data` properties.
 960      @chainable
 961      **/
 962      use: function() {
 963          var args = SLICE.call(arguments, 0),
 964              callback = args[args.length - 1],
 965              Y = this,
 966              i = 0,
 967              name,
 968              Env = Y.Env,
 969              provisioned = true;
 970  
 971          // The last argument supplied to use can be a load complete callback
 972          if (Y.Lang.isFunction(callback)) {
 973              args.pop();
 974              if (Y.config.delayUntil) {
 975                  callback = Y._delayCallback(callback, Y.config.delayUntil);
 976              }
 977          } else {
 978              callback = null;
 979          }
 980          if (Y.Lang.isArray(args[0])) {
 981              args = args[0];
 982          }
 983  
 984          if (Y.config.cacheUse) {
 985              while ((name = args[i++])) {
 986                  if (!Env._attached[name]) {
 987                      provisioned = false;
 988                      break;
 989                  }
 990              }
 991  
 992              if (provisioned) {
 993                  if (args.length) {
 994                  }
 995                  Y._notify(callback, ALREADY_DONE, args);
 996                  return Y;
 997              }
 998          }
 999  
1000          if (Y._loading) {
1001              Y._useQueue = Y._useQueue || new Y.Queue();
1002              Y._useQueue.add([args, callback]);
1003          } else {
1004              Y._use(args, function(Y, response) {
1005                  Y._notify(callback, response, args);
1006              });
1007          }
1008  
1009          return Y;
1010      },
1011  
1012      /**
1013      Sugar for loading both legacy and ES6-based YUI modules.
1014  
1015      @method require
1016      @param {String} [modules*] List of module names to import or a single
1017          module name.
1018      @param {Function} callback Callback that gets called once all the modules
1019          were loaded. Each parameter of the callback is the export value of the
1020          corresponding module in the list. If the module is a legacy YUI module,
1021          the YUI instance is used instead of the module exports.
1022      @example
1023      ```
1024      YUI().require(['es6-set'], function (Y, imports) {
1025          var Set = imports.Set,
1026              set = new Set();
1027      });
1028      ```
1029      **/
1030      require: function () {
1031          var args = SLICE.call(arguments),
1032              callback;
1033  
1034          if (typeof args[args.length - 1] === 'function') {
1035              callback = args.pop();
1036  
1037              // only add the callback if one was provided
1038              // YUI().require('foo'); is valid
1039              args.push(function (Y) {
1040                  var i, length = args.length,
1041                      exported = Y.Env._exported,
1042                      __imports__ = {};
1043  
1044                  // Get only the imports requested as arguments
1045                  for (i = 0; i < length; i++) {
1046                      if (exported.hasOwnProperty(args[i])) {
1047                          __imports__[args[i]] = exported[args[i]];
1048                      }
1049                  }
1050  
1051                  // Using `undefined` because:
1052                  // - Using `Y.config.global` would force the value of `this` to be
1053                  //   the global object even in strict mode
1054                  // - Using `Y` goes against the goal of moving away from a shared
1055                  //   object and start thinking in terms of imported and exported
1056                  //   objects
1057                  callback.call(undefined, Y, __imports__);
1058              });
1059          }
1060          // Do not return the Y object. This makes it hard to follow this
1061          // traditional pattern:
1062          //   var Y = YUI().use(...);
1063          // This is a good idea in the light of ES6 modules, to avoid working
1064          // in the global scope.
1065          // This also leaves the door open for returning a promise, once the
1066          // YUI loader is based on the ES6 loader which uses
1067          // loader.import(...).then(...)
1068          this.use.apply(this, args);
1069      },
1070  
1071      /**
1072      Handles Loader notifications about attachment/load errors.
1073  
1074      @method _notify
1075      @param {Function} callback Callback to pass to `Y.config.loadErrorFn`.
1076      @param {Object} response Response returned from Loader.
1077      @param {Array} args Arguments passed from Loader.
1078      @private
1079      **/
1080      _notify: function(callback, response, args) {
1081          if (!response.success && this.config.loadErrorFn) {
1082              this.config.loadErrorFn.call(this, this, callback, response, args);
1083          } else if (callback) {
1084              if (this.Env._missed && this.Env._missed.length) {
1085                  response.msg = 'Missing modules: ' + this.Env._missed.join();
1086                  response.success = false;
1087              }
1088              if (this.config.throwFail) {
1089                  callback(this, response);
1090              } else {
1091                  try {
1092                      callback(this, response);
1093                  } catch (e) {
1094                      this.error('use callback error', e, args);
1095                  }
1096              }
1097          }
1098      },
1099  
1100      /**
1101      Called from the `use` method queue to ensure that only one set of loading
1102      logic is performed at a time.
1103  
1104      @method _use
1105      @param {String} args* One or more modules to attach.
1106      @param {Function} [callback] Function to call once all required modules have
1107          been attached.
1108      @private
1109      **/
1110      _use: function(args, callback) {
1111  
1112          if (!this.Array) {
1113              this._attach(['yui-base']);
1114          }
1115  
1116          var len, loader, handleBoot,
1117              Y = this,
1118              G_ENV = YUI.Env,
1119              mods = G_ENV.mods,
1120              Env = Y.Env,
1121              used = Env._used,
1122              aliases = G_ENV.aliases,
1123              queue = G_ENV._loaderQueue,
1124              firstArg = args[0],
1125              YArray = Y.Array,
1126              config = Y.config,
1127              boot = config.bootstrap,
1128              missing = [],
1129              i,
1130              r = [],
1131              ret = true,
1132              fetchCSS = config.fetchCSS,
1133              process = function(names, skip) {
1134  
1135                  var i = 0, a = [], name, len, m, req, use;
1136  
1137                  if (!names.length) {
1138                      return;
1139                  }
1140  
1141                  if (aliases) {
1142                      len = names.length;
1143                      for (i = 0; i < len; i++) {
1144                          if (aliases[names[i]] && !mods[names[i]]) {
1145                              a = [].concat(a, aliases[names[i]]);
1146                          } else {
1147                              a.push(names[i]);
1148                          }
1149                      }
1150                      names = a;
1151                  }
1152  
1153                  len = names.length;
1154  
1155                  for (i = 0; i < len; i++) {
1156                      name = names[i];
1157                      if (!skip) {
1158                          r.push(name);
1159                      }
1160  
1161                      // only attach a module once
1162                      if (used[name]) {
1163                          continue;
1164                      }
1165  
1166                      m = mods[name];
1167                      req = null;
1168                      use = null;
1169  
1170                      if (m) {
1171                          used[name] = true;
1172                          req = m.details.requires;
1173                          use = m.details.use;
1174                      } else {
1175                          // CSS files don't register themselves, see if it has
1176                          // been loaded
1177                          if (!G_ENV._loaded[VERSION][name]) {
1178                              missing.push(name);
1179                          } else {
1180                              used[name] = true; // probably css
1181                          }
1182                      }
1183  
1184                      // make sure requirements are attached
1185                      if (req && req.length) {
1186                          process(req);
1187                      }
1188  
1189                      // make sure we grab the submodule dependencies too
1190                      if (use && use.length) {
1191                          process(use, 1);
1192                      }
1193                  }
1194  
1195              },
1196  
1197              handleLoader = function(fromLoader) {
1198                  var response = fromLoader || {
1199                          success: true,
1200                          msg: 'not dynamic'
1201                      },
1202                      redo, origMissing,
1203                      ret = true,
1204                      data = response.data;
1205  
1206                  Y._loading = false;
1207  
1208                  if (data) {
1209                      origMissing = missing;
1210                      missing = [];
1211                      r = [];
1212                      process(data);
1213                      redo = missing.length;
1214                      if (redo) {
1215                          if ([].concat(missing).sort().join() ==
1216                                  origMissing.sort().join()) {
1217                              redo = false;
1218                          }
1219                      }
1220                  }
1221  
1222                  if (redo && data) {
1223                      Y._loading = true;
1224                      Y._use(missing, function() {
1225                          if (Y._attach(data)) {
1226                              Y._notify(callback, response, data);
1227                          }
1228                      });
1229                  } else {
1230                      if (data) {
1231                          ret = Y._attach(data);
1232                      }
1233                      if (ret) {
1234                          Y._notify(callback, response, args);
1235                      }
1236                  }
1237  
1238                  if (Y._useQueue && Y._useQueue.size() && !Y._loading) {
1239                      Y._use.apply(Y, Y._useQueue.next());
1240                  }
1241  
1242              };
1243  
1244  
1245          // YUI().use('*'); // bind everything available
1246          if (firstArg === '*') {
1247              args = [];
1248              for (i in mods) {
1249                  if (mods.hasOwnProperty(i)) {
1250                      args.push(i);
1251                  }
1252              }
1253              ret = Y._attach(args);
1254              if (ret) {
1255                  handleLoader();
1256              }
1257              return Y;
1258          }
1259  
1260          if ((mods.loader || mods['loader-base']) && !Y.Loader) {
1261              Y._attach(['loader' + ((!mods.loader) ? '-base' : '')]);
1262          }
1263  
1264  
1265          // use loader to expand dependencies and sort the
1266          // requirements if it is available.
1267          if (boot && Y.Loader && args.length) {
1268              loader = getLoader(Y);
1269              loader.require(args);
1270              loader.ignoreRegistered = true;
1271              loader._boot = true;
1272              loader.calculate(null, (fetchCSS) ? null : 'js');
1273              args = loader.sorted;
1274              loader._boot = false;
1275          }
1276  
1277          process(args);
1278  
1279          len = missing.length;
1280  
1281  
1282          if (len) {
1283              missing = YArray.dedupe(missing);
1284              len = missing.length;
1285          }
1286  
1287  
1288          // dynamic load
1289          if (boot && len && Y.Loader) {
1290              Y._loading = true;
1291              loader = getLoader(Y);
1292              loader.onEnd = handleLoader;
1293              loader.context = Y;
1294              loader.data = args;
1295              loader.ignoreRegistered = false;
1296              loader.require(missing);
1297              loader.insert(null, (fetchCSS) ? null : 'js');
1298  
1299          } else if (boot && len && Y.Get && !Env.bootstrapped) {
1300  
1301              Y._loading = true;
1302  
1303              handleBoot = function() {
1304                  Y._loading = false;
1305                  queue.running = false;
1306                  Env.bootstrapped = true;
1307                  G_ENV._bootstrapping = false;
1308                  if (Y._attach(['loader'])) {
1309                      Y._use(args, callback);
1310                  }
1311              };
1312  
1313              if (G_ENV._bootstrapping) {
1314                  queue.add(handleBoot);
1315              } else {
1316                  G_ENV._bootstrapping = true;
1317                  Y.Get.script(config.base + config.loaderPath, {
1318                      onEnd: handleBoot
1319                  });
1320              }
1321  
1322          } else {
1323              ret = Y._attach(args);
1324              if (ret) {
1325                  handleLoader();
1326              }
1327          }
1328  
1329          return Y;
1330      },
1331  
1332  
1333      /**
1334      Utility method for safely creating namespaces if they don't already exist.
1335      May be called statically on the YUI global object or as a method on a YUI
1336      instance.
1337  
1338      When called statically, a namespace will be created on the YUI global
1339      object:
1340  
1341          // Create `YUI.your.namespace.here` as nested objects, preserving any
1342          // objects that already exist instead of overwriting them.
1343          YUI.namespace('your.namespace.here');
1344  
1345      When called as a method on a YUI instance, a namespace will be created on
1346      that instance:
1347  
1348          // Creates `Y.property.package`.
1349          Y.namespace('property.package');
1350  
1351      Dots in the input string cause `namespace` to create nested objects for each
1352      token. If any part of the requested namespace already exists, the current
1353      object will be left in place and will not be overwritten. This allows
1354      multiple calls to `namespace` to preserve existing namespaced properties.
1355  
1356      If the first token in the namespace string is "YAHOO", that token is
1357      discarded. This is legacy behavior for backwards compatibility with YUI 2.
1358  
1359      Be careful with namespace tokens. Reserved words may work in some browsers
1360      and not others. For instance, the following will fail in some browsers
1361      because the supported version of JavaScript reserves the word "long":
1362  
1363          Y.namespace('really.long.nested.namespace');
1364  
1365      Note: If you pass multiple arguments to create multiple namespaces, only the
1366      last one created is returned from this function.
1367  
1368      @method namespace
1369      @param {String} namespace* One or more namespaces to create.
1370      @return {Object} Reference to the last namespace object created.
1371      **/
1372      namespace: function() {
1373          var a = arguments, o, i = 0, j, d, arg;
1374  
1375          for (; i < a.length; i++) {
1376              o = this; //Reset base object per argument or it will get reused from the last
1377              arg = a[i];
1378              if (arg.indexOf(PERIOD) > -1) { //Skip this if no "." is present
1379                  d = arg.split(PERIOD);
1380                  for (j = (d[0] == 'YAHOO') ? 1 : 0; j < d.length; j++) {
1381                      o[d[j]] = o[d[j]] || {};
1382                      o = o[d[j]];
1383                  }
1384              } else {
1385                  o[arg] = o[arg] || {};
1386                  o = o[arg]; //Reset base object to the new object so it's returned
1387              }
1388          }
1389          return o;
1390      },
1391  
1392      // this is replaced if the log module is included
1393      log: NOOP,
1394      message: NOOP,
1395      // this is replaced if the dump module is included
1396      dump: function (o) { return ''+o; },
1397  
1398      /**
1399      Reports an error.
1400  
1401      The reporting mechanism is controlled by the `throwFail` configuration
1402      attribute. If `throwFail` is falsy, the message is logged. If `throwFail` is
1403      truthy, a JS exception is thrown.
1404  
1405      If an `errorFn` is specified in the config it must return `true` to indicate
1406      that the exception was handled and keep it from being thrown.
1407  
1408      @method error
1409      @param {String} msg Error message.
1410      @param {Error|String} [e] JavaScript error object or an error string.
1411      @param {String} [src] Source of the error (such as the name of the module in
1412          which the error occurred).
1413      @chainable
1414      **/
1415      error: function(msg, e, src) {
1416          //TODO Add check for window.onerror here
1417  
1418          var Y = this, ret;
1419  
1420          if (Y.config.errorFn) {
1421              ret = Y.config.errorFn.apply(Y, arguments);
1422          }
1423  
1424          if (!ret) {
1425              throw (e || new Error(msg));
1426          } else {
1427              Y.message(msg, 'error', ''+src); // don't scrub this one
1428          }
1429  
1430          return Y;
1431      },
1432  
1433      /**
1434      Generates an id string that is unique among all YUI instances in this
1435      execution context.
1436  
1437      @method guid
1438      @param {String} [pre] Prefix.
1439      @return {String} Unique id.
1440      **/
1441      guid: function(pre) {
1442          var id = this.Env._guidp + '_' + (++this.Env._uidx);
1443          return (pre) ? (pre + id) : id;
1444      },
1445  
1446      /**
1447      Returns a unique id associated with the given object and (if *readOnly* is
1448      falsy) stamps the object with that id so it can be identified in the future.
1449  
1450      Stamping an object involves adding a `_yuid` property to it that contains
1451      the object's id. One exception to this is that in Internet Explorer, DOM
1452      nodes have a `uniqueID` property that contains a browser-generated unique
1453      id, which will be used instead of a YUI-generated id when available.
1454  
1455      @method stamp
1456      @param {Object} o Object to stamp.
1457      @param {Boolean} readOnly If truthy and the given object has not already
1458          been stamped, the object will not be modified and `null` will be
1459          returned.
1460      @return {String} Object's unique id, or `null` if *readOnly* was truthy and
1461          the given object was not already stamped.
1462      **/
1463      stamp: function(o, readOnly) {
1464          var uid;
1465          if (!o) {
1466              return o;
1467          }
1468  
1469          // IE generates its own unique ID for dom nodes
1470          // The uniqueID property of a document node returns a new ID
1471          if (o.uniqueID && o.nodeType && o.nodeType !== 9) {
1472              uid = o.uniqueID;
1473          } else {
1474              uid = (typeof o === 'string') ? o : o._yuid;
1475          }
1476  
1477          if (!uid) {
1478              uid = this.guid();
1479              if (!readOnly) {
1480                  try {
1481                      o._yuid = uid;
1482                  } catch (e) {
1483                      uid = null;
1484                  }
1485              }
1486          }
1487          return uid;
1488      },
1489  
1490      /**
1491      Destroys this YUI instance.
1492  
1493      @method destroy
1494      @since 3.3.0
1495      **/
1496      destroy: function() {
1497          var Y = this;
1498          if (Y.Event) {
1499              Y.Event._unload();
1500          }
1501          delete instances[Y.id];
1502          delete Y.Env;
1503          delete Y.config;
1504      }
1505  
1506      /**
1507      Safe `instanceof` wrapper that works around a memory leak in IE when the
1508      object being tested is `window` or `document`.
1509  
1510      Unless you are testing objects that may be `window` or `document`, you
1511      should use the native `instanceof` operator instead of this method.
1512  
1513      @method instanceOf
1514      @param {Object} o Object to check.
1515      @param {Object} type Class to check against.
1516      @since 3.3.0
1517      **/
1518  };
1519  
1520      YUI.prototype = proto;
1521  
1522      // inheritance utilities are not available yet
1523      for (prop in proto) {
1524          if (proto.hasOwnProperty(prop)) {
1525              YUI[prop] = proto[prop];
1526          }
1527      }
1528  
1529      /**
1530      Applies a configuration to all YUI instances in this execution context.
1531  
1532      The main use case for this method is in "mashups" where several third-party
1533      scripts need to write to a global YUI config, but cannot share a single
1534      centrally-managed config object. This way they can all call
1535      `YUI.applyConfig({})` instead of overwriting the single global config.
1536  
1537      @example
1538  
1539          YUI.applyConfig({
1540              modules: {
1541                  davglass: {
1542                      fullpath: './davglass.js'
1543                  }
1544              }
1545          });
1546  
1547          YUI.applyConfig({
1548              modules: {
1549                  foo: {
1550                      fullpath: './foo.js'
1551                  }
1552              }
1553          });
1554  
1555          YUI().use('davglass', function (Y) {
1556              // Module davglass will be available here.
1557          });
1558  
1559      @method applyConfig
1560      @param {Object} o Configuration object to apply.
1561      @static
1562      @since 3.5.0
1563      **/
1564      YUI.applyConfig = function(o) {
1565          if (!o) {
1566              return;
1567          }
1568          //If there is a GlobalConfig, apply it first to set the defaults
1569          if (YUI.GlobalConfig) {
1570              this.prototype.applyConfig.call(this, YUI.GlobalConfig);
1571          }
1572          //Apply this config to it
1573          this.prototype.applyConfig.call(this, o);
1574          //Reset GlobalConfig to the combined config
1575          YUI.GlobalConfig = this.config;
1576      };
1577  
1578      // set up the environment
1579      YUI._init();
1580  
1581      if (hasWin) {
1582          add(doc, 'DOMContentLoaded', handleReady);
1583  
1584          // add a window load event at load time so we can capture
1585          // the case where it fires before dynamic loading is
1586          // complete.
1587          add(window, 'load', handleLoad);
1588      } else {
1589          handleReady();
1590          handleLoad();
1591      }
1592  
1593      YUI.Env.add = add;
1594      YUI.Env.remove = remove;
1595  
1596      /*global exports*/
1597      // Support the CommonJS method for exporting our single global
1598      if (typeof exports == 'object') {
1599          exports.YUI = YUI;
1600          /**
1601          * Set a method to be called when `Get.script` is called in Node.js
1602          * `Get` will open the file, then pass it's content and it's path
1603          * to this method before attaching it. Commonly used for code coverage
1604          * instrumentation. <strong>Calling this multiple times will only
1605          * attach the last hook method</strong>. This method is only
1606          * available in Node.js.
1607          * @method setLoadHook
1608          * @static
1609          * @param {Function} fn The function to set
1610          * @param {String} fn.data The content of the file
1611          * @param {String} fn.path The file path of the file
1612          */
1613          YUI.setLoadHook = function(fn) {
1614              YUI._getLoadHook = fn;
1615          };
1616          /**
1617          * Load hook for `Y.Get.script` in Node.js, see `YUI.setLoadHook`
1618          * @method _getLoadHook
1619          * @private
1620          * @param {String} data The content of the file
1621          * @param {String} path The file path of the file
1622          */
1623          YUI._getLoadHook = null;
1624      }
1625  
1626      YUI.Env[VERSION] = {};
1627  }());
1628  
1629  
1630  /**
1631  Config object that contains all of the configuration options for
1632  this `YUI` instance.
1633  
1634  This object is supplied by the implementer when instantiating YUI. Some
1635  properties have default values if they are not supplied by the implementer.
1636  
1637  This object should not be updated directly because some values are cached. Use
1638  `applyConfig()` to update the config object on a YUI instance that has already
1639  been configured.
1640  
1641  @class config
1642  @static
1643  **/
1644  
1645  /**
1646  If `true` (the default), YUI will "bootstrap" the YUI Loader and module metadata
1647  if they're needed to load additional dependencies and aren't already available.
1648  
1649  Setting this to `false` will prevent YUI from automatically loading the Loader
1650  and module metadata, so you will need to manually ensure that they're available
1651  or handle dependency resolution yourself.
1652  
1653  @property {Boolean} bootstrap
1654  @default true
1655  **/
1656  
1657  /**
1658  
1659  @property {Object} filters
1660  **/
1661  
1662  /**
1663  If `true`, YUI will use a combo handler to load multiple modules in as few
1664  requests as possible.
1665  
1666  The YUI CDN (which YUI uses by default) supports combo handling, but other
1667  servers may not. If the server from which you're loading YUI does not support
1668  combo handling, set this to `false`.
1669  
1670  Providing a value for the `base` config property will cause `combine` to default
1671  to `false` instead of `true`.
1672  
1673  @property {Boolean} combine
1674  @default true
1675  */
1676  
1677  /**
1678  Array of module names that should never be dynamically loaded.
1679  
1680  @property {String[]} ignore
1681  **/
1682  
1683  /**
1684  Array of module names that should always be loaded when required, even if
1685  already present on the page.
1686  
1687  @property {String[]} force
1688  **/
1689  
1690  /**
1691  DOM element or id that should be used as the insertion point for dynamically
1692  added `<script>` and `<link>` nodes.
1693  
1694  @property {HTMLElement|String} insertBefore
1695  **/
1696  
1697  /**
1698  Object hash containing attributes to add to dynamically added `<script>` nodes.
1699  
1700  @property {Object} jsAttributes
1701  **/
1702  
1703  /**
1704  Object hash containing attributes to add to dynamically added `<link>` nodes.
1705  
1706  @property {Object} cssAttributes
1707  **/
1708  
1709  /**
1710  Timeout in milliseconds before a dynamic JS or CSS request will be considered a
1711  failure. If not set, no timeout will be enforced.
1712  
1713  @property {Number} timeout
1714  **/
1715  
1716  /**
1717  A hash of module definitions to add to the list of available YUI modules. These
1718  modules can then be dynamically loaded via the `use()` method.
1719  
1720  This is a hash in which keys are module names and values are objects containing
1721  module metadata.
1722  
1723  See `Loader.addModule()` for the supported module metadata fields. Also see
1724  `groups`, which provides a way to configure the base and combo spec for a set of
1725  modules.
1726  
1727  @example
1728  
1729      modules: {
1730          mymod1: {
1731              requires: ['node'],
1732              fullpath: '/mymod1/mymod1.js'
1733          },
1734  
1735          mymod2: {
1736              requires: ['mymod1'],
1737              fullpath: '/mymod2/mymod2.js'
1738          },
1739  
1740          mymod3: '/js/mymod3.js',
1741          mycssmod: '/css/mycssmod.css'
1742      }
1743  
1744  @property {Object} modules
1745  **/
1746  
1747  /**
1748  Aliases are dynamic groups of modules that can be used as shortcuts.
1749  
1750  @example
1751  
1752      YUI({
1753          aliases: {
1754              davglass: [ 'node', 'yql', 'dd' ],
1755              mine: [ 'davglass', 'autocomplete']
1756          }
1757      }).use('mine', function (Y) {
1758          // Node, YQL, DD & AutoComplete available here.
1759      });
1760  
1761  @property {Object} aliases
1762  **/
1763  
1764  /**
1765  A hash of module group definitions.
1766  
1767  For each group you can specify a list of modules and the base path and
1768  combo spec to use when dynamically loading the modules.
1769  
1770  @example
1771  
1772      groups: {
1773          yui2: {
1774              // specify whether or not this group has a combo service
1775              combine: true,
1776  
1777              // The comboSeperator to use with this group's combo handler
1778              comboSep: ';',
1779  
1780              // The maxURLLength for this server
1781              maxURLLength: 500,
1782  
1783              // the base path for non-combo paths
1784              base: 'http://yui.yahooapis.com/2.8.0r4/build/',
1785  
1786              // the path to the combo service
1787              comboBase: 'http://yui.yahooapis.com/combo?',
1788  
1789              // a fragment to prepend to the path attribute when
1790              // when building combo urls
1791              root: '2.8.0r4/build/',
1792  
1793              // the module definitions
1794              modules:  {
1795                  yui2_yde: {
1796                      path: "yahoo-dom-event/yahoo-dom-event.js"
1797                  },
1798                  yui2_anim: {
1799                      path: "animation/animation.js",
1800                      requires: ['yui2_yde']
1801                  }
1802              }
1803          }
1804      }
1805  
1806  @property {Object} groups
1807  **/
1808  
1809  /**
1810  Path to the Loader JS file, relative to the `base` path.
1811  
1812  This is used to dynamically bootstrap the Loader when it's needed and isn't yet
1813  available.
1814  
1815  @property {String} loaderPath
1816  @default "loader/loader-min.js"
1817  **/
1818  
1819  /**
1820  If `true`, YUI will attempt to load CSS dependencies and skins. Set this to
1821  `false` to prevent YUI from loading any CSS, or set it to the string `"force"`
1822  to force CSS dependencies to be loaded even if their associated JS modules are
1823  already loaded.
1824  
1825  @property {Boolean|String} fetchCSS
1826  @default true
1827  **/
1828  
1829  /**
1830  Default gallery version used to build gallery module urls.
1831  
1832  @property {String} gallery
1833  @since 3.1.0
1834  **/
1835  
1836  /**
1837  Default YUI 2 version used to build YUI 2 module urls.
1838  
1839  This is used for intrinsic YUI 2 support via the 2in3 project. Also see the
1840  `2in3` config for pulling different revisions of the wrapped YUI 2 modules.
1841  
1842  @property {String} yui2
1843  @default "2.9.0"
1844  @since 3.1.0
1845  **/
1846  
1847  /**
1848  Revision number of YUI 2in3 modules that should be used when loading YUI 2in3.
1849  
1850  @property {String} 2in3
1851  @default "4"
1852  @since 3.1.0
1853  **/
1854  
1855  /**
1856  Alternate console log function that should be used in environments without a
1857  supported native console. This function is executed with the YUI instance as its
1858  `this` object.
1859  
1860  @property {Function} logFn
1861  @since 3.1.0
1862  **/
1863  
1864  /**
1865  The minimum log level to log messages for. Log levels are defined
1866  incrementally. Messages greater than or equal to the level specified will
1867  be shown. All others will be discarded. The order of log levels in
1868  increasing priority is:
1869  
1870      debug
1871      info
1872      warn
1873      error
1874  
1875  @property {String} logLevel
1876  @default 'debug'
1877  @since 3.10.0
1878  **/
1879  
1880  /**
1881  Callback to execute when `Y.error()` is called. It receives the error message
1882  and a JavaScript error object if one was provided.
1883  
1884  This function is executed with the YUI instance as its `this` object.
1885  
1886  Returning `true` from this function will prevent an exception from being thrown.
1887  
1888  @property {Function} errorFn
1889  @param {String} errorFn.msg Error message
1890  @param {Object} [errorFn.err] Error object (if one was provided).
1891  @since 3.2.0
1892  **/
1893  
1894  /**
1895  A callback to execute when Loader fails to load one or more resources.
1896  
1897  This could be because of a script load failure. It could also be because a
1898  module fails to register itself when the `requireRegistration` config is `true`.
1899  
1900  If this function is defined, the `use()` callback will only be called when the
1901  loader succeeds. Otherwise, `use()` will always executes unless there was a
1902  JavaScript error when attaching a module.
1903  
1904  @property {Function} loadErrorFn
1905  @since 3.3.0
1906  **/
1907  
1908  /**
1909  If `true`, Loader will expect all loaded scripts to be first-class YUI modules
1910  that register themselves with the YUI global, and will trigger a failure if a
1911  loaded script does not register a YUI module.
1912  
1913  @property {Boolean} requireRegistration
1914  @default false
1915  @since 3.3.0
1916  **/
1917  
1918  /**
1919  Cache serviced use() requests.
1920  
1921  @property {Boolean} cacheUse
1922  @default true
1923  @since 3.3.0
1924  @deprecated No longer used.
1925  **/
1926  
1927  /**
1928  Whether or not YUI should use native ES5 functionality when available for
1929  features like `Y.Array.each()`, `Y.Object()`, etc.
1930  
1931  When `false`, YUI will always use its own fallback implementations instead of
1932  relying on ES5 functionality, even when ES5 functionality is available.
1933  
1934  @property {Boolean} useNativeES5
1935  @default true
1936  @since 3.5.0
1937  **/
1938  
1939  /**
1940   * Leverage native JSON stringify if the browser has a native
1941   * implementation.  In general, this is a good idea.  See the Known Issues
1942   * section in the JSON user guide for caveats.  The default value is true
1943   * for browsers with native JSON support.
1944   *
1945   * @property useNativeJSONStringify
1946   * @type Boolean
1947   * @default true
1948   * @since 3.8.0
1949   */
1950  
1951   /**
1952   * Leverage native JSON parse if the browser has a native implementation.
1953   * In general, this is a good idea.  See the Known Issues section in the
1954   * JSON user guide for caveats.  The default value is true for browsers with
1955   * native JSON support.
1956   *
1957   * @property useNativeJSONParse
1958   * @type Boolean
1959   * @default true
1960   * @since 3.8.0
1961   */
1962  
1963  /**
1964  Delay the `use` callback until a specific event has passed (`load`, `domready`, `contentready` or `available`)
1965  
1966  @property {Object|String} delayUntil
1967  @since 3.6.0
1968  @example
1969  
1970  You can use `load` or `domready` strings by default:
1971  
1972      YUI({
1973          delayUntil: 'domready'
1974      }, function (Y) {
1975          // This will not execute until 'domeready' occurs.
1976      });
1977  
1978  Or you can delay until a node is available (with `available` or `contentready`):
1979  
1980      YUI({
1981          delayUntil: {
1982              event: 'available',
1983              args : '#foo'
1984          }
1985      }, function (Y) {
1986          // This will not execute until a node matching the selector "#foo" is
1987          // available in the DOM.
1988      });
1989  
1990  **/
1991  YUI.add('yui-base', function (Y, NAME) {
1992  
1993  /*
1994   * YUI stub
1995   * @module yui
1996   * @submodule yui-base
1997   */
1998  /**
1999   * The YUI module contains the components required for building the YUI
2000   * seed file.  This includes the script loading mechanism, a simple queue,
2001   * and the core utilities for the library.
2002   * @module yui
2003   * @submodule yui-base
2004   */
2005  
2006  /**
2007   * Provides core language utilites and extensions used throughout YUI.
2008   *
2009   * @class Lang
2010   * @static
2011   */
2012  
2013  var L = Y.Lang || (Y.Lang = {}),
2014  
2015  STRING_PROTO = String.prototype,
2016  TOSTRING     = Object.prototype.toString,
2017  
2018  TYPES = {
2019      'undefined'        : 'undefined',
2020      'number'           : 'number',
2021      'boolean'          : 'boolean',
2022      'string'           : 'string',
2023      '[object Function]': 'function',
2024      '[object RegExp]'  : 'regexp',
2025      '[object Array]'   : 'array',
2026      '[object Date]'    : 'date',
2027      '[object Error]'   : 'error'
2028  },
2029  
2030  SUBREGEX         = /\{\s*([^|}]+?)\s*(?:\|([^}]*))?\s*\}/g,
2031  
2032  WHITESPACE       = "\x09\x0A\x0B\x0C\x0D\x20\xA0\u1680\u180E\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200A\u2028\u2029\u202F\u205F\u3000\uFEFF",
2033  WHITESPACE_CLASS = "[\x09-\x0D\x20\xA0\u1680\u180E\u2000-\u200A\u2028\u2029\u202F\u205F\u3000\uFEFF]+",
2034  TRIM_LEFT_REGEX  = new RegExp("^" + WHITESPACE_CLASS),
2035  TRIM_RIGHT_REGEX = new RegExp(WHITESPACE_CLASS + "$"),
2036  TRIMREGEX        = new RegExp(TRIM_LEFT_REGEX.source + "|" + TRIM_RIGHT_REGEX.source, "g"),
2037  
2038  NATIVE_FN_REGEX  = /\{\s*\[(?:native code|function)\]\s*\}/i;
2039  
2040  // -- Protected Methods --------------------------------------------------------
2041  
2042  /**
2043  Returns `true` if the given function appears to be implemented in native code,
2044  `false` otherwise. Will always return `false` -- even in ES5-capable browsers --
2045  if the `useNativeES5` YUI config option is set to `false`.
2046  
2047  This isn't guaranteed to be 100% accurate and won't work for anything other than
2048  functions, but it can be useful for determining whether a function like
2049  `Array.prototype.forEach` is native or a JS shim provided by another library.
2050  
2051  There's a great article by @kangax discussing certain flaws with this technique:
2052  <http://perfectionkills.com/detecting-built-in-host-methods/>
2053  
2054  While his points are valid, it's still possible to benefit from this function
2055  as long as it's used carefully and sparingly, and in such a way that false
2056  negatives have minimal consequences. It's used internally to avoid using
2057  potentially broken non-native ES5 shims that have been added to the page by
2058  other libraries.
2059  
2060  @method _isNative
2061  @param {Function} fn Function to test.
2062  @return {Boolean} `true` if _fn_ appears to be native, `false` otherwise.
2063  @static
2064  @protected
2065  @since 3.5.0
2066  **/
2067  L._isNative = function (fn) {
2068      return !!(Y.config.useNativeES5 && fn && NATIVE_FN_REGEX.test(fn));
2069  };
2070  
2071  // -- Public Methods -----------------------------------------------------------
2072  
2073  /**
2074   * Determines whether or not the provided item is an array.
2075   *
2076   * Returns `false` for array-like collections such as the function `arguments`
2077   * collection or `HTMLElement` collections. Use `Y.Array.test()` if you want to
2078   * test for an array-like collection.
2079   *
2080   * @method isArray
2081   * @param o The object to test.
2082   * @return {boolean} true if o is an array.
2083   * @static
2084   */
2085  L.isArray = L._isNative(Array.isArray) ? Array.isArray : function (o) {
2086      return L.type(o) === 'array';
2087  };
2088  
2089  /**
2090   * Determines whether or not the provided item is a boolean.
2091   * @method isBoolean
2092   * @static
2093   * @param o The object to test.
2094   * @return {boolean} true if o is a boolean.
2095   */
2096  L.isBoolean = function(o) {
2097      return typeof o === 'boolean';
2098  };
2099  
2100  /**
2101   * Determines whether or not the supplied item is a date instance.
2102   * @method isDate
2103   * @static
2104   * @param o The object to test.
2105   * @return {boolean} true if o is a date.
2106   */
2107  L.isDate = function(o) {
2108      return L.type(o) === 'date' && o.toString() !== 'Invalid Date' && !isNaN(o);
2109  };
2110  
2111  /**
2112   * <p>
2113   * Determines whether or not the provided item is a function.
2114   * Note: Internet Explorer thinks certain functions are objects:
2115   * </p>
2116   *
2117   * <pre>
2118   * var obj = document.createElement("object");
2119   * Y.Lang.isFunction(obj.getAttribute) // reports false in IE
2120   * &nbsp;
2121   * var input = document.createElement("input"); // append to body
2122   * Y.Lang.isFunction(input.focus) // reports false in IE
2123   * </pre>
2124   *
2125   * <p>
2126   * You will have to implement additional tests if these functions
2127   * matter to you.
2128   * </p>
2129   *
2130   * @method isFunction
2131   * @static
2132   * @param o The object to test.
2133   * @return {boolean} true if o is a function.
2134   */
2135  L.isFunction = function(o) {
2136      return L.type(o) === 'function';
2137  };
2138  
2139  /**
2140   * Determines whether or not the provided item is null.
2141   * @method isNull
2142   * @static
2143   * @param o The object to test.
2144   * @return {boolean} true if o is null.
2145   */
2146  L.isNull = function(o) {
2147      return o === null;
2148  };
2149  
2150  /**
2151   * Determines whether or not the provided item is a legal number.
2152   * @method isNumber
2153   * @static
2154   * @param o The object to test.
2155   * @return {boolean} true if o is a number.
2156   */
2157  L.isNumber = function(o) {
2158      return typeof o === 'number' && isFinite(o);
2159  };
2160  
2161  /**
2162   * Determines whether or not the provided item is of type object
2163   * or function. Note that arrays are also objects, so
2164   * <code>Y.Lang.isObject([]) === true</code>.
2165   * @method isObject
2166   * @static
2167   * @param o The object to test.
2168   * @param failfn {boolean} fail if the input is a function.
2169   * @return {boolean} true if o is an object.
2170   * @see isPlainObject
2171   */
2172  L.isObject = function(o, failfn) {
2173      var t = typeof o;
2174      return (o && (t === 'object' ||
2175          (!failfn && (t === 'function' || L.isFunction(o))))) || false;
2176  };
2177  
2178  /**
2179   * Determines whether or not the provided value is a regexp.
2180   * @method isRegExp
2181   * @static
2182   * @param value The value or object to test.
2183   * @return {boolean} true if value is a regexp.
2184   */
2185  L.isRegExp = function(value) {
2186      return L.type(value) === 'regexp';
2187  };
2188  
2189  /**
2190   * Determines whether or not the provided item is a string.
2191   * @method isString
2192   * @static
2193   * @param o The object to test.
2194   * @return {boolean} true if o is a string.
2195   */
2196  L.isString = function(o) {
2197      return typeof o === 'string';
2198  };
2199  
2200  /**
2201   * Determines whether or not the provided item is undefined.
2202   * @method isUndefined
2203   * @static
2204   * @param o The object to test.
2205   * @return {boolean} true if o is undefined.
2206   */
2207  L.isUndefined = function(o) {
2208      return typeof o === 'undefined';
2209  };
2210  
2211  /**
2212   * A convenience method for detecting a legitimate non-null value.
2213   * Returns false for null/undefined/NaN, true for other values,
2214   * including 0/false/''
2215   * @method isValue
2216   * @static
2217   * @param o The item to test.
2218   * @return {boolean} true if it is not null/undefined/NaN || false.
2219   */
2220  L.isValue = function(o) {
2221      var t = L.type(o);
2222  
2223      switch (t) {
2224          case 'number':
2225              return isFinite(o);
2226  
2227          case 'null': // fallthru
2228          case 'undefined':
2229              return false;
2230  
2231          default:
2232              return !!t;
2233      }
2234  };
2235  
2236  /**
2237   * Returns the current time in milliseconds.
2238   *
2239   * @method now
2240   * @return {Number} Current time in milliseconds.
2241   * @static
2242   * @since 3.3.0
2243   */
2244  L.now = Date.now || function () {
2245      return new Date().getTime();
2246  };
2247  
2248  /**
2249   * Performs `{placeholder}` substitution on a string. The object passed as the 
2250   * second parameter provides values to replace the `{placeholder}`s.
2251   * `{placeholder}` token names must match property names of the object. For example,
2252   * 
2253   *`var greeting = Y.Lang.sub("Hello, {who}!", { who: "World" });`
2254   *
2255   * `{placeholder}` tokens that are undefined on the object map will be left 
2256   * in tact (leaving unsightly `{placeholder}`'s in the output string). 
2257   *
2258   * @method sub
2259   * @param {string} s String to be modified.
2260   * @param {object} o Object containing replacement values.
2261   * @return {string} the substitute result.
2262   * @static
2263   * @since 3.2.0
2264   */
2265  L.sub = function(s, o) {
2266      return s.replace ? s.replace(SUBREGEX, function (match, key) {
2267          return L.isUndefined(o[key]) ? match : o[key];
2268      }) : s;
2269  };
2270  
2271  /**
2272   * Returns a string without any leading or trailing whitespace.  If
2273   * the input is not a string, the input will be returned untouched.
2274   * @method trim
2275   * @static
2276   * @param s {string} the string to trim.
2277   * @return {string} the trimmed string.
2278   */
2279  L.trim = L._isNative(STRING_PROTO.trim) && !WHITESPACE.trim() ? function(s) {
2280      return s && s.trim ? s.trim() : s;
2281  } : function (s) {
2282      try {
2283          return s.replace(TRIMREGEX, '');
2284      } catch (e) {
2285          return s;
2286      }
2287  };
2288  
2289  /**
2290   * Returns a string without any leading whitespace.
2291   * @method trimLeft
2292   * @static
2293   * @param s {string} the string to trim.
2294   * @return {string} the trimmed string.
2295   */
2296  L.trimLeft = L._isNative(STRING_PROTO.trimLeft) && !WHITESPACE.trimLeft() ? function (s) {
2297      return s.trimLeft();
2298  } : function (s) {
2299      return s.replace(TRIM_LEFT_REGEX, '');
2300  };
2301  
2302  /**
2303   * Returns a string without any trailing whitespace.
2304   * @method trimRight
2305   * @static
2306   * @param s {string} the string to trim.
2307   * @return {string} the trimmed string.
2308   */
2309  L.trimRight = L._isNative(STRING_PROTO.trimRight) && !WHITESPACE.trimRight() ? function (s) {
2310      return s.trimRight();
2311  } : function (s) {
2312      return s.replace(TRIM_RIGHT_REGEX, '');
2313  };
2314  
2315  /**
2316  Returns one of the following strings, representing the type of the item passed
2317  in:
2318  
2319   * "array"
2320   * "boolean"
2321   * "date"
2322   * "error"
2323   * "function"
2324   * "null"
2325   * "number"
2326   * "object"
2327   * "regexp"
2328   * "string"
2329   * "undefined"
2330  
2331  Known issues:
2332  
2333   * `typeof HTMLElementCollection` returns function in Safari, but
2334      `Y.Lang.type()` reports "object", which could be a good thing --
2335      but it actually caused the logic in <code>Y.Lang.isObject</code> to fail.
2336  
2337  @method type
2338  @param o the item to test.
2339  @return {string} the detected type.
2340  @static
2341  **/
2342  L.type = function(o) {
2343      return TYPES[typeof o] || TYPES[TOSTRING.call(o)] || (o ? 'object' : 'null');
2344  };
2345  /**
2346  @module yui
2347  @submodule yui-base
2348  */
2349  
2350  var Lang   = Y.Lang,
2351      Native = Array.prototype,
2352  
2353      hasOwn = Object.prototype.hasOwnProperty;
2354  
2355  /**
2356  Provides utility methods for working with arrays. Additional array helpers can
2357  be found in the `collection` and `array-extras` modules.
2358  
2359  `Y.Array(thing)` returns a native array created from _thing_. Depending on
2360  _thing_'s type, one of the following will happen:
2361  
2362    * Arrays are returned unmodified unless a non-zero _startIndex_ is
2363      specified.
2364    * Array-like collections (see `Array.test()`) are converted to arrays.
2365    * For everything else, a new array is created with _thing_ as the sole
2366      item.
2367  
2368  Note: elements that are also collections, such as `<form>` and `<select>`
2369  elements, are not automatically converted to arrays. To force a conversion,
2370  pass `true` as the value of the _force_ parameter.
2371  
2372  @class Array
2373  @constructor
2374  @param {Any} thing The thing to arrayify.
2375  @param {Number} [startIndex=0] If non-zero and _thing_ is an array or array-like
2376    collection, a subset of items starting at the specified index will be
2377    returned.
2378  @param {Boolean} [force=false] If `true`, _thing_ will be treated as an
2379    array-like collection no matter what.
2380  @return {Array} A native array created from _thing_, according to the rules
2381    described above.
2382  **/
2383  function YArray(thing, startIndex, force) {
2384      var len, result;
2385  
2386      /*jshint expr: true*/
2387      startIndex || (startIndex = 0);
2388  
2389      if (force || YArray.test(thing)) {
2390          // IE throws when trying to slice HTMLElement collections.
2391          try {
2392              return Native.slice.call(thing, startIndex);
2393          } catch (ex) {
2394              result = [];
2395  
2396              for (len = thing.length; startIndex < len; ++startIndex) {
2397                  result.push(thing[startIndex]);
2398              }
2399  
2400              return result;
2401          }
2402      }
2403  
2404      return [thing];
2405  }
2406  
2407  Y.Array = YArray;
2408  
2409  /**
2410  Dedupes an array of strings, returning an array that's guaranteed to contain
2411  only one copy of a given string.
2412  
2413  This method differs from `Array.unique()` in that it's optimized for use only
2414  with arrays consisting entirely of strings or entirely of numbers, whereas
2415  `unique` may be used with other value types (but is slower).
2416  
2417  Using `dedupe()` with values other than strings or numbers, or with arrays
2418  containing a mix of strings and numbers, may result in unexpected behavior.
2419  
2420  @method dedupe
2421  @param {String[]|Number[]} array Array of strings or numbers to dedupe.
2422  @return {Array} Copy of _array_ containing no duplicate values.
2423  @static
2424  @since 3.4.0
2425  **/
2426  YArray.dedupe = Lang._isNative(Object.create) ? function (array) {
2427      var hash    = Object.create(null),
2428          results = [],
2429          i, item, len;
2430  
2431      for (i = 0, len = array.length; i < len; ++i) {
2432          item = array[i];
2433  
2434          if (!hash[item]) {
2435              hash[item] = 1;
2436              results.push(item);
2437          }
2438      }
2439  
2440      return results;
2441  } : function (array) {
2442      var hash    = {},
2443          results = [],
2444          i, item, len;
2445  
2446      for (i = 0, len = array.length; i < len; ++i) {
2447          item = array[i];
2448  
2449          if (!hasOwn.call(hash, item)) {
2450              hash[item] = 1;
2451              results.push(item);
2452          }
2453      }
2454  
2455      return results;
2456  };
2457  
2458  /**
2459  Executes the supplied function on each item in the array. This method wraps
2460  the native ES5 `Array.forEach()` method if available.
2461  
2462  @method each
2463  @param {Array} array Array to iterate.
2464  @param {Function} fn Function to execute on each item in the array. The function
2465    will receive the following arguments:
2466      @param {Any} fn.item Current array item.
2467      @param {Number} fn.index Current array index.
2468      @param {Array} fn.array Array being iterated.
2469  @param {Object} [thisObj] `this` object to use when calling _fn_.
2470  @return {YUI} The YUI instance.
2471  @static
2472  **/
2473  YArray.each = YArray.forEach = Lang._isNative(Native.forEach) ? function (array, fn, thisObj) {
2474      Native.forEach.call(array || [], fn, thisObj || Y);
2475      return Y;
2476  } : function (array, fn, thisObj) {
2477      for (var i = 0, len = (array && array.length) || 0; i < len; ++i) {
2478          if (i in array) {
2479              fn.call(thisObj || Y, array[i], i, array);
2480          }
2481      }
2482  
2483      return Y;
2484  };
2485  
2486  /**
2487  Alias for `each()`.
2488  
2489  @method forEach
2490  @static
2491  **/
2492  
2493  /**
2494  Returns an object using the first array as keys and the second as values. If
2495  the second array is not provided, or if it doesn't contain the same number of
2496  values as the first array, then `true` will be used in place of the missing
2497  values.
2498  
2499  @example
2500  
2501      Y.Array.hash(['a', 'b', 'c'], ['foo', 'bar']);
2502      // => {a: 'foo', b: 'bar', c: true}
2503  
2504  @method hash
2505  @param {String[]} keys Array of strings to use as keys.
2506  @param {Array} [values] Array to use as values.
2507  @return {Object} Hash using the first array as keys and the second as values.
2508  @static
2509  **/
2510  YArray.hash = function (keys, values) {
2511      var hash = {},
2512          vlen = (values && values.length) || 0,
2513          i, len;
2514  
2515      for (i = 0, len = keys.length; i < len; ++i) {
2516          if (i in keys) {
2517              hash[keys[i]] = vlen > i && i in values ? values[i] : true;
2518          }
2519      }
2520  
2521      return hash;
2522  };
2523  
2524  /**
2525  Returns the index of the first item in the array that's equal (using a strict
2526  equality check) to the specified _value_, or `-1` if the value isn't found.
2527  
2528  This method wraps the native ES5 `Array.indexOf()` method if available.
2529  
2530  @method indexOf
2531  @param {Array} array Array to search.
2532  @param {Any} value Value to search for.
2533  @param {Number} [from=0] The index at which to begin the search.
2534  @return {Number} Index of the item strictly equal to _value_, or `-1` if not
2535      found.
2536  @static
2537  **/
2538  YArray.indexOf = Lang._isNative(Native.indexOf) ? function (array, value, from) {
2539      return Native.indexOf.call(array, value, from);
2540  } : function (array, value, from) {
2541      // http://es5.github.com/#x15.4.4.14
2542      var len = array.length;
2543  
2544      from = +from || 0;
2545      from = (from > 0 || -1) * Math.floor(Math.abs(from));
2546  
2547      if (from < 0) {
2548          from += len;
2549  
2550          if (from < 0) {
2551              from = 0;
2552          }
2553      }
2554  
2555      for (; from < len; ++from) {
2556          if (from in array && array[from] === value) {
2557              return from;
2558          }
2559      }
2560  
2561      return -1;
2562  };
2563  
2564  /**
2565  Numeric sort convenience function.
2566  
2567  The native `Array.prototype.sort()` function converts values to strings and
2568  sorts them in lexicographic order, which is unsuitable for sorting numeric
2569  values. Provide `Array.numericSort` as a custom sort function when you want
2570  to sort values in numeric order.
2571  
2572  @example
2573  
2574      [42, 23, 8, 16, 4, 15].sort(Y.Array.numericSort);
2575      // => [4, 8, 15, 16, 23, 42]
2576  
2577  @method numericSort
2578  @param {Number} a First value to compare.
2579  @param {Number} b Second value to compare.
2580  @return {Number} Difference between _a_ and _b_.
2581  @static
2582  **/
2583  YArray.numericSort = function (a, b) {
2584      return a - b;
2585  };
2586  
2587  /**
2588  Executes the supplied function on each item in the array. Returning a truthy
2589  value from the function will stop the processing of remaining items.
2590  
2591  @method some
2592  @param {Array} array Array to iterate over.
2593  @param {Function} fn Function to execute on each item. The function will receive
2594    the following arguments:
2595      @param {Any} fn.value Current array item.
2596      @param {Number} fn.index Current array index.
2597      @param {Array} fn.array Array being iterated over.
2598  @param {Object} [thisObj] `this` object to use when calling _fn_.
2599  @return {Boolean} `true` if the function returns a truthy value on any of the
2600    items in the array; `false` otherwise.
2601  @static
2602  **/
2603  YArray.some = Lang._isNative(Native.some) ? function (array, fn, thisObj) {
2604      return Native.some.call(array, fn, thisObj);
2605  } : function (array, fn, thisObj) {
2606      for (var i = 0, len = array.length; i < len; ++i) {
2607          if (i in array && fn.call(thisObj, array[i], i, array)) {
2608              return true;
2609          }
2610      }
2611  
2612      return false;
2613  };
2614  
2615  /**
2616  Evaluates _obj_ to determine if it's an array, an array-like collection, or
2617  something else. This is useful when working with the function `arguments`
2618  collection and `HTMLElement` collections.
2619  
2620  Note: This implementation doesn't consider elements that are also
2621  collections, such as `<form>` and `<select>`, to be array-like.
2622  
2623  @method test
2624  @param {Object} obj Object to test.
2625  @return {Number} A number indicating the results of the test:
2626  
2627    * 0: Neither an array nor an array-like collection.
2628    * 1: Real array.
2629    * 2: Array-like collection.
2630  
2631  @static
2632  **/
2633  YArray.test = function (obj) {
2634      var result = 0;
2635  
2636      if (Lang.isArray(obj)) {
2637          result = 1;
2638      } else if (Lang.isObject(obj)) {
2639          try {
2640              // indexed, but no tagName (element) or scrollTo/document (window. From DOM.isWindow test which we can't use here),
2641              // or functions without apply/call (Safari
2642              // HTMLElementCollection bug).
2643              if ('length' in obj && !obj.tagName && !(obj.scrollTo && obj.document) && !obj.apply) {
2644                  result = 2;
2645              }
2646          } catch (ex) {}
2647      }
2648  
2649      return result;
2650  };
2651  /**
2652   * The YUI module contains the components required for building the YUI
2653   * seed file.  This includes the script loading mechanism, a simple queue,
2654   * and the core utilities for the library.
2655   * @module yui
2656   * @submodule yui-base
2657   */
2658  
2659  /**
2660   * A simple FIFO queue.  Items are added to the Queue with add(1..n items) and
2661   * removed using next().
2662   *
2663   * @class Queue
2664   * @constructor
2665   * @param {MIXED} item* 0..n items to seed the queue.
2666   */
2667  function Queue() {
2668      this._init();
2669      this.add.apply(this, arguments);
2670  }
2671  
2672  Queue.prototype = {
2673      /**
2674       * Initialize the queue
2675       *
2676       * @method _init
2677       * @protected
2678       */
2679      _init: function() {
2680          /**
2681           * The collection of enqueued items
2682           *
2683           * @property _q
2684           * @type Array
2685           * @protected
2686           */
2687          this._q = [];
2688      },
2689  
2690      /**
2691       * Get the next item in the queue. FIFO support
2692       *
2693       * @method next
2694       * @return {MIXED} the next item in the queue.
2695       */
2696      next: function() {
2697          return this._q.shift();
2698      },
2699  
2700      /**
2701       * Get the last in the queue. LIFO support.
2702       *
2703       * @method last
2704       * @return {MIXED} the last item in the queue.
2705       */
2706      last: function() {
2707          return this._q.pop();
2708      },
2709  
2710      /**
2711       * Add 0..n items to the end of the queue.
2712       *
2713       * @method add
2714       * @param {MIXED} item* 0..n items.
2715       * @return {object} this queue.
2716       */
2717      add: function() {
2718          this._q.push.apply(this._q, arguments);
2719  
2720          return this;
2721      },
2722  
2723      /**
2724       * Returns the current number of queued items.
2725       *
2726       * @method size
2727       * @return {Number} The size.
2728       */
2729      size: function() {
2730          return this._q.length;
2731      }
2732  };
2733  
2734  Y.Queue = Queue;
2735  
2736  YUI.Env._loaderQueue = YUI.Env._loaderQueue || new Queue();
2737  
2738  /**
2739  The YUI module contains the components required for building the YUI seed file.
2740  This includes the script loading mechanism, a simple queue, and the core
2741  utilities for the library.
2742  
2743  @module yui
2744  @submodule yui-base
2745  **/
2746  
2747  var CACHED_DELIMITER = '__',
2748  
2749      hasOwn   = Object.prototype.hasOwnProperty,
2750      isObject = Y.Lang.isObject;
2751  
2752  /**
2753  Returns a wrapper for a function which caches the return value of that function,
2754  keyed off of the combined string representation of the argument values provided
2755  when the wrapper is called.
2756  
2757  Calling this function again with the same arguments will return the cached value
2758  rather than executing the wrapped function.
2759  
2760  Note that since the cache is keyed off of the string representation of arguments
2761  passed to the wrapper function, arguments that aren't strings and don't provide
2762  a meaningful `toString()` method may result in unexpected caching behavior. For
2763  example, the objects `{}` and `{foo: 'bar'}` would both be converted to the
2764  string `[object Object]` when used as a cache key.
2765  
2766  @method cached
2767  @param {Function} source The function to memoize.
2768  @param {Object} [cache={}] Object in which to store cached values. You may seed
2769    this object with pre-existing cached values if desired.
2770  @param {any} [refetch] If supplied, this value is compared with the cached value
2771    using a `==` comparison. If the values are equal, the wrapped function is
2772    executed again even though a cached value exists.
2773  @return {Function} Wrapped function.
2774  @for YUI
2775  **/
2776  Y.cached = function (source, cache, refetch) {
2777      /*jshint expr: true*/
2778      cache || (cache = {});
2779  
2780      return function (arg) {
2781          var key = arguments.length > 1 ?
2782                  Array.prototype.join.call(arguments, CACHED_DELIMITER) :
2783                  String(arg);
2784  
2785          /*jshint eqeqeq: false*/
2786          if (!(key in cache) || (refetch && cache[key] == refetch)) {
2787              cache[key] = source.apply(source, arguments);
2788          }
2789  
2790          return cache[key];
2791      };
2792  };
2793  
2794  /**
2795  Returns the `location` object from the window/frame in which this YUI instance
2796  operates, or `undefined` when executing in a non-browser environment
2797  (e.g. Node.js).
2798  
2799  It is _not_ recommended to hold references to the `window.location` object
2800  outside of the scope of a function in which its properties are being accessed or
2801  its methods are being called. This is because of a nasty bug/issue that exists
2802  in both Safari and MobileSafari browsers:
2803  [WebKit Bug 34679](https://bugs.webkit.org/show_bug.cgi?id=34679).
2804  
2805  @method getLocation
2806  @return {location} The `location` object from the window/frame in which this YUI
2807      instance operates.
2808  @since 3.5.0
2809  **/
2810  Y.getLocation = function () {
2811      // It is safer to look this up every time because yui-base is attached to a
2812      // YUI instance before a user's config is applied; i.e. `Y.config.win` does
2813      // not point the correct window object when this file is loaded.
2814      var win = Y.config.win;
2815  
2816      // It is not safe to hold a reference to the `location` object outside the
2817      // scope in which it is being used. The WebKit engine used in Safari and
2818      // MobileSafari will "disconnect" the `location` object from the `window`
2819      // when a page is restored from back/forward history cache.
2820      return win && win.location;
2821  };
2822  
2823  /**
2824  Returns a new object containing all of the properties of all the supplied
2825  objects. The properties from later objects will overwrite those in earlier
2826  objects.
2827  
2828  Passing in a single object will create a shallow copy of it. For a deep copy,
2829  use `clone()`.
2830  
2831  @method merge
2832  @param {Object} objects* One or more objects to merge.
2833  @return {Object} A new merged object.
2834  **/
2835  Y.merge = function () {
2836      var i      = 0,
2837          len    = arguments.length,
2838          result = {},
2839          key,
2840          obj;
2841  
2842      for (; i < len; ++i) {
2843          obj = arguments[i];
2844  
2845          for (key in obj) {
2846              if (hasOwn.call(obj, key)) {
2847                  result[key] = obj[key];
2848              }
2849          }
2850      }
2851  
2852      return result;
2853  };
2854  
2855  /**
2856  Mixes _supplier_'s properties into _receiver_.
2857  
2858  Properties on _receiver_ or _receiver_'s prototype will not be overwritten or
2859  shadowed unless the _overwrite_ parameter is `true`, and will not be merged
2860  unless the _merge_ parameter is `true`.
2861  
2862  In the default mode (0), only properties the supplier owns are copied (prototype
2863  properties are not copied). The following copying modes are available:
2864  
2865    * `0`: _Default_. Object to object.
2866    * `1`: Prototype to prototype.
2867    * `2`: Prototype to prototype and object to object.
2868    * `3`: Prototype to object.
2869    * `4`: Object to prototype.
2870  
2871  @method mix
2872  @param {Function|Object} receiver The object or function to receive the mixed
2873    properties.
2874  @param {Function|Object} supplier The object or function supplying the
2875    properties to be mixed.
2876  @param {Boolean} [overwrite=false] If `true`, properties that already exist
2877    on the receiver will be overwritten with properties from the supplier.
2878  @param {String[]} [whitelist] An array of property names to copy. If
2879    specified, only the whitelisted properties will be copied, and all others
2880    will be ignored.
2881  @param {Number} [mode=0] Mix mode to use. See above for available modes.
2882  @param {Boolean} [merge=false] If `true`, objects and arrays that already
2883    exist on the receiver will have the corresponding object/array from the
2884    supplier merged into them, rather than being skipped or overwritten. When
2885    both _overwrite_ and _merge_ are `true`, _merge_ takes precedence.
2886  @return {Function|Object|YUI} The receiver, or the YUI instance if the
2887    specified receiver is falsy.
2888  **/
2889  Y.mix = function(receiver, supplier, overwrite, whitelist, mode, merge) {
2890      var alwaysOverwrite, exists, from, i, key, len, to;
2891  
2892      // If no supplier is given, we return the receiver. If no receiver is given,
2893      // we return Y. Returning Y doesn't make much sense to me, but it's
2894      // grandfathered in for backcompat reasons.
2895      if (!receiver || !supplier) {
2896          return receiver || Y;
2897      }
2898  
2899      if (mode) {
2900          // In mode 2 (prototype to prototype and object to object), we recurse
2901          // once to do the proto to proto mix. The object to object mix will be
2902          // handled later on.
2903          if (mode === 2) {
2904              Y.mix(receiver.prototype, supplier.prototype, overwrite,
2905                      whitelist, 0, merge);
2906          }
2907  
2908          // Depending on which mode is specified, we may be copying from or to
2909          // the prototypes of the supplier and receiver.
2910          from = mode === 1 || mode === 3 ? supplier.prototype : supplier;
2911          to   = mode === 1 || mode === 4 ? receiver.prototype : receiver;
2912  
2913          // If either the supplier or receiver doesn't actually have a
2914          // prototype property, then we could end up with an undefined `from`
2915          // or `to`. If that happens, we abort and return the receiver.
2916          if (!from || !to) {
2917              return receiver;
2918          }
2919      } else {
2920          from = supplier;
2921          to   = receiver;
2922      }
2923  
2924      // If `overwrite` is truthy and `merge` is falsy, then we can skip a
2925      // property existence check on each iteration and save some time.
2926      alwaysOverwrite = overwrite && !merge;
2927  
2928      if (whitelist) {
2929          for (i = 0, len = whitelist.length; i < len; ++i) {
2930              key = whitelist[i];
2931  
2932              // We call `Object.prototype.hasOwnProperty` instead of calling
2933              // `hasOwnProperty` on the object itself, since the object's
2934              // `hasOwnProperty` method may have been overridden or removed.
2935              // Also, some native objects don't implement a `hasOwnProperty`
2936              // method.
2937              if (!hasOwn.call(from, key)) {
2938                  continue;
2939              }
2940  
2941              // The `key in to` check here is (sadly) intentional for backwards
2942              // compatibility reasons. It prevents undesired shadowing of
2943              // prototype members on `to`.
2944              exists = alwaysOverwrite ? false : key in to;
2945  
2946              if (merge && exists && isObject(to[key], true)
2947                      && isObject(from[key], true)) {
2948                  // If we're in merge mode, and the key is present on both
2949                  // objects, and the value on both objects is either an object or
2950                  // an array (but not a function), then we recurse to merge the
2951                  // `from` value into the `to` value instead of overwriting it.
2952                  //
2953                  // Note: It's intentional that the whitelist isn't passed to the
2954                  // recursive call here. This is legacy behavior that lots of
2955                  // code still depends on.
2956                  Y.mix(to[key], from[key], overwrite, null, 0, merge);
2957              } else if (overwrite || !exists) {
2958                  // We're not in merge mode, so we'll only copy the `from` value
2959                  // to the `to` value if we're in overwrite mode or if the
2960                  // current key doesn't exist on the `to` object.
2961                  to[key] = from[key];
2962              }
2963          }
2964      } else {
2965          for (key in from) {
2966              // The code duplication here is for runtime performance reasons.
2967              // Combining whitelist and non-whitelist operations into a single
2968              // loop or breaking the shared logic out into a function both result
2969              // in worse performance, and Y.mix is critical enough that the byte
2970              // tradeoff is worth it.
2971              if (!hasOwn.call(from, key)) {
2972                  continue;
2973              }
2974  
2975              // The `key in to` check here is (sadly) intentional for backwards
2976              // compatibility reasons. It prevents undesired shadowing of
2977              // prototype members on `to`.
2978              exists = alwaysOverwrite ? false : key in to;
2979  
2980              if (merge && exists && isObject(to[key], true)
2981                      && isObject(from[key], true)) {
2982                  Y.mix(to[key], from[key], overwrite, null, 0, merge);
2983              } else if (overwrite || !exists) {
2984                  to[key] = from[key];
2985              }
2986          }
2987  
2988          // If this is an IE browser with the JScript enumeration bug, force
2989          // enumeration of the buggy properties by making a recursive call with
2990          // the buggy properties as the whitelist.
2991          if (Y.Object._hasEnumBug) {
2992              Y.mix(to, from, overwrite, Y.Object._forceEnum, mode, merge);
2993          }
2994      }
2995  
2996      return receiver;
2997  };
2998  /**
2999   * The YUI module contains the components required for building the YUI
3000   * seed file.  This includes the script loading mechanism, a simple queue,
3001   * and the core utilities for the library.
3002   * @module yui
3003   * @submodule yui-base
3004   */
3005  
3006  /**
3007   * Adds utilities to the YUI instance for working with objects.
3008   *
3009   * @class Object
3010   */
3011  
3012  var Lang   = Y.Lang,
3013      hasOwn = Object.prototype.hasOwnProperty,
3014  
3015      UNDEFINED, // <-- Note the comma. We're still declaring vars.
3016  
3017  /**
3018   * Returns a new object that uses _obj_ as its prototype. This method wraps the
3019   * native ES5 `Object.create()` method if available, but doesn't currently
3020   * pass through `Object.create()`'s second argument (properties) in order to
3021   * ensure compatibility with older browsers.
3022   *
3023   * @method ()
3024   * @param {Object} obj Prototype object.
3025   * @return {Object} New object using _obj_ as its prototype.
3026   * @static
3027   */
3028  O = Y.Object = Lang._isNative(Object.create) ? function (obj) {
3029      // We currently wrap the native Object.create instead of simply aliasing it
3030      // to ensure consistency with our fallback shim, which currently doesn't
3031      // support Object.create()'s second argument (properties). Once we have a
3032      // safe fallback for the properties arg, we can stop wrapping
3033      // Object.create().
3034      return Object.create(obj);
3035  } : (function () {
3036      // Reusable constructor function for the Object.create() shim.
3037      function F() {}
3038  
3039      // The actual shim.
3040      return function (obj) {
3041          F.prototype = obj;
3042          return new F();
3043      };
3044  }()),
3045  
3046  /**
3047   * Property names that IE doesn't enumerate in for..in loops, even when they
3048   * should be enumerable. When `_hasEnumBug` is `true`, it's necessary to
3049   * manually enumerate these properties.
3050   *
3051   * @property _forceEnum
3052   * @type String[]
3053   * @protected
3054   * @static
3055   */
3056  forceEnum = O._forceEnum = [
3057      'hasOwnProperty',
3058      'isPrototypeOf',
3059      'propertyIsEnumerable',
3060      'toString',
3061      'toLocaleString',
3062      'valueOf'
3063  ],
3064  
3065  /**
3066   * `true` if this browser has the JScript enumeration bug that prevents
3067   * enumeration of the properties named in the `_forceEnum` array, `false`
3068   * otherwise.
3069   *
3070   * See:
3071   *   - <https://developer.mozilla.org/en/ECMAScript_DontEnum_attribute#JScript_DontEnum_Bug>
3072   *   - <http://whattheheadsaid.com/2010/10/a-safer-object-keys-compatibility-implementation>
3073   *
3074   * @property _hasEnumBug
3075   * @type Boolean
3076   * @protected
3077   * @static
3078   */
3079  hasEnumBug = O._hasEnumBug = !{valueOf: 0}.propertyIsEnumerable('valueOf'),
3080  
3081  /**
3082   * `true` if this browser incorrectly considers the `prototype` property of
3083   * functions to be enumerable. Currently known to affect Opera 11.50 and Android 2.3.x.
3084   *
3085   * @property _hasProtoEnumBug
3086   * @type Boolean
3087   * @protected
3088   * @static
3089   */
3090  hasProtoEnumBug = O._hasProtoEnumBug = (function () {}).propertyIsEnumerable('prototype'),
3091  
3092  /**
3093   * Returns `true` if _key_ exists on _obj_, `false` if _key_ doesn't exist or
3094   * exists only on _obj_'s prototype. This is essentially a safer version of
3095   * `obj.hasOwnProperty()`.
3096   *
3097   * @method owns
3098   * @param {Object} obj Object to test.
3099   * @param {String} key Property name to look for.
3100   * @return {Boolean} `true` if _key_ exists on _obj_, `false` otherwise.
3101   * @static
3102   */
3103  owns = O.owns = function (obj, key) {
3104      return !!obj && hasOwn.call(obj, key);
3105  }; // <-- End of var declarations.
3106  
3107  /**
3108   * Alias for `owns()`.
3109   *
3110   * @method hasKey
3111   * @param {Object} obj Object to test.
3112   * @param {String} key Property name to look for.
3113   * @return {Boolean} `true` if _key_ exists on _obj_, `false` otherwise.
3114   * @static
3115   */
3116  O.hasKey = owns;
3117  
3118  /**
3119   * Returns an array containing the object's enumerable keys. Does not include
3120   * prototype keys or non-enumerable keys.
3121   *
3122   * Note that keys are returned in enumeration order (that is, in the same order
3123   * that they would be enumerated by a `for-in` loop), which may not be the same
3124   * as the order in which they were defined.
3125   *
3126   * This method is an alias for the native ES5 `Object.keys()` method if
3127   * available and non-buggy. The Opera 11.50 and Android 2.3.x versions of
3128   * `Object.keys()` have an inconsistency as they consider `prototype` to be
3129   * enumerable, so a non-native shim is used to rectify the difference.
3130   *
3131   * @example
3132   *
3133   *     Y.Object.keys({a: 'foo', b: 'bar', c: 'baz'});
3134   *     // => ['a', 'b', 'c']
3135   *
3136   * @method keys
3137   * @param {Object} obj An object.
3138   * @return {String[]} Array of keys.
3139   * @static
3140   */
3141  O.keys = Lang._isNative(Object.keys) && !hasProtoEnumBug ? Object.keys : function (obj) {
3142      if (!Lang.isObject(obj)) {
3143          throw new TypeError('Object.keys called on a non-object');
3144      }
3145  
3146      var keys = [],
3147          i, key, len;
3148  
3149      if (hasProtoEnumBug && typeof obj === 'function') {
3150          for (key in obj) {
3151              if (owns(obj, key) && key !== 'prototype') {
3152                  keys.push(key);
3153              }
3154          }
3155      } else {
3156          for (key in obj) {
3157              if (owns(obj, key)) {
3158                  keys.push(key);
3159              }
3160          }
3161      }
3162  
3163      if (hasEnumBug) {
3164          for (i = 0, len = forceEnum.length; i < len; ++i) {
3165              key = forceEnum[i];
3166  
3167              if (owns(obj, key)) {
3168                  keys.push(key);
3169              }
3170          }
3171      }
3172  
3173      return keys;
3174  };
3175  
3176  /**
3177   * Returns an array containing the values of the object's enumerable keys.
3178   *
3179   * Note that values are returned in enumeration order (that is, in the same
3180   * order that they would be enumerated by a `for-in` loop), which may not be the
3181   * same as the order in which they were defined.
3182   *
3183   * @example
3184   *
3185   *     Y.Object.values({a: 'foo', b: 'bar', c: 'baz'});
3186   *     // => ['foo', 'bar', 'baz']
3187   *
3188   * @method values
3189   * @param {Object} obj An object.
3190   * @return {Array} Array of values.
3191   * @static
3192   */
3193  O.values = function (obj) {
3194      var keys   = O.keys(obj),
3195          i      = 0,
3196          len    = keys.length,
3197          values = [];
3198  
3199      for (; i < len; ++i) {
3200          values.push(obj[keys[i]]);
3201      }
3202  
3203      return values;
3204  };
3205  
3206  /**
3207   * Returns the number of enumerable keys owned by an object.
3208   *
3209   * @method size
3210   * @param {Object} obj An object.
3211   * @return {Number} The object's size.
3212   * @static
3213   */
3214  O.size = function (obj) {
3215      try {
3216          return O.keys(obj).length;
3217      } catch (ex) {
3218          return 0; // Legacy behavior for non-objects.
3219      }
3220  };
3221  
3222  /**
3223   * Returns `true` if the object owns an enumerable property with the specified
3224   * value.
3225   *
3226   * @method hasValue
3227   * @param {Object} obj An object.
3228   * @param {any} value The value to search for.
3229   * @return {Boolean} `true` if _obj_ contains _value_, `false` otherwise.
3230   * @static
3231   */
3232  O.hasValue = function (obj, value) {
3233      return Y.Array.indexOf(O.values(obj), value) > -1;
3234  };
3235  
3236  /**
3237   * Executes a function on each enumerable property in _obj_. The function
3238   * receives the value, the key, and the object itself as parameters (in that
3239   * order).
3240   *
3241   * By default, only properties owned by _obj_ are enumerated. To include
3242   * prototype properties, set the _proto_ parameter to `true`.
3243   *
3244   * @method each
3245   * @param {Object} obj Object to enumerate.
3246   * @param {Function} fn Function to execute on each enumerable property.
3247   *   @param {mixed} fn.value Value of the current property.
3248   *   @param {String} fn.key Key of the current property.
3249   *   @param {Object} fn.obj Object being enumerated.
3250   * @param {Object} [thisObj] `this` object to use when calling _fn_.
3251   * @param {Boolean} [proto=false] Include prototype properties.
3252   * @return {YUI} the YUI instance.
3253   * @chainable
3254   * @static
3255   */
3256  O.each = function (obj, fn, thisObj, proto) {
3257      var key;
3258  
3259      for (key in obj) {
3260          if (proto || owns(obj, key)) {
3261              fn.call(thisObj || Y, obj[key], key, obj);
3262          }
3263      }
3264  
3265      return Y;
3266  };
3267  
3268  /**
3269   * Executes a function on each enumerable property in _obj_, but halts if the
3270   * function returns a truthy value. The function receives the value, the key,
3271   * and the object itself as paramters (in that order).
3272   *
3273   * By default, only properties owned by _obj_ are enumerated. To include
3274   * prototype properties, set the _proto_ parameter to `true`.
3275   *
3276   * @method some
3277   * @param {Object} obj Object to enumerate.
3278   * @param {Function} fn Function to execute on each enumerable property.
3279   *   @param {mixed} fn.value Value of the current property.
3280   *   @param {String} fn.key Key of the current property.
3281   *   @param {Object} fn.obj Object being enumerated.
3282   * @param {Object} [thisObj] `this` object to use when calling _fn_.
3283   * @param {Boolean} [proto=false] Include prototype properties.
3284   * @return {Boolean} `true` if any execution of _fn_ returns a truthy value,
3285   *   `false` otherwise.
3286   * @static
3287   */
3288  O.some = function (obj, fn, thisObj, proto) {
3289      var key;
3290  
3291      for (key in obj) {
3292          if (proto || owns(obj, key)) {
3293              if (fn.call(thisObj || Y, obj[key], key, obj)) {
3294                  return true;
3295              }
3296          }
3297      }
3298  
3299      return false;
3300  };
3301  
3302  /**
3303   * Retrieves the sub value at the provided path,
3304   * from the value object provided.
3305   *
3306   * @method getValue
3307   * @static
3308   * @param o The object from which to extract the property value.
3309   * @param path {Array} A path array, specifying the object traversal path
3310   * from which to obtain the sub value.
3311   * @return {Any} The value stored in the path, undefined if not found,
3312   * undefined if the source is not an object.  Returns the source object
3313   * if an empty path is provided.
3314   */
3315  O.getValue = function(o, path) {
3316      if (!Lang.isObject(o)) {
3317          return UNDEFINED;
3318      }
3319  
3320      var i,
3321          p = Y.Array(path),
3322          l = p.length;
3323  
3324      for (i = 0; o !== UNDEFINED && i < l; i++) {
3325          o = o[p[i]];
3326      }
3327  
3328      return o;
3329  };
3330  
3331  /**
3332   * Sets the sub-attribute value at the provided path on the
3333   * value object.  Returns the modified value object, or
3334   * undefined if the path is invalid.
3335   *
3336   * @method setValue
3337   * @static
3338   * @param o             The object on which to set the sub value.
3339   * @param path {Array}  A path array, specifying the object traversal path
3340   *                      at which to set the sub value.
3341   * @param val {Any}     The new value for the sub-attribute.
3342   * @return {Object}     The modified object, with the new sub value set, or
3343   *                      undefined, if the path was invalid.
3344   */
3345  O.setValue = function(o, path, val) {
3346      var i,
3347          p = Y.Array(path),
3348          leafIdx = p.length - 1,
3349          ref = o;
3350  
3351      if (leafIdx >= 0) {
3352          for (i = 0; ref !== UNDEFINED && i < leafIdx; i++) {
3353              ref = ref[p[i]];
3354          }
3355  
3356          if (ref !== UNDEFINED) {
3357              ref[p[i]] = val;
3358          } else {
3359              return UNDEFINED;
3360          }
3361      }
3362  
3363      return o;
3364  };
3365  
3366  /**
3367   * Returns `true` if the object has no enumerable properties of its own.
3368   *
3369   * @method isEmpty
3370   * @param {Object} obj An object.
3371   * @return {Boolean} `true` if the object is empty.
3372   * @static
3373   * @since 3.2.0
3374   */
3375  O.isEmpty = function (obj) {
3376      return !O.keys(Object(obj)).length;
3377  };
3378  /**
3379   * The YUI module contains the components required for building the YUI seed
3380   * file.  This includes the script loading mechanism, a simple queue, and the
3381   * core utilities for the library.
3382   * @module yui
3383   * @submodule yui-base
3384   */
3385  
3386  /**
3387   * YUI user agent detection.
3388   * Do not fork for a browser if it can be avoided.  Use feature detection when
3389   * you can.  Use the user agent as a last resort.  For all fields listed
3390   * as @type float, UA stores a version number for the browser engine,
3391   * 0 otherwise.  This value may or may not map to the version number of
3392   * the browser using the engine.  The value is presented as a float so
3393   * that it can easily be used for boolean evaluation as well as for
3394   * looking for a particular range of versions.  Because of this,
3395   * some of the granularity of the version info may be lost.  The fields that
3396   * are @type string default to null.  The API docs list the values that
3397   * these fields can have.
3398   * @class UA
3399   * @static
3400   */
3401  
3402  /**
3403  * Static method on `YUI.Env` for parsing a UA string.  Called at instantiation
3404  * to populate `Y.UA`.
3405  *
3406  * @static
3407  * @method parseUA
3408  * @param {String} [subUA=navigator.userAgent] UA string to parse
3409  * @return {Object} The Y.UA object
3410  */
3411  YUI.Env.parseUA = function(subUA) {
3412  
3413      var numberify = function(s) {
3414              var c = 0;
3415              return parseFloat(s.replace(/\./g, function() {
3416                  return (c++ === 1) ? '' : '.';
3417              }));
3418          },
3419  
3420          win = Y.config.win,
3421  
3422          nav = win && win.navigator,
3423  
3424          o = {
3425  
3426          /**
3427           * Internet Explorer version number or 0.  Example: 6
3428           * @property ie
3429           * @type float
3430           * @static
3431           */
3432          ie: 0,
3433  
3434          /**
3435           * Opera version number or 0.  Example: 9.2
3436           * @property opera
3437           * @type float
3438           * @static
3439           */
3440          opera: 0,
3441  
3442          /**
3443           * Gecko engine revision number.  Will evaluate to 1 if Gecko
3444           * is detected but the revision could not be found. Other browsers
3445           * will be 0.  Example: 1.8
3446           * <pre>
3447           * Firefox 1.0.0.4: 1.7.8   <-- Reports 1.7
3448           * Firefox 1.5.0.9: 1.8.0.9 <-- 1.8
3449           * Firefox 2.0.0.3: 1.8.1.3 <-- 1.81
3450           * Firefox 3.0   <-- 1.9
3451           * Firefox 3.5   <-- 1.91
3452           * </pre>
3453           * @property gecko
3454           * @type float
3455           * @static
3456           */
3457          gecko: 0,
3458  
3459          /**
3460           * AppleWebKit version.  KHTML browsers that are not WebKit browsers
3461           * will evaluate to 1, other browsers 0.  Example: 418.9
3462           * <pre>
3463           * Safari 1.3.2 (312.6): 312.8.1 <-- Reports 312.8 -- currently the
3464           *                                   latest available for Mac OSX 10.3.
3465           * Safari 2.0.2:         416     <-- hasOwnProperty introduced
3466           * Safari 2.0.4:         418     <-- preventDefault fixed
3467           * Safari 2.0.4 (419.3): 418.9.1 <-- One version of Safari may run
3468           *                                   different versions of webkit
3469           * Safari 2.0.4 (419.3): 419     <-- Tiger installations that have been
3470           *                                   updated, but not updated
3471           *                                   to the latest patch.
3472           * Webkit 212 nightly:   522+    <-- Safari 3.0 precursor (with native
3473           * SVG and many major issues fixed).
3474           * Safari 3.0.4 (523.12) 523.12  <-- First Tiger release - automatic
3475           * update from 2.x via the 10.4.11 OS patch.
3476           * Webkit nightly 1/2008:525+    <-- Supports DOMContentLoaded event.
3477           *                                   yahoo.com user agent hack removed.
3478           * </pre>
3479           * http://en.wikipedia.org/wiki/Safari_version_history
3480           * @property webkit
3481           * @type float
3482           * @static
3483           */
3484          webkit: 0,
3485  
3486          /**
3487           * Safari will be detected as webkit, but this property will also
3488           * be populated with the Safari version number
3489           * @property safari
3490           * @type float
3491           * @static
3492           */
3493          safari: 0,
3494  
3495          /**
3496           * Chrome will be detected as webkit, but this property will also
3497           * be populated with the Chrome version number
3498           * @property chrome
3499           * @type float
3500           * @static
3501           */
3502          chrome: 0,
3503  
3504          /**
3505           * The mobile property will be set to a string containing any relevant
3506           * user agent information when a modern mobile browser is detected.
3507           * Currently limited to Safari on the iPhone/iPod Touch, Nokia N-series
3508           * devices with the WebKit-based browser, and Opera Mini.
3509           * @property mobile
3510           * @type string
3511           * @default null
3512           * @static
3513           */
3514          mobile: null,
3515  
3516          /**
3517           * Adobe AIR version number or 0.  Only populated if webkit is detected.
3518           * Example: 1.0
3519           * @property air
3520           * @type float
3521           */
3522          air: 0,
3523          /**
3524           * PhantomJS version number or 0.  Only populated if webkit is detected.
3525           * Example: 1.0
3526           * @property phantomjs
3527           * @type float
3528           */
3529          phantomjs: 0,
3530          /**
3531           * Detects Apple iPad's OS version
3532           * @property ipad
3533           * @type float
3534           * @static
3535           */
3536          ipad: 0,
3537          /**
3538           * Detects Apple iPhone's OS version
3539           * @property iphone
3540           * @type float
3541           * @static
3542           */
3543          iphone: 0,
3544          /**
3545           * Detects Apples iPod's OS version
3546           * @property ipod
3547           * @type float
3548           * @static
3549           */
3550          ipod: 0,
3551          /**
3552           * General truthy check for iPad, iPhone or iPod
3553           * @property ios
3554           * @type Boolean
3555           * @default null
3556           * @static
3557           */
3558          ios: null,
3559          /**
3560           * Detects Googles Android OS version
3561           * @property android
3562           * @type float
3563           * @static
3564           */
3565          android: 0,
3566          /**
3567           * Detects Kindle Silk
3568           * @property silk
3569           * @type float
3570           * @static
3571           */
3572          silk: 0,
3573          /**
3574           * Detects Ubuntu version
3575           * @property ubuntu
3576           * @type float
3577           * @static
3578           */
3579          ubuntu: 0,
3580          /**
3581           * Detects Kindle Silk Acceleration
3582           * @property accel
3583           * @type Boolean
3584           * @static
3585           */
3586          accel: false,
3587          /**
3588           * Detects Palms WebOS version
3589           * @property webos
3590           * @type float
3591           * @static
3592           */
3593          webos: 0,
3594  
3595          /**
3596           * Google Caja version number or 0.
3597           * @property caja
3598           * @type float
3599           */
3600          caja: nav && nav.cajaVersion,
3601  
3602          /**
3603           * Set to true if the page appears to be in SSL
3604           * @property secure
3605           * @type boolean
3606           * @static
3607           */
3608          secure: false,
3609  
3610          /**
3611           * The operating system.  Currently only detecting windows or macintosh
3612           * @property os
3613           * @type string
3614           * @default null
3615           * @static
3616           */
3617          os: null,
3618  
3619          /**
3620           * The Nodejs Version
3621           * @property nodejs
3622           * @type float
3623           * @default 0
3624           * @static
3625           */
3626          nodejs: 0,
3627          /**
3628          * Window8/IE10 Application host environment
3629          * @property winjs
3630          * @type Boolean
3631          * @static
3632          */
3633          winjs: !!((typeof Windows !== "undefined") && Windows.System),
3634          /**
3635          * Are touch/msPointer events available on this device
3636          * @property touchEnabled
3637          * @type Boolean
3638          * @static
3639          */
3640          touchEnabled: false
3641      },
3642  
3643      ua = subUA || nav && nav.userAgent,
3644  
3645      loc = win && win.location,
3646  
3647      href = loc && loc.href,
3648  
3649      m;
3650  
3651      /**
3652      * The User Agent string that was parsed
3653      * @property userAgent
3654      * @type String
3655      * @static
3656      */
3657      o.userAgent = ua;
3658  
3659  
3660      o.secure = href && (href.toLowerCase().indexOf('https') === 0);
3661  
3662      if (ua) {
3663  
3664          if ((/windows|win32/i).test(ua)) {
3665              o.os = 'windows';
3666          } else if ((/macintosh|mac_powerpc/i).test(ua)) {
3667              o.os = 'macintosh';
3668          } else if ((/android/i).test(ua)) {
3669              o.os = 'android';
3670          } else if ((/symbos/i).test(ua)) {
3671              o.os = 'symbos';
3672          } else if ((/linux/i).test(ua)) {
3673              o.os = 'linux';
3674          } else if ((/rhino/i).test(ua)) {
3675              o.os = 'rhino';
3676          }
3677  
3678          // Modern KHTML browsers should qualify as Safari X-Grade
3679          if ((/KHTML/).test(ua)) {
3680              o.webkit = 1;
3681          }
3682          if ((/IEMobile|XBLWP7/).test(ua)) {
3683              o.mobile = 'windows';
3684          }
3685          if ((/Fennec/).test(ua)) {
3686              o.mobile = 'gecko';
3687          }
3688          // Modern WebKit browsers are at least X-Grade
3689          m = ua.match(/AppleWebKit\/([^\s]*)/);
3690          if (m && m[1]) {
3691              o.webkit = numberify(m[1]);
3692              o.safari = o.webkit;
3693  
3694              if (/PhantomJS/.test(ua)) {
3695                  m = ua.match(/PhantomJS\/([^\s]*)/);
3696                  if (m && m[1]) {
3697                      o.phantomjs = numberify(m[1]);
3698                  }
3699              }
3700  
3701              // Mobile browser check
3702              if (/ Mobile\//.test(ua) || (/iPad|iPod|iPhone/).test(ua)) {
3703                  o.mobile = 'Apple'; // iPhone or iPod Touch
3704  
3705                  m = ua.match(/OS ([^\s]*)/);
3706                  if (m && m[1]) {
3707                      m = numberify(m[1].replace('_', '.'));
3708                  }
3709                  o.ios = m;
3710                  o.os = 'ios';
3711                  o.ipad = o.ipod = o.iphone = 0;
3712  
3713                  m = ua.match(/iPad|iPod|iPhone/);
3714                  if (m && m[0]) {
3715                      o[m[0].toLowerCase()] = o.ios;
3716                  }
3717              } else {
3718                  m = ua.match(/NokiaN[^\/]*|webOS\/\d\.\d/);
3719                  if (m) {
3720                      // Nokia N-series, webOS, ex: NokiaN95
3721                      o.mobile = m[0];
3722                  }
3723                  if (/webOS/.test(ua)) {
3724                      o.mobile = 'WebOS';
3725                      m = ua.match(/webOS\/([^\s]*);/);
3726                      if (m && m[1]) {
3727                          o.webos = numberify(m[1]);
3728                      }
3729                  }
3730                  if (/ Android/.test(ua)) {
3731                      if (/Mobile/.test(ua)) {
3732                          o.mobile = 'Android';
3733                      }
3734                      m = ua.match(/Android ([^\s]*);/);
3735                      if (m && m[1]) {
3736                          o.android = numberify(m[1]);
3737                      }
3738  
3739                  }
3740                  if (/Silk/.test(ua)) {
3741                      m = ua.match(/Silk\/([^\s]*)/);
3742                      if (m && m[1]) {
3743                          o.silk = numberify(m[1]);
3744                      }
3745                      if (!o.android) {
3746                          o.android = 2.34; //Hack for desktop mode in Kindle
3747                          o.os = 'Android';
3748                      }
3749                      if (/Accelerated=true/.test(ua)) {
3750                          o.accel = true;
3751                      }
3752                  }
3753              }
3754  
3755              m = ua.match(/OPR\/(\d+\.\d+)/);
3756  
3757              if (m && m[1]) {
3758                  // Opera 15+ with Blink (pretends to be both Chrome and Safari)
3759                  o.opera = numberify(m[1]);
3760              } else {
3761                  m = ua.match(/(Chrome|CrMo|CriOS)\/([^\s]*)/);
3762  
3763                  if (m && m[1] && m[2]) {
3764                      o.chrome = numberify(m[2]); // Chrome
3765                      o.safari = 0; //Reset safari back to 0
3766                      if (m[1] === 'CrMo') {
3767                          o.mobile = 'chrome';
3768                      }
3769                  } else {
3770                      m = ua.match(/AdobeAIR\/([^\s]*)/);
3771                      if (m) {
3772                          o.air = m[0]; // Adobe AIR 1.0 or better
3773                      }
3774                  }
3775              }
3776          }
3777  
3778          m = ua.match(/Ubuntu\ (\d+\.\d+)/);
3779          if (m && m[1]) {
3780  
3781              o.os = 'linux';
3782              o.ubuntu = numberify(m[1]);
3783  
3784              m = ua.match(/\ WebKit\/([^\s]*)/);
3785              if (m && m[1]) {
3786                  o.webkit = numberify(m[1]);
3787              }
3788              m = ua.match(/\ Chromium\/([^\s]*)/);
3789              if (m && m[1]) {
3790                  o.chrome = numberify(m[1]);
3791              }
3792              if (/ Mobile$/.test(ua)) {
3793                  o.mobile = 'Ubuntu';
3794              }
3795          }
3796  
3797          if (!o.webkit) { // not webkit
3798  // @todo check Opera/8.01 (J2ME/MIDP; Opera Mini/2.0.4509/1316; fi; U; ssr)
3799              if (/Opera/.test(ua)) {
3800                  m = ua.match(/Opera[\s\/]([^\s]*)/);
3801                  if (m && m[1]) {
3802                      o.opera = numberify(m[1]);
3803                  }
3804                  m = ua.match(/Version\/([^\s]*)/);
3805                  if (m && m[1]) {
3806                      o.opera = numberify(m[1]); // opera 10+
3807                  }
3808  
3809                  if (/Opera Mobi/.test(ua)) {
3810                      o.mobile = 'opera';
3811                      m = ua.replace('Opera Mobi', '').match(/Opera ([^\s]*)/);
3812                      if (m && m[1]) {
3813                          o.opera = numberify(m[1]);
3814                      }
3815                  }
3816                  m = ua.match(/Opera Mini[^;]*/);
3817  
3818                  if (m) {
3819                      o.mobile = m[0]; // ex: Opera Mini/2.0.4509/1316
3820                  }
3821              } else { // not opera or webkit
3822                  m = ua.match(/MSIE ([^;]*)|Trident.*; rv:([0-9.]+)/);
3823  
3824                  if (m && (m[1] || m[2])) {
3825                      o.ie = numberify(m[1] || m[2]);
3826                  } else { // not opera, webkit, or ie
3827                      m = ua.match(/Gecko\/([^\s]*)/);
3828  
3829                      if (m) {
3830                          o.gecko = 1; // Gecko detected, look for revision
3831                          m = ua.match(/rv:([^\s\)]*)/);
3832                          if (m && m[1]) {
3833                              o.gecko = numberify(m[1]);
3834                              if (/Mobile|Tablet/.test(ua)) {
3835                                  o.mobile = "ffos";
3836                              }
3837                          }
3838                      }
3839                  }
3840              }
3841          }
3842      }
3843  
3844      //Check for known properties to tell if touch events are enabled on this device or if
3845      //the number of MSPointer touchpoints on this device is greater than 0.
3846      if (win && nav && !(o.chrome && o.chrome < 6)) {
3847          o.touchEnabled = (("ontouchstart" in win) || (("msMaxTouchPoints" in nav) && (nav.msMaxTouchPoints > 0)));
3848      }
3849  
3850      //It was a parsed UA, do not assign the global value.
3851      if (!subUA) {
3852  
3853          if (typeof process === 'object') {
3854  
3855              if (process.versions && process.versions.node) {
3856                  //NodeJS
3857                  o.os = process.platform;
3858                  o.nodejs = numberify(process.versions.node);
3859              }
3860          }
3861  
3862          YUI.Env.UA = o;
3863  
3864      }
3865  
3866      return o;
3867  };
3868  
3869  
3870  Y.UA = YUI.Env.UA || YUI.Env.parseUA();
3871  
3872  /**
3873  Performs a simple comparison between two version numbers, accounting for
3874  standard versioning logic such as the fact that "535.8" is a lower version than
3875  "535.24", even though a simple numerical comparison would indicate that it's
3876  greater. Also accounts for cases such as "1.1" vs. "1.1.0", which are
3877  considered equivalent.
3878  
3879  Returns -1 if version _a_ is lower than version _b_, 0 if they're equivalent,
3880  1 if _a_ is higher than _b_.
3881  
3882  Versions may be numbers or strings containing numbers and dots. For example,
3883  both `535` and `"535.8.10"` are acceptable. A version string containing
3884  non-numeric characters, like `"535.8.beta"`, may produce unexpected results.
3885  
3886  @method compareVersions
3887  @param {Number|String} a First version number to compare.
3888  @param {Number|String} b Second version number to compare.
3889  @return -1 if _a_ is lower than _b_, 0 if they're equivalent, 1 if _a_ is
3890      higher than _b_.
3891  **/
3892  Y.UA.compareVersions = function (a, b) {
3893      var aPart, aParts, bPart, bParts, i, len;
3894  
3895      if (a === b) {
3896          return 0;
3897      }
3898  
3899      aParts = (a + '').split('.');
3900      bParts = (b + '').split('.');
3901  
3902      for (i = 0, len = Math.max(aParts.length, bParts.length); i < len; ++i) {
3903          aPart = parseInt(aParts[i], 10);
3904          bPart = parseInt(bParts[i], 10);
3905  
3906          /*jshint expr: true*/
3907          isNaN(aPart) && (aPart = 0);
3908          isNaN(bPart) && (bPart = 0);
3909  
3910          if (aPart < bPart) {
3911              return -1;
3912          }
3913  
3914          if (aPart > bPart) {
3915              return 1;
3916          }
3917      }
3918  
3919      return 0;
3920  };
3921  YUI.Env.aliases = {
3922      "anim": ["anim-base","anim-color","anim-curve","anim-easing","anim-node-plugin","anim-scroll","anim-xy"],
3923      "anim-shape-transform": ["anim-shape"],
3924      "app": ["app-base","app-content","app-transitions","lazy-model-list","model","model-list","model-sync-rest","model-sync-local","router","view","view-node-map"],
3925      "attribute": ["attribute-base","attribute-complex"],
3926      "attribute-events": ["attribute-observable"],
3927      "autocomplete": ["autocomplete-base","autocomplete-sources","autocomplete-list","autocomplete-plugin"],
3928      "axes": ["axis-numeric","axis-category","axis-time","axis-stacked"],
3929      "axes-base": ["axis-numeric-base","axis-category-base","axis-time-base","axis-stacked-base"],
3930      "base": ["base-base","base-pluginhost","base-build"],
3931      "cache": ["cache-base","cache-offline","cache-plugin"],
3932      "charts": ["charts-base"],
3933      "collection": ["array-extras","arraylist","arraylist-add","arraylist-filter","array-invoke"],
3934      "color": ["color-base","color-hsl","color-harmony"],
3935      "controller": ["router"],
3936      "dataschema": ["dataschema-base","dataschema-json","dataschema-xml","dataschema-array","dataschema-text"],
3937      "datasource": ["datasource-local","datasource-io","datasource-get","datasource-function","datasource-cache","datasource-jsonschema","datasource-xmlschema","datasource-arrayschema","datasource-textschema","datasource-polling"],
3938      "datatable": ["datatable-core","datatable-table","datatable-head","datatable-body","datatable-base","datatable-column-widths","datatable-message","datatable-mutable","datatable-sort","datatable-datasource"],
3939      "datatype": ["datatype-date","datatype-number","datatype-xml"],
3940      "datatype-date": ["datatype-date-parse","datatype-date-format","datatype-date-math"],
3941      "datatype-number": ["datatype-number-parse","datatype-number-format"],
3942      "datatype-xml": ["datatype-xml-parse","datatype-xml-format"],
3943      "dd": ["dd-ddm-base","dd-ddm","dd-ddm-drop","dd-drag","dd-proxy","dd-constrain","dd-drop","dd-scroll","dd-delegate"],
3944      "dom": ["dom-base","dom-screen","dom-style","selector-native","selector"],
3945      "editor": ["frame","editor-selection","exec-command","editor-base","editor-para","editor-br","editor-bidi","editor-tab","createlink-base"],
3946      "event": ["event-base","event-delegate","event-synthetic","event-mousewheel","event-mouseenter","event-key","event-focus","event-resize","event-hover","event-outside","event-touch","event-move","event-flick","event-valuechange","event-tap"],
3947      "event-custom": ["event-custom-base","event-custom-complex"],
3948      "event-gestures": ["event-flick","event-move"],
3949      "handlebars": ["handlebars-compiler"],
3950      "highlight": ["highlight-base","highlight-accentfold"],
3951      "history": ["history-base","history-hash","history-html5"],
3952      "io": ["io-base","io-xdr","io-form","io-upload-iframe","io-queue"],
3953      "json": ["json-parse","json-stringify"],
3954      "loader": ["loader-base","loader-rollup","loader-yui3"],
3955      "node": ["node-base","node-event-delegate","node-pluginhost","node-screen","node-style"],
3956      "pluginhost": ["pluginhost-base","pluginhost-config"],
3957      "querystring": ["querystring-parse","querystring-stringify"],
3958      "recordset": ["recordset-base","recordset-sort","recordset-filter","recordset-indexer"],
3959      "resize": ["resize-base","resize-proxy","resize-constrain"],
3960      "slider": ["slider-base","slider-value-range","clickable-rail","range-slider"],
3961      "template": ["template-base","template-micro"],
3962      "text": ["text-accentfold","text-wordbreak"],
3963      "widget": ["widget-base","widget-htmlparser","widget-skin","widget-uievents"]
3964  };
3965  
3966  
3967  }, '3.17.2');


Generated: Thu Aug 11 10:00:09 2016 Cross-referenced by PHPXref 0.7.1