MDL-32843 import YUI 3.5.1
[moodle.git] / lib / yui / 3.5.1 / build / yui-core / yui-core-debug.js
bloba5fdcceb0641ed8332249a657863ffc19b8c34ac
1 /*
2 YUI 3.5.1 (build 22)
3 Copyright 2012 Yahoo! Inc. All rights reserved.
4 Licensed under the BSD License.
5 http://yuilibrary.com/license/
6 */
7 /**
8  * The YUI module contains the components required for building the YUI seed
9  * file.  This includes the script loading mechanism, a simple queue, and
10  * the core utilities for the library.
11  * @module yui
12  * @submodule yui-base
13  */
15 if (typeof YUI != 'undefined') {
16     YUI._YUI = YUI;
19 /**
20 The YUI global namespace object.  If YUI is already defined, the
21 existing YUI object will not be overwritten so that defined
22 namespaces are preserved.  It is the constructor for the object
23 the end user interacts with.  As indicated below, each instance
24 has full custom event support, but only if the event system
25 is available.  This is a self-instantiable factory function.  You
26 can invoke it directly like this:
28      YUI().use('*', function(Y) {
29          // ready
30      });
32 But it also works like this:
34      var Y = YUI();
36 Configuring the YUI object:
38     YUI({
39         debug: true,
40         combine: false
41     }).use('node', function(Y) {
42         //Node is ready to use
43     });
45 See the API docs for the <a href="config.html">Config</a> class
46 for the complete list of supported configuration properties accepted
47 by the YUI constuctor.
49 @class YUI
50 @constructor
51 @global
52 @uses EventTarget
53 @param [o]* {Object} 0..n optional configuration objects.  these values
54 are store in Y.config.  See <a href="config.html">Config</a> for the list of supported
55 properties.
57     /*global YUI*/
58     /*global YUI_config*/
59     var YUI = function() {
60         var i = 0,
61             Y = this,
62             args = arguments,
63             l = args.length,
64             instanceOf = function(o, type) {
65                 return (o && o.hasOwnProperty && (o instanceof type));
66             },
67             gconf = (typeof YUI_config !== 'undefined') && YUI_config;
69         if (!(instanceOf(Y, YUI))) {
70             Y = new YUI();
71         } else {
72             // set up the core environment
73             Y._init();
75             /**
76                 YUI.GlobalConfig is a master configuration that might span
77                 multiple contexts in a non-browser environment.  It is applied
78                 first to all instances in all contexts.
79                 @property GlobalConfig
80                 @type {Object}
81                 @global
82                 @static
83                 @example
86                     YUI.GlobalConfig = {
87                         filter: 'debug'
88                     };
90                     YUI().use('node', function(Y) {
91                         //debug files used here
92                     });
94                     YUI({
95                         filter: 'min'
96                     }).use('node', function(Y) {
97                         //min files used here
98                     });
100             */
101             if (YUI.GlobalConfig) {
102                 Y.applyConfig(YUI.GlobalConfig);
103             }
105             /**
106                 YUI_config is a page-level config.  It is applied to all
107                 instances created on the page.  This is applied after
108                 YUI.GlobalConfig, and before the instance level configuration
109                 objects.
110                 @global
111                 @property YUI_config
112                 @type {Object}
113                 @example
116                     //Single global var to include before YUI seed file
117                     YUI_config = {
118                         filter: 'debug'
119                     };
121                     YUI().use('node', function(Y) {
122                         //debug files used here
123                     });
125                     YUI({
126                         filter: 'min'
127                     }).use('node', function(Y) {
128                         //min files used here
129                     });
130             */
131             if (gconf) {
132                 Y.applyConfig(gconf);
133             }
135             // bind the specified additional modules for this instance
136             if (!l) {
137                 Y._setup();
138             }
139         }
141         if (l) {
142             // Each instance can accept one or more configuration objects.
143             // These are applied after YUI.GlobalConfig and YUI_Config,
144             // overriding values set in those config files if there is a '
145             // matching property.
146             for (; i < l; i++) {
147                 Y.applyConfig(args[i]);
148             }
150             Y._setup();
151         }
153         Y.instanceOf = instanceOf;
155         return Y;
156     };
158 (function() {
160     var proto, prop,
161         VERSION = '3.5.1',
162         PERIOD = '.',
163         BASE = 'http://yui.yahooapis.com/',
164         DOC_LABEL = 'yui3-js-enabled',
165         CSS_STAMP_EL = 'yui3-css-stamp',
166         NOOP = function() {},
167         SLICE = Array.prototype.slice,
168         APPLY_TO_AUTH = { 'io.xdrReady': 1,   // the functions applyTo
169                           'io.xdrResponse': 1,   // can call. this should
170                           'SWF.eventHandler': 1 }, // be done at build time
171         hasWin = (typeof window != 'undefined'),
172         win = (hasWin) ? window : null,
173         doc = (hasWin) ? win.document : null,
174         docEl = doc && doc.documentElement,
175         docClass = docEl && docEl.className,
176         instances = {},
177         time = new Date().getTime(),
178         add = function(el, type, fn, capture) {
179             if (el && el.addEventListener) {
180                 el.addEventListener(type, fn, capture);
181             } else if (el && el.attachEvent) {
182                 el.attachEvent('on' + type, fn);
183             }
184         },
185         remove = function(el, type, fn, capture) {
186             if (el && el.removeEventListener) {
187                 // this can throw an uncaught exception in FF
188                 try {
189                     el.removeEventListener(type, fn, capture);
190                 } catch (ex) {}
191             } else if (el && el.detachEvent) {
192                 el.detachEvent('on' + type, fn);
193             }
194         },
195         handleLoad = function() {
196             YUI.Env.windowLoaded = true;
197             YUI.Env.DOMReady = true;
198             if (hasWin) {
199                 remove(window, 'load', handleLoad);
200             }
201         },
202         getLoader = function(Y, o) {
203             var loader = Y.Env._loader;
204             if (loader) {
205                 //loader._config(Y.config);
206                 loader.ignoreRegistered = false;
207                 loader.onEnd = null;
208                 loader.data = null;
209                 loader.required = [];
210                 loader.loadType = null;
211             } else {
212                 loader = new Y.Loader(Y.config);
213                 Y.Env._loader = loader;
214             }
215             YUI.Env.core = Y.Array.dedupe([].concat(YUI.Env.core, [ 'loader-base', 'loader-rollup', 'loader-yui3' ]));
217             return loader;
218         },
220         clobber = function(r, s) {
221             for (var i in s) {
222                 if (s.hasOwnProperty(i)) {
223                     r[i] = s[i];
224                 }
225             }
226         },
228         ALREADY_DONE = { success: true };
230 //  Stamp the documentElement (HTML) with a class of "yui-loaded" to
231 //  enable styles that need to key off of JS being enabled.
232 if (docEl && docClass.indexOf(DOC_LABEL) == -1) {
233     if (docClass) {
234         docClass += ' ';
235     }
236     docClass += DOC_LABEL;
237     docEl.className = docClass;
240 if (VERSION.indexOf('@') > -1) {
241     VERSION = '3.3.0'; // dev time hack for cdn test
244 proto = {
245     /**
246      * Applies a new configuration object to the YUI instance config.
247      * This will merge new group/module definitions, and will also
248      * update the loader cache if necessary.  Updating Y.config directly
249      * will not update the cache.
250      * @method applyConfig
251      * @param {Object} o the configuration object.
252      * @since 3.2.0
253      */
254     applyConfig: function(o) {
256         o = o || NOOP;
258         var attr,
259             name,
260             // detail,
261             config = this.config,
262             mods = config.modules,
263             groups = config.groups,
264             aliases = config.aliases,
265             loader = this.Env._loader;
267         for (name in o) {
268             if (o.hasOwnProperty(name)) {
269                 attr = o[name];
270                 if (mods && name == 'modules') {
271                     clobber(mods, attr);
272                 } else if (aliases && name == 'aliases') {
273                     clobber(aliases, attr);
274                 } else if (groups && name == 'groups') {
275                     clobber(groups, attr);
276                 } else if (name == 'win') {
277                     config[name] = (attr && attr.contentWindow) || attr;
278                     config.doc = config[name] ? config[name].document : null;
279                 } else if (name == '_yuid') {
280                     // preserve the guid
281                 } else {
282                     config[name] = attr;
283                 }
284             }
285         }
287         if (loader) {
288             loader._config(o);
289         }
291     },
292     /**
293     * Old way to apply a config to the instance (calls `applyConfig` under the hood)
294     * @private
295     * @method _config
296     * @param {Object} o The config to apply
297     */
298     _config: function(o) {
299         this.applyConfig(o);
300     },
302     /**
303      * Initialize this YUI instance
304      * @private
305      * @method _init
306      */
307     _init: function() {
308         var filter, el,
309             Y = this,
310             G_ENV = YUI.Env,
311             Env = Y.Env,
312             prop;
314         /**
315          * The version number of the YUI instance.
316          * @property version
317          * @type string
318          */
319         Y.version = VERSION;
321         if (!Env) {
322             Y.Env = {
323                 core: ['get','intl-base'],
324                 mods: {}, // flat module map
325                 versions: {}, // version module map
326                 base: BASE,
327                 cdn: BASE + VERSION + '/build/',
328                 // bootstrapped: false,
329                 _idx: 0,
330                 _used: {},
331                 _attached: {},
332                 _missed: [],
333                 _yidx: 0,
334                 _uidx: 0,
335                 _guidp: 'y',
336                 _loaded: {},
337                 // serviced: {},
338                 // Regex in English:
339                 // I'll start at the \b(simpleyui).
340                 // 1. Look in the test string for "simpleyui" or "yui" or
341                 //    "yui-base" or "yui-davglass" or "yui-foobar" that comes after a word break.  That is, it
342                 //    can't match "foyui" or "i_heart_simpleyui". This can be anywhere in the string.
343                 // 2. After #1 must come a forward slash followed by the string matched in #1, so
344                 //    "yui-base/yui-base" or "simpleyui/simpleyui" or "yui-pants/yui-pants".
345                 // 3. The second occurence of the #1 token can optionally be followed by "-debug" or "-min",
346                 //    so "yui/yui-min", "yui/yui-debug", "yui-base/yui-base-debug". NOT "yui/yui-tshirt".
347                 // 4. This is followed by ".js", so "yui/yui.js", "simpleyui/simpleyui-min.js"
348                 // 0. Going back to the beginning, now. If all that stuff in 1-4 comes after a "?" in the string,
349                 //    then capture the junk between the LAST "&" and the string in 1-4.  So
350                 //    "blah?foo/yui/yui.js" will capture "foo/" and "blah?some/thing.js&3.3.0/build/yui-davglass/yui-davglass.js"
351                 //    will capture "3.3.0/build/"
352                 //
353                 // Regex Exploded:
354                 // (?:\?             Find a ?
355                 //   (?:[^&]*&)      followed by 0..n characters followed by an &
356                 //   *               in fact, find as many sets of characters followed by a & as you can
357                 //   ([^&]*)         capture the stuff after the last & in \1
358                 // )?                but it's ok if all this ?junk&more_junk stuff isn't even there
359                 // \b(simpleyui|     after a word break find either the string "simpleyui" or
360                 //    yui(?:-\w+)?   the string "yui" optionally followed by a -, then more characters
361                 // )                 and store the simpleyui or yui-* string in \2
362                 // \/\2              then comes a / followed by the simpleyui or yui-* string in \2
363                 // (?:-(min|debug))? optionally followed by "-min" or "-debug"
364                 // .js               and ending in ".js"
365                 _BASE_RE: /(?:\?(?:[^&]*&)*([^&]*))?\b(simpleyui|yui(?:-\w+)?)\/\2(?:-(min|debug))?\.js/,
366                 parseBasePath: function(src, pattern) {
367                     var match = src.match(pattern),
368                         path, filter;
370                     if (match) {
371                         path = RegExp.leftContext || src.slice(0, src.indexOf(match[0]));
373                         // this is to set up the path to the loader.  The file
374                         // filter for loader should match the yui include.
375                         filter = match[3];
377                         // extract correct path for mixed combo urls
378                         // http://yuilibrary.com/projects/yui3/ticket/2528423
379                         if (match[1]) {
380                             path += '?' + match[1];
381                         }
382                         path = {
383                             filter: filter,
384                             path: path
385                         }
386                     }
387                     return path;
388                 },
389                 getBase: G_ENV && G_ENV.getBase ||
390                         function(pattern) {
391                             var nodes = (doc && doc.getElementsByTagName('script')) || [],
392                                 path = Env.cdn, parsed,
393                                 i, len, src;
395                             for (i = 0, len = nodes.length; i < len; ++i) {
396                                 src = nodes[i].src;
397                                 if (src) {
398                                     parsed = Y.Env.parseBasePath(src, pattern);
399                                     if (parsed) {
400                                         filter = parsed.filter;
401                                         path = parsed.path;
402                                         break;
403                                     }
404                                 }
405                             }
407                             // use CDN default
408                             return path;
409                         }
411             };
413             Env = Y.Env;
415             Env._loaded[VERSION] = {};
417             if (G_ENV && Y !== YUI) {
418                 Env._yidx = ++G_ENV._yidx;
419                 Env._guidp = ('yui_' + VERSION + '_' +
420                              Env._yidx + '_' + time).replace(/\./g, '_');
421             } else if (YUI._YUI) {
423                 G_ENV = YUI._YUI.Env;
424                 Env._yidx += G_ENV._yidx;
425                 Env._uidx += G_ENV._uidx;
427                 for (prop in G_ENV) {
428                     if (!(prop in Env)) {
429                         Env[prop] = G_ENV[prop];
430                     }
431                 }
433                 delete YUI._YUI;
434             }
436             Y.id = Y.stamp(Y);
437             instances[Y.id] = Y;
439         }
441         Y.constructor = YUI;
443         // configuration defaults
444         Y.config = Y.config || {
445             bootstrap: true,
446             cacheUse: true,
447             debug: true,
448             doc: doc,
449             fetchCSS: true,
450             throwFail: true,
451             useBrowserConsole: true,
452             useNativeES5: true,
453             win: win
454         };
456         //Register the CSS stamp element
457         if (doc && !doc.getElementById(CSS_STAMP_EL)) {
458             el = doc.createElement('div');
459             el.innerHTML = '<div id="' + CSS_STAMP_EL + '" style="position: absolute !important; visibility: hidden !important"></div>';
460             YUI.Env.cssStampEl = el.firstChild;
461             docEl.insertBefore(YUI.Env.cssStampEl, docEl.firstChild);
462         }
464         Y.config.lang = Y.config.lang || 'en-US';
466         Y.config.base = YUI.config.base || Y.Env.getBase(Y.Env._BASE_RE);
468         if (!filter || (!('mindebug').indexOf(filter))) {
469             filter = 'min';
470         }
471         filter = (filter) ? '-' + filter : filter;
472         Y.config.loaderPath = YUI.config.loaderPath || 'loader/loader' + filter + '.js';
474     },
476     /**
477      * Finishes the instance setup. Attaches whatever modules were defined
478      * when the yui modules was registered.
479      * @method _setup
480      * @private
481      */
482     _setup: function(o) {
483         var i, Y = this,
484             core = [],
485             mods = YUI.Env.mods,
486             //extras = Y.config.core || ['get','intl-base'];
487             extras = Y.config.core || [].concat(YUI.Env.core); //Clone it..
489         for (i = 0; i < extras.length; i++) {
490             if (mods[extras[i]]) {
491                 core.push(extras[i]);
492             }
493         }
495         Y._attach(['yui-base']);
496         Y._attach(core);
498         if (Y.Loader) {
499             getLoader(Y);
500         }
502         // Y.log(Y.id + ' initialized', 'info', 'yui');
503     },
505     /**
506      * Executes a method on a YUI instance with
507      * the specified id if the specified method is whitelisted.
508      * @method applyTo
509      * @param id {String} the YUI instance id.
510      * @param method {String} the name of the method to exectute.
511      * Ex: 'Object.keys'.
512      * @param args {Array} the arguments to apply to the method.
513      * @return {Object} the return value from the applied method or null.
514      */
515     applyTo: function(id, method, args) {
516         if (!(method in APPLY_TO_AUTH)) {
517             this.log(method + ': applyTo not allowed', 'warn', 'yui');
518             return null;
519         }
521         var instance = instances[id], nest, m, i;
522         if (instance) {
523             nest = method.split('.');
524             m = instance;
525             for (i = 0; i < nest.length; i = i + 1) {
526                 m = m[nest[i]];
527                 if (!m) {
528                     this.log('applyTo not found: ' + method, 'warn', 'yui');
529                 }
530             }
531             return m && m.apply(instance, args);
532         }
534         return null;
535     },
538 Registers a module with the YUI global.  The easiest way to create a
539 first-class YUI module is to use the YUI component build tool.
541 http://yuilibrary.com/projects/builder
543 The build system will produce the `YUI.add` wrapper for you module, along
544 with any configuration info required for the module.
545 @method add
546 @param name {String} module name.
547 @param fn {Function} entry point into the module that is used to bind module to the YUI instance.
548 @param {YUI} fn.Y The YUI instance this module is executed in.
549 @param {String} fn.name The name of the module
550 @param version {String} version string.
551 @param details {Object} optional config data:
552 @param details.requires {Array} features that must be present before this module can be attached.
553 @param details.optional {Array} optional features that should be present if loadOptional
554  is defined.  Note: modules are not often loaded this way in YUI 3,
555  but this field is still useful to inform the user that certain
556  features in the component will require additional dependencies.
557 @param details.use {Array} features that are included within this module which need to
558  be attached automatically when this module is attached.  This
559  supports the YUI 3 rollup system -- a module with submodules
560  defined will need to have the submodules listed in the 'use'
561  config.  The YUI component build tool does this for you.
562 @return {YUI} the YUI instance.
563 @example
565     YUI.add('davglass', function(Y, name) {
566         Y.davglass = function() {
567             alert('Dav was here!');
568         };
569     }, '3.4.0', { requires: ['yui-base', 'harley-davidson', 'mt-dew'] });
572     add: function(name, fn, version, details) {
573         details = details || {};
574         var env = YUI.Env,
575             mod = {
576                 name: name,
577                 fn: fn,
578                 version: version,
579                 details: details
580             },
581             loader,
582             i, versions = env.versions;
584         env.mods[name] = mod;
585         versions[version] = versions[version] || {};
586         versions[version][name] = mod;
588         for (i in instances) {
589             if (instances.hasOwnProperty(i)) {
590                 loader = instances[i].Env._loader;
591                 if (loader) {
592                     if (!loader.moduleInfo[name] || loader.moduleInfo[name].temp) {
593                         loader.addModule(details, name);
594                     }
595                 }
596             }
597         }
599         return this;
600     },
602     /**
603      * Executes the function associated with each required
604      * module, binding the module to the YUI instance.
605      * @param {Array} r The array of modules to attach
606      * @param {Boolean} [moot=false] Don't throw a warning if the module is not attached
607      * @method _attach
608      * @private
609      */
610     _attach: function(r, moot) {
611         var i, name, mod, details, req, use, after,
612             mods = YUI.Env.mods,
613             aliases = YUI.Env.aliases,
614             Y = this, j,
615             loader = Y.Env._loader,
616             done = Y.Env._attached,
617             len = r.length, loader,
618             c = [];
620         //Check for conditional modules (in a second+ instance) and add their requirements
621         //TODO I hate this entire method, it needs to be fixed ASAP (3.5.0) ^davglass
622         for (i = 0; i < len; i++) {
623             name = r[i];
624             mod = mods[name];
625             c.push(name);
626             if (loader && loader.conditions[name]) {
627                 Y.Object.each(loader.conditions[name], function(def) {
628                     var go = def && ((def.ua && Y.UA[def.ua]) || (def.test && def.test(Y)));
629                     if (go) {
630                         c.push(def.name);
631                     }
632                 });
633             }
634         }
635         r = c;
636         len = r.length;
638         for (i = 0; i < len; i++) {
639             if (!done[r[i]]) {
640                 name = r[i];
641                 mod = mods[name];
643                 if (aliases && aliases[name]) {
644                     Y._attach(aliases[name]);
645                     continue;
646                 }
647                 if (!mod) {
648                     if (loader && loader.moduleInfo[name]) {
649                         mod = loader.moduleInfo[name];
650                         moot = true;
651                     }
653                     // Y.log('no js def for: ' + name, 'info', 'yui');
655                     //if (!loader || !loader.moduleInfo[name]) {
656                     //if ((!loader || !loader.moduleInfo[name]) && !moot) {
657                     if (!moot && name) {
658                         if ((name.indexOf('skin-') === -1) && (name.indexOf('css') === -1)) {
659                             Y.Env._missed.push(name);
660                             Y.Env._missed = Y.Array.dedupe(Y.Env._missed);
661                             Y.message('NOT loaded: ' + name, 'warn', 'yui');
662                         }
663                     }
664                 } else {
665                     done[name] = true;
666                     //Don't like this, but in case a mod was asked for once, then we fetch it
667                     //We need to remove it from the missed list ^davglass
668                     for (j = 0; j < Y.Env._missed.length; j++) {
669                         if (Y.Env._missed[j] === name) {
670                             Y.message('Found: ' + name + ' (was reported as missing earlier)', 'warn', 'yui');
671                             Y.Env._missed.splice(j, 1);
672                         }
673                     }
674                     details = mod.details;
675                     req = details.requires;
676                     use = details.use;
677                     after = details.after;
679                     if (req) {
680                         for (j = 0; j < req.length; j++) {
681                             if (!done[req[j]]) {
682                                 if (!Y._attach(req)) {
683                                     return false;
684                                 }
685                                 break;
686                             }
687                         }
688                     }
690                     if (after) {
691                         for (j = 0; j < after.length; j++) {
692                             if (!done[after[j]]) {
693                                 if (!Y._attach(after, true)) {
694                                     return false;
695                                 }
696                                 break;
697                             }
698                         }
699                     }
701                     if (mod.fn) {
702                         try {
703                             mod.fn(Y, name);
704                         } catch (e) {
705                             Y.error('Attach error: ' + name, e, name);
706                             return false;
707                         }
708                     }
710                     if (use) {
711                         for (j = 0; j < use.length; j++) {
712                             if (!done[use[j]]) {
713                                 if (!Y._attach(use)) {
714                                     return false;
715                                 }
716                                 break;
717                             }
718                         }
719                     }
723                 }
724             }
725         }
727         return true;
728     },
730     /**
731      * Attaches one or more modules to the YUI instance.  When this
732      * is executed, the requirements are analyzed, and one of
733      * several things can happen:
734      *
735      *  * All requirements are available on the page --  The modules
736      *   are attached to the instance.  If supplied, the use callback
737      *   is executed synchronously.
738      *
739      *  * Modules are missing, the Get utility is not available OR
740      *   the 'bootstrap' config is false -- A warning is issued about
741      *   the missing modules and all available modules are attached.
742      *
743      *  * Modules are missing, the Loader is not available but the Get
744      *   utility is and boostrap is not false -- The loader is bootstrapped
745      *   before doing the following....
746      *
747      *  * Modules are missing and the Loader is available -- The loader
748      *   expands the dependency tree and fetches missing modules.  When
749      *   the loader is finshed the callback supplied to use is executed
750      *   asynchronously.
751      *
752      * @method use
753      * @param modules* {String|Array} 1-n modules to bind (uses arguments array).
754      * @param [callback] {Function} callback function executed when
755      * the instance has the required functionality.  If included, it
756      * must be the last parameter.
757      * @param callback.Y {YUI} The `YUI` instance created for this sandbox
758      * @param callback.data {Object} Object data returned from `Loader`.
759      *
760      * @example
761      *      // loads and attaches dd and its dependencies
762      *      YUI().use('dd', function(Y) {});
763      *
764      *      // loads and attaches dd and node as well as all of their dependencies (since 3.4.0)
765      *      YUI().use(['dd', 'node'], function(Y) {});
766      *
767      *      // attaches all modules that are available on the page
768      *      YUI().use('*', function(Y) {});
769      *
770      *      // intrinsic YUI gallery support (since 3.1.0)
771      *      YUI().use('gallery-yql', function(Y) {});
772      *
773      *      // intrinsic YUI 2in3 support (since 3.1.0)
774      *      YUI().use('yui2-datatable', function(Y) {});
775      *
776      * @return {YUI} the YUI instance.
777      */
778     use: function() {
779         var args = SLICE.call(arguments, 0),
780             callback = args[args.length - 1],
781             Y = this,
782             i = 0,
783             a = [],
784             name,
785             Env = Y.Env,
786             provisioned = true;
788         // The last argument supplied to use can be a load complete callback
789         if (Y.Lang.isFunction(callback)) {
790             args.pop();
791         } else {
792             callback = null;
793         }
794         if (Y.Lang.isArray(args[0])) {
795             args = args[0];
796         }
798         if (Y.config.cacheUse) {
799             while ((name = args[i++])) {
800                 if (!Env._attached[name]) {
801                     provisioned = false;
802                     break;
803                 }
804             }
806             if (provisioned) {
807                 if (args.length) {
808                     Y.log('already provisioned: ' + args, 'info', 'yui');
809                 }
810                 Y._notify(callback, ALREADY_DONE, args);
811                 return Y;
812             }
813         }
815         if (Y._loading) {
816             Y._useQueue = Y._useQueue || new Y.Queue();
817             Y._useQueue.add([args, callback]);
818         } else {
819             Y._use(args, function(Y, response) {
820                 Y._notify(callback, response, args);
821             });
822         }
824         return Y;
825     },
826     /**
827     * Notify handler from Loader for attachment/load errors
828     * @method _notify
829     * @param callback {Function} The callback to pass to the `Y.config.loadErrorFn`
830     * @param response {Object} The response returned from Loader
831     * @param args {Array} The aruments passed from Loader
832     * @private
833     */
834     _notify: function(callback, response, args) {
835         if (!response.success && this.config.loadErrorFn) {
836             this.config.loadErrorFn.call(this, this, callback, response, args);
837         } else if (callback) {
838             try {
839                 callback(this, response);
840             } catch (e) {
841                 this.error('use callback error', e, args);
842             }
843         }
844     },
846     /**
847     * This private method is called from the `use` method queue. To ensure that only one set of loading
848     * logic is performed at a time.
849     * @method _use
850     * @private
851     * @param args* {String} 1-n modules to bind (uses arguments array).
852     * @param *callback {Function} callback function executed when
853     * the instance has the required functionality.  If included, it
854     * must be the last parameter.
855     */
856     _use: function(args, callback) {
858         if (!this.Array) {
859             this._attach(['yui-base']);
860         }
862         var len, loader, handleBoot, handleRLS,
863             Y = this,
864             G_ENV = YUI.Env,
865             mods = G_ENV.mods,
866             Env = Y.Env,
867             used = Env._used,
868             aliases = G_ENV.aliases,
869             queue = G_ENV._loaderQueue,
870             firstArg = args[0],
871             YArray = Y.Array,
872             config = Y.config,
873             boot = config.bootstrap,
874             missing = [],
875             r = [],
876             ret = true,
877             fetchCSS = config.fetchCSS,
878             process = function(names, skip) {
880                 var i = 0, a = [];
882                 if (!names.length) {
883                     return;
884                 }
886                 if (aliases) {
887                     for (i = 0; i < names.length; i++) {
888                         if (aliases[names[i]]) {
889                             a = [].concat(a, aliases[names[i]]);
890                         } else {
891                             a.push(names[i]);
892                         }
893                     }
894                     names = a;
895                 }
897                 YArray.each(names, function(name) {
899                     // add this module to full list of things to attach
900                     if (!skip) {
901                         r.push(name);
902                     }
904                     // only attach a module once
905                     if (used[name]) {
906                         return;
907                     }
909                     var m = mods[name], req, use;
911                     if (m) {
912                         used[name] = true;
913                         req = m.details.requires;
914                         use = m.details.use;
915                     } else {
916                         // CSS files don't register themselves, see if it has
917                         // been loaded
918                         if (!G_ENV._loaded[VERSION][name]) {
919                             missing.push(name);
920                         } else {
921                             used[name] = true; // probably css
922                         }
923                     }
925                     // make sure requirements are attached
926                     if (req && req.length) {
927                         process(req);
928                     }
930                     // make sure we grab the submodule dependencies too
931                     if (use && use.length) {
932                         process(use, 1);
933                     }
934                 });
935             },
937             handleLoader = function(fromLoader) {
938                 var response = fromLoader || {
939                         success: true,
940                         msg: 'not dynamic'
941                     },
942                     redo, origMissing,
943                     ret = true,
944                     data = response.data;
946                 Y._loading = false;
948                 if (data) {
949                     origMissing = missing;
950                     missing = [];
951                     r = [];
952                     process(data);
953                     redo = missing.length;
954                     if (redo) {
955                         if (missing.sort().join() ==
956                                 origMissing.sort().join()) {
957                             redo = false;
958                         }
959                     }
960                 }
962                 if (redo && data) {
963                     Y._loading = true;
964                     Y._use(missing, function() {
965                         Y.log('Nested use callback: ' + data, 'info', 'yui');
966                         if (Y._attach(data)) {
967                             Y._notify(callback, response, data);
968                         }
969                     });
970                 } else {
971                     if (data) {
972                         // Y.log('attaching from loader: ' + data, 'info', 'yui');
973                         ret = Y._attach(data);
974                     }
975                     if (ret) {
976                         Y._notify(callback, response, args);
977                     }
978                 }
980                 if (Y._useQueue && Y._useQueue.size() && !Y._loading) {
981                     Y._use.apply(Y, Y._useQueue.next());
982                 }
984             };
986 // Y.log(Y.id + ': use called: ' + a + ' :: ' + callback, 'info', 'yui');
988         // YUI().use('*'); // bind everything available
989         if (firstArg === '*') {
990             ret = Y._attach(Y.Object.keys(mods));
991             if (ret) {
992                 handleLoader();
993             }
994             return Y;
995         }
997         if (mods['loader'] && !Y.Loader) {
998             Y.log('Loader was found in meta, but it is not attached. Attaching..', 'info', 'yui');
999             Y._attach(['loader']);
1000         }
1002         // Y.log('before loader requirements: ' + args, 'info', 'yui');
1004         // use loader to expand dependencies and sort the
1005         // requirements if it is available.
1006         if (boot && Y.Loader && args.length) {
1007             loader = getLoader(Y);
1008             loader.require(args);
1009             loader.ignoreRegistered = true;
1010             loader._boot = true;
1011             loader.calculate(null, (fetchCSS) ? null : 'js');
1012             args = loader.sorted;
1013             loader._boot = false;
1014         }
1016         // process each requirement and any additional requirements
1017         // the module metadata specifies
1018         process(args);
1020         len = missing.length;
1022         if (len) {
1023             missing = Y.Object.keys(YArray.hash(missing));
1024             len = missing.length;
1025 Y.log('Modules missing: ' + missing + ', ' + missing.length, 'info', 'yui');
1026         }
1029         // dynamic load
1030         if (boot && len && Y.Loader) {
1031 // Y.log('Using loader to fetch missing deps: ' + missing, 'info', 'yui');
1032             Y.log('Using Loader', 'info', 'yui');
1033             Y._loading = true;
1034             loader = getLoader(Y);
1035             loader.onEnd = handleLoader;
1036             loader.context = Y;
1037             loader.data = args;
1038             loader.ignoreRegistered = false;
1039             loader.require(args);
1040             loader.insert(null, (fetchCSS) ? null : 'js');
1042         } else if (boot && len && Y.Get && !Env.bootstrapped) {
1044             Y._loading = true;
1046             handleBoot = function() {
1047                 Y._loading = false;
1048                 queue.running = false;
1049                 Env.bootstrapped = true;
1050                 G_ENV._bootstrapping = false;
1051                 if (Y._attach(['loader'])) {
1052                     Y._use(args, callback);
1053                 }
1054             };
1056             if (G_ENV._bootstrapping) {
1057 Y.log('Waiting for loader', 'info', 'yui');
1058                 queue.add(handleBoot);
1059             } else {
1060                 G_ENV._bootstrapping = true;
1061 Y.log('Fetching loader: ' + config.base + config.loaderPath, 'info', 'yui');
1062                 Y.Get.script(config.base + config.loaderPath, {
1063                     onEnd: handleBoot
1064                 });
1065             }
1067         } else {
1068             Y.log('Attaching available dependencies: ' + args, 'info', 'yui');
1069             ret = Y._attach(args);
1070             if (ret) {
1071                 handleLoader();
1072             }
1073         }
1075         return Y;
1076     },
1079     /**
1080     Adds a namespace object onto the YUI global if called statically.
1082         // creates YUI.your.namespace.here as nested objects
1083         YUI.namespace("your.namespace.here");
1085     If called as a method on a YUI <em>instance</em>, it creates the
1086     namespace on the instance.
1088          // creates Y.property.package
1089          Y.namespace("property.package");
1091     Dots in the input string cause `namespace` to create nested objects for
1092     each token. If any part of the requested namespace already exists, the
1093     current object will be left in place.  This allows multiple calls to
1094     `namespace` to preserve existing namespaced properties.
1096     If the first token in the namespace string is "YAHOO", the token is
1097     discarded.
1099     Be careful with namespace tokens. Reserved words may work in some browsers
1100     and not others. For instance, the following will fail in some browsers
1101     because the supported version of JavaScript reserves the word "long":
1103          Y.namespace("really.long.nested.namespace");
1105     <em>Note: If you pass multiple arguments to create multiple namespaces, only
1106     the last one created is returned from this function.</em>
1108     @method namespace
1109     @param  {String} namespace* namespaces to create.
1110     @return {Object}  A reference to the last namespace object created.
1111     **/
1112     namespace: function() {
1113         var a = arguments, o, i = 0, j, d, arg;
1115         for (; i < a.length; i++) {
1116             o = this; //Reset base object per argument or it will get reused from the last
1117             arg = a[i];
1118             if (arg.indexOf(PERIOD) > -1) { //Skip this if no "." is present
1119                 d = arg.split(PERIOD);
1120                 for (j = (d[0] == 'YAHOO') ? 1 : 0; j < d.length; j++) {
1121                     o[d[j]] = o[d[j]] || {};
1122                     o = o[d[j]];
1123                 }
1124             } else {
1125                 o[arg] = o[arg] || {};
1126                 o = o[arg]; //Reset base object to the new object so it's returned
1127             }
1128         }
1129         return o;
1130     },
1132     // this is replaced if the log module is included
1133     log: NOOP,
1134     message: NOOP,
1135     // this is replaced if the dump module is included
1136     dump: function (o) { return ''+o; },
1138     /**
1139      * Report an error.  The reporting mechanism is controlled by
1140      * the `throwFail` configuration attribute.  If throwFail is
1141      * not specified, the message is written to the Logger, otherwise
1142      * a JS error is thrown. If an `errorFn` is specified in the config
1143      * it must return `true` to keep the error from being thrown.
1144      * @method error
1145      * @param msg {String} the error message.
1146      * @param e {Error|String} Optional JS error that was caught, or an error string.
1147      * @param src Optional additional info (passed to `Y.config.errorFn` and `Y.message`)
1148      * and `throwFail` is specified, this error will be re-thrown.
1149      * @return {YUI} this YUI instance.
1150      */
1151     error: function(msg, e, src) {
1152         //TODO Add check for window.onerror here
1154         var Y = this, ret;
1156         if (Y.config.errorFn) {
1157             ret = Y.config.errorFn.apply(Y, arguments);
1158         }
1160         if (Y.config.throwFail && !ret) {
1161             throw (e || new Error(msg));
1162         } else {
1163             Y.message(msg, 'error', ''+src); // don't scrub this one
1164         }
1166         return Y;
1167     },
1169     /**
1170      * Generate an id that is unique among all YUI instances
1171      * @method guid
1172      * @param pre {String} optional guid prefix.
1173      * @return {String} the guid.
1174      */
1175     guid: function(pre) {
1176         var id = this.Env._guidp + '_' + (++this.Env._uidx);
1177         return (pre) ? (pre + id) : id;
1178     },
1180     /**
1181      * Returns a `guid` associated with an object.  If the object
1182      * does not have one, a new one is created unless `readOnly`
1183      * is specified.
1184      * @method stamp
1185      * @param o {Object} The object to stamp.
1186      * @param readOnly {Boolean} if `true`, a valid guid will only
1187      * be returned if the object has one assigned to it.
1188      * @return {String} The object's guid or null.
1189      */
1190     stamp: function(o, readOnly) {
1191         var uid;
1192         if (!o) {
1193             return o;
1194         }
1196         // IE generates its own unique ID for dom nodes
1197         // The uniqueID property of a document node returns a new ID
1198         if (o.uniqueID && o.nodeType && o.nodeType !== 9) {
1199             uid = o.uniqueID;
1200         } else {
1201             uid = (typeof o === 'string') ? o : o._yuid;
1202         }
1204         if (!uid) {
1205             uid = this.guid();
1206             if (!readOnly) {
1207                 try {
1208                     o._yuid = uid;
1209                 } catch (e) {
1210                     uid = null;
1211                 }
1212             }
1213         }
1214         return uid;
1215     },
1217     /**
1218      * Destroys the YUI instance
1219      * @method destroy
1220      * @since 3.3.0
1221      */
1222     destroy: function() {
1223         var Y = this;
1224         if (Y.Event) {
1225             Y.Event._unload();
1226         }
1227         delete instances[Y.id];
1228         delete Y.Env;
1229         delete Y.config;
1230     }
1232     /**
1233      * instanceof check for objects that works around
1234      * memory leak in IE when the item tested is
1235      * window/document
1236      * @method instanceOf
1237      * @param o {Object} The object to check.
1238      * @param type {Object} The class to check against.
1239      * @since 3.3.0
1240      */
1243     YUI.prototype = proto;
1245     // inheritance utilities are not available yet
1246     for (prop in proto) {
1247         if (proto.hasOwnProperty(prop)) {
1248             YUI[prop] = proto[prop];
1249         }
1250     }
1252     /**
1253 Static method on the Global YUI object to apply a config to all YUI instances.
1254 It's main use case is "mashups" where several third party scripts are trying to write to
1255 a global YUI config at the same time. This way they can all call `YUI.applyConfig({})` instead of
1256 overwriting other scripts configs.
1257 @static
1258 @since 3.5.0
1259 @method applyConfig
1260 @param {Object} o the configuration object.
1261 @example
1263     YUI.applyConfig({
1264         modules: {
1265             davglass: {
1266                 fullpath: './davglass.js'
1267             }
1268         }
1269     });
1271     YUI.applyConfig({
1272         modules: {
1273             foo: {
1274                 fullpath: './foo.js'
1275             }
1276         }
1277     });
1279     YUI().use('davglass', function(Y) {
1280         //Module davglass will be available here..
1281     });
1283     */
1284     YUI.applyConfig = function(o) {
1285         if (!o) {
1286             return;
1287         }
1288         //If there is a GlobalConfig, apply it first to set the defaults
1289         if (YUI.GlobalConfig) {
1290             this.prototype.applyConfig.call(this, YUI.GlobalConfig);
1291         }
1292         //Apply this config to it
1293         this.prototype.applyConfig.call(this, o);
1294         //Reset GlobalConfig to the combined config
1295         YUI.GlobalConfig = this.config;
1296     };
1298     // set up the environment
1299     YUI._init();
1301     if (hasWin) {
1302         // add a window load event at load time so we can capture
1303         // the case where it fires before dynamic loading is
1304         // complete.
1305         add(window, 'load', handleLoad);
1306     } else {
1307         handleLoad();
1308     }
1310     YUI.Env.add = add;
1311     YUI.Env.remove = remove;
1313     /*global exports*/
1314     // Support the CommonJS method for exporting our single global
1315     if (typeof exports == 'object') {
1316         exports.YUI = YUI;
1317     }
1319 }());
1323  * The config object contains all of the configuration options for
1324  * the `YUI` instance.  This object is supplied by the implementer
1325  * when instantiating a `YUI` instance.  Some properties have default
1326  * values if they are not supplied by the implementer.  This should
1327  * not be updated directly because some values are cached.  Use
1328  * `applyConfig()` to update the config object on a YUI instance that
1329  * has already been configured.
1331  * @class config
1332  * @static
1333  */
1336  * Allows the YUI seed file to fetch the loader component and library
1337  * metadata to dynamically load additional dependencies.
1339  * @property bootstrap
1340  * @type boolean
1341  * @default true
1342  */
1345  * Turns on writing Ylog messages to the browser console.
1347  * @property debug
1348  * @type boolean
1349  * @default true
1350  */
1353  * Log to the browser console if debug is on and the browser has a
1354  * supported console.
1356  * @property useBrowserConsole
1357  * @type boolean
1358  * @default true
1359  */
1362  * A hash of log sources that should be logged.  If specified, only
1363  * log messages from these sources will be logged.
1365  * @property logInclude
1366  * @type object
1367  */
1370  * A hash of log sources that should be not be logged.  If specified,
1371  * all sources are logged if not on this list.
1373  * @property logExclude
1374  * @type object
1375  */
1378  * Set to true if the yui seed file was dynamically loaded in
1379  * order to bootstrap components relying on the window load event
1380  * and the `domready` custom event.
1382  * @property injected
1383  * @type boolean
1384  * @default false
1385  */
1388  * If `throwFail` is set, `Y.error` will generate or re-throw a JS Error.
1389  * Otherwise the failure is logged.
1391  * @property throwFail
1392  * @type boolean
1393  * @default true
1394  */
1397  * The window/frame that this instance should operate in.
1399  * @property win
1400  * @type Window
1401  * @default the window hosting YUI
1402  */
1405  * The document associated with the 'win' configuration.
1407  * @property doc
1408  * @type Document
1409  * @default the document hosting YUI
1410  */
1413  * A list of modules that defines the YUI core (overrides the default list).
1415  * @property core
1416  * @type Array
1417  * @default [ get,features,intl-base,yui-log,yui-later,loader-base, loader-rollup, loader-yui3 ]
1418  */
1421  * A list of languages in order of preference. This list is matched against
1422  * the list of available languages in modules that the YUI instance uses to
1423  * determine the best possible localization of language sensitive modules.
1424  * Languages are represented using BCP 47 language tags, such as "en-GB" for
1425  * English as used in the United Kingdom, or "zh-Hans-CN" for simplified
1426  * Chinese as used in China. The list can be provided as a comma-separated
1427  * list or as an array.
1429  * @property lang
1430  * @type string|string[]
1431  */
1434  * The default date format
1435  * @property dateFormat
1436  * @type string
1437  * @deprecated use configuration in `DataType.Date.format()` instead.
1438  */
1441  * The default locale
1442  * @property locale
1443  * @type string
1444  * @deprecated use `config.lang` instead.
1445  */
1448  * The default interval when polling in milliseconds.
1449  * @property pollInterval
1450  * @type int
1451  * @default 20
1452  */
1455  * The number of dynamic nodes to insert by default before
1456  * automatically removing them.  This applies to script nodes
1457  * because removing the node will not make the evaluated script
1458  * unavailable.  Dynamic CSS is not auto purged, because removing
1459  * a linked style sheet will also remove the style definitions.
1460  * @property purgethreshold
1461  * @type int
1462  * @default 20
1463  */
1466  * The default interval when polling in milliseconds.
1467  * @property windowResizeDelay
1468  * @type int
1469  * @default 40
1470  */
1473  * Base directory for dynamic loading
1474  * @property base
1475  * @type string
1476  */
1479  * The secure base dir (not implemented)
1480  * For dynamic loading.
1481  * @property secureBase
1482  * @type string
1483  */
1486  * The YUI combo service base dir. Ex: `http://yui.yahooapis.com/combo?`
1487  * For dynamic loading.
1488  * @property comboBase
1489  * @type string
1490  */
1493  * The root path to prepend to module path for the combo service.
1494  * Ex: 3.0.0b1/build/
1495  * For dynamic loading.
1496  * @property root
1497  * @type string
1498  */
1501  * A filter to apply to result urls.  This filter will modify the default
1502  * path for all modules.  The default path for the YUI library is the
1503  * minified version of the files (e.g., event-min.js).  The filter property
1504  * can be a predefined filter or a custom filter.  The valid predefined
1505  * filters are:
1506  * <dl>
1507  *  <dt>DEBUG</dt>
1508  *  <dd>Selects the debug versions of the library (e.g., event-debug.js).
1509  *      This option will automatically include the Logger widget</dd>
1510  *  <dt>RAW</dt>
1511  *  <dd>Selects the non-minified version of the library (e.g., event.js).</dd>
1512  * </dl>
1513  * You can also define a custom filter, which must be an object literal
1514  * containing a search expression and a replace string:
1516  *      myFilter: {
1517  *          'searchExp': "-min\\.js",
1518  *          'replaceStr': "-debug.js"
1519  *      }
1521  * For dynamic loading.
1523  * @property filter
1524  * @type string|object
1525  */
1528  * The `skin` config let's you configure application level skin
1529  * customizations.  It contains the following attributes which
1530  * can be specified to override the defaults:
1532  *      // The default skin, which is automatically applied if not
1533  *      // overriden by a component-specific skin definition.
1534  *      // Change this in to apply a different skin globally
1535  *      defaultSkin: 'sam',
1537  *      // This is combined with the loader base property to get
1538  *      // the default root directory for a skin.
1539  *      base: 'assets/skins/',
1541  *      // Any component-specific overrides can be specified here,
1542  *      // making it possible to load different skins for different
1543  *      // components.  It is possible to load more than one skin
1544  *      // for a given component as well.
1545  *      overrides: {
1546  *          slider: ['capsule', 'round']
1547  *      }
1549  * For dynamic loading.
1551  *  @property skin
1552  */
1555  * Hash of per-component filter specification.  If specified for a given
1556  * component, this overrides the filter config.
1558  * For dynamic loading.
1560  * @property filters
1561  */
1564  * Use the YUI combo service to reduce the number of http connections
1565  * required to load your dependencies.  Turning this off will
1566  * disable combo handling for YUI and all module groups configured
1567  * with a combo service.
1569  * For dynamic loading.
1571  * @property combine
1572  * @type boolean
1573  * @default true if 'base' is not supplied, false if it is.
1574  */
1577  * A list of modules that should never be dynamically loaded
1579  * @property ignore
1580  * @type string[]
1581  */
1584  * A list of modules that should always be loaded when required, even if already
1585  * present on the page.
1587  * @property force
1588  * @type string[]
1589  */
1592  * Node or id for a node that should be used as the insertion point for new
1593  * nodes.  For dynamic loading.
1595  * @property insertBefore
1596  * @type string
1597  */
1600  * Object literal containing attributes to add to dynamically loaded script
1601  * nodes.
1602  * @property jsAttributes
1603  * @type string
1604  */
1607  * Object literal containing attributes to add to dynamically loaded link
1608  * nodes.
1609  * @property cssAttributes
1610  * @type string
1611  */
1614  * Number of milliseconds before a timeout occurs when dynamically
1615  * loading nodes. If not set, there is no timeout.
1616  * @property timeout
1617  * @type int
1618  */
1621  * Callback for the 'CSSComplete' event.  When dynamically loading YUI
1622  * components with CSS, this property fires when the CSS is finished
1623  * loading but script loading is still ongoing.  This provides an
1624  * opportunity to enhance the presentation of a loading page a little
1625  * bit before the entire loading process is done.
1627  * @property onCSS
1628  * @type function
1629  */
1632  * A hash of module definitions to add to the list of YUI components.
1633  * These components can then be dynamically loaded side by side with
1634  * YUI via the `use()` method. This is a hash, the key is the module
1635  * name, and the value is an object literal specifying the metdata
1636  * for the module.  See `Loader.addModule` for the supported module
1637  * metadata fields.  Also see groups, which provides a way to
1638  * configure the base and combo spec for a set of modules.
1640  *      modules: {
1641  *          mymod1: {
1642  *              requires: ['node'],
1643  *              fullpath: '/mymod1/mymod1.js'
1644  *          },
1645  *          mymod2: {
1646  *              requires: ['mymod1'],
1647  *              fullpath: '/mymod2/mymod2.js'
1648  *          },
1649  *          mymod3: '/js/mymod3.js',
1650  *          mycssmod: '/css/mycssmod.css'
1651  *      }
1654  * @property modules
1655  * @type object
1656  */
1659  * Aliases are dynamic groups of modules that can be used as
1660  * shortcuts.
1662  *      YUI({
1663  *          aliases: {
1664  *              davglass: [ 'node', 'yql', 'dd' ],
1665  *              mine: [ 'davglass', 'autocomplete']
1666  *          }
1667  *      }).use('mine', function(Y) {
1668  *          //Node, YQL, DD &amp; AutoComplete available here..
1669  *      });
1671  * @property aliases
1672  * @type object
1673  */
1676  * A hash of module group definitions.  It for each group you
1677  * can specify a list of modules and the base path and
1678  * combo spec to use when dynamically loading the modules.
1680  *      groups: {
1681  *          yui2: {
1682  *              // specify whether or not this group has a combo service
1683  *              combine: true,
1685  *              // The comboSeperator to use with this group's combo handler
1686  *              comboSep: ';',
1688  *              // The maxURLLength for this server
1689  *              maxURLLength: 500,
1691  *              // the base path for non-combo paths
1692  *              base: 'http://yui.yahooapis.com/2.8.0r4/build/',
1694  *              // the path to the combo service
1695  *              comboBase: 'http://yui.yahooapis.com/combo?',
1697  *              // a fragment to prepend to the path attribute when
1698  *              // when building combo urls
1699  *              root: '2.8.0r4/build/',
1701  *              // the module definitions
1702  *              modules:  {
1703  *                  yui2_yde: {
1704  *                      path: "yahoo-dom-event/yahoo-dom-event.js"
1705  *                  },
1706  *                  yui2_anim: {
1707  *                      path: "animation/animation.js",
1708  *                      requires: ['yui2_yde']
1709  *                  }
1710  *              }
1711  *          }
1712  *      }
1714  * @property groups
1715  * @type object
1716  */
1719  * The loader 'path' attribute to the loader itself.  This is combined
1720  * with the 'base' attribute to dynamically load the loader component
1721  * when boostrapping with the get utility alone.
1723  * @property loaderPath
1724  * @type string
1725  * @default loader/loader-min.js
1726  */
1729  * Specifies whether or not YUI().use(...) will attempt to load CSS
1730  * resources at all.  Any truthy value will cause CSS dependencies
1731  * to load when fetching script.  The special value 'force' will
1732  * cause CSS dependencies to be loaded even if no script is needed.
1734  * @property fetchCSS
1735  * @type boolean|string
1736  * @default true
1737  */
1740  * The default gallery version to build gallery module urls
1741  * @property gallery
1742  * @type string
1743  * @since 3.1.0
1744  */
1747  * The default YUI 2 version to build yui2 module urls.  This is for
1748  * intrinsic YUI 2 support via the 2in3 project.  Also see the '2in3'
1749  * config for pulling different revisions of the wrapped YUI 2
1750  * modules.
1751  * @since 3.1.0
1752  * @property yui2
1753  * @type string
1754  * @default 2.9.0
1755  */
1758  * The 2in3 project is a deployment of the various versions of YUI 2
1759  * deployed as first-class YUI 3 modules.  Eventually, the wrapper
1760  * for the modules will change (but the underlying YUI 2 code will
1761  * be the same), and you can select a particular version of
1762  * the wrapper modules via this config.
1763  * @since 3.1.0
1764  * @property 2in3
1765  * @type string
1766  * @default 4
1767  */
1770  * Alternative console log function for use in environments without
1771  * a supported native console.  The function is executed in the
1772  * YUI instance context.
1773  * @since 3.1.0
1774  * @property logFn
1775  * @type Function
1776  */
1779  * A callback to execute when Y.error is called.  It receives the
1780  * error message and an javascript error object if Y.error was
1781  * executed because a javascript error was caught.  The function
1782  * is executed in the YUI instance context. Returning `true` from this
1783  * function will stop the Error from being thrown.
1785  * @since 3.2.0
1786  * @property errorFn
1787  * @type Function
1788  */
1791  * A callback to execute when the loader fails to load one or
1792  * more resource.  This could be because of a script load
1793  * failure.  It can also fail if a javascript module fails
1794  * to register itself, but only when the 'requireRegistration'
1795  * is true.  If this function is defined, the use() callback will
1796  * only be called when the loader succeeds, otherwise it always
1797  * executes unless there was a javascript error when attaching
1798  * a module.
1800  * @since 3.3.0
1801  * @property loadErrorFn
1802  * @type Function
1803  */
1806  * When set to true, the YUI loader will expect that all modules
1807  * it is responsible for loading will be first-class YUI modules
1808  * that register themselves with the YUI global.  If this is
1809  * set to true, loader will fail if the module registration fails
1810  * to happen after the script is loaded.
1812  * @since 3.3.0
1813  * @property requireRegistration
1814  * @type boolean
1815  * @default false
1816  */
1819  * Cache serviced use() requests.
1820  * @since 3.3.0
1821  * @property cacheUse
1822  * @type boolean
1823  * @default true
1824  * @deprecated no longer used
1825  */
1828  * Whether or not YUI should use native ES5 functionality when available for
1829  * features like `Y.Array.each()`, `Y.Object()`, etc. When `false`, YUI will
1830  * always use its own fallback implementations instead of relying on ES5
1831  * functionality, even when it's available.
1833  * @method useNativeES5
1834  * @type Boolean
1835  * @default true
1836  * @since 3.5.0
1837  */
1838 YUI.add('yui-base', function(Y) {
1841  * YUI stub
1842  * @module yui
1843  * @submodule yui-base
1844  */
1846  * The YUI module contains the components required for building the YUI
1847  * seed file.  This includes the script loading mechanism, a simple queue,
1848  * and the core utilities for the library.
1849  * @module yui
1850  * @submodule yui-base
1851  */
1854  * Provides core language utilites and extensions used throughout YUI.
1856  * @class Lang
1857  * @static
1858  */
1860 var L = Y.Lang || (Y.Lang = {}),
1862 STRING_PROTO = String.prototype,
1863 TOSTRING     = Object.prototype.toString,
1865 TYPES = {
1866     'undefined'        : 'undefined',
1867     'number'           : 'number',
1868     'boolean'          : 'boolean',
1869     'string'           : 'string',
1870     '[object Function]': 'function',
1871     '[object RegExp]'  : 'regexp',
1872     '[object Array]'   : 'array',
1873     '[object Date]'    : 'date',
1874     '[object Error]'   : 'error'
1877 SUBREGEX        = /\{\s*([^|}]+?)\s*(?:\|([^}]*))?\s*\}/g,
1878 TRIMREGEX       = /^\s+|\s+$/g,
1879 NATIVE_FN_REGEX = /\{\s*\[(?:native code|function)\]\s*\}/i;
1881 // -- Protected Methods --------------------------------------------------------
1884 Returns `true` if the given function appears to be implemented in native code,
1885 `false` otherwise. Will always return `false` -- even in ES5-capable browsers --
1886 if the `useNativeES5` YUI config option is set to `false`.
1888 This isn't guaranteed to be 100% accurate and won't work for anything other than
1889 functions, but it can be useful for determining whether a function like
1890 `Array.prototype.forEach` is native or a JS shim provided by another library.
1892 There's a great article by @kangax discussing certain flaws with this technique:
1893 <http://perfectionkills.com/detecting-built-in-host-methods/>
1895 While his points are valid, it's still possible to benefit from this function
1896 as long as it's used carefully and sparingly, and in such a way that false
1897 negatives have minimal consequences. It's used internally to avoid using
1898 potentially broken non-native ES5 shims that have been added to the page by
1899 other libraries.
1901 @method _isNative
1902 @param {Function} fn Function to test.
1903 @return {Boolean} `true` if _fn_ appears to be native, `false` otherwise.
1904 @static
1905 @protected
1906 @since 3.5.0
1908 L._isNative = function (fn) {
1909     return !!(Y.config.useNativeES5 && fn && NATIVE_FN_REGEX.test(fn));
1912 // -- Public Methods -----------------------------------------------------------
1915  * Determines whether or not the provided item is an array.
1917  * Returns `false` for array-like collections such as the function `arguments`
1918  * collection or `HTMLElement` collections. Use `Y.Array.test()` if you want to
1919  * test for an array-like collection.
1921  * @method isArray
1922  * @param o The object to test.
1923  * @return {boolean} true if o is an array.
1924  * @static
1925  */
1926 L.isArray = L._isNative(Array.isArray) ? Array.isArray : function (o) {
1927     return L.type(o) === 'array';
1931  * Determines whether or not the provided item is a boolean.
1932  * @method isBoolean
1933  * @static
1934  * @param o The object to test.
1935  * @return {boolean} true if o is a boolean.
1936  */
1937 L.isBoolean = function(o) {
1938     return typeof o === 'boolean';
1942  * Determines whether or not the supplied item is a date instance.
1943  * @method isDate
1944  * @static
1945  * @param o The object to test.
1946  * @return {boolean} true if o is a date.
1947  */
1948 L.isDate = function(o) {
1949     return L.type(o) === 'date' && o.toString() !== 'Invalid Date' && !isNaN(o);
1953  * <p>
1954  * Determines whether or not the provided item is a function.
1955  * Note: Internet Explorer thinks certain functions are objects:
1956  * </p>
1958  * <pre>
1959  * var obj = document.createElement("object");
1960  * Y.Lang.isFunction(obj.getAttribute) // reports false in IE
1961  * &nbsp;
1962  * var input = document.createElement("input"); // append to body
1963  * Y.Lang.isFunction(input.focus) // reports false in IE
1964  * </pre>
1966  * <p>
1967  * You will have to implement additional tests if these functions
1968  * matter to you.
1969  * </p>
1971  * @method isFunction
1972  * @static
1973  * @param o The object to test.
1974  * @return {boolean} true if o is a function.
1975  */
1976 L.isFunction = function(o) {
1977     return L.type(o) === 'function';
1981  * Determines whether or not the provided item is null.
1982  * @method isNull
1983  * @static
1984  * @param o The object to test.
1985  * @return {boolean} true if o is null.
1986  */
1987 L.isNull = function(o) {
1988     return o === null;
1992  * Determines whether or not the provided item is a legal number.
1993  * @method isNumber
1994  * @static
1995  * @param o The object to test.
1996  * @return {boolean} true if o is a number.
1997  */
1998 L.isNumber = function(o) {
1999     return typeof o === 'number' && isFinite(o);
2003  * Determines whether or not the provided item is of type object
2004  * or function. Note that arrays are also objects, so
2005  * <code>Y.Lang.isObject([]) === true</code>.
2006  * @method isObject
2007  * @static
2008  * @param o The object to test.
2009  * @param failfn {boolean} fail if the input is a function.
2010  * @return {boolean} true if o is an object.
2011  * @see isPlainObject
2012  */
2013 L.isObject = function(o, failfn) {
2014     var t = typeof o;
2015     return (o && (t === 'object' ||
2016         (!failfn && (t === 'function' || L.isFunction(o))))) || false;
2020  * Determines whether or not the provided item is a string.
2021  * @method isString
2022  * @static
2023  * @param o The object to test.
2024  * @return {boolean} true if o is a string.
2025  */
2026 L.isString = function(o) {
2027     return typeof o === 'string';
2031  * Determines whether or not the provided item is undefined.
2032  * @method isUndefined
2033  * @static
2034  * @param o The object to test.
2035  * @return {boolean} true if o is undefined.
2036  */
2037 L.isUndefined = function(o) {
2038     return typeof o === 'undefined';
2042  * A convenience method for detecting a legitimate non-null value.
2043  * Returns false for null/undefined/NaN, true for other values,
2044  * including 0/false/''
2045  * @method isValue
2046  * @static
2047  * @param o The item to test.
2048  * @return {boolean} true if it is not null/undefined/NaN || false.
2049  */
2050 L.isValue = function(o) {
2051     var t = L.type(o);
2053     switch (t) {
2054         case 'number':
2055             return isFinite(o);
2057         case 'null': // fallthru
2058         case 'undefined':
2059             return false;
2061         default:
2062             return !!t;
2063     }
2067  * Returns the current time in milliseconds.
2069  * @method now
2070  * @return {Number} Current time in milliseconds.
2071  * @static
2072  * @since 3.3.0
2073  */
2074 L.now = Date.now || function () {
2075     return new Date().getTime();
2079  * Lightweight version of <code>Y.substitute</code>. Uses the same template
2080  * structure as <code>Y.substitute</code>, but doesn't support recursion,
2081  * auto-object coersion, or formats.
2082  * @method sub
2083  * @param {string} s String to be modified.
2084  * @param {object} o Object containing replacement values.
2085  * @return {string} the substitute result.
2086  * @static
2087  * @since 3.2.0
2088  */
2089 L.sub = function(s, o) {
2090     return s.replace ? s.replace(SUBREGEX, function (match, key) {
2091         return L.isUndefined(o[key]) ? match : o[key];
2092     }) : s;
2096  * Returns a string without any leading or trailing whitespace.  If
2097  * the input is not a string, the input will be returned untouched.
2098  * @method trim
2099  * @static
2100  * @param s {string} the string to trim.
2101  * @return {string} the trimmed string.
2102  */
2103 L.trim = STRING_PROTO.trim ? function(s) {
2104     return s && s.trim ? s.trim() : s;
2105 } : function (s) {
2106     try {
2107         return s.replace(TRIMREGEX, '');
2108     } catch (e) {
2109         return s;
2110     }
2114  * Returns a string without any leading whitespace.
2115  * @method trimLeft
2116  * @static
2117  * @param s {string} the string to trim.
2118  * @return {string} the trimmed string.
2119  */
2120 L.trimLeft = STRING_PROTO.trimLeft ? function (s) {
2121     return s.trimLeft();
2122 } : function (s) {
2123     return s.replace(/^\s+/, '');
2127  * Returns a string without any trailing whitespace.
2128  * @method trimRight
2129  * @static
2130  * @param s {string} the string to trim.
2131  * @return {string} the trimmed string.
2132  */
2133 L.trimRight = STRING_PROTO.trimRight ? function (s) {
2134     return s.trimRight();
2135 } : function (s) {
2136     return s.replace(/\s+$/, '');
2140 Returns one of the following strings, representing the type of the item passed
2143  * "array"
2144  * "boolean"
2145  * "date"
2146  * "error"
2147  * "function"
2148  * "null"
2149  * "number"
2150  * "object"
2151  * "regexp"
2152  * "string"
2153  * "undefined"
2155 Known issues:
2157  * `typeof HTMLElementCollection` returns function in Safari, but
2158     `Y.Lang.type()` reports "object", which could be a good thing --
2159     but it actually caused the logic in <code>Y.Lang.isObject</code> to fail.
2161 @method type
2162 @param o the item to test.
2163 @return {string} the detected type.
2164 @static
2166 L.type = function(o) {
2167     return TYPES[typeof o] || TYPES[TOSTRING.call(o)] || (o ? 'object' : 'null');
2170 @module yui
2171 @submodule yui-base
2174 var Lang   = Y.Lang,
2175     Native = Array.prototype,
2177     hasOwn = Object.prototype.hasOwnProperty;
2180 Provides utility methods for working with arrays. Additional array helpers can
2181 be found in the `collection` and `array-extras` modules.
2183 `Y.Array(thing)` returns a native array created from _thing_. Depending on
2184 _thing_'s type, one of the following will happen:
2186   * Arrays are returned unmodified unless a non-zero _startIndex_ is
2187     specified.
2188   * Array-like collections (see `Array.test()`) are converted to arrays.
2189   * For everything else, a new array is created with _thing_ as the sole
2190     item.
2192 Note: elements that are also collections, such as `<form>` and `<select>`
2193 elements, are not automatically converted to arrays. To force a conversion,
2194 pass `true` as the value of the _force_ parameter.
2196 @class Array
2197 @constructor
2198 @param {Any} thing The thing to arrayify.
2199 @param {Number} [startIndex=0] If non-zero and _thing_ is an array or array-like
2200   collection, a subset of items starting at the specified index will be
2201   returned.
2202 @param {Boolean} [force=false] If `true`, _thing_ will be treated as an
2203   array-like collection no matter what.
2204 @return {Array} A native array created from _thing_, according to the rules
2205   described above.
2207 function YArray(thing, startIndex, force) {
2208     var len, result;
2210     startIndex || (startIndex = 0);
2212     if (force || YArray.test(thing)) {
2213         // IE throws when trying to slice HTMLElement collections.
2214         try {
2215             return Native.slice.call(thing, startIndex);
2216         } catch (ex) {
2217             result = [];
2219             for (len = thing.length; startIndex < len; ++startIndex) {
2220                 result.push(thing[startIndex]);
2221             }
2223             return result;
2224         }
2225     }
2227     return [thing];
2230 Y.Array = YArray;
2233 Dedupes an array of strings, returning an array that's guaranteed to contain
2234 only one copy of a given string.
2236 This method differs from `Array.unique()` in that it's optimized for use only
2237 with strings, whereas `unique` may be used with other types (but is slower).
2238 Using `dedupe()` with non-string values may result in unexpected behavior.
2240 @method dedupe
2241 @param {String[]} array Array of strings to dedupe.
2242 @return {Array} Deduped copy of _array_.
2243 @static
2244 @since 3.4.0
2246 YArray.dedupe = function (array) {
2247     var hash    = {},
2248         results = [],
2249         i, item, len;
2251     for (i = 0, len = array.length; i < len; ++i) {
2252         item = array[i];
2254         if (!hasOwn.call(hash, item)) {
2255             hash[item] = 1;
2256             results.push(item);
2257         }
2258     }
2260     return results;
2264 Executes the supplied function on each item in the array. This method wraps
2265 the native ES5 `Array.forEach()` method if available.
2267 @method each
2268 @param {Array} array Array to iterate.
2269 @param {Function} fn Function to execute on each item in the array. The function
2270   will receive the following arguments:
2271     @param {Any} fn.item Current array item.
2272     @param {Number} fn.index Current array index.
2273     @param {Array} fn.array Array being iterated.
2274 @param {Object} [thisObj] `this` object to use when calling _fn_.
2275 @return {YUI} The YUI instance.
2276 @static
2278 YArray.each = YArray.forEach = Lang._isNative(Native.forEach) ? function (array, fn, thisObj) {
2279     Native.forEach.call(array || [], fn, thisObj || Y);
2280     return Y;
2281 } : function (array, fn, thisObj) {
2282     for (var i = 0, len = (array && array.length) || 0; i < len; ++i) {
2283         if (i in array) {
2284             fn.call(thisObj || Y, array[i], i, array);
2285         }
2286     }
2288     return Y;
2292 Alias for `each()`.
2294 @method forEach
2295 @static
2299 Returns an object using the first array as keys and the second as values. If
2300 the second array is not provided, or if it doesn't contain the same number of
2301 values as the first array, then `true` will be used in place of the missing
2302 values.
2304 @example
2306     Y.Array.hash(['a', 'b', 'c'], ['foo', 'bar']);
2307     // => {a: 'foo', b: 'bar', c: true}
2309 @method hash
2310 @param {String[]} keys Array of strings to use as keys.
2311 @param {Array} [values] Array to use as values.
2312 @return {Object} Hash using the first array as keys and the second as values.
2313 @static
2315 YArray.hash = function (keys, values) {
2316     var hash = {},
2317         vlen = (values && values.length) || 0,
2318         i, len;
2320     for (i = 0, len = keys.length; i < len; ++i) {
2321         if (i in keys) {
2322             hash[keys[i]] = vlen > i && i in values ? values[i] : true;
2323         }
2324     }
2326     return hash;
2330 Returns the index of the first item in the array that's equal (using a strict
2331 equality check) to the specified _value_, or `-1` if the value isn't found.
2333 This method wraps the native ES5 `Array.indexOf()` method if available.
2335 @method indexOf
2336 @param {Array} array Array to search.
2337 @param {Any} value Value to search for.
2338 @param {Number} [from=0] The index at which to begin the search.
2339 @return {Number} Index of the item strictly equal to _value_, or `-1` if not
2340     found.
2341 @static
2343 YArray.indexOf = Lang._isNative(Native.indexOf) ? function (array, value, from) {
2344     return Native.indexOf.call(array, value, from);
2345 } : function (array, value, from) {
2346     // http://es5.github.com/#x15.4.4.14
2347     var len = array.length;
2349     from = +from || 0;
2350     from = (from > 0 || -1) * Math.floor(Math.abs(from));
2352     if (from < 0) {
2353         from += len;
2355         if (from < 0) {
2356             from = 0;
2357         }
2358     }
2360     for (; from < len; ++from) {
2361         if (from in array && array[from] === value) {
2362             return from;
2363         }
2364     }
2366     return -1;
2370 Numeric sort convenience function.
2372 The native `Array.prototype.sort()` function converts values to strings and
2373 sorts them in lexicographic order, which is unsuitable for sorting numeric
2374 values. Provide `Array.numericSort` as a custom sort function when you want
2375 to sort values in numeric order.
2377 @example
2379     [42, 23, 8, 16, 4, 15].sort(Y.Array.numericSort);
2380     // => [4, 8, 15, 16, 23, 42]
2382 @method numericSort
2383 @param {Number} a First value to compare.
2384 @param {Number} b Second value to compare.
2385 @return {Number} Difference between _a_ and _b_.
2386 @static
2388 YArray.numericSort = function (a, b) {
2389     return a - b;
2393 Executes the supplied function on each item in the array. Returning a truthy
2394 value from the function will stop the processing of remaining items.
2396 @method some
2397 @param {Array} array Array to iterate over.
2398 @param {Function} fn Function to execute on each item. The function will receive
2399   the following arguments:
2400     @param {Any} fn.value Current array item.
2401     @param {Number} fn.index Current array index.
2402     @param {Array} fn.array Array being iterated over.
2403 @param {Object} [thisObj] `this` object to use when calling _fn_.
2404 @return {Boolean} `true` if the function returns a truthy value on any of the
2405   items in the array; `false` otherwise.
2406 @static
2408 YArray.some = Lang._isNative(Native.some) ? function (array, fn, thisObj) {
2409     return Native.some.call(array, fn, thisObj);
2410 } : function (array, fn, thisObj) {
2411     for (var i = 0, len = array.length; i < len; ++i) {
2412         if (i in array && fn.call(thisObj, array[i], i, array)) {
2413             return true;
2414         }
2415     }
2417     return false;
2421 Evaluates _obj_ to determine if it's an array, an array-like collection, or
2422 something else. This is useful when working with the function `arguments`
2423 collection and `HTMLElement` collections.
2425 Note: This implementation doesn't consider elements that are also
2426 collections, such as `<form>` and `<select>`, to be array-like.
2428 @method test
2429 @param {Object} obj Object to test.
2430 @return {Number} A number indicating the results of the test:
2432   * 0: Neither an array nor an array-like collection.
2433   * 1: Real array.
2434   * 2: Array-like collection.
2436 @static
2438 YArray.test = function (obj) {
2439     var result = 0;
2441     if (Lang.isArray(obj)) {
2442         result = 1;
2443     } else if (Lang.isObject(obj)) {
2444         try {
2445             // indexed, but no tagName (element) or alert (window),
2446             // or functions without apply/call (Safari
2447             // HTMLElementCollection bug).
2448             if ('length' in obj && !obj.tagName && !obj.alert && !obj.apply) {
2449                 result = 2;
2450             }
2451         } catch (ex) {}
2452     }
2454     return result;
2457  * The YUI module contains the components required for building the YUI
2458  * seed file.  This includes the script loading mechanism, a simple queue,
2459  * and the core utilities for the library.
2460  * @module yui
2461  * @submodule yui-base
2462  */
2465  * A simple FIFO queue.  Items are added to the Queue with add(1..n items) and
2466  * removed using next().
2468  * @class Queue
2469  * @constructor
2470  * @param {MIXED} item* 0..n items to seed the queue.
2471  */
2472 function Queue() {
2473     this._init();
2474     this.add.apply(this, arguments);
2477 Queue.prototype = {
2478     /**
2479      * Initialize the queue
2480      *
2481      * @method _init
2482      * @protected
2483      */
2484     _init: function() {
2485         /**
2486          * The collection of enqueued items
2487          *
2488          * @property _q
2489          * @type Array
2490          * @protected
2491          */
2492         this._q = [];
2493     },
2495     /**
2496      * Get the next item in the queue. FIFO support
2497      *
2498      * @method next
2499      * @return {MIXED} the next item in the queue.
2500      */
2501     next: function() {
2502         return this._q.shift();
2503     },
2505     /**
2506      * Get the last in the queue. LIFO support.
2507      *
2508      * @method last
2509      * @return {MIXED} the last item in the queue.
2510      */
2511     last: function() {
2512         return this._q.pop();
2513     },
2515     /**
2516      * Add 0..n items to the end of the queue.
2517      *
2518      * @method add
2519      * @param {MIXED} item* 0..n items.
2520      * @return {object} this queue.
2521      */
2522     add: function() {
2523         this._q.push.apply(this._q, arguments);
2525         return this;
2526     },
2528     /**
2529      * Returns the current number of queued items.
2530      *
2531      * @method size
2532      * @return {Number} The size.
2533      */
2534     size: function() {
2535         return this._q.length;
2536     }
2539 Y.Queue = Queue;
2541 YUI.Env._loaderQueue = YUI.Env._loaderQueue || new Queue();
2544 The YUI module contains the components required for building the YUI seed file.
2545 This includes the script loading mechanism, a simple queue, and the core
2546 utilities for the library.
2548 @module yui
2549 @submodule yui-base
2552 var CACHED_DELIMITER = '__',
2554     hasOwn   = Object.prototype.hasOwnProperty,
2555     isObject = Y.Lang.isObject;
2558 Returns a wrapper for a function which caches the return value of that function,
2559 keyed off of the combined string representation of the argument values provided
2560 when the wrapper is called.
2562 Calling this function again with the same arguments will return the cached value
2563 rather than executing the wrapped function.
2565 Note that since the cache is keyed off of the string representation of arguments
2566 passed to the wrapper function, arguments that aren't strings and don't provide
2567 a meaningful `toString()` method may result in unexpected caching behavior. For
2568 example, the objects `{}` and `{foo: 'bar'}` would both be converted to the
2569 string `[object Object]` when used as a cache key.
2571 @method cached
2572 @param {Function} source The function to memoize.
2573 @param {Object} [cache={}] Object in which to store cached values. You may seed
2574   this object with pre-existing cached values if desired.
2575 @param {any} [refetch] If supplied, this value is compared with the cached value
2576   using a `==` comparison. If the values are equal, the wrapped function is
2577   executed again even though a cached value exists.
2578 @return {Function} Wrapped function.
2579 @for YUI
2581 Y.cached = function (source, cache, refetch) {
2582     cache || (cache = {});
2584     return function (arg) {
2585         var key = arguments.length > 1 ?
2586                 Array.prototype.join.call(arguments, CACHED_DELIMITER) :
2587                 String(arg);
2589         if (!(key in cache) || (refetch && cache[key] == refetch)) {
2590             cache[key] = source.apply(source, arguments);
2591         }
2593         return cache[key];
2594     };
2598 Returns the `location` object from the window/frame in which this YUI instance
2599 operates, or `undefined` when executing in a non-browser environment
2600 (e.g. Node.js).
2602 It is _not_ recommended to hold references to the `window.location` object
2603 outside of the scope of a function in which its properties are being accessed or
2604 its methods are being called. This is because of a nasty bug/issue that exists
2605 in both Safari and MobileSafari browsers:
2606 [WebKit Bug 34679](https://bugs.webkit.org/show_bug.cgi?id=34679).
2608 @method getLocation
2609 @return {location} The `location` object from the window/frame in which this YUI
2610     instance operates.
2611 @since 3.5.0
2613 Y.getLocation = function () {
2614     // It is safer to look this up every time because yui-base is attached to a
2615     // YUI instance before a user's config is applied; i.e. `Y.config.win` does
2616     // not point the correct window object when this file is loaded.
2617     var win = Y.config.win;
2619     // It is not safe to hold a reference to the `location` object outside the
2620     // scope in which it is being used. The WebKit engine used in Safari and
2621     // MobileSafari will "disconnect" the `location` object from the `window`
2622     // when a page is restored from back/forward history cache.
2623     return win && win.location;
2627 Returns a new object containing all of the properties of all the supplied
2628 objects. The properties from later objects will overwrite those in earlier
2629 objects.
2631 Passing in a single object will create a shallow copy of it. For a deep copy,
2632 use `clone()`.
2634 @method merge
2635 @param {Object} objects* One or more objects to merge.
2636 @return {Object} A new merged object.
2638 Y.merge = function () {
2639     var args   = arguments,
2640         i      = 0,
2641         len    = args.length,
2642         result = {};
2644     for (; i < len; ++i) {
2645         Y.mix(result, args[i], true);
2646     }
2648     return result;
2652 Mixes _supplier_'s properties into _receiver_.
2654 Properties on _receiver_ or _receiver_'s prototype will not be overwritten or
2655 shadowed unless the _overwrite_ parameter is `true`, and will not be merged
2656 unless the _merge_ parameter is `true`.
2658 In the default mode (0), only properties the supplier owns are copied (prototype
2659 properties are not copied). The following copying modes are available:
2661   * `0`: _Default_. Object to object.
2662   * `1`: Prototype to prototype.
2663   * `2`: Prototype to prototype and object to object.
2664   * `3`: Prototype to object.
2665   * `4`: Object to prototype.
2667 @method mix
2668 @param {Function|Object} receiver The object or function to receive the mixed
2669   properties.
2670 @param {Function|Object} supplier The object or function supplying the
2671   properties to be mixed.
2672 @param {Boolean} [overwrite=false] If `true`, properties that already exist
2673   on the receiver will be overwritten with properties from the supplier.
2674 @param {String[]} [whitelist] An array of property names to copy. If
2675   specified, only the whitelisted properties will be copied, and all others
2676   will be ignored.
2677 @param {Number} [mode=0] Mix mode to use. See above for available modes.
2678 @param {Boolean} [merge=false] If `true`, objects and arrays that already
2679   exist on the receiver will have the corresponding object/array from the
2680   supplier merged into them, rather than being skipped or overwritten. When
2681   both _overwrite_ and _merge_ are `true`, _merge_ takes precedence.
2682 @return {Function|Object|YUI} The receiver, or the YUI instance if the
2683   specified receiver is falsy.
2685 Y.mix = function(receiver, supplier, overwrite, whitelist, mode, merge) {
2686     var alwaysOverwrite, exists, from, i, key, len, to;
2688     // If no supplier is given, we return the receiver. If no receiver is given,
2689     // we return Y. Returning Y doesn't make much sense to me, but it's
2690     // grandfathered in for backcompat reasons.
2691     if (!receiver || !supplier) {
2692         return receiver || Y;
2693     }
2695     if (mode) {
2696         // In mode 2 (prototype to prototype and object to object), we recurse
2697         // once to do the proto to proto mix. The object to object mix will be
2698         // handled later on.
2699         if (mode === 2) {
2700             Y.mix(receiver.prototype, supplier.prototype, overwrite,
2701                     whitelist, 0, merge);
2702         }
2704         // Depending on which mode is specified, we may be copying from or to
2705         // the prototypes of the supplier and receiver.
2706         from = mode === 1 || mode === 3 ? supplier.prototype : supplier;
2707         to   = mode === 1 || mode === 4 ? receiver.prototype : receiver;
2709         // If either the supplier or receiver doesn't actually have a
2710         // prototype property, then we could end up with an undefined `from`
2711         // or `to`. If that happens, we abort and return the receiver.
2712         if (!from || !to) {
2713             return receiver;
2714         }
2715     } else {
2716         from = supplier;
2717         to   = receiver;
2718     }
2720     // If `overwrite` is truthy and `merge` is falsy, then we can skip a
2721     // property existence check on each iteration and save some time.
2722     alwaysOverwrite = overwrite && !merge;
2724     if (whitelist) {
2725         for (i = 0, len = whitelist.length; i < len; ++i) {
2726             key = whitelist[i];
2728             // We call `Object.prototype.hasOwnProperty` instead of calling
2729             // `hasOwnProperty` on the object itself, since the object's
2730             // `hasOwnProperty` method may have been overridden or removed.
2731             // Also, some native objects don't implement a `hasOwnProperty`
2732             // method.
2733             if (!hasOwn.call(from, key)) {
2734                 continue;
2735             }
2737             // The `key in to` check here is (sadly) intentional for backwards
2738             // compatibility reasons. It prevents undesired shadowing of
2739             // prototype members on `to`.
2740             exists = alwaysOverwrite ? false : key in to;
2742             if (merge && exists && isObject(to[key], true)
2743                     && isObject(from[key], true)) {
2744                 // If we're in merge mode, and the key is present on both
2745                 // objects, and the value on both objects is either an object or
2746                 // an array (but not a function), then we recurse to merge the
2747                 // `from` value into the `to` value instead of overwriting it.
2748                 //
2749                 // Note: It's intentional that the whitelist isn't passed to the
2750                 // recursive call here. This is legacy behavior that lots of
2751                 // code still depends on.
2752                 Y.mix(to[key], from[key], overwrite, null, 0, merge);
2753             } else if (overwrite || !exists) {
2754                 // We're not in merge mode, so we'll only copy the `from` value
2755                 // to the `to` value if we're in overwrite mode or if the
2756                 // current key doesn't exist on the `to` object.
2757                 to[key] = from[key];
2758             }
2759         }
2760     } else {
2761         for (key in from) {
2762             // The code duplication here is for runtime performance reasons.
2763             // Combining whitelist and non-whitelist operations into a single
2764             // loop or breaking the shared logic out into a function both result
2765             // in worse performance, and Y.mix is critical enough that the byte
2766             // tradeoff is worth it.
2767             if (!hasOwn.call(from, key)) {
2768                 continue;
2769             }
2771             // The `key in to` check here is (sadly) intentional for backwards
2772             // compatibility reasons. It prevents undesired shadowing of
2773             // prototype members on `to`.
2774             exists = alwaysOverwrite ? false : key in to;
2776             if (merge && exists && isObject(to[key], true)
2777                     && isObject(from[key], true)) {
2778                 Y.mix(to[key], from[key], overwrite, null, 0, merge);
2779             } else if (overwrite || !exists) {
2780                 to[key] = from[key];
2781             }
2782         }
2784         // If this is an IE browser with the JScript enumeration bug, force
2785         // enumeration of the buggy properties by making a recursive call with
2786         // the buggy properties as the whitelist.
2787         if (Y.Object._hasEnumBug) {
2788             Y.mix(to, from, overwrite, Y.Object._forceEnum, mode, merge);
2789         }
2790     }
2792     return receiver;
2795  * The YUI module contains the components required for building the YUI
2796  * seed file.  This includes the script loading mechanism, a simple queue,
2797  * and the core utilities for the library.
2798  * @module yui
2799  * @submodule yui-base
2800  */
2803  * Adds utilities to the YUI instance for working with objects.
2805  * @class Object
2806  */
2808 var Lang   = Y.Lang,
2809     hasOwn = Object.prototype.hasOwnProperty,
2811     UNDEFINED, // <-- Note the comma. We're still declaring vars.
2814  * Returns a new object that uses _obj_ as its prototype. This method wraps the
2815  * native ES5 `Object.create()` method if available, but doesn't currently
2816  * pass through `Object.create()`'s second argument (properties) in order to
2817  * ensure compatibility with older browsers.
2819  * @method ()
2820  * @param {Object} obj Prototype object.
2821  * @return {Object} New object using _obj_ as its prototype.
2822  * @static
2823  */
2824 O = Y.Object = Lang._isNative(Object.create) ? function (obj) {
2825     // We currently wrap the native Object.create instead of simply aliasing it
2826     // to ensure consistency with our fallback shim, which currently doesn't
2827     // support Object.create()'s second argument (properties). Once we have a
2828     // safe fallback for the properties arg, we can stop wrapping
2829     // Object.create().
2830     return Object.create(obj);
2831 } : (function () {
2832     // Reusable constructor function for the Object.create() shim.
2833     function F() {}
2835     // The actual shim.
2836     return function (obj) {
2837         F.prototype = obj;
2838         return new F();
2839     };
2840 }()),
2843  * Property names that IE doesn't enumerate in for..in loops, even when they
2844  * should be enumerable. When `_hasEnumBug` is `true`, it's necessary to
2845  * manually enumerate these properties.
2847  * @property _forceEnum
2848  * @type String[]
2849  * @protected
2850  * @static
2851  */
2852 forceEnum = O._forceEnum = [
2853     'hasOwnProperty',
2854     'isPrototypeOf',
2855     'propertyIsEnumerable',
2856     'toString',
2857     'toLocaleString',
2858     'valueOf'
2862  * `true` if this browser has the JScript enumeration bug that prevents
2863  * enumeration of the properties named in the `_forceEnum` array, `false`
2864  * otherwise.
2866  * See:
2867  *   - <https://developer.mozilla.org/en/ECMAScript_DontEnum_attribute#JScript_DontEnum_Bug>
2868  *   - <http://whattheheadsaid.com/2010/10/a-safer-object-keys-compatibility-implementation>
2870  * @property _hasEnumBug
2871  * @type Boolean
2872  * @protected
2873  * @static
2874  */
2875 hasEnumBug = O._hasEnumBug = !{valueOf: 0}.propertyIsEnumerable('valueOf'),
2878  * `true` if this browser incorrectly considers the `prototype` property of
2879  * functions to be enumerable. Currently known to affect Opera 11.50.
2881  * @property _hasProtoEnumBug
2882  * @type Boolean
2883  * @protected
2884  * @static
2885  */
2886 hasProtoEnumBug = O._hasProtoEnumBug = (function () {}).propertyIsEnumerable('prototype'),
2889  * Returns `true` if _key_ exists on _obj_, `false` if _key_ doesn't exist or
2890  * exists only on _obj_'s prototype. This is essentially a safer version of
2891  * `obj.hasOwnProperty()`.
2893  * @method owns
2894  * @param {Object} obj Object to test.
2895  * @param {String} key Property name to look for.
2896  * @return {Boolean} `true` if _key_ exists on _obj_, `false` otherwise.
2897  * @static
2898  */
2899 owns = O.owns = function (obj, key) {
2900     return !!obj && hasOwn.call(obj, key);
2901 }; // <-- End of var declarations.
2904  * Alias for `owns()`.
2906  * @method hasKey
2907  * @param {Object} obj Object to test.
2908  * @param {String} key Property name to look for.
2909  * @return {Boolean} `true` if _key_ exists on _obj_, `false` otherwise.
2910  * @static
2911  */
2912 O.hasKey = owns;
2915  * Returns an array containing the object's enumerable keys. Does not include
2916  * prototype keys or non-enumerable keys.
2918  * Note that keys are returned in enumeration order (that is, in the same order
2919  * that they would be enumerated by a `for-in` loop), which may not be the same
2920  * as the order in which they were defined.
2922  * This method is an alias for the native ES5 `Object.keys()` method if
2923  * available.
2925  * @example
2927  *     Y.Object.keys({a: 'foo', b: 'bar', c: 'baz'});
2928  *     // => ['a', 'b', 'c']
2930  * @method keys
2931  * @param {Object} obj An object.
2932  * @return {String[]} Array of keys.
2933  * @static
2934  */
2935 O.keys = Lang._isNative(Object.keys) ? Object.keys : function (obj) {
2936     if (!Lang.isObject(obj)) {
2937         throw new TypeError('Object.keys called on a non-object');
2938     }
2940     var keys = [],
2941         i, key, len;
2943     if (hasProtoEnumBug && typeof obj === 'function') {
2944         for (key in obj) {
2945             if (owns(obj, key) && key !== 'prototype') {
2946                 keys.push(key);
2947             }
2948         }
2949     } else {
2950         for (key in obj) {
2951             if (owns(obj, key)) {
2952                 keys.push(key);
2953             }
2954         }
2955     }
2957     if (hasEnumBug) {
2958         for (i = 0, len = forceEnum.length; i < len; ++i) {
2959             key = forceEnum[i];
2961             if (owns(obj, key)) {
2962                 keys.push(key);
2963             }
2964         }
2965     }
2967     return keys;
2971  * Returns an array containing the values of the object's enumerable keys.
2973  * Note that values are returned in enumeration order (that is, in the same
2974  * order that they would be enumerated by a `for-in` loop), which may not be the
2975  * same as the order in which they were defined.
2977  * @example
2979  *     Y.Object.values({a: 'foo', b: 'bar', c: 'baz'});
2980  *     // => ['foo', 'bar', 'baz']
2982  * @method values
2983  * @param {Object} obj An object.
2984  * @return {Array} Array of values.
2985  * @static
2986  */
2987 O.values = function (obj) {
2988     var keys   = O.keys(obj),
2989         i      = 0,
2990         len    = keys.length,
2991         values = [];
2993     for (; i < len; ++i) {
2994         values.push(obj[keys[i]]);
2995     }
2997     return values;
3001  * Returns the number of enumerable keys owned by an object.
3003  * @method size
3004  * @param {Object} obj An object.
3005  * @return {Number} The object's size.
3006  * @static
3007  */
3008 O.size = function (obj) {
3009     try {
3010         return O.keys(obj).length;
3011     } catch (ex) {
3012         return 0; // Legacy behavior for non-objects.
3013     }
3017  * Returns `true` if the object owns an enumerable property with the specified
3018  * value.
3020  * @method hasValue
3021  * @param {Object} obj An object.
3022  * @param {any} value The value to search for.
3023  * @return {Boolean} `true` if _obj_ contains _value_, `false` otherwise.
3024  * @static
3025  */
3026 O.hasValue = function (obj, value) {
3027     return Y.Array.indexOf(O.values(obj), value) > -1;
3031  * Executes a function on each enumerable property in _obj_. The function
3032  * receives the value, the key, and the object itself as parameters (in that
3033  * order).
3035  * By default, only properties owned by _obj_ are enumerated. To include
3036  * prototype properties, set the _proto_ parameter to `true`.
3038  * @method each
3039  * @param {Object} obj Object to enumerate.
3040  * @param {Function} fn Function to execute on each enumerable property.
3041  *   @param {mixed} fn.value Value of the current property.
3042  *   @param {String} fn.key Key of the current property.
3043  *   @param {Object} fn.obj Object being enumerated.
3044  * @param {Object} [thisObj] `this` object to use when calling _fn_.
3045  * @param {Boolean} [proto=false] Include prototype properties.
3046  * @return {YUI} the YUI instance.
3047  * @chainable
3048  * @static
3049  */
3050 O.each = function (obj, fn, thisObj, proto) {
3051     var key;
3053     for (key in obj) {
3054         if (proto || owns(obj, key)) {
3055             fn.call(thisObj || Y, obj[key], key, obj);
3056         }
3057     }
3059     return Y;
3063  * Executes a function on each enumerable property in _obj_, but halts if the
3064  * function returns a truthy value. The function receives the value, the key,
3065  * and the object itself as paramters (in that order).
3067  * By default, only properties owned by _obj_ are enumerated. To include
3068  * prototype properties, set the _proto_ parameter to `true`.
3070  * @method some
3071  * @param {Object} obj Object to enumerate.
3072  * @param {Function} fn Function to execute on each enumerable property.
3073  *   @param {mixed} fn.value Value of the current property.
3074  *   @param {String} fn.key Key of the current property.
3075  *   @param {Object} fn.obj Object being enumerated.
3076  * @param {Object} [thisObj] `this` object to use when calling _fn_.
3077  * @param {Boolean} [proto=false] Include prototype properties.
3078  * @return {Boolean} `true` if any execution of _fn_ returns a truthy value,
3079  *   `false` otherwise.
3080  * @static
3081  */
3082 O.some = function (obj, fn, thisObj, proto) {
3083     var key;
3085     for (key in obj) {
3086         if (proto || owns(obj, key)) {
3087             if (fn.call(thisObj || Y, obj[key], key, obj)) {
3088                 return true;
3089             }
3090         }
3091     }
3093     return false;
3097  * Retrieves the sub value at the provided path,
3098  * from the value object provided.
3100  * @method getValue
3101  * @static
3102  * @param o The object from which to extract the property value.
3103  * @param path {Array} A path array, specifying the object traversal path
3104  * from which to obtain the sub value.
3105  * @return {Any} The value stored in the path, undefined if not found,
3106  * undefined if the source is not an object.  Returns the source object
3107  * if an empty path is provided.
3108  */
3109 O.getValue = function(o, path) {
3110     if (!Lang.isObject(o)) {
3111         return UNDEFINED;
3112     }
3114     var i,
3115         p = Y.Array(path),
3116         l = p.length;
3118     for (i = 0; o !== UNDEFINED && i < l; i++) {
3119         o = o[p[i]];
3120     }
3122     return o;
3126  * Sets the sub-attribute value at the provided path on the
3127  * value object.  Returns the modified value object, or
3128  * undefined if the path is invalid.
3130  * @method setValue
3131  * @static
3132  * @param o             The object on which to set the sub value.
3133  * @param path {Array}  A path array, specifying the object traversal path
3134  *                      at which to set the sub value.
3135  * @param val {Any}     The new value for the sub-attribute.
3136  * @return {Object}     The modified object, with the new sub value set, or
3137  *                      undefined, if the path was invalid.
3138  */
3139 O.setValue = function(o, path, val) {
3140     var i,
3141         p = Y.Array(path),
3142         leafIdx = p.length - 1,
3143         ref = o;
3145     if (leafIdx >= 0) {
3146         for (i = 0; ref !== UNDEFINED && i < leafIdx; i++) {
3147             ref = ref[p[i]];
3148         }
3150         if (ref !== UNDEFINED) {
3151             ref[p[i]] = val;
3152         } else {
3153             return UNDEFINED;
3154         }
3155     }
3157     return o;
3161  * Returns `true` if the object has no enumerable properties of its own.
3163  * @method isEmpty
3164  * @param {Object} obj An object.
3165  * @return {Boolean} `true` if the object is empty.
3166  * @static
3167  * @since 3.2.0
3168  */
3169 O.isEmpty = function (obj) {
3170     return !O.keys(Object(obj)).length;
3173  * The YUI module contains the components required for building the YUI seed
3174  * file.  This includes the script loading mechanism, a simple queue, and the
3175  * core utilities for the library.
3176  * @module yui
3177  * @submodule yui-base
3178  */
3181  * YUI user agent detection.
3182  * Do not fork for a browser if it can be avoided.  Use feature detection when
3183  * you can.  Use the user agent as a last resort.  For all fields listed
3184  * as @type float, UA stores a version number for the browser engine,
3185  * 0 otherwise.  This value may or may not map to the version number of
3186  * the browser using the engine.  The value is presented as a float so
3187  * that it can easily be used for boolean evaluation as well as for
3188  * looking for a particular range of versions.  Because of this,
3189  * some of the granularity of the version info may be lost.  The fields that
3190  * are @type string default to null.  The API docs list the values that
3191  * these fields can have.
3192  * @class UA
3193  * @static
3194  */
3197 * Static method on `YUI.Env` for parsing a UA string.  Called at instantiation
3198 * to populate `Y.UA`.
3200 * @static
3201 * @method parseUA
3202 * @param {String} [subUA=navigator.userAgent] UA string to parse
3203 * @return {Object} The Y.UA object
3205 YUI.Env.parseUA = function(subUA) {
3207     var numberify = function(s) {
3208             var c = 0;
3209             return parseFloat(s.replace(/\./g, function() {
3210                 return (c++ == 1) ? '' : '.';
3211             }));
3212         },
3214         win = Y.config.win,
3216         nav = win && win.navigator,
3218         o = {
3220         /**
3221          * Internet Explorer version number or 0.  Example: 6
3222          * @property ie
3223          * @type float
3224          * @static
3225          */
3226         ie: 0,
3228         /**
3229          * Opera version number or 0.  Example: 9.2
3230          * @property opera
3231          * @type float
3232          * @static
3233          */
3234         opera: 0,
3236         /**
3237          * Gecko engine revision number.  Will evaluate to 1 if Gecko
3238          * is detected but the revision could not be found. Other browsers
3239          * will be 0.  Example: 1.8
3240          * <pre>
3241          * Firefox 1.0.0.4: 1.7.8   <-- Reports 1.7
3242          * Firefox 1.5.0.9: 1.8.0.9 <-- 1.8
3243          * Firefox 2.0.0.3: 1.8.1.3 <-- 1.81
3244          * Firefox 3.0   <-- 1.9
3245          * Firefox 3.5   <-- 1.91
3246          * </pre>
3247          * @property gecko
3248          * @type float
3249          * @static
3250          */
3251         gecko: 0,
3253         /**
3254          * AppleWebKit version.  KHTML browsers that are not WebKit browsers
3255          * will evaluate to 1, other browsers 0.  Example: 418.9
3256          * <pre>
3257          * Safari 1.3.2 (312.6): 312.8.1 <-- Reports 312.8 -- currently the
3258          *                                   latest available for Mac OSX 10.3.
3259          * Safari 2.0.2:         416     <-- hasOwnProperty introduced
3260          * Safari 2.0.4:         418     <-- preventDefault fixed
3261          * Safari 2.0.4 (419.3): 418.9.1 <-- One version of Safari may run
3262          *                                   different versions of webkit
3263          * Safari 2.0.4 (419.3): 419     <-- Tiger installations that have been
3264          *                                   updated, but not updated
3265          *                                   to the latest patch.
3266          * Webkit 212 nightly:   522+    <-- Safari 3.0 precursor (with native
3267          * SVG and many major issues fixed).
3268          * Safari 3.0.4 (523.12) 523.12  <-- First Tiger release - automatic
3269          * update from 2.x via the 10.4.11 OS patch.
3270          * Webkit nightly 1/2008:525+    <-- Supports DOMContentLoaded event.
3271          *                                   yahoo.com user agent hack removed.
3272          * </pre>
3273          * http://en.wikipedia.org/wiki/Safari_version_history
3274          * @property webkit
3275          * @type float
3276          * @static
3277          */
3278         webkit: 0,
3280         /**
3281          * Safari will be detected as webkit, but this property will also
3282          * be populated with the Safari version number
3283          * @property safari
3284          * @type float
3285          * @static
3286          */
3287         safari: 0,
3289         /**
3290          * Chrome will be detected as webkit, but this property will also
3291          * be populated with the Chrome version number
3292          * @property chrome
3293          * @type float
3294          * @static
3295          */
3296         chrome: 0,
3298         /**
3299          * The mobile property will be set to a string containing any relevant
3300          * user agent information when a modern mobile browser is detected.
3301          * Currently limited to Safari on the iPhone/iPod Touch, Nokia N-series
3302          * devices with the WebKit-based browser, and Opera Mini.
3303          * @property mobile
3304          * @type string
3305          * @default null
3306          * @static
3307          */
3308         mobile: null,
3310         /**
3311          * Adobe AIR version number or 0.  Only populated if webkit is detected.
3312          * Example: 1.0
3313          * @property air
3314          * @type float
3315          */
3316         air: 0,
3317         /**
3318          * Detects Apple iPad's OS version
3319          * @property ipad
3320          * @type float
3321          * @static
3322          */
3323         ipad: 0,
3324         /**
3325          * Detects Apple iPhone's OS version
3326          * @property iphone
3327          * @type float
3328          * @static
3329          */
3330         iphone: 0,
3331         /**
3332          * Detects Apples iPod's OS version
3333          * @property ipod
3334          * @type float
3335          * @static
3336          */
3337         ipod: 0,
3338         /**
3339          * General truthy check for iPad, iPhone or iPod
3340          * @property ios
3341          * @type float
3342          * @default null
3343          * @static
3344          */
3345         ios: null,
3346         /**
3347          * Detects Googles Android OS version
3348          * @property android
3349          * @type float
3350          * @static
3351          */
3352         android: 0,
3353         /**
3354          * Detects Kindle Silk
3355          * @property silk
3356          * @type float
3357          * @static
3358          */
3359         silk: 0,
3360         /**
3361          * Detects Kindle Silk Acceleration
3362          * @property accel
3363          * @type Boolean
3364          * @static
3365          */
3366         accel: false,
3367         /**
3368          * Detects Palms WebOS version
3369          * @property webos
3370          * @type float
3371          * @static
3372          */
3373         webos: 0,
3375         /**
3376          * Google Caja version number or 0.
3377          * @property caja
3378          * @type float
3379          */
3380         caja: nav && nav.cajaVersion,
3382         /**
3383          * Set to true if the page appears to be in SSL
3384          * @property secure
3385          * @type boolean
3386          * @static
3387          */
3388         secure: false,
3390         /**
3391          * The operating system.  Currently only detecting windows or macintosh
3392          * @property os
3393          * @type string
3394          * @default null
3395          * @static
3396          */
3397         os: null,
3399         /**
3400          * The Nodejs Version
3401          * @property nodejs
3402          * @type float
3403          * @default 0
3404          * @static
3405          */
3406         nodejs: 0
3407     },
3409     ua = subUA || nav && nav.userAgent,
3411     loc = win && win.location,
3413     href = loc && loc.href,
3415     m;
3417     /**
3418     * The User Agent string that was parsed
3419     * @property userAgent
3420     * @type String
3421     * @static
3422     */
3423     o.userAgent = ua;
3426     o.secure = href && (href.toLowerCase().indexOf('https') === 0);
3428     if (ua) {
3430         if ((/windows|win32/i).test(ua)) {
3431             o.os = 'windows';
3432         } else if ((/macintosh|mac_powerpc/i).test(ua)) {
3433             o.os = 'macintosh';
3434         } else if ((/android/i).test(ua)) {
3435             o.os = 'android';
3436         } else if ((/symbos/i).test(ua)) {
3437             o.os = 'symbos';
3438         } else if ((/linux/i).test(ua)) {
3439             o.os = 'linux';
3440         } else if ((/rhino/i).test(ua)) {
3441             o.os = 'rhino';
3442         }
3444         // Modern KHTML browsers should qualify as Safari X-Grade
3445         if ((/KHTML/).test(ua)) {
3446             o.webkit = 1;
3447         }
3448         if ((/IEMobile|XBLWP7/).test(ua)) {
3449             o.mobile = 'windows';
3450         }
3451         if ((/Fennec/).test(ua)) {
3452             o.mobile = 'gecko';
3453         }
3454         // Modern WebKit browsers are at least X-Grade
3455         m = ua.match(/AppleWebKit\/([^\s]*)/);
3456         if (m && m[1]) {
3457             o.webkit = numberify(m[1]);
3458             o.safari = o.webkit;
3460             // Mobile browser check
3461             if (/ Mobile\//.test(ua) || (/iPad|iPod|iPhone/).test(ua)) {
3462                 o.mobile = 'Apple'; // iPhone or iPod Touch
3464                 m = ua.match(/OS ([^\s]*)/);
3465                 if (m && m[1]) {
3466                     m = numberify(m[1].replace('_', '.'));
3467                 }
3468                 o.ios = m;
3469                 o.os = 'ios';
3470                 o.ipad = o.ipod = o.iphone = 0;
3472                 m = ua.match(/iPad|iPod|iPhone/);
3473                 if (m && m[0]) {
3474                     o[m[0].toLowerCase()] = o.ios;
3475                 }
3476             } else {
3477                 m = ua.match(/NokiaN[^\/]*|webOS\/\d\.\d/);
3478                 if (m) {
3479                     // Nokia N-series, webOS, ex: NokiaN95
3480                     o.mobile = m[0];
3481                 }
3482                 if (/webOS/.test(ua)) {
3483                     o.mobile = 'WebOS';
3484                     m = ua.match(/webOS\/([^\s]*);/);
3485                     if (m && m[1]) {
3486                         o.webos = numberify(m[1]);
3487                     }
3488                 }
3489                 if (/ Android/.test(ua)) {
3490                     if (/Mobile/.test(ua)) {
3491                         o.mobile = 'Android';
3492                     }
3493                     m = ua.match(/Android ([^\s]*);/);
3494                     if (m && m[1]) {
3495                         o.android = numberify(m[1]);
3496                     }
3498                 }
3499                 if (/Silk/.test(ua)) {
3500                     m = ua.match(/Silk\/([^\s]*)\)/);
3501                     if (m && m[1]) {
3502                         o.silk = numberify(m[1]);
3503                     }
3504                     if (!o.android) {
3505                         o.android = 2.34; //Hack for desktop mode in Kindle
3506                         o.os = 'Android';
3507                     }
3508                     if (/Accelerated=true/.test(ua)) {
3509                         o.accel = true;
3510                     }
3511                 }
3512             }
3514             m = ua.match(/(Chrome|CrMo)\/([^\s]*)/);
3515             if (m && m[1] && m[2]) {
3516                 o.chrome = numberify(m[2]); // Chrome
3517                 o.safari = 0; //Reset safari back to 0
3518                 if (m[1] === 'CrMo') {
3519                     o.mobile = 'chrome';
3520                 }
3521             } else {
3522                 m = ua.match(/AdobeAIR\/([^\s]*)/);
3523                 if (m) {
3524                     o.air = m[0]; // Adobe AIR 1.0 or better
3525                 }
3526             }
3527         }
3529         if (!o.webkit) { // not webkit
3530 // @todo check Opera/8.01 (J2ME/MIDP; Opera Mini/2.0.4509/1316; fi; U; ssr)
3531             if (/Opera/.test(ua)) {
3532                 m = ua.match(/Opera[\s\/]([^\s]*)/);
3533                 if (m && m[1]) {
3534                     o.opera = numberify(m[1]);
3535                 }
3536                 m = ua.match(/Version\/([^\s]*)/);
3537                 if (m && m[1]) {
3538                     o.opera = numberify(m[1]); // opera 10+
3539                 }
3541                 if (/Opera Mobi/.test(ua)) {
3542                     o.mobile = 'opera';
3543                     m = ua.replace('Opera Mobi', '').match(/Opera ([^\s]*)/);
3544                     if (m && m[1]) {
3545                         o.opera = numberify(m[1]);
3546                     }
3547                 }
3548                 m = ua.match(/Opera Mini[^;]*/);
3550                 if (m) {
3551                     o.mobile = m[0]; // ex: Opera Mini/2.0.4509/1316
3552                 }
3553             } else { // not opera or webkit
3554                 m = ua.match(/MSIE\s([^;]*)/);
3555                 if (m && m[1]) {
3556                     o.ie = numberify(m[1]);
3557                 } else { // not opera, webkit, or ie
3558                     m = ua.match(/Gecko\/([^\s]*)/);
3559                     if (m) {
3560                         o.gecko = 1; // Gecko detected, look for revision
3561                         m = ua.match(/rv:([^\s\)]*)/);
3562                         if (m && m[1]) {
3563                             o.gecko = numberify(m[1]);
3564                         }
3565                     }
3566                 }
3567             }
3568         }
3569     }
3571     //It was a parsed UA, do not assign the global value.
3572     if (!subUA) {
3574         if (typeof process == 'object') {
3576             if (process.versions && process.versions.node) {
3577                 //NodeJS
3578                 o.os = process.platform;
3579                 o.nodejs = process.versions.node;
3580             }
3581         }
3583         YUI.Env.UA = o;
3585     }
3587     return o;
3591 Y.UA = YUI.Env.UA || YUI.Env.parseUA();
3594 Performs a simple comparison between two version numbers, accounting for
3595 standard versioning logic such as the fact that "535.8" is a lower version than
3596 "535.24", even though a simple numerical comparison would indicate that it's
3597 greater. Also accounts for cases such as "1.1" vs. "1.1.0", which are
3598 considered equivalent.
3600 Returns -1 if version _a_ is lower than version _b_, 0 if they're equivalent,
3601 1 if _a_ is higher than _b_.
3603 Versions may be numbers or strings containing numbers and dots. For example,
3604 both `535` and `"535.8.10"` are acceptable. A version string containing
3605 non-numeric characters, like `"535.8.beta"`, may produce unexpected results.
3607 @method compareVersions
3608 @param {Number|String} a First version number to compare.
3609 @param {Number|String} b Second version number to compare.
3610 @return -1 if _a_ is lower than _b_, 0 if they're equivalent, 1 if _a_ is
3611     higher than _b_.
3613 Y.UA.compareVersions = function (a, b) {
3614     var aPart, aParts, bPart, bParts, i, len;
3616     if (a === b) {
3617         return 0;
3618     }
3620     aParts = (a + '').split('.');
3621     bParts = (b + '').split('.');
3623     for (i = 0, len = Math.max(aParts.length, bParts.length); i < len; ++i) {
3624         aPart = parseInt(aParts[i], 10);
3625         bPart = parseInt(bParts[i], 10);
3627         isNaN(aPart) && (aPart = 0);
3628         isNaN(bPart) && (bPart = 0);
3630         if (aPart < bPart) {
3631             return -1;
3632         }
3634         if (aPart > bPart) {
3635             return 1;
3636         }
3637     }
3639     return 0;
3641 YUI.Env.aliases = {
3642     "anim": ["anim-base","anim-color","anim-curve","anim-easing","anim-node-plugin","anim-scroll","anim-xy"],
3643     "app": ["app-base","app-transitions","model","model-list","router","view"],
3644     "attribute": ["attribute-base","attribute-complex"],
3645     "autocomplete": ["autocomplete-base","autocomplete-sources","autocomplete-list","autocomplete-plugin"],
3646     "base": ["base-base","base-pluginhost","base-build"],
3647     "cache": ["cache-base","cache-offline","cache-plugin"],
3648     "collection": ["array-extras","arraylist","arraylist-add","arraylist-filter","array-invoke"],
3649     "controller": ["router"],
3650     "dataschema": ["dataschema-base","dataschema-json","dataschema-xml","dataschema-array","dataschema-text"],
3651     "datasource": ["datasource-local","datasource-io","datasource-get","datasource-function","datasource-cache","datasource-jsonschema","datasource-xmlschema","datasource-arrayschema","datasource-textschema","datasource-polling"],
3652     "datatable": ["datatable-core","datatable-head","datatable-body","datatable-base","datatable-column-widths","datatable-message","datatable-mutable","datatable-sort","datatable-datasource"],
3653     "datatable-deprecated": ["datatable-base-deprecated","datatable-datasource-deprecated","datatable-sort-deprecated","datatable-scroll-deprecated"],
3654     "datatype": ["datatype-number","datatype-date","datatype-xml"],
3655     "datatype-date": ["datatype-date-parse","datatype-date-format"],
3656     "datatype-number": ["datatype-number-parse","datatype-number-format"],
3657     "datatype-xml": ["datatype-xml-parse","datatype-xml-format"],
3658     "dd": ["dd-ddm-base","dd-ddm","dd-ddm-drop","dd-drag","dd-proxy","dd-constrain","dd-drop","dd-scroll","dd-delegate"],
3659     "dom": ["dom-base","dom-screen","dom-style","selector-native","selector"],
3660     "editor": ["frame","editor-selection","exec-command","editor-base","editor-para","editor-br","editor-bidi","editor-tab","createlink-base"],
3661     "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"],
3662     "event-custom": ["event-custom-base","event-custom-complex"],
3663     "event-gestures": ["event-flick","event-move"],
3664     "handlebars": ["handlebars-compiler"],
3665     "highlight": ["highlight-base","highlight-accentfold"],
3666     "history": ["history-base","history-hash","history-hash-ie","history-html5"],
3667     "io": ["io-base","io-xdr","io-form","io-upload-iframe","io-queue"],
3668     "json": ["json-parse","json-stringify"],
3669     "loader": ["loader-base","loader-rollup","loader-yui3"],
3670     "node": ["node-base","node-event-delegate","node-pluginhost","node-screen","node-style"],
3671     "pluginhost": ["pluginhost-base","pluginhost-config"],
3672     "querystring": ["querystring-parse","querystring-stringify"],
3673     "recordset": ["recordset-base","recordset-sort","recordset-filter","recordset-indexer"],
3674     "resize": ["resize-base","resize-proxy","resize-constrain"],
3675     "slider": ["slider-base","slider-value-range","clickable-rail","range-slider"],
3676     "text": ["text-accentfold","text-wordbreak"],
3677     "widget": ["widget-base","widget-htmlparser","widget-skin","widget-uievents"]
3681 }, '3.5.1' );