]> CyberLeo.Net >> Repos - Github/sugarcrm.git/blob - jssource/src_files/include/javascript/yui3/build/yui/yui-base.js
Release 6.5.0
[Github/sugarcrm.git] / jssource / src_files / include / javascript / yui3 / build / yui / yui-base.js
1 /*
2 Copyright (c) 2010, Yahoo! Inc. All rights reserved.
3 Code licensed under the BSD License:
4 http://developer.yahoo.com/yui/license.html
5 version: 3.3.0
6 build: 3167
7 */
8 /**
9  * The YUI module contains the components required for building the YUI seed
10  * file.  This includes the script loading mechanism, a simple queue, and
11  * the core utilities for the library.
12  * @module yui
13  * @submodule yui-base
14  */
15
16 if (typeof YUI != 'undefined') {
17     YUI._YUI = YUI;
18 }
19
20 /**
21  * The YUI global namespace object.  If YUI is already defined, the
22  * existing YUI object will not be overwritten so that defined
23  * namespaces are preserved.  It is the constructor for the object
24  * the end user interacts with.  As indicated below, each instance
25  * has full custom event support, but only if the event system
26  * is available.  This is a self-instantiable factory function.  You
27  * can invoke it directly like this:
28  *
29  * YUI().use('*', function(Y) {
30  *   // ready
31  * });
32  *
33  * But it also works like this:
34  *
35  * var Y = YUI();
36  *
37  * @class YUI
38  * @constructor
39  * @global
40  * @uses EventTarget
41  * @param o* {object} 0..n optional configuration objects.  these values
42  * are store in Y.config.  See config for the list of supported
43  * properties.
44  */
45     /*global YUI*/
46     /*global YUI_config*/
47     var YUI = function() {
48         var i = 0,
49             Y = this,
50             args = arguments,
51             l = args.length,
52             instanceOf = function(o, type) {
53                 return (o && o.hasOwnProperty && (o instanceof type));
54             },
55             gconf = (typeof YUI_config !== 'undefined') && YUI_config;
56
57         if (!(instanceOf(Y, YUI))) {
58             Y = new YUI();
59         } else {
60             // set up the core environment
61             Y._init();
62
63             // YUI.GlobalConfig is a master configuration that might span
64             // multiple contexts in a non-browser environment.  It is applied
65             // first to all instances in all contexts.
66             if (YUI.GlobalConfig) {
67                 Y.applyConfig(YUI.GlobalConfig);
68             }
69
70             // YUI_Config is a page-level config.  It is applied to all
71             // instances created on the page.  This is applied after
72             // YUI.GlobalConfig, and before the instance level configuration
73             // objects.
74             if (gconf) {
75                 Y.applyConfig(gconf);
76             }
77
78             // bind the specified additional modules for this instance
79             if (!l) {
80                 Y._setup();
81             }
82         }
83
84         if (l) {
85             // Each instance can accept one or more configuration objects.
86             // These are applied after YUI.GlobalConfig and YUI_Config,
87             // overriding values set in those config files if there is a '
88             // matching property.
89             for (; i < l; i++) {
90                 Y.applyConfig(args[i]);
91             }
92
93             Y._setup();
94         }
95
96         Y.instanceOf = instanceOf;
97
98         return Y;
99     };
100
101 (function() {
102
103     var proto, prop,
104         VERSION = '3.3.0',
105         PERIOD = '.',
106         BASE = 'http://yui.yahooapis.com/',
107         DOC_LABEL = 'yui3-js-enabled',
108         NOOP = function() {},
109         SLICE = Array.prototype.slice,
110         APPLY_TO_AUTH = { 'io.xdrReady': 1,   // the functions applyTo
111                           'io.xdrResponse': 1,   // can call. this should
112                           'SWF.eventHandler': 1 }, // be done at build time
113         hasWin = (typeof window != 'undefined'),
114         win = (hasWin) ? window : null,
115         doc = (hasWin) ? win.document : null,
116         docEl = doc && doc.documentElement,
117         docClass = docEl && docEl.className,
118         instances = {},
119         time = new Date().getTime(),
120         add = function(el, type, fn, capture) {
121             if (el && el.addEventListener) {
122                 el.addEventListener(type, fn, capture);
123             } else if (el && el.attachEvent) {
124                 el.attachEvent('on' + type, fn);
125             }
126         },
127         remove = function(el, type, fn, capture) {
128             if (el && el.removeEventListener) {
129                 // this can throw an uncaught exception in FF
130                 try {
131                     el.removeEventListener(type, fn, capture);
132                 } catch (ex) {}
133             } else if (el && el.detachEvent) {
134                 el.detachEvent('on' + type, fn);
135             }
136         },
137         handleLoad = function() {
138             YUI.Env.windowLoaded = true;
139             YUI.Env.DOMReady = true;
140             if (hasWin) {
141                 remove(window, 'load', handleLoad);
142             }
143         },
144         getLoader = function(Y, o) {
145             var loader = Y.Env._loader;
146             if (loader) {
147                 loader.ignoreRegistered = false;
148                 loader.onEnd = null;
149                 loader.data = null;
150                 loader.required = [];
151                 loader.loadType = null;
152             } else {
153                 loader = new Y.Loader(Y.config);
154                 Y.Env._loader = loader;
155             }
156
157             return loader;
158         },
159
160         clobber = function(r, s) {
161             for (var i in s) {
162                 if (s.hasOwnProperty(i)) {
163                     r[i] = s[i];
164                 }
165             }
166         },
167
168         ALREADY_DONE = { success: true };
169
170 //  Stamp the documentElement (HTML) with a class of "yui-loaded" to
171 //  enable styles that need to key off of JS being enabled.
172 if (docEl && docClass.indexOf(DOC_LABEL) == -1) {
173     if (docClass) {
174         docClass += ' ';
175     }
176     docClass += DOC_LABEL;
177     docEl.className = docClass;
178 }
179
180 if (VERSION.indexOf('@') > -1) {
181     VERSION = '3.2.0'; // dev time hack for cdn test
182 }
183
184 proto = {
185     /**
186      * Applies a new configuration object to the YUI instance config.
187      * This will merge new group/module definitions, and will also
188      * update the loader cache if necessary.  Updating Y.config directly
189      * will not update the cache.
190      * @method applyConfig
191      * @param {object} the configuration object.
192      * @since 3.2.0
193      */
194     applyConfig: function(o) {
195
196         o = o || NOOP;
197
198         var attr,
199             name,
200             // detail,
201             config = this.config,
202             mods = config.modules,
203             groups = config.groups,
204             rls = config.rls,
205             loader = this.Env._loader;
206
207         for (name in o) {
208             if (o.hasOwnProperty(name)) {
209                 attr = o[name];
210                 if (mods && name == 'modules') {
211                     clobber(mods, attr);
212                 } else if (groups && name == 'groups') {
213                     clobber(groups, attr);
214                 } else if (rls && name == 'rls') {
215                     clobber(rls, attr);
216                 } else if (name == 'win') {
217                     config[name] = attr.contentWindow || attr;
218                     config.doc = config[name].document;
219                 } else if (name == '_yuid') {
220                     // preserve the guid
221                 } else {
222                     config[name] = attr;
223                 }
224             }
225         }
226
227         if (loader) {
228             loader._config(o);
229         }
230     },
231
232     _config: function(o) {
233         this.applyConfig(o);
234     },
235
236     /**
237      * Initialize this YUI instance
238      * @private
239      */
240     _init: function() {
241         var filter,
242             Y = this,
243             G_ENV = YUI.Env,
244             Env = Y.Env,
245             prop;
246
247         /**
248          * The version number of the YUI instance.
249          * @property version
250          * @type string
251          */
252         Y.version = VERSION;
253
254         if (!Env) {
255             Y.Env = {
256                 mods: {}, // flat module map
257                 versions: {}, // version module map
258                 base: BASE,
259                 cdn: BASE + VERSION + '/build/',
260                 // bootstrapped: false,
261                 _idx: 0,
262                 _used: {},
263                 _attached: {},
264                 _yidx: 0,
265                 _uidx: 0,
266                 _guidp: 'y',
267                 _loaded: {},
268                 serviced: {},
269                 getBase: G_ENV && G_ENV.getBase ||
270
271     function(srcPattern, comboPattern) {
272         var b, nodes, i, src, match;
273         // get from querystring
274         nodes = (doc && doc.getElementsByTagName('script')) || [];
275         for (i = 0; i < nodes.length; i = i + 1) {
276             src = nodes[i].src;
277             if (src) {
278
279                 match = src.match(srcPattern);
280                 b = match && match[1];
281                 if (b) {
282                     // this is to set up the path to the loader.  The file
283                     // filter for loader should match the yui include.
284                     filter = match[2];
285
286                     if (filter) {
287                         match = filter.indexOf('js');
288
289                         if (match > -1) {
290                             filter = filter.substr(0, match);
291                         }
292                     }
293
294                     // extract correct path for mixed combo urls
295                     // http://yuilibrary.com/projects/yui3/ticket/2528423
296                     match = src.match(comboPattern);
297                     if (match && match[3]) {
298                         b = match[1] + match[3];
299                     }
300
301                     break;
302                 }
303             }
304         }
305
306         // use CDN default
307         return b || Env.cdn;
308     }
309             };
310
311             Env = Y.Env;
312
313             Env._loaded[VERSION] = {};
314
315             if (G_ENV && Y !== YUI) {
316                 Env._yidx = ++G_ENV._yidx;
317                 Env._guidp = ('yui_' + VERSION + '_' +
318                              Env._yidx + '_' + time).replace(/\./g, '_');
319             } else if (YUI._YUI) {
320
321                 G_ENV = YUI._YUI.Env;
322                 Env._yidx += G_ENV._yidx;
323                 Env._uidx += G_ENV._uidx;
324
325                 for (prop in G_ENV) {
326                     if (!(prop in Env)) {
327                         Env[prop] = G_ENV[prop];
328                     }
329                 }
330
331                 delete YUI._YUI;
332             }
333
334             Y.id = Y.stamp(Y);
335             instances[Y.id] = Y;
336
337         }
338
339         Y.constructor = YUI;
340
341         // configuration defaults
342         Y.config = Y.config || {
343             win: win,
344             doc: doc,
345             debug: true,
346             useBrowserConsole: true,
347             throwFail: true,
348             bootstrap: true,
349             cacheUse: true,
350             fetchCSS: true
351         };
352
353         Y.config.base = YUI.config.base ||
354             Y.Env.getBase(/^(.*)yui\/yui([\.\-].*)js(\?.*)?$/,
355                           /^(.*\?)(.*\&)(.*)yui\/yui[\.\-].*js(\?.*)?$/);
356
357         if (!filter || (!('-min.-debug.').indexOf(filter))) {
358             filter = '-min.';
359         }
360
361         Y.config.loaderPath = YUI.config.loaderPath ||
362             'loader/loader' + (filter || '-min.') + 'js';
363
364     },
365
366     /**
367      * Finishes the instance setup. Attaches whatever modules were defined
368      * when the yui modules was registered.
369      * @method _setup
370      * @private
371      */
372     _setup: function(o) {
373         var i, Y = this,
374             core = [],
375             mods = YUI.Env.mods,
376             extras = Y.config.core || ['get',
377                                         'rls',
378                                         'intl-base',
379                                         'loader',
380                                         'yui-log',
381                                         'yui-later',
382                                         'yui-throttle'];
383
384         for (i = 0; i < extras.length; i++) {
385             if (mods[extras[i]]) {
386                 core.push(extras[i]);
387             }
388         }
389
390         Y._attach(['yui-base']);
391         Y._attach(core);
392
393     },
394
395     /**
396      * Executes a method on a YUI instance with
397      * the specified id if the specified method is whitelisted.
398      * @method applyTo
399      * @param id {string} the YUI instance id.
400      * @param method {string} the name of the method to exectute.
401      * Ex: 'Object.keys'.
402      * @param args {Array} the arguments to apply to the method.
403      * @return {object} the return value from the applied method or null.
404      */
405     applyTo: function(id, method, args) {
406         if (!(method in APPLY_TO_AUTH)) {
407             this.log(method + ': applyTo not allowed', 'warn', 'yui');
408             return null;
409         }
410
411         var instance = instances[id], nest, m, i;
412         if (instance) {
413             nest = method.split('.');
414             m = instance;
415             for (i = 0; i < nest.length; i = i + 1) {
416                 m = m[nest[i]];
417                 if (!m) {
418                     this.log('applyTo not found: ' + method, 'warn', 'yui');
419                 }
420             }
421             return m.apply(instance, args);
422         }
423
424         return null;
425     },
426
427     /**
428      * Registers a module with the YUI global.  The easiest way to create a
429      * first-class YUI module is to use the YUI component build tool.
430      *
431      * http://yuilibrary.com/projects/builder
432      *
433      * The build system will produce the YUI.add wrapper for you module, along
434      * with any configuration info required for the module.
435      * @method add
436      * @param name {string} module name.
437      * @param fn {Function} entry point into the module that
438      * is used to bind module to the YUI instance.
439      * @param version {string} version string.
440      * @param details {object} optional config data:
441      * requires: features that must be present before this module can be
442      * attached.
443      * optional: optional features that should be present if loadOptional
444      * is defined.  Note: modules are not often loaded this way in YUI 3,
445      * but this field is still useful to inform the user that certain
446      * features in the component will require additional dependencies.
447      * use: features that are included within this module which need to
448      * be attached automatically when this module is attached.  This
449      * supports the YUI 3 rollup system -- a module with submodules
450      * defined will need to have the submodules listed in the 'use'
451      * config.  The YUI component build tool does this for you.
452      * @return {YUI} the YUI instance.
453      *
454      */
455     add: function(name, fn, version, details) {
456         details = details || {};
457         var env = YUI.Env,
458             mod = {
459                 name: name,
460                 fn: fn,
461                 version: version,
462                 details: details
463             },
464             loader,
465             i, versions = env.versions;
466
467         env.mods[name] = mod;
468         versions[version] = versions[version] || {};
469         versions[version][name] = mod;
470
471         for (i in instances) {
472             if (instances.hasOwnProperty(i)) {
473                 loader = instances[i].Env._loader;
474                 if (loader) {
475                     if (!loader.moduleInfo[name]) {
476                         loader.addModule(details, name);
477                     }
478                 }
479             }
480         }
481
482         return this;
483     },
484
485     /**
486      * Executes the function associated with each required
487      * module, binding the module to the YUI instance.
488      * @method _attach
489      * @private
490      */
491     _attach: function(r, fromLoader) {
492         var i, name, mod, details, req, use, after,
493             mods = YUI.Env.mods,
494             Y = this, j,
495             done = Y.Env._attached,
496             len = r.length, loader;
497
498
499         for (i = 0; i < len; i++) {
500             if (!done[r[i]]) {
501                 name = r[i];
502                 mod = mods[name];
503                 if (!mod) {
504                     loader = Y.Env._loader;
505
506
507                     if (!loader || !loader.moduleInfo[name]) {
508                         Y.message('NOT loaded: ' + name, 'warn', 'yui');
509                     }
510                 } else {
511                     done[name] = true;
512                     details = mod.details;
513                     req = details.requires;
514                     use = details.use;
515                     after = details.after;
516
517                     if (req) {
518                         for (j = 0; j < req.length; j++) {
519                             if (!done[req[j]]) {
520                                 if (!Y._attach(req)) {
521                                     return false;
522                                 }
523                                 break;
524                             }
525                         }
526                     }
527
528                     if (after) {
529                         for (j = 0; j < after.length; j++) {
530                             if (!done[after[j]]) {
531                                 if (!Y._attach(after)) {
532                                     return false;
533                                 }
534                                 break;
535                             }
536                         }
537                     }
538
539                     if (use) {
540                         for (j = 0; j < use.length; j++) {
541                             if (!done[use[j]]) {
542                                 if (!Y._attach(use)) {
543                                     return false;
544                                 }
545                                 break;
546                             }
547                         }
548                     }
549
550                     if (mod.fn) {
551                         try {
552                             mod.fn(Y, name);
553                         } catch (e) {
554                             Y.error('Attach error: ' + name, e, name);
555                             return false;
556                         }
557                     }
558
559                 }
560             }
561         }
562
563         return true;
564     },
565
566     /**
567      * Attaches one or more modules to the YUI instance.  When this
568      * is executed, the requirements are analyzed, and one of
569      * several things can happen:
570      *
571      * - All requirements are available on the page --  The modules
572      *   are attached to the instance.  If supplied, the use callback
573      *   is executed synchronously.
574      *
575      * - Modules are missing, the Get utility is not available OR
576      *   the 'bootstrap' config is false -- A warning is issued about
577      *   the missing modules and all available modules are attached.
578      *
579      * - Modules are missing, the Loader is not available but the Get
580      *   utility is and boostrap is not false -- The loader is bootstrapped
581      *   before doing the following....
582      *
583      * - Modules are missing and the Loader is available -- The loader
584      *   expands the dependency tree and fetches missing modules.  When
585      *   the loader is finshed the callback supplied to use is executed
586      *   asynchronously.
587      *
588      * @param modules* {string} 1-n modules to bind (uses arguments array).
589      * @param *callback {function} callback function executed when
590      * the instance has the required functionality.  If included, it
591      * must be the last parameter.
592      * <code>
593      * // loads and attaches drag and drop and its dependencies
594      * YUI().use('dd', function(Y) &#123;&#125);
595      * // attaches all modules that are available on the page
596      * YUI().use('*', function(Y) &#123;&#125);
597      * // intrinsic YUI gallery support (since 3.1.0)
598      * YUI().use('gallery-yql', function(Y) &#123;&#125);
599      * // intrinsic YUI 2in3 support (since 3.1.0)
600      * YUI().use('yui2-datatable', function(Y) &#123;&#125);.
601      * </code>
602      *
603      * @return {YUI} the YUI instance.
604      */
605     use: function() {
606         var args = SLICE.call(arguments, 0),
607             callback = args[args.length - 1],
608             Y = this,
609             key;
610
611         // The last argument supplied to use can be a load complete callback
612         if (Y.Lang.isFunction(callback)) {
613             args.pop();
614         } else {
615             callback = null;
616         }
617
618         if (Y._loading) {
619             Y._useQueue = Y._useQueue || new Y.Queue();
620             Y._useQueue.add([args, callback]);
621         } else {
622             key = args.join();
623
624             if (Y.config.cacheUse && Y.Env.serviced[key]) {
625                 Y._notify(callback, ALREADY_DONE, args);
626             } else {
627                 Y._use(args, function(Y, response) {
628                     if (Y.config.cacheUse) {
629                         Y.Env.serviced[key] = true;
630                     }
631                     Y._notify(callback, response, args);
632                 });
633             }
634         }
635
636         return Y;
637     },
638
639     _notify: function(callback, response, args) {
640         if (!response.success && this.config.loadErrorFn) {
641             this.config.loadErrorFn.call(this, this, callback, response, args);
642         } else if (callback) {
643             try {
644                 callback(this, response);
645             } catch (e) {
646                 this.error('use callback error', e, args);
647             }
648         }
649     },
650
651     _use: function(args, callback) {
652
653         if (!this.Array) {
654             this._attach(['yui-base']);
655         }
656
657         var len, loader, handleBoot,
658             Y = this,
659             G_ENV = YUI.Env,
660             mods = G_ENV.mods,
661             Env = Y.Env,
662             used = Env._used,
663             queue = G_ENV._loaderQueue,
664             firstArg = args[0],
665             YArray = Y.Array,
666             config = Y.config,
667             boot = config.bootstrap,
668             missing = [],
669             r = [],
670             ret = true,
671             fetchCSS = config.fetchCSS,
672             process = function(names, skip) {
673
674                 if (!names.length) {
675                     return;
676                 }
677
678                 YArray.each(names, function(name) {
679
680                     // add this module to full list of things to attach
681                     if (!skip) {
682                         r.push(name);
683                     }
684
685                     // only attach a module once
686                     if (used[name]) {
687                         return;
688                     }
689
690                     var m = mods[name], req, use;
691
692                     if (m) {
693                         used[name] = true;
694                         req = m.details.requires;
695                         use = m.details.use;
696                     } else {
697                         // CSS files don't register themselves, see if it has
698                         // been loaded
699                         if (!G_ENV._loaded[VERSION][name]) {
700                             missing.push(name);
701                         } else {
702                             used[name] = true; // probably css
703                         }
704                     }
705
706                     // make sure requirements are attached
707                     if (req && req.length) {
708                         process(req);
709                     }
710
711                     // make sure we grab the submodule dependencies too
712                     if (use && use.length) {
713                         process(use, 1);
714                     }
715                 });
716             },
717
718             handleLoader = function(fromLoader) {
719                 var response = fromLoader || {
720                         success: true,
721                         msg: 'not dynamic'
722                     },
723                     redo, origMissing,
724                     ret = true,
725                     data = response.data;
726
727
728                 Y._loading = false;
729
730                 if (data) {
731                     origMissing = missing;
732                     missing = [];
733                     r = [];
734                     process(data);
735                     redo = missing.length;
736                     if (redo) {
737                         if (missing.sort().join() ==
738                                 origMissing.sort().join()) {
739                             redo = false;
740                         }
741                     }
742                 }
743
744                 if (redo && data) {
745                     Y._loading = false;
746                     Y._use(args, function() {
747                         if (Y._attach(data)) {
748                             Y._notify(callback, response, data);
749                         }
750                     });
751                 } else {
752                     if (data) {
753                         ret = Y._attach(data);
754                     }
755                     if (ret) {
756                         Y._notify(callback, response, args);
757                     }
758                 }
759
760                 if (Y._useQueue && Y._useQueue.size() && !Y._loading) {
761                     Y._use.apply(Y, Y._useQueue.next());
762                 }
763
764             };
765
766
767         // YUI().use('*'); // bind everything available
768         if (firstArg === '*') {
769             ret = Y._attach(Y.Object.keys(mods));
770             if (ret) {
771                 handleLoader();
772             }
773             return Y;
774         }
775
776
777         // use loader to expand dependencies and sort the
778         // requirements if it is available.
779         if (boot && Y.Loader && args.length) {
780             loader = getLoader(Y);
781             loader.require(args);
782             loader.ignoreRegistered = true;
783             loader.calculate(null, (fetchCSS) ? null : 'js');
784             args = loader.sorted;
785         }
786
787         // process each requirement and any additional requirements
788         // the module metadata specifies
789         process(args);
790
791         len = missing.length;
792
793         if (len) {
794             missing = Y.Object.keys(YArray.hash(missing));
795             len = missing.length;
796         }
797
798         // dynamic load
799         if (boot && len && Y.Loader) {
800             Y._loading = true;
801             loader = getLoader(Y);
802             loader.onEnd = handleLoader;
803             loader.context = Y;
804             loader.data = args;
805             loader.ignoreRegistered = false;
806             loader.require(args);
807             loader.insert(null, (fetchCSS) ? null : 'js');
808             // loader.partial(missing, (fetchCSS) ? null : 'js');
809
810         } else if (len && Y.config.use_rls) {
811
812             // server side loader service
813             Y.Get.script(Y._rls(args), {
814                 onEnd: function(o) {
815                     handleLoader(o);
816                 },
817                 data: args
818             });
819
820         } else if (boot && len && Y.Get && !Env.bootstrapped) {
821
822             Y._loading = true;
823
824             handleBoot = function() {
825                 Y._loading = false;
826                 queue.running = false;
827                 Env.bootstrapped = true;
828                 if (Y._attach(['loader'])) {
829                     Y._use(args, callback);
830                 }
831             };
832
833             if (G_ENV._bootstrapping) {
834                 queue.add(handleBoot);
835             } else {
836                 G_ENV._bootstrapping = true;
837                 Y.Get.script(config.base + config.loaderPath, {
838                     onEnd: handleBoot
839                 });
840             }
841
842         } else {
843             ret = Y._attach(args);
844             if (ret) {
845                 handleLoader();
846             }
847         }
848
849         return Y;
850     },
851
852
853     /**
854      * Returns the namespace specified and creates it if it doesn't exist
855      * <pre>
856      * YUI.namespace("property.package");
857      * YUI.namespace("YAHOO.property.package");
858      * </pre>
859      * Either of the above would create YUI.property, then
860      * YUI.property.package (YAHOO is scrubbed out, this is
861      * to remain compatible with YUI2)
862      *
863      * Be careful when naming packages. Reserved words may work in some browsers
864      * and not others. For instance, the following will fail in Safari:
865      * <pre>
866      * YUI.namespace("really.long.nested.namespace");
867      * </pre>
868      * This fails because "long" is a future reserved word in ECMAScript
869      *
870      * @method namespace
871      * @param  {string*} arguments 1-n namespaces to create.
872      * @return {object}  A reference to the last namespace object created.
873      */
874     namespace: function() {
875         var a = arguments, o = this, i = 0, j, d, arg;
876         for (; i < a.length; i++) {
877             // d = ('' + a[i]).split('.');
878             arg = a[i];
879             if (arg.indexOf(PERIOD)) {
880                 d = arg.split(PERIOD);
881                 for (j = (d[0] == 'YAHOO') ? 1 : 0; j < d.length; j++) {
882                     o[d[j]] = o[d[j]] || {};
883                     o = o[d[j]];
884                 }
885             } else {
886                 o[arg] = o[arg] || {};
887             }
888         }
889         return o;
890     },
891
892     // this is replaced if the log module is included
893     log: NOOP,
894     message: NOOP,
895
896     /**
897      * Report an error.  The reporting mechanism is controled by
898      * the 'throwFail' configuration attribute.  If throwFail is
899      * not specified, the message is written to the Logger, otherwise
900      * a JS error is thrown
901      * @method error
902      * @param msg {string} the error message.
903      * @param e {Error|string} Optional JS error that was caught, or an error string.
904      * @param data Optional additional info
905      * and throwFail is specified, this error will be re-thrown.
906      * @return {YUI} this YUI instance.
907      */
908     error: function(msg, e, data) {
909
910         var Y = this, ret;
911
912         if (Y.config.errorFn) {
913             ret = Y.config.errorFn.apply(Y, arguments);
914         }
915
916         if (Y.config.throwFail && !ret) {
917             throw (e || new Error(msg));
918         } else {
919             Y.message(msg, 'error'); // don't scrub this one
920         }
921
922         return Y;
923     },
924
925     /**
926      * Generate an id that is unique among all YUI instances
927      * @method guid
928      * @param pre {string} optional guid prefix.
929      * @return {string} the guid.
930      */
931     guid: function(pre) {
932         var id = this.Env._guidp + (++this.Env._uidx);
933         return (pre) ? (pre + id) : id;
934     },
935
936     /**
937      * Returns a guid associated with an object.  If the object
938      * does not have one, a new one is created unless readOnly
939      * is specified.
940      * @method stamp
941      * @param o The object to stamp.
942      * @param readOnly {boolean} if true, a valid guid will only
943      * be returned if the object has one assigned to it.
944      * @return {string} The object's guid or null.
945      */
946     stamp: function(o, readOnly) {
947         var uid;
948         if (!o) {
949             return o;
950         }
951
952         // IE generates its own unique ID for dom nodes
953         // The uniqueID property of a document node returns a new ID
954         if (o.uniqueID && o.nodeType && o.nodeType !== 9) {
955             uid = o.uniqueID;
956         } else {
957             uid = (typeof o === 'string') ? o : o._yuid;
958         }
959
960         if (!uid) {
961             uid = this.guid();
962             if (!readOnly) {
963                 try {
964                     o._yuid = uid;
965                 } catch (e) {
966                     uid = null;
967                 }
968             }
969         }
970         return uid;
971     },
972
973     /**
974      * Destroys the YUI instance
975      * @method destroy
976      * @since 3.3.0
977      */
978     destroy: function() {
979         var Y = this;
980         if (Y.Event) {
981             Y.Event._unload();
982         }
983         delete instances[Y.id];
984         delete Y.Env;
985         delete Y.config;
986     }
987
988     /**
989      * instanceof check for objects that works around
990      * memory leak in IE when the item tested is
991      * window/document
992      * @method instanceOf
993      * @since 3.3.0
994      */
995 };
996
997
998
999     YUI.prototype = proto;
1000
1001     // inheritance utilities are not available yet
1002     for (prop in proto) {
1003         if (proto.hasOwnProperty(prop)) {
1004             YUI[prop] = proto[prop];
1005         }
1006     }
1007
1008     // set up the environment
1009     YUI._init();
1010
1011     if (hasWin) {
1012         // add a window load event at load time so we can capture
1013         // the case where it fires before dynamic loading is
1014         // complete.
1015         add(window, 'load', handleLoad);
1016     } else {
1017         handleLoad();
1018     }
1019
1020     YUI.Env.add = add;
1021     YUI.Env.remove = remove;
1022
1023     /*global exports*/
1024     // Support the CommonJS method for exporting our single global
1025     if (typeof exports == 'object') {
1026         exports.YUI = YUI;
1027     }
1028
1029 }());
1030
1031
1032 /**
1033  * The config object contains all of the configuration options for
1034  * the YUI instance.  This object is supplied by the implementer
1035  * when instantiating a YUI instance.  Some properties have default
1036  * values if they are not supplied by the implementer.  This should
1037  * not be updated directly because some values are cached.  Use
1038  * applyConfig() to update the config object on a YUI instance that
1039  * has already been configured.
1040  *
1041  * @class config
1042  * @static
1043  */
1044
1045 /**
1046  * Allows the YUI seed file to fetch the loader component and library
1047  * metadata to dynamically load additional dependencies.
1048  *
1049  * @property bootstrap
1050  * @type boolean
1051  * @default true
1052  */
1053
1054 /**
1055  * Log to the browser console if debug is on and the browser has a
1056  * supported console.
1057  *
1058  * @property useBrowserConsole
1059  * @type boolean
1060  * @default true
1061  */
1062
1063 /**
1064  * A hash of log sources that should be logged.  If specified, only
1065  * log messages from these sources will be logged.
1066  *
1067  * @property logInclude
1068  * @type object
1069  */
1070
1071 /**
1072  * A hash of log sources that should be not be logged.  If specified,
1073  * all sources are logged if not on this list.
1074  *
1075  * @property logExclude
1076  * @type object
1077  */
1078
1079 /**
1080  * Set to true if the yui seed file was dynamically loaded in
1081  * order to bootstrap components relying on the window load event
1082  * and the 'domready' custom event.
1083  *
1084  * @property injected
1085  * @type boolean
1086  * @default false
1087  */
1088
1089 /**
1090  * If throwFail is set, Y.error will generate or re-throw a JS Error.
1091  * Otherwise the failure is logged.
1092  *
1093  * @property throwFail
1094  * @type boolean
1095  * @default true
1096  */
1097
1098 /**
1099  * The window/frame that this instance should operate in.
1100  *
1101  * @property win
1102  * @type Window
1103  * @default the window hosting YUI
1104  */
1105
1106 /**
1107  * The document associated with the 'win' configuration.
1108  *
1109  * @property doc
1110  * @type Document
1111  * @default the document hosting YUI
1112  */
1113
1114 /**
1115  * A list of modules that defines the YUI core (overrides the default).
1116  *
1117  * @property core
1118  * @type string[]
1119  */
1120
1121 /**
1122  * A list of languages in order of preference. This list is matched against
1123  * the list of available languages in modules that the YUI instance uses to
1124  * determine the best possible localization of language sensitive modules.
1125  * Languages are represented using BCP 47 language tags, such as "en-GB" for
1126  * English as used in the United Kingdom, or "zh-Hans-CN" for simplified
1127  * Chinese as used in China. The list can be provided as a comma-separated
1128  * list or as an array.
1129  *
1130  * @property lang
1131  * @type string|string[]
1132  */
1133
1134 /**
1135  * The default date format
1136  * @property dateFormat
1137  * @type string
1138  * @deprecated use configuration in DataType.Date.format() instead.
1139  */
1140
1141 /**
1142  * The default locale
1143  * @property locale
1144  * @type string
1145  * @deprecated use config.lang instead.
1146  */
1147
1148 /**
1149  * The default interval when polling in milliseconds.
1150  * @property pollInterval
1151  * @type int
1152  * @default 20
1153  */
1154
1155 /**
1156  * The number of dynamic nodes to insert by default before
1157  * automatically removing them.  This applies to script nodes
1158  * because remove the node will not make the evaluated script
1159  * unavailable.  Dynamic CSS is not auto purged, because removing
1160  * a linked style sheet will also remove the style definitions.
1161  * @property purgethreshold
1162  * @type int
1163  * @default 20
1164  */
1165
1166 /**
1167  * The default interval when polling in milliseconds.
1168  * @property windowResizeDelay
1169  * @type int
1170  * @default 40
1171  */
1172
1173 /**
1174  * Base directory for dynamic loading
1175  * @property base
1176  * @type string
1177  */
1178
1179 /*
1180  * The secure base dir (not implemented)
1181  * For dynamic loading.
1182  * @property secureBase
1183  * @type string
1184  */
1185
1186 /**
1187  * The YUI combo service base dir. Ex: http://yui.yahooapis.com/combo?
1188  * For dynamic loading.
1189  * @property comboBase
1190  * @type string
1191  */
1192
1193 /**
1194  * The root path to prepend to module path for the combo service.
1195  * Ex: 3.0.0b1/build/
1196  * For dynamic loading.
1197  * @property root
1198  * @type string
1199  */
1200
1201 /**
1202  * A filter to apply to result urls.  This filter will modify the default
1203  * path for all modules.  The default path for the YUI library is the
1204  * minified version of the files (e.g., event-min.js).  The filter property
1205  * can be a predefined filter or a custom filter.  The valid predefined
1206  * filters are:
1207  * <dl>
1208  *  <dt>DEBUG</dt>
1209  *  <dd>Selects the debug versions of the library (e.g., event-debug.js).
1210  *      This option will automatically include the Logger widget</dd>
1211  *  <dt>RAW</dt>
1212  *  <dd>Selects the non-minified version of the library (e.g., event.js).</dd>
1213  * </dl>
1214  * You can also define a custom filter, which must be an object literal
1215  * containing a search expression and a replace string:
1216  * <pre>
1217  *  myFilter: &#123;
1218  *      'searchExp': "-min\\.js",
1219  *      'replaceStr': "-debug.js"
1220  *  &#125;
1221  * </pre>
1222  *
1223  * For dynamic loading.
1224  *
1225  * @property filter
1226  * @type string|object
1227  */
1228
1229 /**
1230  * The 'skin' config let's you configure application level skin
1231  * customizations.  It contains the following attributes which
1232  * can be specified to override the defaults:
1233  *
1234  *      // The default skin, which is automatically applied if not
1235  *      // overriden by a component-specific skin definition.
1236  *      // Change this in to apply a different skin globally
1237  *      defaultSkin: 'sam',
1238  *
1239  *      // This is combined with the loader base property to get
1240  *      // the default root directory for a skin.
1241  *      base: 'assets/skins/',
1242  *
1243  *      // Any component-specific overrides can be specified here,
1244  *      // making it possible to load different skins for different
1245  *      // components.  It is possible to load more than one skin
1246  *      // for a given component as well.
1247  *      overrides: {
1248  *          slider: ['capsule', 'round']
1249  *      }
1250  *
1251  * For dynamic loading.
1252  *
1253  *  @property skin
1254  */
1255
1256 /**
1257  * Hash of per-component filter specification.  If specified for a given
1258  * component, this overrides the filter config.
1259  *
1260  * For dynamic loading.
1261  *
1262  * @property filters
1263  */
1264
1265 /**
1266  * Use the YUI combo service to reduce the number of http connections
1267  * required to load your dependencies.  Turning this off will
1268  * disable combo handling for YUI and all module groups configured
1269  * with a combo service.
1270  *
1271  * For dynamic loading.
1272  *
1273  * @property combine
1274  * @type boolean
1275  * @default true if 'base' is not supplied, false if it is.
1276  */
1277
1278 /**
1279  * A list of modules that should never be dynamically loaded
1280  *
1281  * @property ignore
1282  * @type string[]
1283  */
1284
1285 /**
1286  * A list of modules that should always be loaded when required, even if already
1287  * present on the page.
1288  *
1289  * @property force
1290  * @type string[]
1291  */
1292
1293 /**
1294  * Node or id for a node that should be used as the insertion point for new
1295  * nodes.  For dynamic loading.
1296  *
1297  * @property insertBefore
1298  * @type string
1299  */
1300
1301 /**
1302  * Object literal containing attributes to add to dynamically loaded script
1303  * nodes.
1304  * @property jsAttributes
1305  * @type string
1306  */
1307
1308 /**
1309  * Object literal containing attributes to add to dynamically loaded link
1310  * nodes.
1311  * @property cssAttributes
1312  * @type string
1313  */
1314
1315 /**
1316  * Number of milliseconds before a timeout occurs when dynamically
1317  * loading nodes. If not set, there is no timeout.
1318  * @property timeout
1319  * @type int
1320  */
1321
1322 /**
1323  * Callback for the 'CSSComplete' event.  When dynamically loading YUI
1324  * components with CSS, this property fires when the CSS is finished
1325  * loading but script loading is still ongoing.  This provides an
1326  * opportunity to enhance the presentation of a loading page a little
1327  * bit before the entire loading process is done.
1328  *
1329  * @property onCSS
1330  * @type function
1331  */
1332
1333 /**
1334  * A hash of module definitions to add to the list of YUI components.
1335  * These components can then be dynamically loaded side by side with
1336  * YUI via the use() method. This is a hash, the key is the module
1337  * name, and the value is an object literal specifying the metdata
1338  * for the module.  * See Loader.addModule for the supported module
1339  * metadata fields.  Also @see groups, which provides a way to
1340  * configure the base and combo spec for a set of modules.
1341  * <code>
1342  * modules: {
1343  * &nbsp; mymod1: {
1344  * &nbsp;   requires: ['node'],
1345  * &nbsp;   fullpath: 'http://myserver.mydomain.com/mymod1/mymod1.js'
1346  * &nbsp; },
1347  * &nbsp; mymod2: {
1348  * &nbsp;   requires: ['mymod1'],
1349  * &nbsp;   fullpath: 'http://myserver.mydomain.com/mymod2/mymod2.js'
1350  * &nbsp; }
1351  * }
1352  * </code>
1353  *
1354  * @property modules
1355  * @type object
1356  */
1357
1358 /**
1359  * A hash of module group definitions.  It for each group you
1360  * can specify a list of modules and the base path and
1361  * combo spec to use when dynamically loading the modules.  @see
1362  * @see modules for the details about the modules part of the
1363  * group definition.
1364  * <code>
1365  * &nbsp; groups: {
1366  * &nbsp;     yui2: {
1367  * &nbsp;         // specify whether or not this group has a combo service
1368  * &nbsp;         combine: true,
1369  * &nbsp;
1370  * &nbsp;         // the base path for non-combo paths
1371  * &nbsp;         base: 'http://yui.yahooapis.com/2.8.0r4/build/',
1372  * &nbsp;
1373  * &nbsp;         // the path to the combo service
1374  * &nbsp;         comboBase: 'http://yui.yahooapis.com/combo?',
1375  * &nbsp;
1376  * &nbsp;         // a fragment to prepend to the path attribute when
1377  * &nbsp;         // when building combo urls
1378  * &nbsp;         root: '2.8.0r4/build/',
1379  * &nbsp;
1380  * &nbsp;         // the module definitions
1381  * &nbsp;         modules:  {
1382  * &nbsp;             yui2_yde: {
1383  * &nbsp;                 path: "yahoo-dom-event/yahoo-dom-event.js"
1384  * &nbsp;             },
1385  * &nbsp;             yui2_anim: {
1386  * &nbsp;                 path: "animation/animation.js",
1387  * &nbsp;                 requires: ['yui2_yde']
1388  * &nbsp;             }
1389  * &nbsp;         }
1390  * &nbsp;     }
1391  * &nbsp; }
1392  * </code>
1393  * @property modules
1394  * @type object
1395  */
1396
1397 /**
1398  * The loader 'path' attribute to the loader itself.  This is combined
1399  * with the 'base' attribute to dynamically load the loader component
1400  * when boostrapping with the get utility alone.
1401  *
1402  * @property loaderPath
1403  * @type string
1404  * @default loader/loader-min.js
1405  */
1406
1407 /**
1408  * Specifies whether or not YUI().use(...) will attempt to load CSS
1409  * resources at all.  Any truthy value will cause CSS dependencies
1410  * to load when fetching script.  The special value 'force' will
1411  * cause CSS dependencies to be loaded even if no script is needed.
1412  *
1413  * @property fetchCSS
1414  * @type boolean|string
1415  * @default true
1416  */
1417
1418 /**
1419  * The default gallery version to build gallery module urls
1420  * @property gallery
1421  * @type string
1422  * @since 3.1.0
1423  */
1424
1425 /**
1426  * The default YUI 2 version to build yui2 module urls.  This is for
1427  * intrinsic YUI 2 support via the 2in3 project.  Also @see the '2in3'
1428  * config for pulling different revisions of the wrapped YUI 2
1429  * modules.
1430  * @since 3.1.0
1431  * @property yui2
1432  * @type string
1433  * @default 2.8.1
1434  */
1435
1436 /**
1437  * The 2in3 project is a deployment of the various versions of YUI 2
1438  * deployed as first-class YUI 3 modules.  Eventually, the wrapper
1439  * for the modules will change (but the underlying YUI 2 code will
1440  * be the same), and you can select a particular version of
1441  * the wrapper modules via this config.
1442  * @since 3.1.0
1443  * @property 2in3
1444  * @type string
1445  * @default 1
1446  */
1447
1448 /**
1449  * Alternative console log function for use in environments without
1450  * a supported native console.  The function is executed in the
1451  * YUI instance context.
1452  * @since 3.1.0
1453  * @property logFn
1454  * @type Function
1455  */
1456
1457 /**
1458  * A callback to execute when Y.error is called.  It receives the
1459  * error message and an javascript error object if Y.error was
1460  * executed because a javascript error was caught.  The function
1461  * is executed in the YUI instance context.
1462  *
1463  * @since 3.2.0
1464  * @property errorFn
1465  * @type Function
1466  */
1467
1468 /**
1469  * A callback to execute when the loader fails to load one or
1470  * more resource.  This could be because of a script load
1471  * failure.  It can also fail if a javascript module fails
1472  * to register itself, but only when the 'requireRegistration'
1473  * is true.  If this function is defined, the use() callback will
1474  * only be called when the loader succeeds, otherwise it always
1475  * executes unless there was a javascript error when attaching
1476  * a module.
1477  *
1478  * @since 3.3.0
1479  * @property loadErrorFn
1480  * @type Function
1481  */
1482
1483 /**
1484  * When set to true, the YUI loader will expect that all modules
1485  * it is responsible for loading will be first-class YUI modules
1486  * that register themselves with the YUI global.  If this is
1487  * set to true, loader will fail if the module registration fails
1488  * to happen after the script is loaded.
1489  *
1490  * @since 3.3.0
1491  * @property requireRegistration
1492  * @type boolean
1493  * @default false
1494  */
1495
1496 /**
1497  * Cache serviced use() requests.
1498  * @since 3.3.0
1499  * @property cacheUse
1500  * @type boolean
1501  * @default true
1502  */
1503
1504 /**
1505  * The parameter defaults for the remote loader service.
1506  * Requires the rls submodule.  The properties that are
1507  * supported:
1508  * <pre>
1509  * m: comma separated list of module requirements.  This
1510  *    must be the param name even for custom implemetations.
1511  * v: the version of YUI to load.  Defaults to the version
1512  *    of YUI that is being used.
1513  * gv: the version of the gallery to load (@see the gallery config)
1514  * env: comma separated list of modules already on the page.
1515  *      this must be the param name even for custom implemetations.
1516  * lang: the languages supported on the page (@see the lang config)
1517  * '2in3v':  the version of the 2in3 wrapper to use (@see the 2in3 config).
1518  * '2v': the version of yui2 to use in the yui 2in3 wrappers
1519  *       (@see the yui2 config)
1520  * filt: a filter def to apply to the urls (@see the filter config).
1521  * filts: a list of custom filters to apply per module
1522  *        (@see the filters config).
1523  * tests: this is a map of conditional module test function id keys
1524  * with the values of 1 if the test passes, 0 if not.  This must be
1525  * the name of the querystring param in custom templates.
1526  *</pre>
1527  *
1528  * @since 3.2.0
1529  * @property rls
1530  */
1531
1532 /**
1533  * The base path to the remote loader service
1534  *
1535  * @since 3.2.0
1536  * @property rls_base
1537  */
1538
1539 /**
1540  * The template to use for building the querystring portion
1541  * of the remote loader service url.  The default is determined
1542  * by the rls config -- each property that has a value will be
1543  * represented.
1544  *
1545  * ex: m={m}&v={v}&env={env}&lang={lang}&filt={filt}&tests={tests}
1546  *
1547  *
1548  * @since 3.2.0
1549  * @property rls_tmpl
1550  */
1551
1552 /**
1553  * Configure the instance to use a remote loader service instead of
1554  * the client loader.
1555  *
1556  * @since 3.2.0
1557  * @property use_rls
1558  */
1559 YUI.add('yui-base', function(Y) {
1560
1561 /*
1562  * YUI stub
1563  * @module yui
1564  * @submodule yui-base
1565  */
1566 /**
1567  * The YUI module contains the components required for building the YUI
1568  * seed file.  This includes the script loading mechanism, a simple queue,
1569  * and the core utilities for the library.
1570  * @module yui
1571  * @submodule yui-base
1572  */
1573
1574 /**
1575  * Provides the language utilites and extensions used by the library
1576  * @class Lang
1577  * @static
1578  */
1579 Y.Lang = Y.Lang || {};
1580
1581 var L = Y.Lang,
1582
1583 ARRAY = 'array',
1584 BOOLEAN = 'boolean',
1585 DATE = 'date',
1586 ERROR = 'error',
1587 FUNCTION = 'function',
1588 NUMBER = 'number',
1589 NULL = 'null',
1590 OBJECT = 'object',
1591 REGEX = 'regexp',
1592 STRING = 'string',
1593 STRING_PROTO = String.prototype,
1594 TOSTRING = Object.prototype.toString,
1595 UNDEFINED = 'undefined',
1596
1597 TYPES = {
1598     'undefined' : UNDEFINED,
1599     'number' : NUMBER,
1600     'boolean' : BOOLEAN,
1601     'string' : STRING,
1602     '[object Function]' : FUNCTION,
1603     '[object RegExp]' : REGEX,
1604     '[object Array]' : ARRAY,
1605     '[object Date]' : DATE,
1606     '[object Error]' : ERROR
1607 },
1608
1609 TRIMREGEX = /^\s+|\s+$/g,
1610 EMPTYSTRING = '',
1611 SUBREGEX = /\{\s*([^\|\}]+?)\s*(?:\|([^\}]*))?\s*\}/g;
1612
1613 /**
1614  * Determines whether or not the provided item is an array.
1615  * Returns false for array-like collections such as the
1616  * function arguments collection or HTMLElement collection
1617  * will return false.  Use <code>Y.Array.test</code> if you
1618  * want to test for an array-like collection.
1619  * @method isArray
1620  * @static
1621  * @param o The object to test.
1622  * @return {boolean} true if o is an array.
1623  */
1624 // L.isArray = Array.isArray || function(o) {
1625 //     return L.type(o) === ARRAY;
1626 // };
1627
1628 L.isArray = function(o) {
1629     return L.type(o) === ARRAY;
1630 };
1631
1632 /**
1633  * Determines whether or not the provided item is a boolean.
1634  * @method isBoolean
1635  * @static
1636  * @param o The object to test.
1637  * @return {boolean} true if o is a boolean.
1638  */
1639 L.isBoolean = function(o) {
1640     return typeof o === BOOLEAN;
1641 };
1642
1643 /**
1644  * <p>
1645  * Determines whether or not the provided item is a function.
1646  * Note: Internet Explorer thinks certain functions are objects:
1647  * </p>
1648  *
1649  * <pre>
1650  * var obj = document.createElement("object");
1651  * Y.Lang.isFunction(obj.getAttribute) // reports false in IE
1652  * &nbsp;
1653  * var input = document.createElement("input"); // append to body
1654  * Y.Lang.isFunction(input.focus) // reports false in IE
1655  * </pre>
1656  *
1657  * <p>
1658  * You will have to implement additional tests if these functions
1659  * matter to you.
1660  * </p>
1661  *
1662  * @method isFunction
1663  * @static
1664  * @param o The object to test.
1665  * @return {boolean} true if o is a function.
1666  */
1667 L.isFunction = function(o) {
1668     return L.type(o) === FUNCTION;
1669 };
1670
1671 /**
1672  * Determines whether or not the supplied item is a date instance.
1673  * @method isDate
1674  * @static
1675  * @param o The object to test.
1676  * @return {boolean} true if o is a date.
1677  */
1678 L.isDate = function(o) {
1679     // return o instanceof Date;
1680     return L.type(o) === DATE && o.toString() !== 'Invalid Date' && !isNaN(o);
1681 };
1682
1683 /**
1684  * Determines whether or not the provided item is null.
1685  * @method isNull
1686  * @static
1687  * @param o The object to test.
1688  * @return {boolean} true if o is null.
1689  */
1690 L.isNull = function(o) {
1691     return o === null;
1692 };
1693
1694 /**
1695  * Determines whether or not the provided item is a legal number.
1696  * @method isNumber
1697  * @static
1698  * @param o The object to test.
1699  * @return {boolean} true if o is a number.
1700  */
1701 L.isNumber = function(o) {
1702     return typeof o === NUMBER && isFinite(o);
1703 };
1704
1705 /**
1706  * Determines whether or not the provided item is of type object
1707  * or function. Note that arrays are also objects, so
1708  * <code>Y.Lang.isObject([]) === true</code>.
1709  * @method isObject
1710  * @static
1711  * @param o The object to test.
1712  * @param failfn {boolean} fail if the input is a function.
1713  * @return {boolean} true if o is an object.
1714  */
1715 L.isObject = function(o, failfn) {
1716     var t = typeof o;
1717     return (o && (t === OBJECT ||
1718         (!failfn && (t === FUNCTION || L.isFunction(o))))) || false;
1719 };
1720
1721 /**
1722  * Determines whether or not the provided item is a string.
1723  * @method isString
1724  * @static
1725  * @param o The object to test.
1726  * @return {boolean} true if o is a string.
1727  */
1728 L.isString = function(o) {
1729     return typeof o === STRING;
1730 };
1731
1732 /**
1733  * Determines whether or not the provided item is undefined.
1734  * @method isUndefined
1735  * @static
1736  * @param o The object to test.
1737  * @return {boolean} true if o is undefined.
1738  */
1739 L.isUndefined = function(o) {
1740     return typeof o === UNDEFINED;
1741 };
1742
1743 /**
1744  * Returns a string without any leading or trailing whitespace.  If
1745  * the input is not a string, the input will be returned untouched.
1746  * @method trim
1747  * @static
1748  * @param s {string} the string to trim.
1749  * @return {string} the trimmed string.
1750  */
1751 L.trim = STRING_PROTO.trim ? function(s) {
1752     return (s && s.trim) ? s.trim() : s;
1753 } : function (s) {
1754     try {
1755         return s.replace(TRIMREGEX, EMPTYSTRING);
1756     } catch (e) {
1757         return s;
1758     }
1759 };
1760
1761 /**
1762  * Returns a string without any leading whitespace.
1763  * @method trimLeft
1764  * @static
1765  * @param s {string} the string to trim.
1766  * @return {string} the trimmed string.
1767  */
1768 L.trimLeft = STRING_PROTO.trimLeft ? function (s) {
1769     return s.trimLeft();
1770 } : function (s) {
1771     return s.replace(/^\s+/, '');
1772 };
1773
1774 /**
1775  * Returns a string without any trailing whitespace.
1776  * @method trimRight
1777  * @static
1778  * @param s {string} the string to trim.
1779  * @return {string} the trimmed string.
1780  */
1781 L.trimRight = STRING_PROTO.trimRight ? function (s) {
1782     return s.trimRight();
1783 } : function (s) {
1784     return s.replace(/\s+$/, '');
1785 };
1786
1787 /**
1788  * A convenience method for detecting a legitimate non-null value.
1789  * Returns false for null/undefined/NaN, true for other values,
1790  * including 0/false/''
1791  * @method isValue
1792  * @static
1793  * @param o The item to test.
1794  * @return {boolean} true if it is not null/undefined/NaN || false.
1795  */
1796 L.isValue = function(o) {
1797     var t = L.type(o);
1798     switch (t) {
1799         case NUMBER:
1800             return isFinite(o);
1801         case NULL:
1802         case UNDEFINED:
1803             return false;
1804         default:
1805             return !!(t);
1806     }
1807 };
1808
1809 /**
1810  * <p>
1811  * Returns a string representing the type of the item passed in.
1812  * </p>
1813  *
1814  * <p>
1815  * Known issues:
1816  * </p>
1817  *
1818  * <ul>
1819  *   <li>
1820  *     <code>typeof HTMLElementCollection</code> returns function in Safari, but
1821  *     <code>Y.type()</code> reports object, which could be a good thing --
1822  *     but it actually caused the logic in <code>Y.Lang.isObject</code> to fail.
1823  *   </li>
1824  * </ul>
1825  *
1826  * @method type
1827  * @param o the item to test.
1828  * @return {string} the detected type.
1829  * @static
1830  */
1831 L.type = function(o) {
1832     return TYPES[typeof o] || TYPES[TOSTRING.call(o)] || (o ? OBJECT : NULL);
1833 };
1834
1835 /**
1836  * Lightweight version of <code>Y.substitute</code>. Uses the same template
1837  * structure as <code>Y.substitute</code>, but doesn't support recursion,
1838  * auto-object coersion, or formats.
1839  * @method sub
1840  * @param {string} s String to be modified.
1841  * @param {object} o Object containing replacement values.
1842  * @return {string} the substitute result.
1843  * @static
1844  * @since 3.2.0
1845  */
1846 L.sub = function(s, o) {
1847     return ((s.replace) ? s.replace(SUBREGEX, function(match, key) {
1848         return (!L.isUndefined(o[key])) ? o[key] : match;
1849     }) : s);
1850 };
1851
1852 /**
1853  * Returns the current time in milliseconds.
1854  * @method now
1855  * @return {int} the current date
1856  * @since 3.3.0
1857  */
1858 L.now = Date.now || function () {
1859   return new Date().getTime();
1860 };
1861
1862 /**
1863  * The YUI module contains the components required for building the YUI seed
1864  * file.  This includes the script loading mechanism, a simple queue, and the
1865  * core utilities for the library.
1866  * @module yui
1867  * @submodule yui-base
1868  */
1869
1870
1871 var Native = Array.prototype, LENGTH = 'length',
1872
1873 /**
1874  * Adds the following array utilities to the YUI instance.  Additional
1875  * array helpers can be found in the collection component.
1876  * @class Array
1877  */
1878
1879 /**
1880  * Y.Array(o) returns an array:
1881  * - Arrays are return unmodified unless the start position is specified.
1882  * - "Array-like" collections (@see Array.test) are converted to arrays
1883  * - For everything else, a new array is created with the input as the sole
1884  *   item.
1885  * - The start position is used if the input is or is like an array to return
1886  *   a subset of the collection.
1887  *
1888  *   @todo this will not automatically convert elements that are also
1889  *   collections such as forms and selects.  Passing true as the third
1890  *   param will force a conversion.
1891  *
1892  * @method ()
1893  * @static
1894  *   @param {object} o the item to arrayify.
1895  *   @param {int} startIdx if an array or array-like, this is the start index.
1896  *   @param {boolean} arraylike if true, it forces the array-like fork.  This
1897  *   can be used to avoid multiple Array.test calls.
1898  *   @return {Array} the resulting array.
1899  */
1900 YArray = function(o, startIdx, arraylike) {
1901     var t = (arraylike) ? 2 : YArray.test(o),
1902         l, a, start = startIdx || 0;
1903
1904     if (t) {
1905         // IE errors when trying to slice HTMLElement collections
1906         try {
1907             return Native.slice.call(o, start);
1908         } catch (e) {
1909             a = [];
1910             l = o.length;
1911             for (; start < l; start++) {
1912                 a.push(o[start]);
1913             }
1914             return a;
1915         }
1916     } else {
1917         return [o];
1918     }
1919 };
1920
1921 Y.Array = YArray;
1922
1923 /**
1924  * Evaluates the input to determine if it is an array, array-like, or
1925  * something else.  This is used to handle the arguments collection
1926  * available within functions, and HTMLElement collections
1927  *
1928  * @method test
1929  * @static
1930  *
1931  * @todo current implementation (intenionally) will not implicitly
1932  * handle html elements that are array-like (forms, selects, etc).
1933  *
1934  * @param {object} o the object to test.
1935  *
1936  * @return {int} a number indicating the results:
1937  * 0: Not an array or an array-like collection
1938  * 1: A real array.
1939  * 2: array-like collection.
1940  */
1941 YArray.test = function(o) {
1942     var r = 0;
1943     if (Y.Lang.isObject(o)) {
1944         if (Y.Lang.isArray(o)) {
1945             r = 1;
1946         } else {
1947             try {
1948                 // indexed, but no tagName (element) or alert (window),
1949                 // or functions without apply/call (Safari
1950                 // HTMLElementCollection bug).
1951                 if ((LENGTH in o) && !o.tagName && !o.alert && !o.apply) {
1952                     r = 2;
1953                 }
1954
1955             } catch (e) {}
1956         }
1957     }
1958     return r;
1959 };
1960
1961 /**
1962  * Executes the supplied function on each item in the array.
1963  * @method each
1964  * @param {Array} a the array to iterate.
1965  * @param {Function} f the function to execute on each item.  The
1966  * function receives three arguments: the value, the index, the full array.
1967  * @param {object} o Optional context object.
1968  * @static
1969  * @return {YUI} the YUI instance.
1970  */
1971 YArray.each = (Native.forEach) ?
1972     function(a, f, o) {
1973         Native.forEach.call(a || [], f, o || Y);
1974         return Y;
1975     } :
1976     function(a, f, o) {
1977         var l = (a && a.length) || 0, i;
1978         for (i = 0; i < l; i = i + 1) {
1979             f.call(o || Y, a[i], i, a);
1980         }
1981         return Y;
1982     };
1983
1984 /**
1985  * Returns an object using the first array as keys, and
1986  * the second as values.  If the second array is not
1987  * provided the value is set to true for each.
1988  * @method hash
1989  * @static
1990  * @param {Array} k keyset.
1991  * @param {Array} v optional valueset.
1992  * @return {object} the hash.
1993  */
1994 YArray.hash = function(k, v) {
1995     var o = {}, l = k.length, vl = v && v.length, i;
1996     for (i = 0; i < l; i = i + 1) {
1997         o[k[i]] = (vl && vl > i) ? v[i] : true;
1998     }
1999
2000     return o;
2001 };
2002
2003 /**
2004  * Returns the index of the first item in the array
2005  * that contains the specified value, -1 if the
2006  * value isn't found.
2007  * @method indexOf
2008  * @static
2009  * @param {Array} a the array to search.
2010  * @param {any} val the value to search for.
2011  * @return {int} the index of the item that contains the value or -1.
2012  */
2013 YArray.indexOf = (Native.indexOf) ?
2014     function(a, val) {
2015         return Native.indexOf.call(a, val);
2016     } :
2017     function(a, val) {
2018         for (var i = 0; i < a.length; i = i + 1) {
2019             if (a[i] === val) {
2020                 return i;
2021             }
2022         }
2023
2024         return -1;
2025     };
2026
2027 /**
2028  * Numeric sort convenience function.
2029  * Y.ArrayAssert.itemsAreEqual([1,2,3], [3,1,2].sort(Y.Array.numericSort));
2030  * @method numericSort
2031  * @static
2032  * @param {number} a a number.
2033  * @param {number} b a number.
2034  */
2035 YArray.numericSort = function(a, b) {
2036     return (a - b);
2037 };
2038
2039 /**
2040  * Executes the supplied function on each item in the array.
2041  * Returning true from the processing function will stop the
2042  * processing of the remaining items.
2043  * @method some
2044  * @param {Array} a the array to iterate.
2045  * @param {Function} f the function to execute on each item. The function
2046  * receives three arguments: the value, the index, the full array.
2047  * @param {object} o Optional context object.
2048  * @static
2049  * @return {boolean} true if the function returns true on
2050  * any of the items in the array.
2051  */
2052 YArray.some = (Native.some) ?
2053     function(a, f, o) {
2054         return Native.some.call(a, f, o);
2055     } :
2056     function(a, f, o) {
2057         var l = a.length, i;
2058         for (i = 0; i < l; i = i + 1) {
2059             if (f.call(o, a[i], i, a)) {
2060                 return true;
2061             }
2062         }
2063         return false;
2064     };
2065
2066 /**
2067  * The YUI module contains the components required for building the YUI
2068  * seed file.  This includes the script loading mechanism, a simple queue,
2069  * and the core utilities for the library.
2070  * @module yui
2071  * @submodule yui-base
2072  */
2073
2074 /**
2075  * A simple FIFO queue.  Items are added to the Queue with add(1..n items) and
2076  * removed using next().
2077  *
2078  * @class Queue
2079  * @constructor
2080  * @param {MIXED} item* 0..n items to seed the queue.
2081  */
2082 function Queue() {
2083     this._init();
2084     this.add.apply(this, arguments);
2085 }
2086
2087 Queue.prototype = {
2088     /**
2089      * Initialize the queue
2090      *
2091      * @method _init
2092      * @protected
2093      */
2094     _init: function() {
2095         /**
2096          * The collection of enqueued items
2097          *
2098          * @property _q
2099          * @type Array
2100          * @protected
2101          */
2102         this._q = [];
2103     },
2104
2105     /**
2106      * Get the next item in the queue. FIFO support
2107      *
2108      * @method next
2109      * @return {MIXED} the next item in the queue.
2110      */
2111     next: function() {
2112         return this._q.shift();
2113     },
2114
2115     /**
2116      * Get the last in the queue. LIFO support.
2117      *
2118      * @method last
2119      * @return {MIXED} the last item in the queue.
2120      */
2121     last: function() {
2122         return this._q.pop();
2123     },
2124
2125     /**
2126      * Add 0..n items to the end of the queue.
2127      *
2128      * @method add
2129      * @param {MIXED} item* 0..n items.
2130      * @return {object} this queue.
2131      */
2132     add: function() {
2133         this._q.push.apply(this._q, arguments);
2134
2135         return this;
2136     },
2137
2138     /**
2139      * Returns the current number of queued items.
2140      *
2141      * @method size
2142      * @return {Number} The size.
2143      */
2144     size: function() {
2145         return this._q.length;
2146     }
2147 };
2148
2149 Y.Queue = Queue;
2150
2151 YUI.Env._loaderQueue = YUI.Env._loaderQueue || new Queue();
2152
2153 /**
2154  * The YUI module contains the components required for building the YUI
2155  * seed file.  This includes the script loading mechanism, a simple queue,
2156  * and the core utilities for the library.
2157  * @module yui
2158  * @submodule yui-base
2159  */
2160
2161 var CACHED_DELIMITER = '__',
2162
2163 /*
2164  * IE will not enumerate native functions in a derived object even if the
2165  * function was overridden.  This is a workaround for specific functions
2166  * we care about on the Object prototype.
2167  * @property _iefix
2168  * @for YUI
2169  * @param {Function} r  the object to receive the augmentation
2170  * @param {Function} s  the object that supplies the properties to augment
2171  * @private
2172  */
2173 _iefix = function(r, s) {
2174     var fn = s.toString;
2175     if (Y.Lang.isFunction(fn) && fn != Object.prototype.toString) {
2176         r.toString = fn;
2177     }
2178 };
2179
2180
2181 /**
2182  * Returns a new object containing all of the properties of
2183  * all the supplied objects.  The properties from later objects
2184  * will overwrite those in earlier objects.  Passing in a
2185  * single object will create a shallow copy of it.  For a deep
2186  * copy, use clone.
2187  * @method merge
2188  * @for YUI
2189  * @param arguments {Object*} the objects to merge.
2190  * @return {object} the new merged object.
2191  */
2192 Y.merge = function() {
2193     var a = arguments, o = {}, i, l = a.length;
2194     for (i = 0; i < l; i = i + 1) {
2195         Y.mix(o, a[i], true);
2196     }
2197     return o;
2198 };
2199
2200 /**
2201  * Applies the supplier's properties to the receiver.  By default
2202  * all prototype and static propertes on the supplier are applied
2203  * to the corresponding spot on the receiver.  By default all
2204  * properties are applied, and a property that is already on the
2205  * reciever will not be overwritten.  The default behavior can
2206  * be modified by supplying the appropriate parameters.
2207  *
2208  * @todo add constants for the modes
2209  *
2210  * @method mix
2211  * @param {Function} r  the object to receive the augmentation.
2212  * @param {Function} s  the object that supplies the properties to augment.
2213  * @param ov {boolean} if true, properties already on the receiver
2214  * will be overwritten if found on the supplier.
2215  * @param wl {string[]} a whitelist.  If supplied, only properties in
2216  * this list will be applied to the receiver.
2217  * @param {int} mode what should be copies, and to where
2218  *        default(0): object to object
2219  *        1: prototype to prototype (old augment)
2220  *        2: prototype to prototype and object props (new augment)
2221  *        3: prototype to object
2222  *        4: object to prototype.
2223  * @param merge {boolean/int} merge objects instead of overwriting/ignoring.
2224  * A value of 2 will skip array merge
2225  * Used by Y.aggregate.
2226  * @return {object} the augmented object.
2227  */
2228 Y.mix = function(r, s, ov, wl, mode, merge) {
2229
2230     if (!s || !r) {
2231         return r || Y;
2232     }
2233
2234     if (mode) {
2235         switch (mode) {
2236             case 1: // proto to proto
2237                 return Y.mix(r.prototype, s.prototype, ov, wl, 0, merge);
2238             case 2: // object to object and proto to proto
2239                 Y.mix(r.prototype, s.prototype, ov, wl, 0, merge);
2240                 break; // pass through
2241             case 3: // proto to static
2242                 return Y.mix(r, s.prototype, ov, wl, 0, merge);
2243             case 4: // static to proto
2244                 return Y.mix(r.prototype, s, ov, wl, 0, merge);
2245             default:  // object to object is what happens below
2246         }
2247     }
2248
2249     // Maybe don't even need this wl && wl.length check anymore??
2250     var i, l, p, type;
2251
2252     if (wl && wl.length) {
2253         for (i = 0, l = wl.length; i < l; ++i) {
2254             p = wl[i];
2255             type = Y.Lang.type(r[p]);
2256             if (s.hasOwnProperty(p)) {
2257                 if (merge && type == 'object') {
2258                     Y.mix(r[p], s[p]);
2259                 } else if (ov || !(p in r)) {
2260                     r[p] = s[p];
2261                 }
2262             }
2263         }
2264     } else {
2265         for (i in s) {
2266             // if (s.hasOwnProperty(i) && !(i in FROZEN)) {
2267             if (s.hasOwnProperty(i)) {
2268                 // check white list if it was supplied
2269                 // if the receiver has this property, it is an object,
2270                 // and merge is specified, merge the two objects.
2271                 if (merge && Y.Lang.isObject(r[i], true)) {
2272                     Y.mix(r[i], s[i], ov, wl, 0, true); // recursive
2273                 // otherwise apply the property only if overwrite
2274                 // is specified or the receiver doesn't have one.
2275                 } else if (ov || !(i in r)) {
2276                     r[i] = s[i];
2277                 }
2278                 // if merge is specified and the receiver is an array,
2279                 // append the array item
2280                 // } else if (arr) {
2281                     // r.push(s[i]);
2282                 // }
2283             }
2284         }
2285
2286         if (Y.UA.ie) {
2287             _iefix(r, s);
2288         }
2289     }
2290
2291     return r;
2292 };
2293
2294 /**
2295  * Returns a wrapper for a function which caches the
2296  * return value of that function, keyed off of the combined
2297  * argument values.
2298  * @method cached
2299  * @param source {function} the function to memoize.
2300  * @param cache an optional cache seed.
2301  * @param refetch if supplied, this value is tested against the cached
2302  * value.  If the values are equal, the wrapped function is executed again.
2303  * @return {Function} the wrapped function.
2304  */
2305 Y.cached = function(source, cache, refetch) {
2306     cache = cache || {};
2307
2308     return function(arg1) {
2309
2310         var k = (arguments.length > 1) ?
2311             Array.prototype.join.call(arguments, CACHED_DELIMITER) : arg1;
2312
2313         if (!(k in cache) || (refetch && cache[k] == refetch)) {
2314             cache[k] = source.apply(source, arguments);
2315         }
2316
2317         return cache[k];
2318     };
2319
2320 };
2321
2322 /**
2323  * The YUI module contains the components required for building the YUI
2324  * seed file.  This includes the script loading mechanism, a simple queue,
2325  * and the core utilities for the library.
2326  * @module yui
2327  * @submodule yui-base
2328  */
2329
2330 /**
2331  * Adds the following Object utilities to the YUI instance
2332  * @class Object
2333  */
2334
2335 /**
2336  * Y.Object(o) returns a new object based upon the supplied object.
2337  * @method ()
2338  * @static
2339  * @param o the supplier object.
2340  * @return {Object} the new object.
2341  */
2342 var F = function() {},
2343
2344 // O = Object.create || function(o) {
2345 //     F.prototype = o;
2346 //     return new F();
2347 // },
2348
2349 O = function(o) {
2350     F.prototype = o;
2351     return new F();
2352 },
2353
2354 owns = function(o, k) {
2355     return o && o.hasOwnProperty && o.hasOwnProperty(k);
2356     // return Object.prototype.hasOwnProperty.call(o, k);
2357 },
2358
2359 UNDEF,
2360
2361 /**
2362  * Extracts the keys, values, or size from an object
2363  *
2364  * @method _extract
2365  * @param o the object.
2366  * @param what what to extract (0: keys, 1: values, 2: size).
2367  * @return {boolean|Array} the extracted info.
2368  * @static
2369  * @private
2370  */
2371 _extract = function(o, what) {
2372     var count = (what === 2), out = (count) ? 0 : [], i;
2373
2374     for (i in o) {
2375         if (owns(o, i)) {
2376             if (count) {
2377                 out++;
2378             } else {
2379                 out.push((what) ? o[i] : i);
2380             }
2381         }
2382     }
2383
2384     return out;
2385 };
2386
2387 Y.Object = O;
2388
2389 /**
2390  * Returns an array containing the object's keys
2391  * @method keys
2392  * @static
2393  * @param o an object.
2394  * @return {string[]} the keys.
2395  */
2396 // O.keys = Object.keys || function(o) {
2397 //     return _extract(o);
2398 // };
2399
2400 O.keys = function(o) {
2401     return _extract(o);
2402 };
2403
2404 /**
2405  * Returns an array containing the object's values
2406  * @method values
2407  * @static
2408  * @param o an object.
2409  * @return {Array} the values.
2410  */
2411 // O.values = Object.values || function(o) {
2412 //     return _extract(o, 1);
2413 // };
2414
2415 O.values = function(o) {
2416     return _extract(o, 1);
2417 };
2418
2419 /**
2420  * Returns the size of an object
2421  * @method size
2422  * @static
2423  * @param o an object.
2424  * @return {int} the size.
2425  */
2426 O.size = Object.size || function(o) {
2427     return _extract(o, 2);
2428 };
2429
2430 /**
2431  * Returns true if the object contains a given key
2432  * @method hasKey
2433  * @static
2434  * @param o an object.
2435  * @param k the key to query.
2436  * @return {boolean} true if the object contains the key.
2437  */
2438 O.hasKey = owns;
2439 /**
2440  * Returns true if the object contains a given value
2441  * @method hasValue
2442  * @static
2443  * @param o an object.
2444  * @param v the value to query.
2445  * @return {boolean} true if the object contains the value.
2446  */
2447 O.hasValue = function(o, v) {
2448     return (Y.Array.indexOf(O.values(o), v) > -1);
2449 };
2450
2451 /**
2452  * Determines whether or not the property was added
2453  * to the object instance.  Returns false if the property is not present
2454  * in the object, or was inherited from the prototype.
2455  *
2456  * @method owns
2457  * @static
2458  * @param o {any} The object being testing.
2459  * @param p {string} the property to look for.
2460  * @return {boolean} true if the object has the property on the instance.
2461  */
2462 O.owns = owns;
2463
2464 /**
2465  * Executes a function on each item. The function
2466  * receives the value, the key, and the object
2467  * as parameters (in that order).
2468  * @method each
2469  * @static
2470  * @param o the object to iterate.
2471  * @param f {Function} the function to execute on each item. The function
2472  * receives three arguments: the value, the the key, the full object.
2473  * @param c the execution context.
2474  * @param proto {boolean} include proto.
2475  * @return {YUI} the YUI instance.
2476  */
2477 O.each = function(o, f, c, proto) {
2478     var s = c || Y, i;
2479
2480     for (i in o) {
2481         if (proto || owns(o, i)) {
2482             f.call(s, o[i], i, o);
2483         }
2484     }
2485     return Y;
2486 };
2487
2488 /**
2489  * Executes a function on each item, but halts if the
2490  * function returns true.  The function
2491  * receives the value, the key, and the object
2492  * as paramters (in that order).
2493  * @method some
2494  * @static
2495  * @param o the object to iterate.
2496  * @param f {Function} the function to execute on each item. The function
2497  * receives three arguments: the value, the the key, the full object.
2498  * @param c the execution context.
2499  * @param proto {boolean} include proto.
2500  * @return {boolean} true if any execution of the function returns true,
2501  * false otherwise.
2502  */
2503 O.some = function(o, f, c, proto) {
2504     var s = c || Y, i;
2505
2506     for (i in o) {
2507         if (proto || owns(o, i)) {
2508             if (f.call(s, o[i], i, o)) {
2509                 return true;
2510             }
2511         }
2512     }
2513     return false;
2514 };
2515
2516 /**
2517  * Retrieves the sub value at the provided path,
2518  * from the value object provided.
2519  *
2520  * @method getValue
2521  * @static
2522  * @param o The object from which to extract the property value.
2523  * @param path {Array} A path array, specifying the object traversal path
2524  * from which to obtain the sub value.
2525  * @return {Any} The value stored in the path, undefined if not found,
2526  * undefined if the source is not an object.  Returns the source object
2527  * if an empty path is provided.
2528  */
2529 O.getValue = function(o, path) {
2530     if (!Y.Lang.isObject(o)) {
2531         return UNDEF;
2532     }
2533
2534     var i,
2535         p = Y.Array(path),
2536         l = p.length;
2537
2538     for (i = 0; o !== UNDEF && i < l; i++) {
2539         o = o[p[i]];
2540     }
2541
2542     return o;
2543 };
2544
2545 /**
2546  * Sets the sub-attribute value at the provided path on the
2547  * value object.  Returns the modified value object, or
2548  * undefined if the path is invalid.
2549  *
2550  * @method setValue
2551  * @static
2552  * @param o             The object on which to set the sub value.
2553  * @param path {Array}  A path array, specifying the object traversal path
2554  *                      at which to set the sub value.
2555  * @param val {Any}     The new value for the sub-attribute.
2556  * @return {Object}     The modified object, with the new sub value set, or
2557  *                      undefined, if the path was invalid.
2558  */
2559 O.setValue = function(o, path, val) {
2560     var i,
2561         p = Y.Array(path),
2562         leafIdx = p.length - 1,
2563         ref = o;
2564
2565     if (leafIdx >= 0) {
2566         for (i = 0; ref !== UNDEF && i < leafIdx; i++) {
2567             ref = ref[p[i]];
2568         }
2569
2570         if (ref !== UNDEF) {
2571             ref[p[i]] = val;
2572         } else {
2573             return UNDEF;
2574         }
2575     }
2576
2577     return o;
2578 };
2579
2580 /**
2581  * Returns true if the object has no properties of its own
2582  * @method isEmpty
2583  * @static
2584  * @return {boolean} true if the object is empty.
2585  * @since 3.2.0
2586  */
2587 O.isEmpty = function(o) {
2588     for (var i in o) {
2589         if (owns(o, i)) {
2590             return false;
2591         }
2592     }
2593     return true;
2594 };
2595 /**
2596  * The YUI module contains the components required for building the YUI seed
2597  * file.  This includes the script loading mechanism, a simple queue, and the
2598  * core utilities for the library.
2599  * @module yui
2600  * @submodule yui-base
2601  */
2602
2603 /**
2604  * YUI user agent detection.
2605  * Do not fork for a browser if it can be avoided.  Use feature detection when
2606  * you can.  Use the user agent as a last resort.  UA stores a version
2607  * number for the browser engine, 0 otherwise.  This value may or may not map
2608  * to the version number of the browser using the engine.  The value is
2609  * presented as a float so that it can easily be used for boolean evaluation
2610  * as well as for looking for a particular range of versions.  Because of this,
2611  * some of the granularity of the version info may be lost (e.g., Gecko 1.8.0.9
2612  * reports 1.8).
2613  * @class UA
2614  * @static
2615  */
2616 /**
2617 * Static method for parsing the UA string. Defaults to assigning it's value to Y.UA
2618 * @static
2619 * @method Env.parseUA
2620 * @param {String} subUA Parse this UA string instead of navigator.userAgent
2621 * @returns {Object} The Y.UA object
2622 */
2623 YUI.Env.parseUA = function(subUA) {
2624     
2625     var numberify = function(s) {
2626             var c = 0;
2627             return parseFloat(s.replace(/\./g, function() {
2628                 return (c++ == 1) ? '' : '.';
2629             }));
2630         },
2631
2632         win = Y.config.win,
2633
2634         nav = win && win.navigator,
2635
2636         o = {
2637
2638         /**
2639          * Internet Explorer version number or 0.  Example: 6
2640          * @property ie
2641          * @type float
2642          * @static
2643          */
2644         ie: 0,
2645
2646         /**
2647          * Opera version number or 0.  Example: 9.2
2648          * @property opera
2649          * @type float
2650          * @static
2651          */
2652         opera: 0,
2653
2654         /**
2655          * Gecko engine revision number.  Will evaluate to 1 if Gecko
2656          * is detected but the revision could not be found. Other browsers
2657          * will be 0.  Example: 1.8
2658          * <pre>
2659          * Firefox 1.0.0.4: 1.7.8   <-- Reports 1.7
2660          * Firefox 1.5.0.9: 1.8.0.9 <-- 1.8
2661          * Firefox 2.0.0.3: 1.8.1.3 <-- 1.81
2662          * Firefox 3.0   <-- 1.9
2663          * Firefox 3.5   <-- 1.91
2664          * </pre>
2665          * @property gecko
2666          * @type float
2667          * @static
2668          */
2669         gecko: 0,
2670
2671         /**
2672          * AppleWebKit version.  KHTML browsers that are not WebKit browsers
2673          * will evaluate to 1, other browsers 0.  Example: 418.9
2674          * <pre>
2675          * Safari 1.3.2 (312.6): 312.8.1 <-- Reports 312.8 -- currently the
2676          *                                   latest available for Mac OSX 10.3.
2677          * Safari 2.0.2:         416     <-- hasOwnProperty introduced
2678          * Safari 2.0.4:         418     <-- preventDefault fixed
2679          * Safari 2.0.4 (419.3): 418.9.1 <-- One version of Safari may run
2680          *                                   different versions of webkit
2681          * Safari 2.0.4 (419.3): 419     <-- Tiger installations that have been
2682          *                                   updated, but not updated
2683          *                                   to the latest patch.
2684          * Webkit 212 nightly:   522+    <-- Safari 3.0 precursor (with native
2685          * SVG and many major issues fixed).
2686          * Safari 3.0.4 (523.12) 523.12  <-- First Tiger release - automatic
2687          * update from 2.x via the 10.4.11 OS patch.
2688          * Webkit nightly 1/2008:525+    <-- Supports DOMContentLoaded event.
2689          *                                   yahoo.com user agent hack removed.
2690          * </pre>
2691          * http://en.wikipedia.org/wiki/Safari_version_history
2692          * @property webkit
2693          * @type float
2694          * @static
2695          */
2696         webkit: 0,
2697
2698         /**
2699          * Chrome will be detected as webkit, but this property will also
2700          * be populated with the Chrome version number
2701          * @property chrome
2702          * @type float
2703          * @static
2704          */
2705         chrome: 0,
2706
2707         /**
2708          * The mobile property will be set to a string containing any relevant
2709          * user agent information when a modern mobile browser is detected.
2710          * Currently limited to Safari on the iPhone/iPod Touch, Nokia N-series
2711          * devices with the WebKit-based browser, and Opera Mini.
2712          * @property mobile
2713          * @type string
2714          * @static
2715          */
2716         mobile: null,
2717
2718         /**
2719          * Adobe AIR version number or 0.  Only populated if webkit is detected.
2720          * Example: 1.0
2721          * @property air
2722          * @type float
2723          */
2724         air: 0,
2725         /**
2726          * Detects Apple iPad's OS version
2727          * @property ipad
2728          * @type float
2729          * @static
2730          */
2731         ipad: 0,
2732         /**
2733          * Detects Apple iPhone's OS version
2734          * @property iphone
2735          * @type float
2736          * @static
2737          */
2738         iphone: 0,
2739         /**
2740          * Detects Apples iPod's OS version
2741          * @property ipod
2742          * @type float
2743          * @static
2744          */
2745         ipod: 0,
2746         /**
2747          * General truthy check for iPad, iPhone or iPod
2748          * @property ios
2749          * @type float
2750          * @static
2751          */
2752         ios: null,
2753         /**
2754          * Detects Googles Android OS version
2755          * @property android
2756          * @type float
2757          * @static
2758          */
2759         android: 0,
2760         /**
2761          * Detects Palms WebOS version
2762          * @property webos
2763          * @type float
2764          * @static
2765          */
2766         webos: 0,
2767
2768         /**
2769          * Google Caja version number or 0.
2770          * @property caja
2771          * @type float
2772          */
2773         caja: nav && nav.cajaVersion,
2774
2775         /**
2776          * Set to true if the page appears to be in SSL
2777          * @property secure
2778          * @type boolean
2779          * @static
2780          */
2781         secure: false,
2782
2783         /**
2784          * The operating system.  Currently only detecting windows or macintosh
2785          * @property os
2786          * @type string
2787          * @static
2788          */
2789         os: null
2790
2791     },
2792
2793     ua = subUA || nav && nav.userAgent,
2794
2795     loc = win && win.location,
2796
2797     href = loc && loc.href,
2798
2799     m;
2800
2801     o.secure = href && (href.toLowerCase().indexOf('https') === 0);
2802
2803     if (ua) {
2804
2805         if ((/windows|win32/i).test(ua)) {
2806             o.os = 'windows';
2807         } else if ((/macintosh/i).test(ua)) {
2808             o.os = 'macintosh';
2809         } else if ((/rhino/i).test(ua)) {
2810             o.os = 'rhino';
2811         }
2812
2813         // Modern KHTML browsers should qualify as Safari X-Grade
2814         if ((/KHTML/).test(ua)) {
2815             o.webkit = 1;
2816         }
2817         // Modern WebKit browsers are at least X-Grade
2818         m = ua.match(/AppleWebKit\/([^\s]*)/);
2819         if (m && m[1]) {
2820             o.webkit = numberify(m[1]);
2821
2822             // Mobile browser check
2823             if (/ Mobile\//.test(ua)) {
2824                 o.mobile = 'Apple'; // iPhone or iPod Touch
2825
2826                 m = ua.match(/OS ([^\s]*)/);
2827                 if (m && m[1]) {
2828                     m = numberify(m[1].replace('_', '.'));
2829                 }
2830                 o.ios = m;
2831                 o.ipad = o.ipod = o.iphone = 0;
2832
2833                 m = ua.match(/iPad|iPod|iPhone/);
2834                 if (m && m[0]) {
2835                     o[m[0].toLowerCase()] = o.ios;
2836                 }
2837             } else {
2838                 m = ua.match(/NokiaN[^\/]*|Android \d\.\d|webOS\/\d\.\d/);
2839                 if (m) {
2840                     // Nokia N-series, Android, webOS, ex: NokiaN95
2841                     o.mobile = m[0];
2842                 }
2843                 if (/webOS/.test(ua)) {
2844                     o.mobile = 'WebOS';
2845                     m = ua.match(/webOS\/([^\s]*);/);
2846                     if (m && m[1]) {
2847                         o.webos = numberify(m[1]);
2848                     }
2849                 }
2850                 if (/ Android/.test(ua)) {
2851                     o.mobile = 'Android';
2852                     m = ua.match(/Android ([^\s]*);/);
2853                     if (m && m[1]) {
2854                         o.android = numberify(m[1]);
2855                     }
2856
2857                 }
2858             }
2859
2860             m = ua.match(/Chrome\/([^\s]*)/);
2861             if (m && m[1]) {
2862                 o.chrome = numberify(m[1]); // Chrome
2863             } else {
2864                 m = ua.match(/AdobeAIR\/([^\s]*)/);
2865                 if (m) {
2866                     o.air = m[0]; // Adobe AIR 1.0 or better
2867                 }
2868             }
2869         }
2870
2871         if (!o.webkit) { // not webkit
2872 // @todo check Opera/8.01 (J2ME/MIDP; Opera Mini/2.0.4509/1316; fi; U; ssr)
2873             m = ua.match(/Opera[\s\/]([^\s]*)/);
2874             if (m && m[1]) {
2875                 o.opera = numberify(m[1]);
2876                 m = ua.match(/Opera Mini[^;]*/);
2877                 if (m) {
2878                     o.mobile = m[0]; // ex: Opera Mini/2.0.4509/1316
2879                 }
2880             } else { // not opera or webkit
2881                 m = ua.match(/MSIE\s([^;]*)/);
2882                 if (m && m[1]) {
2883                     o.ie = numberify(m[1]);
2884                 } else { // not opera, webkit, or ie
2885                     m = ua.match(/Gecko\/([^\s]*)/);
2886                     if (m) {
2887                         o.gecko = 1; // Gecko detected, look for revision
2888                         m = ua.match(/rv:([^\s\)]*)/);
2889                         if (m && m[1]) {
2890                             o.gecko = numberify(m[1]);
2891                         }
2892                     }
2893                 }
2894             }
2895         }
2896     }
2897
2898     YUI.Env.UA = o;
2899
2900     return o;
2901 };
2902
2903
2904 Y.UA = YUI.Env.UA || YUI.Env.parseUA();
2905
2906
2907 }, '3.3.0' );