[ Index ]

PHP Cross Reference of Unnamed Project

title

Body

[close]

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


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