]> CyberLeo.Net >> Repos - Github/sugarcrm.git/blob - jssource/src_files/include/javascript/yui3/build/simpleyui/simpleyui.js
Release 6.2.2
[Github/sugarcrm.git] / jssource / src_files / include / javascript / yui3 / build / simpleyui / simpleyui.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 /**
10  * The YUI module contains the components required for building the YUI seed
11  * file.  This includes the script loading mechanism, a simple queue, and
12  * the core utilities for the library.
13  * @module yui
14  * @submodule yui-base
15  */
16
17 if (typeof YUI != 'undefined') {
18     YUI._YUI = YUI;
19 }
20
21 /**
22  * The YUI global namespace object.  If YUI is already defined, the
23  * existing YUI object will not be overwritten so that defined
24  * namespaces are preserved.  It is the constructor for the object
25  * the end user interacts with.  As indicated below, each instance
26  * has full custom event support, but only if the event system
27  * is available.  This is a self-instantiable factory function.  You
28  * can invoke it directly like this:
29  *
30  * YUI().use('*', function(Y) {
31  *   // ready
32  * });
33  *
34  * But it also works like this:
35  *
36  * var Y = YUI();
37  *
38  * @class YUI
39  * @constructor
40  * @global
41  * @uses EventTarget
42  * @param o* {object} 0..n optional configuration objects.  these values
43  * are store in Y.config.  See config for the list of supported
44  * properties.
45  */
46     /*global YUI*/
47     /*global YUI_config*/
48     var YUI = function() {
49         var i = 0,
50             Y = this,
51             args = arguments,
52             l = args.length,
53             instanceOf = function(o, type) {
54                 return (o && o.hasOwnProperty && (o instanceof type));
55             },
56             gconf = (typeof YUI_config !== 'undefined') && YUI_config;
57
58         if (!(instanceOf(Y, YUI))) {
59             Y = new YUI();
60         } else {
61             // set up the core environment
62             Y._init();
63
64             // YUI.GlobalConfig is a master configuration that might span
65             // multiple contexts in a non-browser environment.  It is applied
66             // first to all instances in all contexts.
67             if (YUI.GlobalConfig) {
68                 Y.applyConfig(YUI.GlobalConfig);
69             }
70
71             // YUI_Config is a page-level config.  It is applied to all
72             // instances created on the page.  This is applied after
73             // YUI.GlobalConfig, and before the instance level configuration
74             // objects.
75             if (gconf) {
76                 Y.applyConfig(gconf);
77             }
78
79             // bind the specified additional modules for this instance
80             if (!l) {
81                 Y._setup();
82             }
83         }
84
85         if (l) {
86             // Each instance can accept one or more configuration objects.
87             // These are applied after YUI.GlobalConfig and YUI_Config,
88             // overriding values set in those config files if there is a '
89             // matching property.
90             for (; i < l; i++) {
91                 Y.applyConfig(args[i]);
92             }
93
94             Y._setup();
95         }
96
97         Y.instanceOf = instanceOf;
98
99         return Y;
100     };
101
102 (function() {
103
104     var proto, prop,
105         VERSION = '3.3.0',
106         PERIOD = '.',
107         BASE = 'http://yui.yahooapis.com/',
108         DOC_LABEL = 'yui3-js-enabled',
109         NOOP = function() {},
110         SLICE = Array.prototype.slice,
111         APPLY_TO_AUTH = { 'io.xdrReady': 1,   // the functions applyTo
112                           'io.xdrResponse': 1,   // can call. this should
113                           'SWF.eventHandler': 1 }, // be done at build time
114         hasWin = (typeof window != 'undefined'),
115         win = (hasWin) ? window : null,
116         doc = (hasWin) ? win.document : null,
117         docEl = doc && doc.documentElement,
118         docClass = docEl && docEl.className,
119         instances = {},
120         time = new Date().getTime(),
121         add = function(el, type, fn, capture) {
122             if (el && el.addEventListener) {
123                 el.addEventListener(type, fn, capture);
124             } else if (el && el.attachEvent) {
125                 el.attachEvent('on' + type, fn);
126             }
127         },
128         remove = function(el, type, fn, capture) {
129             if (el && el.removeEventListener) {
130                 // this can throw an uncaught exception in FF
131                 try {
132                     el.removeEventListener(type, fn, capture);
133                 } catch (ex) {}
134             } else if (el && el.detachEvent) {
135                 el.detachEvent('on' + type, fn);
136             }
137         },
138         handleLoad = function() {
139             YUI.Env.windowLoaded = true;
140             YUI.Env.DOMReady = true;
141             if (hasWin) {
142                 remove(window, 'load', handleLoad);
143             }
144         },
145         getLoader = function(Y, o) {
146             var loader = Y.Env._loader;
147             if (loader) {
148                 loader.ignoreRegistered = false;
149                 loader.onEnd = null;
150                 loader.data = null;
151                 loader.required = [];
152                 loader.loadType = null;
153             } else {
154                 loader = new Y.Loader(Y.config);
155                 Y.Env._loader = loader;
156             }
157
158             return loader;
159         },
160
161         clobber = function(r, s) {
162             for (var i in s) {
163                 if (s.hasOwnProperty(i)) {
164                     r[i] = s[i];
165                 }
166             }
167         },
168
169         ALREADY_DONE = { success: true };
170
171 //  Stamp the documentElement (HTML) with a class of "yui-loaded" to
172 //  enable styles that need to key off of JS being enabled.
173 if (docEl && docClass.indexOf(DOC_LABEL) == -1) {
174     if (docClass) {
175         docClass += ' ';
176     }
177     docClass += DOC_LABEL;
178     docEl.className = docClass;
179 }
180
181 if (VERSION.indexOf('@') > -1) {
182     VERSION = '3.2.0'; // dev time hack for cdn test
183 }
184
185 proto = {
186     /**
187      * Applies a new configuration object to the YUI instance config.
188      * This will merge new group/module definitions, and will also
189      * update the loader cache if necessary.  Updating Y.config directly
190      * will not update the cache.
191      * @method applyConfig
192      * @param {object} the configuration object.
193      * @since 3.2.0
194      */
195     applyConfig: function(o) {
196
197         o = o || NOOP;
198
199         var attr,
200             name,
201             // detail,
202             config = this.config,
203             mods = config.modules,
204             groups = config.groups,
205             rls = config.rls,
206             loader = this.Env._loader;
207
208         for (name in o) {
209             if (o.hasOwnProperty(name)) {
210                 attr = o[name];
211                 if (mods && name == 'modules') {
212                     clobber(mods, attr);
213                 } else if (groups && name == 'groups') {
214                     clobber(groups, attr);
215                 } else if (rls && name == 'rls') {
216                     clobber(rls, attr);
217                 } else if (name == 'win') {
218                     config[name] = attr.contentWindow || attr;
219                     config.doc = config[name].document;
220                 } else if (name == '_yuid') {
221                     // preserve the guid
222                 } else {
223                     config[name] = attr;
224                 }
225             }
226         }
227
228         if (loader) {
229             loader._config(o);
230         }
231     },
232
233     _config: function(o) {
234         this.applyConfig(o);
235     },
236
237     /**
238      * Initialize this YUI instance
239      * @private
240      */
241     _init: function() {
242         var filter,
243             Y = this,
244             G_ENV = YUI.Env,
245             Env = Y.Env,
246             prop;
247
248         /**
249          * The version number of the YUI instance.
250          * @property version
251          * @type string
252          */
253         Y.version = VERSION;
254
255         if (!Env) {
256             Y.Env = {
257                 mods: {}, // flat module map
258                 versions: {}, // version module map
259                 base: BASE,
260                 cdn: BASE + VERSION + '/build/',
261                 // bootstrapped: false,
262                 _idx: 0,
263                 _used: {},
264                 _attached: {},
265                 _yidx: 0,
266                 _uidx: 0,
267                 _guidp: 'y',
268                 _loaded: {},
269                 serviced: {},
270                 getBase: G_ENV && G_ENV.getBase ||
271
272     function(srcPattern, comboPattern) {
273         var b, nodes, i, src, match;
274         // get from querystring
275         nodes = (doc && doc.getElementsByTagName('script')) || [];
276         for (i = 0; i < nodes.length; i = i + 1) {
277             src = nodes[i].src;
278             if (src) {
279
280                 match = src.match(srcPattern);
281                 b = match && match[1];
282                 if (b) {
283                     // this is to set up the path to the loader.  The file
284                     // filter for loader should match the yui include.
285                     filter = match[2];
286
287                     if (filter) {
288                         match = filter.indexOf('js');
289
290                         if (match > -1) {
291                             filter = filter.substr(0, match);
292                         }
293                     }
294
295                     // extract correct path for mixed combo urls
296                     // http://yuilibrary.com/projects/yui3/ticket/2528423
297                     match = src.match(comboPattern);
298                     if (match && match[3]) {
299                         b = match[1] + match[3];
300                     }
301
302                     break;
303                 }
304             }
305         }
306
307         // use CDN default
308         return b || Env.cdn;
309     }
310             };
311
312             Env = Y.Env;
313
314             Env._loaded[VERSION] = {};
315
316             if (G_ENV && Y !== YUI) {
317                 Env._yidx = ++G_ENV._yidx;
318                 Env._guidp = ('yui_' + VERSION + '_' +
319                              Env._yidx + '_' + time).replace(/\./g, '_');
320             } else if (YUI._YUI) {
321
322                 G_ENV = YUI._YUI.Env;
323                 Env._yidx += G_ENV._yidx;
324                 Env._uidx += G_ENV._uidx;
325
326                 for (prop in G_ENV) {
327                     if (!(prop in Env)) {
328                         Env[prop] = G_ENV[prop];
329                     }
330                 }
331
332                 delete YUI._YUI;
333             }
334
335             Y.id = Y.stamp(Y);
336             instances[Y.id] = Y;
337
338         }
339
340         Y.constructor = YUI;
341
342         // configuration defaults
343         Y.config = Y.config || {
344             win: win,
345             doc: doc,
346             debug: true,
347             useBrowserConsole: true,
348             throwFail: true,
349             bootstrap: true,
350             cacheUse: true,
351             fetchCSS: true
352         };
353
354         Y.config.base = YUI.config.base ||
355             Y.Env.getBase(/^(.*)yui\/yui([\.\-].*)js(\?.*)?$/,
356                           /^(.*\?)(.*\&)(.*)yui\/yui[\.\-].*js(\?.*)?$/);
357
358         if (!filter || (!('-min.-debug.').indexOf(filter))) {
359             filter = '-min.';
360         }
361
362         Y.config.loaderPath = YUI.config.loaderPath ||
363             'loader/loader' + (filter || '-min.') + 'js';
364
365     },
366
367     /**
368      * Finishes the instance setup. Attaches whatever modules were defined
369      * when the yui modules was registered.
370      * @method _setup
371      * @private
372      */
373     _setup: function(o) {
374         var i, Y = this,
375             core = [],
376             mods = YUI.Env.mods,
377             extras = Y.config.core || ['get',
378                                         'rls',
379                                         'intl-base',
380                                         'loader',
381                                         'yui-log',
382                                         'yui-later',
383                                         'yui-throttle'];
384
385         for (i = 0; i < extras.length; i++) {
386             if (mods[extras[i]]) {
387                 core.push(extras[i]);
388             }
389         }
390
391         Y._attach(['yui-base']);
392         Y._attach(core);
393
394     },
395
396     /**
397      * Executes a method on a YUI instance with
398      * the specified id if the specified method is whitelisted.
399      * @method applyTo
400      * @param id {string} the YUI instance id.
401      * @param method {string} the name of the method to exectute.
402      * Ex: 'Object.keys'.
403      * @param args {Array} the arguments to apply to the method.
404      * @return {object} the return value from the applied method or null.
405      */
406     applyTo: function(id, method, args) {
407         if (!(method in APPLY_TO_AUTH)) {
408             this.log(method + ': applyTo not allowed', 'warn', 'yui');
409             return null;
410         }
411
412         var instance = instances[id], nest, m, i;
413         if (instance) {
414             nest = method.split('.');
415             m = instance;
416             for (i = 0; i < nest.length; i = i + 1) {
417                 m = m[nest[i]];
418                 if (!m) {
419                     this.log('applyTo not found: ' + method, 'warn', 'yui');
420                 }
421             }
422             return m.apply(instance, args);
423         }
424
425         return null;
426     },
427
428     /**
429      * Registers a module with the YUI global.  The easiest way to create a
430      * first-class YUI module is to use the YUI component build tool.
431      *
432      * http://yuilibrary.com/projects/builder
433      *
434      * The build system will produce the YUI.add wrapper for you module, along
435      * with any configuration info required for the module.
436      * @method add
437      * @param name {string} module name.
438      * @param fn {Function} entry point into the module that
439      * is used to bind module to the YUI instance.
440      * @param version {string} version string.
441      * @param details {object} optional config data:
442      * requires: features that must be present before this module can be
443      * attached.
444      * optional: optional features that should be present if loadOptional
445      * is defined.  Note: modules are not often loaded this way in YUI 3,
446      * but this field is still useful to inform the user that certain
447      * features in the component will require additional dependencies.
448      * use: features that are included within this module which need to
449      * be attached automatically when this module is attached.  This
450      * supports the YUI 3 rollup system -- a module with submodules
451      * defined will need to have the submodules listed in the 'use'
452      * config.  The YUI component build tool does this for you.
453      * @return {YUI} the YUI instance.
454      *
455      */
456     add: function(name, fn, version, details) {
457         details = details || {};
458         var env = YUI.Env,
459             mod = {
460                 name: name,
461                 fn: fn,
462                 version: version,
463                 details: details
464             },
465             loader,
466             i, versions = env.versions;
467
468         env.mods[name] = mod;
469         versions[version] = versions[version] || {};
470         versions[version][name] = mod;
471
472         for (i in instances) {
473             if (instances.hasOwnProperty(i)) {
474                 loader = instances[i].Env._loader;
475                 if (loader) {
476                     if (!loader.moduleInfo[name]) {
477                         loader.addModule(details, name);
478                     }
479                 }
480             }
481         }
482
483         return this;
484     },
485
486     /**
487      * Executes the function associated with each required
488      * module, binding the module to the YUI instance.
489      * @method _attach
490      * @private
491      */
492     _attach: function(r, fromLoader) {
493         var i, name, mod, details, req, use, after,
494             mods = YUI.Env.mods,
495             Y = this, j,
496             done = Y.Env._attached,
497             len = r.length, loader;
498
499
500         for (i = 0; i < len; i++) {
501             if (!done[r[i]]) {
502                 name = r[i];
503                 mod = mods[name];
504                 if (!mod) {
505                     loader = Y.Env._loader;
506
507
508                     if (!loader || !loader.moduleInfo[name]) {
509                         Y.message('NOT loaded: ' + name, 'warn', 'yui');
510                     }
511                 } else {
512                     done[name] = true;
513                     details = mod.details;
514                     req = details.requires;
515                     use = details.use;
516                     after = details.after;
517
518                     if (req) {
519                         for (j = 0; j < req.length; j++) {
520                             if (!done[req[j]]) {
521                                 if (!Y._attach(req)) {
522                                     return false;
523                                 }
524                                 break;
525                             }
526                         }
527                     }
528
529                     if (after) {
530                         for (j = 0; j < after.length; j++) {
531                             if (!done[after[j]]) {
532                                 if (!Y._attach(after)) {
533                                     return false;
534                                 }
535                                 break;
536                             }
537                         }
538                     }
539
540                     if (use) {
541                         for (j = 0; j < use.length; j++) {
542                             if (!done[use[j]]) {
543                                 if (!Y._attach(use)) {
544                                     return false;
545                                 }
546                                 break;
547                             }
548                         }
549                     }
550
551                     if (mod.fn) {
552                         try {
553                             mod.fn(Y, name);
554                         } catch (e) {
555                             Y.error('Attach error: ' + name, e, name);
556                             return false;
557                         }
558                     }
559
560                 }
561             }
562         }
563
564         return true;
565     },
566
567     /**
568      * Attaches one or more modules to the YUI instance.  When this
569      * is executed, the requirements are analyzed, and one of
570      * several things can happen:
571      *
572      * - All requirements are available on the page --  The modules
573      *   are attached to the instance.  If supplied, the use callback
574      *   is executed synchronously.
575      *
576      * - Modules are missing, the Get utility is not available OR
577      *   the 'bootstrap' config is false -- A warning is issued about
578      *   the missing modules and all available modules are attached.
579      *
580      * - Modules are missing, the Loader is not available but the Get
581      *   utility is and boostrap is not false -- The loader is bootstrapped
582      *   before doing the following....
583      *
584      * - Modules are missing and the Loader is available -- The loader
585      *   expands the dependency tree and fetches missing modules.  When
586      *   the loader is finshed the callback supplied to use is executed
587      *   asynchronously.
588      *
589      * @param modules* {string} 1-n modules to bind (uses arguments array).
590      * @param *callback {function} callback function executed when
591      * the instance has the required functionality.  If included, it
592      * must be the last parameter.
593      * <code>
594      * // loads and attaches drag and drop and its dependencies
595      * YUI().use('dd', function(Y) &#123;&#125);
596      * // attaches all modules that are available on the page
597      * YUI().use('*', function(Y) &#123;&#125);
598      * // intrinsic YUI gallery support (since 3.1.0)
599      * YUI().use('gallery-yql', function(Y) &#123;&#125);
600      * // intrinsic YUI 2in3 support (since 3.1.0)
601      * YUI().use('yui2-datatable', function(Y) &#123;&#125);.
602      * </code>
603      *
604      * @return {YUI} the YUI instance.
605      */
606     use: function() {
607         var args = SLICE.call(arguments, 0),
608             callback = args[args.length - 1],
609             Y = this,
610             key;
611
612         // The last argument supplied to use can be a load complete callback
613         if (Y.Lang.isFunction(callback)) {
614             args.pop();
615         } else {
616             callback = null;
617         }
618
619         if (Y._loading) {
620             Y._useQueue = Y._useQueue || new Y.Queue();
621             Y._useQueue.add([args, callback]);
622         } else {
623             key = args.join();
624
625             if (Y.config.cacheUse && Y.Env.serviced[key]) {
626                 Y._notify(callback, ALREADY_DONE, args);
627             } else {
628                 Y._use(args, function(Y, response) {
629                     if (Y.config.cacheUse) {
630                         Y.Env.serviced[key] = true;
631                     }
632                     Y._notify(callback, response, args);
633                 });
634             }
635         }
636
637         return Y;
638     },
639
640     _notify: function(callback, response, args) {
641         if (!response.success && this.config.loadErrorFn) {
642             this.config.loadErrorFn.call(this, this, callback, response, args);
643         } else if (callback) {
644             try {
645                 callback(this, response);
646             } catch (e) {
647                 this.error('use callback error', e, args);
648             }
649         }
650     },
651
652     _use: function(args, callback) {
653
654         if (!this.Array) {
655             this._attach(['yui-base']);
656         }
657
658         var len, loader, handleBoot,
659             Y = this,
660             G_ENV = YUI.Env,
661             mods = G_ENV.mods,
662             Env = Y.Env,
663             used = Env._used,
664             queue = G_ENV._loaderQueue,
665             firstArg = args[0],
666             YArray = Y.Array,
667             config = Y.config,
668             boot = config.bootstrap,
669             missing = [],
670             r = [],
671             ret = true,
672             fetchCSS = config.fetchCSS,
673             process = function(names, skip) {
674
675                 if (!names.length) {
676                     return;
677                 }
678
679                 YArray.each(names, function(name) {
680
681                     // add this module to full list of things to attach
682                     if (!skip) {
683                         r.push(name);
684                     }
685
686                     // only attach a module once
687                     if (used[name]) {
688                         return;
689                     }
690
691                     var m = mods[name], req, use;
692
693                     if (m) {
694                         used[name] = true;
695                         req = m.details.requires;
696                         use = m.details.use;
697                     } else {
698                         // CSS files don't register themselves, see if it has
699                         // been loaded
700                         if (!G_ENV._loaded[VERSION][name]) {
701                             missing.push(name);
702                         } else {
703                             used[name] = true; // probably css
704                         }
705                     }
706
707                     // make sure requirements are attached
708                     if (req && req.length) {
709                         process(req);
710                     }
711
712                     // make sure we grab the submodule dependencies too
713                     if (use && use.length) {
714                         process(use, 1);
715                     }
716                 });
717             },
718
719             handleLoader = function(fromLoader) {
720                 var response = fromLoader || {
721                         success: true,
722                         msg: 'not dynamic'
723                     },
724                     redo, origMissing,
725                     ret = true,
726                     data = response.data;
727
728
729                 Y._loading = false;
730
731                 if (data) {
732                     origMissing = missing;
733                     missing = [];
734                     r = [];
735                     process(data);
736                     redo = missing.length;
737                     if (redo) {
738                         if (missing.sort().join() ==
739                                 origMissing.sort().join()) {
740                             redo = false;
741                         }
742                     }
743                 }
744
745                 if (redo && data) {
746                     Y._loading = false;
747                     Y._use(args, function() {
748                         if (Y._attach(data)) {
749                             Y._notify(callback, response, data);
750                         }
751                     });
752                 } else {
753                     if (data) {
754                         ret = Y._attach(data);
755                     }
756                     if (ret) {
757                         Y._notify(callback, response, args);
758                     }
759                 }
760
761                 if (Y._useQueue && Y._useQueue.size() && !Y._loading) {
762                     Y._use.apply(Y, Y._useQueue.next());
763                 }
764
765             };
766
767
768         // YUI().use('*'); // bind everything available
769         if (firstArg === '*') {
770             ret = Y._attach(Y.Object.keys(mods));
771             if (ret) {
772                 handleLoader();
773             }
774             return Y;
775         }
776
777
778         // use loader to expand dependencies and sort the
779         // requirements if it is available.
780         if (boot && Y.Loader && args.length) {
781             loader = getLoader(Y);
782             loader.require(args);
783             loader.ignoreRegistered = true;
784             loader.calculate(null, (fetchCSS) ? null : 'js');
785             args = loader.sorted;
786         }
787
788         // process each requirement and any additional requirements
789         // the module metadata specifies
790         process(args);
791
792         len = missing.length;
793
794         if (len) {
795             missing = Y.Object.keys(YArray.hash(missing));
796             len = missing.length;
797         }
798
799         // dynamic load
800         if (boot && len && Y.Loader) {
801             Y._loading = true;
802             loader = getLoader(Y);
803             loader.onEnd = handleLoader;
804             loader.context = Y;
805             loader.data = args;
806             loader.ignoreRegistered = false;
807             loader.require(args);
808             loader.insert(null, (fetchCSS) ? null : 'js');
809             // loader.partial(missing, (fetchCSS) ? null : 'js');
810
811         } else if (len && Y.config.use_rls) {
812
813             // server side loader service
814             Y.Get.script(Y._rls(args), {
815                 onEnd: function(o) {
816                     handleLoader(o);
817                 },
818                 data: args
819             });
820
821         } else if (boot && len && Y.Get && !Env.bootstrapped) {
822
823             Y._loading = true;
824
825             handleBoot = function() {
826                 Y._loading = false;
827                 queue.running = false;
828                 Env.bootstrapped = true;
829                 if (Y._attach(['loader'])) {
830                     Y._use(args, callback);
831                 }
832             };
833
834             if (G_ENV._bootstrapping) {
835                 queue.add(handleBoot);
836             } else {
837                 G_ENV._bootstrapping = true;
838                 Y.Get.script(config.base + config.loaderPath, {
839                     onEnd: handleBoot
840                 });
841             }
842
843         } else {
844             ret = Y._attach(args);
845             if (ret) {
846                 handleLoader();
847             }
848         }
849
850         return Y;
851     },
852
853
854     /**
855      * Returns the namespace specified and creates it if it doesn't exist
856      * <pre>
857      * YUI.namespace("property.package");
858      * YUI.namespace("YAHOO.property.package");
859      * </pre>
860      * Either of the above would create YUI.property, then
861      * YUI.property.package (YAHOO is scrubbed out, this is
862      * to remain compatible with YUI2)
863      *
864      * Be careful when naming packages. Reserved words may work in some browsers
865      * and not others. For instance, the following will fail in Safari:
866      * <pre>
867      * YUI.namespace("really.long.nested.namespace");
868      * </pre>
869      * This fails because "long" is a future reserved word in ECMAScript
870      *
871      * @method namespace
872      * @param  {string*} arguments 1-n namespaces to create.
873      * @return {object}  A reference to the last namespace object created.
874      */
875     namespace: function() {
876         var a = arguments, o = this, i = 0, j, d, arg;
877         for (; i < a.length; i++) {
878             // d = ('' + a[i]).split('.');
879             arg = a[i];
880             if (arg.indexOf(PERIOD)) {
881                 d = arg.split(PERIOD);
882                 for (j = (d[0] == 'YAHOO') ? 1 : 0; j < d.length; j++) {
883                     o[d[j]] = o[d[j]] || {};
884                     o = o[d[j]];
885                 }
886             } else {
887                 o[arg] = o[arg] || {};
888             }
889         }
890         return o;
891     },
892
893     // this is replaced if the log module is included
894     log: NOOP,
895     message: NOOP,
896
897     /**
898      * Report an error.  The reporting mechanism is controled by
899      * the 'throwFail' configuration attribute.  If throwFail is
900      * not specified, the message is written to the Logger, otherwise
901      * a JS error is thrown
902      * @method error
903      * @param msg {string} the error message.
904      * @param e {Error|string} Optional JS error that was caught, or an error string.
905      * @param data Optional additional info
906      * and throwFail is specified, this error will be re-thrown.
907      * @return {YUI} this YUI instance.
908      */
909     error: function(msg, e, data) {
910
911         var Y = this, ret;
912
913         if (Y.config.errorFn) {
914             ret = Y.config.errorFn.apply(Y, arguments);
915         }
916
917         if (Y.config.throwFail && !ret) {
918             throw (e || new Error(msg));
919         } else {
920             Y.message(msg, 'error'); // don't scrub this one
921         }
922
923         return Y;
924     },
925
926     /**
927      * Generate an id that is unique among all YUI instances
928      * @method guid
929      * @param pre {string} optional guid prefix.
930      * @return {string} the guid.
931      */
932     guid: function(pre) {
933         var id = this.Env._guidp + (++this.Env._uidx);
934         return (pre) ? (pre + id) : id;
935     },
936
937     /**
938      * Returns a guid associated with an object.  If the object
939      * does not have one, a new one is created unless readOnly
940      * is specified.
941      * @method stamp
942      * @param o The object to stamp.
943      * @param readOnly {boolean} if true, a valid guid will only
944      * be returned if the object has one assigned to it.
945      * @return {string} The object's guid or null.
946      */
947     stamp: function(o, readOnly) {
948         var uid;
949         if (!o) {
950             return o;
951         }
952
953         // IE generates its own unique ID for dom nodes
954         // The uniqueID property of a document node returns a new ID
955         if (o.uniqueID && o.nodeType && o.nodeType !== 9) {
956             uid = o.uniqueID;
957         } else {
958             uid = (typeof o === 'string') ? o : o._yuid;
959         }
960
961         if (!uid) {
962             uid = this.guid();
963             if (!readOnly) {
964                 try {
965                     o._yuid = uid;
966                 } catch (e) {
967                     uid = null;
968                 }
969             }
970         }
971         return uid;
972     },
973
974     /**
975      * Destroys the YUI instance
976      * @method destroy
977      * @since 3.3.0
978      */
979     destroy: function() {
980         var Y = this;
981         if (Y.Event) {
982             Y.Event._unload();
983         }
984         delete instances[Y.id];
985         delete Y.Env;
986         delete Y.config;
987     }
988
989     /**
990      * instanceof check for objects that works around
991      * memory leak in IE when the item tested is
992      * window/document
993      * @method instanceOf
994      * @since 3.3.0
995      */
996 };
997
998
999
1000     YUI.prototype = proto;
1001
1002     // inheritance utilities are not available yet
1003     for (prop in proto) {
1004         if (proto.hasOwnProperty(prop)) {
1005             YUI[prop] = proto[prop];
1006         }
1007     }
1008
1009     // set up the environment
1010     YUI._init();
1011
1012     if (hasWin) {
1013         // add a window load event at load time so we can capture
1014         // the case where it fires before dynamic loading is
1015         // complete.
1016         add(window, 'load', handleLoad);
1017     } else {
1018         handleLoad();
1019     }
1020
1021     YUI.Env.add = add;
1022     YUI.Env.remove = remove;
1023
1024     /*global exports*/
1025     // Support the CommonJS method for exporting our single global
1026     if (typeof exports == 'object') {
1027         exports.YUI = YUI;
1028     }
1029
1030 }());
1031
1032
1033 /**
1034  * The config object contains all of the configuration options for
1035  * the YUI instance.  This object is supplied by the implementer
1036  * when instantiating a YUI instance.  Some properties have default
1037  * values if they are not supplied by the implementer.  This should
1038  * not be updated directly because some values are cached.  Use
1039  * applyConfig() to update the config object on a YUI instance that
1040  * has already been configured.
1041  *
1042  * @class config
1043  * @static
1044  */
1045
1046 /**
1047  * Allows the YUI seed file to fetch the loader component and library
1048  * metadata to dynamically load additional dependencies.
1049  *
1050  * @property bootstrap
1051  * @type boolean
1052  * @default true
1053  */
1054
1055 /**
1056  * Log to the browser console if debug is on and the browser has a
1057  * supported console.
1058  *
1059  * @property useBrowserConsole
1060  * @type boolean
1061  * @default true
1062  */
1063
1064 /**
1065  * A hash of log sources that should be logged.  If specified, only
1066  * log messages from these sources will be logged.
1067  *
1068  * @property logInclude
1069  * @type object
1070  */
1071
1072 /**
1073  * A hash of log sources that should be not be logged.  If specified,
1074  * all sources are logged if not on this list.
1075  *
1076  * @property logExclude
1077  * @type object
1078  */
1079
1080 /**
1081  * Set to true if the yui seed file was dynamically loaded in
1082  * order to bootstrap components relying on the window load event
1083  * and the 'domready' custom event.
1084  *
1085  * @property injected
1086  * @type boolean
1087  * @default false
1088  */
1089
1090 /**
1091  * If throwFail is set, Y.error will generate or re-throw a JS Error.
1092  * Otherwise the failure is logged.
1093  *
1094  * @property throwFail
1095  * @type boolean
1096  * @default true
1097  */
1098
1099 /**
1100  * The window/frame that this instance should operate in.
1101  *
1102  * @property win
1103  * @type Window
1104  * @default the window hosting YUI
1105  */
1106
1107 /**
1108  * The document associated with the 'win' configuration.
1109  *
1110  * @property doc
1111  * @type Document
1112  * @default the document hosting YUI
1113  */
1114
1115 /**
1116  * A list of modules that defines the YUI core (overrides the default).
1117  *
1118  * @property core
1119  * @type string[]
1120  */
1121
1122 /**
1123  * A list of languages in order of preference. This list is matched against
1124  * the list of available languages in modules that the YUI instance uses to
1125  * determine the best possible localization of language sensitive modules.
1126  * Languages are represented using BCP 47 language tags, such as "en-GB" for
1127  * English as used in the United Kingdom, or "zh-Hans-CN" for simplified
1128  * Chinese as used in China. The list can be provided as a comma-separated
1129  * list or as an array.
1130  *
1131  * @property lang
1132  * @type string|string[]
1133  */
1134
1135 /**
1136  * The default date format
1137  * @property dateFormat
1138  * @type string
1139  * @deprecated use configuration in DataType.Date.format() instead.
1140  */
1141
1142 /**
1143  * The default locale
1144  * @property locale
1145  * @type string
1146  * @deprecated use config.lang instead.
1147  */
1148
1149 /**
1150  * The default interval when polling in milliseconds.
1151  * @property pollInterval
1152  * @type int
1153  * @default 20
1154  */
1155
1156 /**
1157  * The number of dynamic nodes to insert by default before
1158  * automatically removing them.  This applies to script nodes
1159  * because remove the node will not make the evaluated script
1160  * unavailable.  Dynamic CSS is not auto purged, because removing
1161  * a linked style sheet will also remove the style definitions.
1162  * @property purgethreshold
1163  * @type int
1164  * @default 20
1165  */
1166
1167 /**
1168  * The default interval when polling in milliseconds.
1169  * @property windowResizeDelay
1170  * @type int
1171  * @default 40
1172  */
1173
1174 /**
1175  * Base directory for dynamic loading
1176  * @property base
1177  * @type string
1178  */
1179
1180 /*
1181  * The secure base dir (not implemented)
1182  * For dynamic loading.
1183  * @property secureBase
1184  * @type string
1185  */
1186
1187 /**
1188  * The YUI combo service base dir. Ex: http://yui.yahooapis.com/combo?
1189  * For dynamic loading.
1190  * @property comboBase
1191  * @type string
1192  */
1193
1194 /**
1195  * The root path to prepend to module path for the combo service.
1196  * Ex: 3.0.0b1/build/
1197  * For dynamic loading.
1198  * @property root
1199  * @type string
1200  */
1201
1202 /**
1203  * A filter to apply to result urls.  This filter will modify the default
1204  * path for all modules.  The default path for the YUI library is the
1205  * minified version of the files (e.g., event-min.js).  The filter property
1206  * can be a predefined filter or a custom filter.  The valid predefined
1207  * filters are:
1208  * <dl>
1209  *  <dt>DEBUG</dt>
1210  *  <dd>Selects the debug versions of the library (e.g., event-debug.js).
1211  *      This option will automatically include the Logger widget</dd>
1212  *  <dt>RAW</dt>
1213  *  <dd>Selects the non-minified version of the library (e.g., event.js).</dd>
1214  * </dl>
1215  * You can also define a custom filter, which must be an object literal
1216  * containing a search expression and a replace string:
1217  * <pre>
1218  *  myFilter: &#123;
1219  *      'searchExp': "-min\\.js",
1220  *      'replaceStr': "-debug.js"
1221  *  &#125;
1222  * </pre>
1223  *
1224  * For dynamic loading.
1225  *
1226  * @property filter
1227  * @type string|object
1228  */
1229
1230 /**
1231  * The 'skin' config let's you configure application level skin
1232  * customizations.  It contains the following attributes which
1233  * can be specified to override the defaults:
1234  *
1235  *      // The default skin, which is automatically applied if not
1236  *      // overriden by a component-specific skin definition.
1237  *      // Change this in to apply a different skin globally
1238  *      defaultSkin: 'sam',
1239  *
1240  *      // This is combined with the loader base property to get
1241  *      // the default root directory for a skin.
1242  *      base: 'assets/skins/',
1243  *
1244  *      // Any component-specific overrides can be specified here,
1245  *      // making it possible to load different skins for different
1246  *      // components.  It is possible to load more than one skin
1247  *      // for a given component as well.
1248  *      overrides: {
1249  *          slider: ['capsule', 'round']
1250  *      }
1251  *
1252  * For dynamic loading.
1253  *
1254  *  @property skin
1255  */
1256
1257 /**
1258  * Hash of per-component filter specification.  If specified for a given
1259  * component, this overrides the filter config.
1260  *
1261  * For dynamic loading.
1262  *
1263  * @property filters
1264  */
1265
1266 /**
1267  * Use the YUI combo service to reduce the number of http connections
1268  * required to load your dependencies.  Turning this off will
1269  * disable combo handling for YUI and all module groups configured
1270  * with a combo service.
1271  *
1272  * For dynamic loading.
1273  *
1274  * @property combine
1275  * @type boolean
1276  * @default true if 'base' is not supplied, false if it is.
1277  */
1278
1279 /**
1280  * A list of modules that should never be dynamically loaded
1281  *
1282  * @property ignore
1283  * @type string[]
1284  */
1285
1286 /**
1287  * A list of modules that should always be loaded when required, even if already
1288  * present on the page.
1289  *
1290  * @property force
1291  * @type string[]
1292  */
1293
1294 /**
1295  * Node or id for a node that should be used as the insertion point for new
1296  * nodes.  For dynamic loading.
1297  *
1298  * @property insertBefore
1299  * @type string
1300  */
1301
1302 /**
1303  * Object literal containing attributes to add to dynamically loaded script
1304  * nodes.
1305  * @property jsAttributes
1306  * @type string
1307  */
1308
1309 /**
1310  * Object literal containing attributes to add to dynamically loaded link
1311  * nodes.
1312  * @property cssAttributes
1313  * @type string
1314  */
1315
1316 /**
1317  * Number of milliseconds before a timeout occurs when dynamically
1318  * loading nodes. If not set, there is no timeout.
1319  * @property timeout
1320  * @type int
1321  */
1322
1323 /**
1324  * Callback for the 'CSSComplete' event.  When dynamically loading YUI
1325  * components with CSS, this property fires when the CSS is finished
1326  * loading but script loading is still ongoing.  This provides an
1327  * opportunity to enhance the presentation of a loading page a little
1328  * bit before the entire loading process is done.
1329  *
1330  * @property onCSS
1331  * @type function
1332  */
1333
1334 /**
1335  * A hash of module definitions to add to the list of YUI components.
1336  * These components can then be dynamically loaded side by side with
1337  * YUI via the use() method. This is a hash, the key is the module
1338  * name, and the value is an object literal specifying the metdata
1339  * for the module.  * See Loader.addModule for the supported module
1340  * metadata fields.  Also @see groups, which provides a way to
1341  * configure the base and combo spec for a set of modules.
1342  * <code>
1343  * modules: {
1344  * &nbsp; mymod1: {
1345  * &nbsp;   requires: ['node'],
1346  * &nbsp;   fullpath: 'http://myserver.mydomain.com/mymod1/mymod1.js'
1347  * &nbsp; },
1348  * &nbsp; mymod2: {
1349  * &nbsp;   requires: ['mymod1'],
1350  * &nbsp;   fullpath: 'http://myserver.mydomain.com/mymod2/mymod2.js'
1351  * &nbsp; }
1352  * }
1353  * </code>
1354  *
1355  * @property modules
1356  * @type object
1357  */
1358
1359 /**
1360  * A hash of module group definitions.  It for each group you
1361  * can specify a list of modules and the base path and
1362  * combo spec to use when dynamically loading the modules.  @see
1363  * @see modules for the details about the modules part of the
1364  * group definition.
1365  * <code>
1366  * &nbsp; groups: {
1367  * &nbsp;     yui2: {
1368  * &nbsp;         // specify whether or not this group has a combo service
1369  * &nbsp;         combine: true,
1370  * &nbsp;
1371  * &nbsp;         // the base path for non-combo paths
1372  * &nbsp;         base: 'http://yui.yahooapis.com/2.8.0r4/build/',
1373  * &nbsp;
1374  * &nbsp;         // the path to the combo service
1375  * &nbsp;         comboBase: 'http://yui.yahooapis.com/combo?',
1376  * &nbsp;
1377  * &nbsp;         // a fragment to prepend to the path attribute when
1378  * &nbsp;         // when building combo urls
1379  * &nbsp;         root: '2.8.0r4/build/',
1380  * &nbsp;
1381  * &nbsp;         // the module definitions
1382  * &nbsp;         modules:  {
1383  * &nbsp;             yui2_yde: {
1384  * &nbsp;                 path: "yahoo-dom-event/yahoo-dom-event.js"
1385  * &nbsp;             },
1386  * &nbsp;             yui2_anim: {
1387  * &nbsp;                 path: "animation/animation.js",
1388  * &nbsp;                 requires: ['yui2_yde']
1389  * &nbsp;             }
1390  * &nbsp;         }
1391  * &nbsp;     }
1392  * &nbsp; }
1393  * </code>
1394  * @property modules
1395  * @type object
1396  */
1397
1398 /**
1399  * The loader 'path' attribute to the loader itself.  This is combined
1400  * with the 'base' attribute to dynamically load the loader component
1401  * when boostrapping with the get utility alone.
1402  *
1403  * @property loaderPath
1404  * @type string
1405  * @default loader/loader-min.js
1406  */
1407
1408 /**
1409  * Specifies whether or not YUI().use(...) will attempt to load CSS
1410  * resources at all.  Any truthy value will cause CSS dependencies
1411  * to load when fetching script.  The special value 'force' will
1412  * cause CSS dependencies to be loaded even if no script is needed.
1413  *
1414  * @property fetchCSS
1415  * @type boolean|string
1416  * @default true
1417  */
1418
1419 /**
1420  * The default gallery version to build gallery module urls
1421  * @property gallery
1422  * @type string
1423  * @since 3.1.0
1424  */
1425
1426 /**
1427  * The default YUI 2 version to build yui2 module urls.  This is for
1428  * intrinsic YUI 2 support via the 2in3 project.  Also @see the '2in3'
1429  * config for pulling different revisions of the wrapped YUI 2
1430  * modules.
1431  * @since 3.1.0
1432  * @property yui2
1433  * @type string
1434  * @default 2.8.1
1435  */
1436
1437 /**
1438  * The 2in3 project is a deployment of the various versions of YUI 2
1439  * deployed as first-class YUI 3 modules.  Eventually, the wrapper
1440  * for the modules will change (but the underlying YUI 2 code will
1441  * be the same), and you can select a particular version of
1442  * the wrapper modules via this config.
1443  * @since 3.1.0
1444  * @property 2in3
1445  * @type string
1446  * @default 1
1447  */
1448
1449 /**
1450  * Alternative console log function for use in environments without
1451  * a supported native console.  The function is executed in the
1452  * YUI instance context.
1453  * @since 3.1.0
1454  * @property logFn
1455  * @type Function
1456  */
1457
1458 /**
1459  * A callback to execute when Y.error is called.  It receives the
1460  * error message and an javascript error object if Y.error was
1461  * executed because a javascript error was caught.  The function
1462  * is executed in the YUI instance context.
1463  *
1464  * @since 3.2.0
1465  * @property errorFn
1466  * @type Function
1467  */
1468
1469 /**
1470  * A callback to execute when the loader fails to load one or
1471  * more resource.  This could be because of a script load
1472  * failure.  It can also fail if a javascript module fails
1473  * to register itself, but only when the 'requireRegistration'
1474  * is true.  If this function is defined, the use() callback will
1475  * only be called when the loader succeeds, otherwise it always
1476  * executes unless there was a javascript error when attaching
1477  * a module.
1478  *
1479  * @since 3.3.0
1480  * @property loadErrorFn
1481  * @type Function
1482  */
1483
1484 /**
1485  * When set to true, the YUI loader will expect that all modules
1486  * it is responsible for loading will be first-class YUI modules
1487  * that register themselves with the YUI global.  If this is
1488  * set to true, loader will fail if the module registration fails
1489  * to happen after the script is loaded.
1490  *
1491  * @since 3.3.0
1492  * @property requireRegistration
1493  * @type boolean
1494  * @default false
1495  */
1496
1497 /**
1498  * Cache serviced use() requests.
1499  * @since 3.3.0
1500  * @property cacheUse
1501  * @type boolean
1502  * @default true
1503  */
1504
1505 /**
1506  * The parameter defaults for the remote loader service.
1507  * Requires the rls submodule.  The properties that are
1508  * supported:
1509  * <pre>
1510  * m: comma separated list of module requirements.  This
1511  *    must be the param name even for custom implemetations.
1512  * v: the version of YUI to load.  Defaults to the version
1513  *    of YUI that is being used.
1514  * gv: the version of the gallery to load (@see the gallery config)
1515  * env: comma separated list of modules already on the page.
1516  *      this must be the param name even for custom implemetations.
1517  * lang: the languages supported on the page (@see the lang config)
1518  * '2in3v':  the version of the 2in3 wrapper to use (@see the 2in3 config).
1519  * '2v': the version of yui2 to use in the yui 2in3 wrappers
1520  *       (@see the yui2 config)
1521  * filt: a filter def to apply to the urls (@see the filter config).
1522  * filts: a list of custom filters to apply per module
1523  *        (@see the filters config).
1524  * tests: this is a map of conditional module test function id keys
1525  * with the values of 1 if the test passes, 0 if not.  This must be
1526  * the name of the querystring param in custom templates.
1527  *</pre>
1528  *
1529  * @since 3.2.0
1530  * @property rls
1531  */
1532
1533 /**
1534  * The base path to the remote loader service
1535  *
1536  * @since 3.2.0
1537  * @property rls_base
1538  */
1539
1540 /**
1541  * The template to use for building the querystring portion
1542  * of the remote loader service url.  The default is determined
1543  * by the rls config -- each property that has a value will be
1544  * represented.
1545  *
1546  * ex: m={m}&v={v}&env={env}&lang={lang}&filt={filt}&tests={tests}
1547  *
1548  *
1549  * @since 3.2.0
1550  * @property rls_tmpl
1551  */
1552
1553 /**
1554  * Configure the instance to use a remote loader service instead of
1555  * the client loader.
1556  *
1557  * @since 3.2.0
1558  * @property use_rls
1559  */
1560 YUI.add('yui-base', function(Y) {
1561
1562 /*
1563  * YUI stub
1564  * @module yui
1565  * @submodule yui-base
1566  */
1567 /**
1568  * The YUI module contains the components required for building the YUI
1569  * seed file.  This includes the script loading mechanism, a simple queue,
1570  * and the core utilities for the library.
1571  * @module yui
1572  * @submodule yui-base
1573  */
1574
1575 /**
1576  * Provides the language utilites and extensions used by the library
1577  * @class Lang
1578  * @static
1579  */
1580 Y.Lang = Y.Lang || {};
1581
1582 var L = Y.Lang,
1583
1584 ARRAY = 'array',
1585 BOOLEAN = 'boolean',
1586 DATE = 'date',
1587 ERROR = 'error',
1588 FUNCTION = 'function',
1589 NUMBER = 'number',
1590 NULL = 'null',
1591 OBJECT = 'object',
1592 REGEX = 'regexp',
1593 STRING = 'string',
1594 STRING_PROTO = String.prototype,
1595 TOSTRING = Object.prototype.toString,
1596 UNDEFINED = 'undefined',
1597
1598 TYPES = {
1599     'undefined' : UNDEFINED,
1600     'number' : NUMBER,
1601     'boolean' : BOOLEAN,
1602     'string' : STRING,
1603     '[object Function]' : FUNCTION,
1604     '[object RegExp]' : REGEX,
1605     '[object Array]' : ARRAY,
1606     '[object Date]' : DATE,
1607     '[object Error]' : ERROR
1608 },
1609
1610 TRIMREGEX = /^\s+|\s+$/g,
1611 EMPTYSTRING = '',
1612 SUBREGEX = /\{\s*([^\|\}]+?)\s*(?:\|([^\}]*))?\s*\}/g;
1613
1614 /**
1615  * Determines whether or not the provided item is an array.
1616  * Returns false for array-like collections such as the
1617  * function arguments collection or HTMLElement collection
1618  * will return false.  Use <code>Y.Array.test</code> if you
1619  * want to test for an array-like collection.
1620  * @method isArray
1621  * @static
1622  * @param o The object to test.
1623  * @return {boolean} true if o is an array.
1624  */
1625 // L.isArray = Array.isArray || function(o) {
1626 //     return L.type(o) === ARRAY;
1627 // };
1628
1629 L.isArray = function(o) {
1630     return L.type(o) === ARRAY;
1631 };
1632
1633 /**
1634  * Determines whether or not the provided item is a boolean.
1635  * @method isBoolean
1636  * @static
1637  * @param o The object to test.
1638  * @return {boolean} true if o is a boolean.
1639  */
1640 L.isBoolean = function(o) {
1641     return typeof o === BOOLEAN;
1642 };
1643
1644 /**
1645  * <p>
1646  * Determines whether or not the provided item is a function.
1647  * Note: Internet Explorer thinks certain functions are objects:
1648  * </p>
1649  *
1650  * <pre>
1651  * var obj = document.createElement("object");
1652  * Y.Lang.isFunction(obj.getAttribute) // reports false in IE
1653  * &nbsp;
1654  * var input = document.createElement("input"); // append to body
1655  * Y.Lang.isFunction(input.focus) // reports false in IE
1656  * </pre>
1657  *
1658  * <p>
1659  * You will have to implement additional tests if these functions
1660  * matter to you.
1661  * </p>
1662  *
1663  * @method isFunction
1664  * @static
1665  * @param o The object to test.
1666  * @return {boolean} true if o is a function.
1667  */
1668 L.isFunction = function(o) {
1669     return L.type(o) === FUNCTION;
1670 };
1671
1672 /**
1673  * Determines whether or not the supplied item is a date instance.
1674  * @method isDate
1675  * @static
1676  * @param o The object to test.
1677  * @return {boolean} true if o is a date.
1678  */
1679 L.isDate = function(o) {
1680     // return o instanceof Date;
1681     return L.type(o) === DATE && o.toString() !== 'Invalid Date' && !isNaN(o);
1682 };
1683
1684 /**
1685  * Determines whether or not the provided item is null.
1686  * @method isNull
1687  * @static
1688  * @param o The object to test.
1689  * @return {boolean} true if o is null.
1690  */
1691 L.isNull = function(o) {
1692     return o === null;
1693 };
1694
1695 /**
1696  * Determines whether or not the provided item is a legal number.
1697  * @method isNumber
1698  * @static
1699  * @param o The object to test.
1700  * @return {boolean} true if o is a number.
1701  */
1702 L.isNumber = function(o) {
1703     return typeof o === NUMBER && isFinite(o);
1704 };
1705
1706 /**
1707  * Determines whether or not the provided item is of type object
1708  * or function. Note that arrays are also objects, so
1709  * <code>Y.Lang.isObject([]) === true</code>.
1710  * @method isObject
1711  * @static
1712  * @param o The object to test.
1713  * @param failfn {boolean} fail if the input is a function.
1714  * @return {boolean} true if o is an object.
1715  */
1716 L.isObject = function(o, failfn) {
1717     var t = typeof o;
1718     return (o && (t === OBJECT ||
1719         (!failfn && (t === FUNCTION || L.isFunction(o))))) || false;
1720 };
1721
1722 /**
1723  * Determines whether or not the provided item is a string.
1724  * @method isString
1725  * @static
1726  * @param o The object to test.
1727  * @return {boolean} true if o is a string.
1728  */
1729 L.isString = function(o) {
1730     return typeof o === STRING;
1731 };
1732
1733 /**
1734  * Determines whether or not the provided item is undefined.
1735  * @method isUndefined
1736  * @static
1737  * @param o The object to test.
1738  * @return {boolean} true if o is undefined.
1739  */
1740 L.isUndefined = function(o) {
1741     return typeof o === UNDEFINED;
1742 };
1743
1744 /**
1745  * Returns a string without any leading or trailing whitespace.  If
1746  * the input is not a string, the input will be returned untouched.
1747  * @method trim
1748  * @static
1749  * @param s {string} the string to trim.
1750  * @return {string} the trimmed string.
1751  */
1752 L.trim = STRING_PROTO.trim ? function(s) {
1753     return (s && s.trim) ? s.trim() : s;
1754 } : function (s) {
1755     try {
1756         return s.replace(TRIMREGEX, EMPTYSTRING);
1757     } catch (e) {
1758         return s;
1759     }
1760 };
1761
1762 /**
1763  * Returns a string without any leading whitespace.
1764  * @method trimLeft
1765  * @static
1766  * @param s {string} the string to trim.
1767  * @return {string} the trimmed string.
1768  */
1769 L.trimLeft = STRING_PROTO.trimLeft ? function (s) {
1770     return s.trimLeft();
1771 } : function (s) {
1772     return s.replace(/^\s+/, '');
1773 };
1774
1775 /**
1776  * Returns a string without any trailing whitespace.
1777  * @method trimRight
1778  * @static
1779  * @param s {string} the string to trim.
1780  * @return {string} the trimmed string.
1781  */
1782 L.trimRight = STRING_PROTO.trimRight ? function (s) {
1783     return s.trimRight();
1784 } : function (s) {
1785     return s.replace(/\s+$/, '');
1786 };
1787
1788 /**
1789  * A convenience method for detecting a legitimate non-null value.
1790  * Returns false for null/undefined/NaN, true for other values,
1791  * including 0/false/''
1792  * @method isValue
1793  * @static
1794  * @param o The item to test.
1795  * @return {boolean} true if it is not null/undefined/NaN || false.
1796  */
1797 L.isValue = function(o) {
1798     var t = L.type(o);
1799     switch (t) {
1800         case NUMBER:
1801             return isFinite(o);
1802         case NULL:
1803         case UNDEFINED:
1804             return false;
1805         default:
1806             return !!(t);
1807     }
1808 };
1809
1810 /**
1811  * <p>
1812  * Returns a string representing the type of the item passed in.
1813  * </p>
1814  *
1815  * <p>
1816  * Known issues:
1817  * </p>
1818  *
1819  * <ul>
1820  *   <li>
1821  *     <code>typeof HTMLElementCollection</code> returns function in Safari, but
1822  *     <code>Y.type()</code> reports object, which could be a good thing --
1823  *     but it actually caused the logic in <code>Y.Lang.isObject</code> to fail.
1824  *   </li>
1825  * </ul>
1826  *
1827  * @method type
1828  * @param o the item to test.
1829  * @return {string} the detected type.
1830  * @static
1831  */
1832 L.type = function(o) {
1833     return TYPES[typeof o] || TYPES[TOSTRING.call(o)] || (o ? OBJECT : NULL);
1834 };
1835
1836 /**
1837  * Lightweight version of <code>Y.substitute</code>. Uses the same template
1838  * structure as <code>Y.substitute</code>, but doesn't support recursion,
1839  * auto-object coersion, or formats.
1840  * @method sub
1841  * @param {string} s String to be modified.
1842  * @param {object} o Object containing replacement values.
1843  * @return {string} the substitute result.
1844  * @static
1845  * @since 3.2.0
1846  */
1847 L.sub = function(s, o) {
1848     return ((s.replace) ? s.replace(SUBREGEX, function(match, key) {
1849         return (!L.isUndefined(o[key])) ? o[key] : match;
1850     }) : s);
1851 };
1852
1853 /**
1854  * Returns the current time in milliseconds.
1855  * @method now
1856  * @return {int} the current date
1857  * @since 3.3.0
1858  */
1859 L.now = Date.now || function () {
1860   return new Date().getTime();
1861 };
1862
1863 /**
1864  * The YUI module contains the components required for building the YUI seed
1865  * file.  This includes the script loading mechanism, a simple queue, and the
1866  * core utilities for the library.
1867  * @module yui
1868  * @submodule yui-base
1869  */
1870
1871
1872 var Native = Array.prototype, LENGTH = 'length',
1873
1874 /**
1875  * Adds the following array utilities to the YUI instance.  Additional
1876  * array helpers can be found in the collection component.
1877  * @class Array
1878  */
1879
1880 /**
1881  * Y.Array(o) returns an array:
1882  * - Arrays are return unmodified unless the start position is specified.
1883  * - "Array-like" collections (@see Array.test) are converted to arrays
1884  * - For everything else, a new array is created with the input as the sole
1885  *   item.
1886  * - The start position is used if the input is or is like an array to return
1887  *   a subset of the collection.
1888  *
1889  *   @todo this will not automatically convert elements that are also
1890  *   collections such as forms and selects.  Passing true as the third
1891  *   param will force a conversion.
1892  *
1893  * @method ()
1894  * @static
1895  *   @param {object} o the item to arrayify.
1896  *   @param {int} startIdx if an array or array-like, this is the start index.
1897  *   @param {boolean} arraylike if true, it forces the array-like fork.  This
1898  *   can be used to avoid multiple Array.test calls.
1899  *   @return {Array} the resulting array.
1900  */
1901 YArray = function(o, startIdx, arraylike) {
1902     var t = (arraylike) ? 2 : YArray.test(o),
1903         l, a, start = startIdx || 0;
1904
1905     if (t) {
1906         // IE errors when trying to slice HTMLElement collections
1907         try {
1908             return Native.slice.call(o, start);
1909         } catch (e) {
1910             a = [];
1911             l = o.length;
1912             for (; start < l; start++) {
1913                 a.push(o[start]);
1914             }
1915             return a;
1916         }
1917     } else {
1918         return [o];
1919     }
1920 };
1921
1922 Y.Array = YArray;
1923
1924 /**
1925  * Evaluates the input to determine if it is an array, array-like, or
1926  * something else.  This is used to handle the arguments collection
1927  * available within functions, and HTMLElement collections
1928  *
1929  * @method test
1930  * @static
1931  *
1932  * @todo current implementation (intenionally) will not implicitly
1933  * handle html elements that are array-like (forms, selects, etc).
1934  *
1935  * @param {object} o the object to test.
1936  *
1937  * @return {int} a number indicating the results:
1938  * 0: Not an array or an array-like collection
1939  * 1: A real array.
1940  * 2: array-like collection.
1941  */
1942 YArray.test = function(o) {
1943     var r = 0;
1944     if (Y.Lang.isObject(o)) {
1945         if (Y.Lang.isArray(o)) {
1946             r = 1;
1947         } else {
1948             try {
1949                 // indexed, but no tagName (element) or alert (window),
1950                 // or functions without apply/call (Safari
1951                 // HTMLElementCollection bug).
1952                 if ((LENGTH in o) && !o.tagName && !o.alert && !o.apply) {
1953                     r = 2;
1954                 }
1955
1956             } catch (e) {}
1957         }
1958     }
1959     return r;
1960 };
1961
1962 /**
1963  * Executes the supplied function on each item in the array.
1964  * @method each
1965  * @param {Array} a the array to iterate.
1966  * @param {Function} f the function to execute on each item.  The
1967  * function receives three arguments: the value, the index, the full array.
1968  * @param {object} o Optional context object.
1969  * @static
1970  * @return {YUI} the YUI instance.
1971  */
1972 YArray.each = (Native.forEach) ?
1973     function(a, f, o) {
1974         Native.forEach.call(a || [], f, o || Y);
1975         return Y;
1976     } :
1977     function(a, f, o) {
1978         var l = (a && a.length) || 0, i;
1979         for (i = 0; i < l; i = i + 1) {
1980             f.call(o || Y, a[i], i, a);
1981         }
1982         return Y;
1983     };
1984
1985 /**
1986  * Returns an object using the first array as keys, and
1987  * the second as values.  If the second array is not
1988  * provided the value is set to true for each.
1989  * @method hash
1990  * @static
1991  * @param {Array} k keyset.
1992  * @param {Array} v optional valueset.
1993  * @return {object} the hash.
1994  */
1995 YArray.hash = function(k, v) {
1996     var o = {}, l = k.length, vl = v && v.length, i;
1997     for (i = 0; i < l; i = i + 1) {
1998         o[k[i]] = (vl && vl > i) ? v[i] : true;
1999     }
2000
2001     return o;
2002 };
2003
2004 /**
2005  * Returns the index of the first item in the array
2006  * that contains the specified value, -1 if the
2007  * value isn't found.
2008  * @method indexOf
2009  * @static
2010  * @param {Array} a the array to search.
2011  * @param {any} val the value to search for.
2012  * @return {int} the index of the item that contains the value or -1.
2013  */
2014 YArray.indexOf = (Native.indexOf) ?
2015     function(a, val) {
2016         return Native.indexOf.call(a, val);
2017     } :
2018     function(a, val) {
2019         for (var i = 0; i < a.length; i = i + 1) {
2020             if (a[i] === val) {
2021                 return i;
2022             }
2023         }
2024
2025         return -1;
2026     };
2027
2028 /**
2029  * Numeric sort convenience function.
2030  * Y.ArrayAssert.itemsAreEqual([1,2,3], [3,1,2].sort(Y.Array.numericSort));
2031  * @method numericSort
2032  * @static
2033  * @param {number} a a number.
2034  * @param {number} b a number.
2035  */
2036 YArray.numericSort = function(a, b) {
2037     return (a - b);
2038 };
2039
2040 /**
2041  * Executes the supplied function on each item in the array.
2042  * Returning true from the processing function will stop the
2043  * processing of the remaining items.
2044  * @method some
2045  * @param {Array} a the array to iterate.
2046  * @param {Function} f the function to execute on each item. The function
2047  * receives three arguments: the value, the index, the full array.
2048  * @param {object} o Optional context object.
2049  * @static
2050  * @return {boolean} true if the function returns true on
2051  * any of the items in the array.
2052  */
2053 YArray.some = (Native.some) ?
2054     function(a, f, o) {
2055         return Native.some.call(a, f, o);
2056     } :
2057     function(a, f, o) {
2058         var l = a.length, i;
2059         for (i = 0; i < l; i = i + 1) {
2060             if (f.call(o, a[i], i, a)) {
2061                 return true;
2062             }
2063         }
2064         return false;
2065     };
2066
2067 /**
2068  * The YUI module contains the components required for building the YUI
2069  * seed file.  This includes the script loading mechanism, a simple queue,
2070  * and the core utilities for the library.
2071  * @module yui
2072  * @submodule yui-base
2073  */
2074
2075 /**
2076  * A simple FIFO queue.  Items are added to the Queue with add(1..n items) and
2077  * removed using next().
2078  *
2079  * @class Queue
2080  * @constructor
2081  * @param {MIXED} item* 0..n items to seed the queue.
2082  */
2083 function Queue() {
2084     this._init();
2085     this.add.apply(this, arguments);
2086 }
2087
2088 Queue.prototype = {
2089     /**
2090      * Initialize the queue
2091      *
2092      * @method _init
2093      * @protected
2094      */
2095     _init: function() {
2096         /**
2097          * The collection of enqueued items
2098          *
2099          * @property _q
2100          * @type Array
2101          * @protected
2102          */
2103         this._q = [];
2104     },
2105
2106     /**
2107      * Get the next item in the queue. FIFO support
2108      *
2109      * @method next
2110      * @return {MIXED} the next item in the queue.
2111      */
2112     next: function() {
2113         return this._q.shift();
2114     },
2115
2116     /**
2117      * Get the last in the queue. LIFO support.
2118      *
2119      * @method last
2120      * @return {MIXED} the last item in the queue.
2121      */
2122     last: function() {
2123         return this._q.pop();
2124     },
2125
2126     /**
2127      * Add 0..n items to the end of the queue.
2128      *
2129      * @method add
2130      * @param {MIXED} item* 0..n items.
2131      * @return {object} this queue.
2132      */
2133     add: function() {
2134         this._q.push.apply(this._q, arguments);
2135
2136         return this;
2137     },
2138
2139     /**
2140      * Returns the current number of queued items.
2141      *
2142      * @method size
2143      * @return {Number} The size.
2144      */
2145     size: function() {
2146         return this._q.length;
2147     }
2148 };
2149
2150 Y.Queue = Queue;
2151
2152 YUI.Env._loaderQueue = YUI.Env._loaderQueue || new Queue();
2153
2154 /**
2155  * The YUI module contains the components required for building the YUI
2156  * seed file.  This includes the script loading mechanism, a simple queue,
2157  * and the core utilities for the library.
2158  * @module yui
2159  * @submodule yui-base
2160  */
2161
2162 var CACHED_DELIMITER = '__',
2163
2164 /*
2165  * IE will not enumerate native functions in a derived object even if the
2166  * function was overridden.  This is a workaround for specific functions
2167  * we care about on the Object prototype.
2168  * @property _iefix
2169  * @for YUI
2170  * @param {Function} r  the object to receive the augmentation
2171  * @param {Function} s  the object that supplies the properties to augment
2172  * @private
2173  */
2174 _iefix = function(r, s) {
2175     var fn = s.toString;
2176     if (Y.Lang.isFunction(fn) && fn != Object.prototype.toString) {
2177         r.toString = fn;
2178     }
2179 };
2180
2181
2182 /**
2183  * Returns a new object containing all of the properties of
2184  * all the supplied objects.  The properties from later objects
2185  * will overwrite those in earlier objects.  Passing in a
2186  * single object will create a shallow copy of it.  For a deep
2187  * copy, use clone.
2188  * @method merge
2189  * @for YUI
2190  * @param arguments {Object*} the objects to merge.
2191  * @return {object} the new merged object.
2192  */
2193 Y.merge = function() {
2194     var a = arguments, o = {}, i, l = a.length;
2195     for (i = 0; i < l; i = i + 1) {
2196         Y.mix(o, a[i], true);
2197     }
2198     return o;
2199 };
2200
2201 /**
2202  * Applies the supplier's properties to the receiver.  By default
2203  * all prototype and static propertes on the supplier are applied
2204  * to the corresponding spot on the receiver.  By default all
2205  * properties are applied, and a property that is already on the
2206  * reciever will not be overwritten.  The default behavior can
2207  * be modified by supplying the appropriate parameters.
2208  *
2209  * @todo add constants for the modes
2210  *
2211  * @method mix
2212  * @param {Function} r  the object to receive the augmentation.
2213  * @param {Function} s  the object that supplies the properties to augment.
2214  * @param ov {boolean} if true, properties already on the receiver
2215  * will be overwritten if found on the supplier.
2216  * @param wl {string[]} a whitelist.  If supplied, only properties in
2217  * this list will be applied to the receiver.
2218  * @param {int} mode what should be copies, and to where
2219  *        default(0): object to object
2220  *        1: prototype to prototype (old augment)
2221  *        2: prototype to prototype and object props (new augment)
2222  *        3: prototype to object
2223  *        4: object to prototype.
2224  * @param merge {boolean/int} merge objects instead of overwriting/ignoring.
2225  * A value of 2 will skip array merge
2226  * Used by Y.aggregate.
2227  * @return {object} the augmented object.
2228  */
2229 Y.mix = function(r, s, ov, wl, mode, merge) {
2230
2231     if (!s || !r) {
2232         return r || Y;
2233     }
2234
2235     if (mode) {
2236         switch (mode) {
2237             case 1: // proto to proto
2238                 return Y.mix(r.prototype, s.prototype, ov, wl, 0, merge);
2239             case 2: // object to object and proto to proto
2240                 Y.mix(r.prototype, s.prototype, ov, wl, 0, merge);
2241                 break; // pass through
2242             case 3: // proto to static
2243                 return Y.mix(r, s.prototype, ov, wl, 0, merge);
2244             case 4: // static to proto
2245                 return Y.mix(r.prototype, s, ov, wl, 0, merge);
2246             default:  // object to object is what happens below
2247         }
2248     }
2249
2250     // Maybe don't even need this wl && wl.length check anymore??
2251     var i, l, p, type;
2252
2253     if (wl && wl.length) {
2254         for (i = 0, l = wl.length; i < l; ++i) {
2255             p = wl[i];
2256             type = Y.Lang.type(r[p]);
2257             if (s.hasOwnProperty(p)) {
2258                 if (merge && type == 'object') {
2259                     Y.mix(r[p], s[p]);
2260                 } else if (ov || !(p in r)) {
2261                     r[p] = s[p];
2262                 }
2263             }
2264         }
2265     } else {
2266         for (i in s) {
2267             // if (s.hasOwnProperty(i) && !(i in FROZEN)) {
2268             if (s.hasOwnProperty(i)) {
2269                 // check white list if it was supplied
2270                 // if the receiver has this property, it is an object,
2271                 // and merge is specified, merge the two objects.
2272                 if (merge && Y.Lang.isObject(r[i], true)) {
2273                     Y.mix(r[i], s[i], ov, wl, 0, true); // recursive
2274                 // otherwise apply the property only if overwrite
2275                 // is specified or the receiver doesn't have one.
2276                 } else if (ov || !(i in r)) {
2277                     r[i] = s[i];
2278                 }
2279                 // if merge is specified and the receiver is an array,
2280                 // append the array item
2281                 // } else if (arr) {
2282                     // r.push(s[i]);
2283                 // }
2284             }
2285         }
2286
2287         if (Y.UA.ie) {
2288             _iefix(r, s);
2289         }
2290     }
2291
2292     return r;
2293 };
2294
2295 /**
2296  * Returns a wrapper for a function which caches the
2297  * return value of that function, keyed off of the combined
2298  * argument values.
2299  * @method cached
2300  * @param source {function} the function to memoize.
2301  * @param cache an optional cache seed.
2302  * @param refetch if supplied, this value is tested against the cached
2303  * value.  If the values are equal, the wrapped function is executed again.
2304  * @return {Function} the wrapped function.
2305  */
2306 Y.cached = function(source, cache, refetch) {
2307     cache = cache || {};
2308
2309     return function(arg1) {
2310
2311         var k = (arguments.length > 1) ?
2312             Array.prototype.join.call(arguments, CACHED_DELIMITER) : arg1;
2313
2314         if (!(k in cache) || (refetch && cache[k] == refetch)) {
2315             cache[k] = source.apply(source, arguments);
2316         }
2317
2318         return cache[k];
2319     };
2320
2321 };
2322
2323 /**
2324  * The YUI module contains the components required for building the YUI
2325  * seed file.  This includes the script loading mechanism, a simple queue,
2326  * and the core utilities for the library.
2327  * @module yui
2328  * @submodule yui-base
2329  */
2330
2331 /**
2332  * Adds the following Object utilities to the YUI instance
2333  * @class Object
2334  */
2335
2336 /**
2337  * Y.Object(o) returns a new object based upon the supplied object.
2338  * @method ()
2339  * @static
2340  * @param o the supplier object.
2341  * @return {Object} the new object.
2342  */
2343 var F = function() {},
2344
2345 // O = Object.create || function(o) {
2346 //     F.prototype = o;
2347 //     return new F();
2348 // },
2349
2350 O = function(o) {
2351     F.prototype = o;
2352     return new F();
2353 },
2354
2355 owns = function(o, k) {
2356     return o && o.hasOwnProperty && o.hasOwnProperty(k);
2357     // return Object.prototype.hasOwnProperty.call(o, k);
2358 },
2359
2360 UNDEF,
2361
2362 /**
2363  * Extracts the keys, values, or size from an object
2364  *
2365  * @method _extract
2366  * @param o the object.
2367  * @param what what to extract (0: keys, 1: values, 2: size).
2368  * @return {boolean|Array} the extracted info.
2369  * @static
2370  * @private
2371  */
2372 _extract = function(o, what) {
2373     var count = (what === 2), out = (count) ? 0 : [], i;
2374
2375     for (i in o) {
2376         if (owns(o, i)) {
2377             if (count) {
2378                 out++;
2379             } else {
2380                 out.push((what) ? o[i] : i);
2381             }
2382         }
2383     }
2384
2385     return out;
2386 };
2387
2388 Y.Object = O;
2389
2390 /**
2391  * Returns an array containing the object's keys
2392  * @method keys
2393  * @static
2394  * @param o an object.
2395  * @return {string[]} the keys.
2396  */
2397 // O.keys = Object.keys || function(o) {
2398 //     return _extract(o);
2399 // };
2400
2401 O.keys = function(o) {
2402     return _extract(o);
2403 };
2404
2405 /**
2406  * Returns an array containing the object's values
2407  * @method values
2408  * @static
2409  * @param o an object.
2410  * @return {Array} the values.
2411  */
2412 // O.values = Object.values || function(o) {
2413 //     return _extract(o, 1);
2414 // };
2415
2416 O.values = function(o) {
2417     return _extract(o, 1);
2418 };
2419
2420 /**
2421  * Returns the size of an object
2422  * @method size
2423  * @static
2424  * @param o an object.
2425  * @return {int} the size.
2426  */
2427 O.size = Object.size || function(o) {
2428     return _extract(o, 2);
2429 };
2430
2431 /**
2432  * Returns true if the object contains a given key
2433  * @method hasKey
2434  * @static
2435  * @param o an object.
2436  * @param k the key to query.
2437  * @return {boolean} true if the object contains the key.
2438  */
2439 O.hasKey = owns;
2440 /**
2441  * Returns true if the object contains a given value
2442  * @method hasValue
2443  * @static
2444  * @param o an object.
2445  * @param v the value to query.
2446  * @return {boolean} true if the object contains the value.
2447  */
2448 O.hasValue = function(o, v) {
2449     return (Y.Array.indexOf(O.values(o), v) > -1);
2450 };
2451
2452 /**
2453  * Determines whether or not the property was added
2454  * to the object instance.  Returns false if the property is not present
2455  * in the object, or was inherited from the prototype.
2456  *
2457  * @method owns
2458  * @static
2459  * @param o {any} The object being testing.
2460  * @param p {string} the property to look for.
2461  * @return {boolean} true if the object has the property on the instance.
2462  */
2463 O.owns = owns;
2464
2465 /**
2466  * Executes a function on each item. The function
2467  * receives the value, the key, and the object
2468  * as parameters (in that order).
2469  * @method each
2470  * @static
2471  * @param o the object to iterate.
2472  * @param f {Function} the function to execute on each item. The function
2473  * receives three arguments: the value, the the key, the full object.
2474  * @param c the execution context.
2475  * @param proto {boolean} include proto.
2476  * @return {YUI} the YUI instance.
2477  */
2478 O.each = function(o, f, c, proto) {
2479     var s = c || Y, i;
2480
2481     for (i in o) {
2482         if (proto || owns(o, i)) {
2483             f.call(s, o[i], i, o);
2484         }
2485     }
2486     return Y;
2487 };
2488
2489 /**
2490  * Executes a function on each item, but halts if the
2491  * function returns true.  The function
2492  * receives the value, the key, and the object
2493  * as paramters (in that order).
2494  * @method some
2495  * @static
2496  * @param o the object to iterate.
2497  * @param f {Function} the function to execute on each item. The function
2498  * receives three arguments: the value, the the key, the full object.
2499  * @param c the execution context.
2500  * @param proto {boolean} include proto.
2501  * @return {boolean} true if any execution of the function returns true,
2502  * false otherwise.
2503  */
2504 O.some = function(o, f, c, proto) {
2505     var s = c || Y, i;
2506
2507     for (i in o) {
2508         if (proto || owns(o, i)) {
2509             if (f.call(s, o[i], i, o)) {
2510                 return true;
2511             }
2512         }
2513     }
2514     return false;
2515 };
2516
2517 /**
2518  * Retrieves the sub value at the provided path,
2519  * from the value object provided.
2520  *
2521  * @method getValue
2522  * @static
2523  * @param o The object from which to extract the property value.
2524  * @param path {Array} A path array, specifying the object traversal path
2525  * from which to obtain the sub value.
2526  * @return {Any} The value stored in the path, undefined if not found,
2527  * undefined if the source is not an object.  Returns the source object
2528  * if an empty path is provided.
2529  */
2530 O.getValue = function(o, path) {
2531     if (!Y.Lang.isObject(o)) {
2532         return UNDEF;
2533     }
2534
2535     var i,
2536         p = Y.Array(path),
2537         l = p.length;
2538
2539     for (i = 0; o !== UNDEF && i < l; i++) {
2540         o = o[p[i]];
2541     }
2542
2543     return o;
2544 };
2545
2546 /**
2547  * Sets the sub-attribute value at the provided path on the
2548  * value object.  Returns the modified value object, or
2549  * undefined if the path is invalid.
2550  *
2551  * @method setValue
2552  * @static
2553  * @param o             The object on which to set the sub value.
2554  * @param path {Array}  A path array, specifying the object traversal path
2555  *                      at which to set the sub value.
2556  * @param val {Any}     The new value for the sub-attribute.
2557  * @return {Object}     The modified object, with the new sub value set, or
2558  *                      undefined, if the path was invalid.
2559  */
2560 O.setValue = function(o, path, val) {
2561     var i,
2562         p = Y.Array(path),
2563         leafIdx = p.length - 1,
2564         ref = o;
2565
2566     if (leafIdx >= 0) {
2567         for (i = 0; ref !== UNDEF && i < leafIdx; i++) {
2568             ref = ref[p[i]];
2569         }
2570
2571         if (ref !== UNDEF) {
2572             ref[p[i]] = val;
2573         } else {
2574             return UNDEF;
2575         }
2576     }
2577
2578     return o;
2579 };
2580
2581 /**
2582  * Returns true if the object has no properties of its own
2583  * @method isEmpty
2584  * @static
2585  * @return {boolean} true if the object is empty.
2586  * @since 3.2.0
2587  */
2588 O.isEmpty = function(o) {
2589     for (var i in o) {
2590         if (owns(o, i)) {
2591             return false;
2592         }
2593     }
2594     return true;
2595 };
2596 /**
2597  * The YUI module contains the components required for building the YUI seed
2598  * file.  This includes the script loading mechanism, a simple queue, and the
2599  * core utilities for the library.
2600  * @module yui
2601  * @submodule yui-base
2602  */
2603
2604 /**
2605  * YUI user agent detection.
2606  * Do not fork for a browser if it can be avoided.  Use feature detection when
2607  * you can.  Use the user agent as a last resort.  UA stores a version
2608  * number for the browser engine, 0 otherwise.  This value may or may not map
2609  * to the version number of the browser using the engine.  The value is
2610  * presented as a float so that it can easily be used for boolean evaluation
2611  * as well as for looking for a particular range of versions.  Because of this,
2612  * some of the granularity of the version info may be lost (e.g., Gecko 1.8.0.9
2613  * reports 1.8).
2614  * @class UA
2615  * @static
2616  */
2617 /**
2618 * Static method for parsing the UA string. Defaults to assigning it's value to Y.UA
2619 * @static
2620 * @method Env.parseUA
2621 * @param {String} subUA Parse this UA string instead of navigator.userAgent
2622 * @returns {Object} The Y.UA object
2623 */
2624 YUI.Env.parseUA = function(subUA) {
2625     
2626     var numberify = function(s) {
2627             var c = 0;
2628             return parseFloat(s.replace(/\./g, function() {
2629                 return (c++ == 1) ? '' : '.';
2630             }));
2631         },
2632
2633         win = Y.config.win,
2634
2635         nav = win && win.navigator,
2636
2637         o = {
2638
2639         /**
2640          * Internet Explorer version number or 0.  Example: 6
2641          * @property ie
2642          * @type float
2643          * @static
2644          */
2645         ie: 0,
2646
2647         /**
2648          * Opera version number or 0.  Example: 9.2
2649          * @property opera
2650          * @type float
2651          * @static
2652          */
2653         opera: 0,
2654
2655         /**
2656          * Gecko engine revision number.  Will evaluate to 1 if Gecko
2657          * is detected but the revision could not be found. Other browsers
2658          * will be 0.  Example: 1.8
2659          * <pre>
2660          * Firefox 1.0.0.4: 1.7.8   <-- Reports 1.7
2661          * Firefox 1.5.0.9: 1.8.0.9 <-- 1.8
2662          * Firefox 2.0.0.3: 1.8.1.3 <-- 1.81
2663          * Firefox 3.0   <-- 1.9
2664          * Firefox 3.5   <-- 1.91
2665          * </pre>
2666          * @property gecko
2667          * @type float
2668          * @static
2669          */
2670         gecko: 0,
2671
2672         /**
2673          * AppleWebKit version.  KHTML browsers that are not WebKit browsers
2674          * will evaluate to 1, other browsers 0.  Example: 418.9
2675          * <pre>
2676          * Safari 1.3.2 (312.6): 312.8.1 <-- Reports 312.8 -- currently the
2677          *                                   latest available for Mac OSX 10.3.
2678          * Safari 2.0.2:         416     <-- hasOwnProperty introduced
2679          * Safari 2.0.4:         418     <-- preventDefault fixed
2680          * Safari 2.0.4 (419.3): 418.9.1 <-- One version of Safari may run
2681          *                                   different versions of webkit
2682          * Safari 2.0.4 (419.3): 419     <-- Tiger installations that have been
2683          *                                   updated, but not updated
2684          *                                   to the latest patch.
2685          * Webkit 212 nightly:   522+    <-- Safari 3.0 precursor (with native
2686          * SVG and many major issues fixed).
2687          * Safari 3.0.4 (523.12) 523.12  <-- First Tiger release - automatic
2688          * update from 2.x via the 10.4.11 OS patch.
2689          * Webkit nightly 1/2008:525+    <-- Supports DOMContentLoaded event.
2690          *                                   yahoo.com user agent hack removed.
2691          * </pre>
2692          * http://en.wikipedia.org/wiki/Safari_version_history
2693          * @property webkit
2694          * @type float
2695          * @static
2696          */
2697         webkit: 0,
2698
2699         /**
2700          * Chrome will be detected as webkit, but this property will also
2701          * be populated with the Chrome version number
2702          * @property chrome
2703          * @type float
2704          * @static
2705          */
2706         chrome: 0,
2707
2708         /**
2709          * The mobile property will be set to a string containing any relevant
2710          * user agent information when a modern mobile browser is detected.
2711          * Currently limited to Safari on the iPhone/iPod Touch, Nokia N-series
2712          * devices with the WebKit-based browser, and Opera Mini.
2713          * @property mobile
2714          * @type string
2715          * @static
2716          */
2717         mobile: null,
2718
2719         /**
2720          * Adobe AIR version number or 0.  Only populated if webkit is detected.
2721          * Example: 1.0
2722          * @property air
2723          * @type float
2724          */
2725         air: 0,
2726         /**
2727          * Detects Apple iPad's OS version
2728          * @property ipad
2729          * @type float
2730          * @static
2731          */
2732         ipad: 0,
2733         /**
2734          * Detects Apple iPhone's OS version
2735          * @property iphone
2736          * @type float
2737          * @static
2738          */
2739         iphone: 0,
2740         /**
2741          * Detects Apples iPod's OS version
2742          * @property ipod
2743          * @type float
2744          * @static
2745          */
2746         ipod: 0,
2747         /**
2748          * General truthy check for iPad, iPhone or iPod
2749          * @property ios
2750          * @type float
2751          * @static
2752          */
2753         ios: null,
2754         /**
2755          * Detects Googles Android OS version
2756          * @property android
2757          * @type float
2758          * @static
2759          */
2760         android: 0,
2761         /**
2762          * Detects Palms WebOS version
2763          * @property webos
2764          * @type float
2765          * @static
2766          */
2767         webos: 0,
2768
2769         /**
2770          * Google Caja version number or 0.
2771          * @property caja
2772          * @type float
2773          */
2774         caja: nav && nav.cajaVersion,
2775
2776         /**
2777          * Set to true if the page appears to be in SSL
2778          * @property secure
2779          * @type boolean
2780          * @static
2781          */
2782         secure: false,
2783
2784         /**
2785          * The operating system.  Currently only detecting windows or macintosh
2786          * @property os
2787          * @type string
2788          * @static
2789          */
2790         os: null
2791
2792     },
2793
2794     ua = subUA || nav && nav.userAgent,
2795
2796     loc = win && win.location,
2797
2798     href = loc && loc.href,
2799
2800     m;
2801
2802     o.secure = href && (href.toLowerCase().indexOf('https') === 0);
2803
2804     if (ua) {
2805
2806         if ((/windows|win32/i).test(ua)) {
2807             o.os = 'windows';
2808         } else if ((/macintosh/i).test(ua)) {
2809             o.os = 'macintosh';
2810         } else if ((/rhino/i).test(ua)) {
2811             o.os = 'rhino';
2812         }
2813
2814         // Modern KHTML browsers should qualify as Safari X-Grade
2815         if ((/KHTML/).test(ua)) {
2816             o.webkit = 1;
2817         }
2818         // Modern WebKit browsers are at least X-Grade
2819         m = ua.match(/AppleWebKit\/([^\s]*)/);
2820         if (m && m[1]) {
2821             o.webkit = numberify(m[1]);
2822
2823             // Mobile browser check
2824             if (/ Mobile\//.test(ua)) {
2825                 o.mobile = 'Apple'; // iPhone or iPod Touch
2826
2827                 m = ua.match(/OS ([^\s]*)/);
2828                 if (m && m[1]) {
2829                     m = numberify(m[1].replace('_', '.'));
2830                 }
2831                 o.ios = m;
2832                 o.ipad = o.ipod = o.iphone = 0;
2833
2834                 m = ua.match(/iPad|iPod|iPhone/);
2835                 if (m && m[0]) {
2836                     o[m[0].toLowerCase()] = o.ios;
2837                 }
2838             } else {
2839                 m = ua.match(/NokiaN[^\/]*|Android \d\.\d|webOS\/\d\.\d/);
2840                 if (m) {
2841                     // Nokia N-series, Android, webOS, ex: NokiaN95
2842                     o.mobile = m[0];
2843                 }
2844                 if (/webOS/.test(ua)) {
2845                     o.mobile = 'WebOS';
2846                     m = ua.match(/webOS\/([^\s]*);/);
2847                     if (m && m[1]) {
2848                         o.webos = numberify(m[1]);
2849                     }
2850                 }
2851                 if (/ Android/.test(ua)) {
2852                     o.mobile = 'Android';
2853                     m = ua.match(/Android ([^\s]*);/);
2854                     if (m && m[1]) {
2855                         o.android = numberify(m[1]);
2856                     }
2857
2858                 }
2859             }
2860
2861             m = ua.match(/Chrome\/([^\s]*)/);
2862             if (m && m[1]) {
2863                 o.chrome = numberify(m[1]); // Chrome
2864             } else {
2865                 m = ua.match(/AdobeAIR\/([^\s]*)/);
2866                 if (m) {
2867                     o.air = m[0]; // Adobe AIR 1.0 or better
2868                 }
2869             }
2870         }
2871
2872         if (!o.webkit) { // not webkit
2873 // @todo check Opera/8.01 (J2ME/MIDP; Opera Mini/2.0.4509/1316; fi; U; ssr)
2874             m = ua.match(/Opera[\s\/]([^\s]*)/);
2875             if (m && m[1]) {
2876                 o.opera = numberify(m[1]);
2877                 m = ua.match(/Opera Mini[^;]*/);
2878                 if (m) {
2879                     o.mobile = m[0]; // ex: Opera Mini/2.0.4509/1316
2880                 }
2881             } else { // not opera or webkit
2882                 m = ua.match(/MSIE\s([^;]*)/);
2883                 if (m && m[1]) {
2884                     o.ie = numberify(m[1]);
2885                 } else { // not opera, webkit, or ie
2886                     m = ua.match(/Gecko\/([^\s]*)/);
2887                     if (m) {
2888                         o.gecko = 1; // Gecko detected, look for revision
2889                         m = ua.match(/rv:([^\s\)]*)/);
2890                         if (m && m[1]) {
2891                             o.gecko = numberify(m[1]);
2892                         }
2893                     }
2894                 }
2895             }
2896         }
2897     }
2898
2899     YUI.Env.UA = o;
2900
2901     return o;
2902 };
2903
2904
2905 Y.UA = YUI.Env.UA || YUI.Env.parseUA();
2906
2907
2908 }, '3.3.0' );
2909 YUI.add('get', function(Y) {
2910
2911
2912 /**
2913  * Provides a mechanism to fetch remote resources and
2914  * insert them into a document.
2915  * @module yui
2916  * @submodule get
2917  */
2918
2919 var ua = Y.UA,
2920     L = Y.Lang,
2921     TYPE_JS = 'text/javascript',
2922     TYPE_CSS = 'text/css',
2923     STYLESHEET = 'stylesheet';
2924
2925 /**
2926  * Fetches and inserts one or more script or link nodes into the document
2927  * @class Get
2928  * @static
2929  */
2930 Y.Get = function() {
2931
2932     /**
2933      * hash of queues to manage multiple requests
2934      * @property queues
2935      * @private
2936      */
2937     var _get, _purge, _track,
2938
2939     queues = {},
2940
2941     /**
2942      * queue index used to generate transaction ids
2943      * @property qidx
2944      * @type int
2945      * @private
2946      */
2947     qidx = 0,
2948
2949     /**
2950      * interal property used to prevent multiple simultaneous purge
2951      * processes
2952      * @property purging
2953      * @type boolean
2954      * @private
2955      */
2956     purging,
2957
2958
2959     /**
2960      * Generates an HTML element, this is not appended to a document
2961      * @method _node
2962      * @param {string} type the type of element.
2963      * @param {string} attr the attributes.
2964      * @param {Window} win optional window to create the element in.
2965      * @return {HTMLElement} the generated node.
2966      * @private
2967      */
2968     _node = function(type, attr, win) {
2969         var w = win || Y.config.win,
2970             d = w.document,
2971             n = d.createElement(type),
2972             i;
2973
2974         for (i in attr) {
2975             if (attr[i] && attr.hasOwnProperty(i)) {
2976                 n.setAttribute(i, attr[i]);
2977             }
2978         }
2979
2980         return n;
2981     },
2982
2983     /**
2984      * Generates a link node
2985      * @method _linkNode
2986      * @param {string} url the url for the css file.
2987      * @param {Window} win optional window to create the node in.
2988      * @param {object} attributes optional attributes collection to apply to the
2989      * new node.
2990      * @return {HTMLElement} the generated node.
2991      * @private
2992      */
2993     _linkNode = function(url, win, attributes) {
2994         var o = {
2995             id: Y.guid(),
2996             type: TYPE_CSS,
2997             rel: STYLESHEET,
2998             href: url
2999         };
3000         if (attributes) {
3001             Y.mix(o, attributes);
3002         }
3003         return _node('link', o, win);
3004     },
3005
3006     /**
3007      * Generates a script node
3008      * @method _scriptNode
3009      * @param {string} url the url for the script file.
3010      * @param {Window} win optional window to create the node in.
3011      * @param {object} attributes optional attributes collection to apply to the
3012      * new node.
3013      * @return {HTMLElement} the generated node.
3014      * @private
3015      */
3016     _scriptNode = function(url, win, attributes) {
3017         var o = {
3018             id: Y.guid(),
3019             type: TYPE_JS
3020         };
3021
3022         if (attributes) {
3023             Y.mix(o, attributes);
3024         }
3025
3026         o.src = url;
3027
3028         return _node('script', o, win);
3029     },
3030
3031     /**
3032      * Returns the data payload for callback functions.
3033      * @method _returnData
3034      * @param {object} q the queue.
3035      * @param {string} msg the result message.
3036      * @param {string} result the status message from the request.
3037      * @return {object} the state data from the request.
3038      * @private
3039      */
3040     _returnData = function(q, msg, result) {
3041         return {
3042                 tId: q.tId,
3043                 win: q.win,
3044                 data: q.data,
3045                 nodes: q.nodes,
3046                 msg: msg,
3047                 statusText: result,
3048                 purge: function() {
3049                     _purge(this.tId);
3050                 }
3051             };
3052     },
3053
3054     /**
3055      * The transaction is finished
3056      * @method _end
3057      * @param {string} id the id of the request.
3058      * @param {string} msg the result message.
3059      * @param {string} result the status message from the request.
3060      * @private
3061      */
3062     _end = function(id, msg, result) {
3063         var q = queues[id], sc;
3064         if (q && q.onEnd) {
3065             sc = q.context || q;
3066             q.onEnd.call(sc, _returnData(q, msg, result));
3067         }
3068     },
3069
3070     /*
3071      * The request failed, execute fail handler with whatever
3072      * was accomplished.  There isn't a failure case at the
3073      * moment unless you count aborted transactions
3074      * @method _fail
3075      * @param {string} id the id of the request
3076      * @private
3077      */
3078     _fail = function(id, msg) {
3079
3080         var q = queues[id], sc;
3081         if (q.timer) {
3082             // q.timer.cancel();
3083             clearTimeout(q.timer);
3084         }
3085
3086         // execute failure callback
3087         if (q.onFailure) {
3088             sc = q.context || q;
3089             q.onFailure.call(sc, _returnData(q, msg));
3090         }
3091
3092         _end(id, msg, 'failure');
3093     },
3094
3095     /**
3096      * The request is complete, so executing the requester's callback
3097      * @method _finish
3098      * @param {string} id the id of the request.
3099      * @private
3100      */
3101     _finish = function(id) {
3102         var q = queues[id], msg, sc;
3103         if (q.timer) {
3104             // q.timer.cancel();
3105             clearTimeout(q.timer);
3106         }
3107         q.finished = true;
3108
3109         if (q.aborted) {
3110             msg = 'transaction ' + id + ' was aborted';
3111             _fail(id, msg);
3112             return;
3113         }
3114
3115         // execute success callback
3116         if (q.onSuccess) {
3117             sc = q.context || q;
3118             q.onSuccess.call(sc, _returnData(q));
3119         }
3120
3121         _end(id, msg, 'OK');
3122     },
3123
3124     /**
3125      * Timeout detected
3126      * @method _timeout
3127      * @param {string} id the id of the request.
3128      * @private
3129      */
3130     _timeout = function(id) {
3131         var q = queues[id], sc;
3132         if (q.onTimeout) {
3133             sc = q.context || q;
3134             q.onTimeout.call(sc, _returnData(q));
3135         }
3136
3137         _end(id, 'timeout', 'timeout');
3138     },
3139
3140
3141     /**
3142      * Loads the next item for a given request
3143      * @method _next
3144      * @param {string} id the id of the request.
3145      * @param {string} loaded the url that was just loaded, if any.
3146      * @return {string} the result.
3147      * @private
3148      */
3149     _next = function(id, loaded) {
3150         var q = queues[id], msg, w, d, h, n, url, s,
3151             insertBefore;
3152
3153         if (q.timer) {
3154             // q.timer.cancel();
3155             clearTimeout(q.timer);
3156         }
3157
3158         if (q.aborted) {
3159             msg = 'transaction ' + id + ' was aborted';
3160             _fail(id, msg);
3161             return;
3162         }
3163
3164         if (loaded) {
3165             q.url.shift();
3166             if (q.varName) {
3167                 q.varName.shift();
3168             }
3169         } else {
3170             // This is the first pass: make sure the url is an array
3171             q.url = (L.isString(q.url)) ? [q.url] : q.url;
3172             if (q.varName) {
3173                 q.varName = (L.isString(q.varName)) ? [q.varName] : q.varName;
3174             }
3175         }
3176
3177         w = q.win;
3178         d = w.document;
3179         h = d.getElementsByTagName('head')[0];
3180
3181         if (q.url.length === 0) {
3182             _finish(id);
3183             return;
3184         }
3185
3186         url = q.url[0];
3187
3188         // if the url is undefined, this is probably a trailing comma
3189         // problem in IE.
3190         if (!url) {
3191             q.url.shift();
3192             return _next(id);
3193         }
3194
3195
3196         if (q.timeout) {
3197             // q.timer = L.later(q.timeout, q, _timeout, id);
3198             q.timer = setTimeout(function() {
3199                 _timeout(id);
3200             }, q.timeout);
3201         }
3202
3203         if (q.type === 'script') {
3204             n = _scriptNode(url, w, q.attributes);
3205         } else {
3206             n = _linkNode(url, w, q.attributes);
3207         }
3208
3209         // track this node's load progress
3210         _track(q.type, n, id, url, w, q.url.length);
3211
3212         // add the node to the queue so we can return it to the user supplied
3213         // callback
3214         q.nodes.push(n);
3215
3216         // add it to the head or insert it before 'insertBefore'.  Work around
3217         // IE bug if there is a base tag.
3218         insertBefore = q.insertBefore ||
3219                        d.getElementsByTagName('base')[0];
3220
3221         if (insertBefore) {
3222             s = _get(insertBefore, id);
3223             if (s) {
3224                 s.parentNode.insertBefore(n, s);
3225             }
3226         } else {
3227             h.appendChild(n);
3228         }
3229
3230
3231         // FireFox does not support the onload event for link nodes, so
3232         // there is no way to make the css requests synchronous. This means
3233         // that the css rules in multiple files could be applied out of order
3234         // in this browser if a later request returns before an earlier one.
3235         // Safari too.
3236         if ((ua.webkit || ua.gecko) && q.type === 'css') {
3237             _next(id, url);
3238         }
3239     },
3240
3241     /**
3242      * Removes processed queues and corresponding nodes
3243      * @method _autoPurge
3244      * @private
3245      */
3246     _autoPurge = function() {
3247         if (purging) {
3248             return;
3249         }
3250         purging = true;
3251
3252         var i, q;
3253
3254         for (i in queues) {
3255             if (queues.hasOwnProperty(i)) {
3256                 q = queues[i];
3257                 if (q.autopurge && q.finished) {
3258                     _purge(q.tId);
3259                     delete queues[i];
3260                 }
3261             }
3262         }
3263
3264         purging = false;
3265     },
3266
3267     /**
3268      * Saves the state for the request and begins loading
3269      * the requested urls
3270      * @method queue
3271      * @param {string} type the type of node to insert.
3272      * @param {string} url the url to load.
3273      * @param {object} opts the hash of options for this request.
3274      * @return {object} transaction object.
3275      * @private
3276      */
3277     _queue = function(type, url, opts) {
3278         opts = opts || {};
3279
3280         var id = 'q' + (qidx++), q,
3281             thresh = opts.purgethreshold || Y.Get.PURGE_THRESH;
3282
3283         if (qidx % thresh === 0) {
3284             _autoPurge();
3285         }
3286
3287         queues[id] = Y.merge(opts, {
3288             tId: id,
3289             type: type,
3290             url: url,
3291             finished: false,
3292             nodes: []
3293         });
3294
3295         q = queues[id];
3296         q.win = q.win || Y.config.win;
3297         q.context = q.context || q;
3298         q.autopurge = ('autopurge' in q) ? q.autopurge :
3299                       (type === 'script') ? true : false;
3300
3301         q.attributes = q.attributes || {};
3302         q.attributes.charset = opts.charset || q.attributes.charset || 'utf-8';
3303
3304         _next(id);
3305
3306         return {
3307             tId: id
3308         };
3309     };
3310
3311     /**
3312      * Detects when a node has been loaded.  In the case of
3313      * script nodes, this does not guarantee that contained
3314      * script is ready to use.
3315      * @method _track
3316      * @param {string} type the type of node to track.
3317      * @param {HTMLElement} n the node to track.
3318      * @param {string} id the id of the request.
3319      * @param {string} url the url that is being loaded.
3320      * @param {Window} win the targeted window.
3321      * @param {int} qlength the number of remaining items in the queue,
3322      * including this one.
3323      * @param {Function} trackfn function to execute when finished
3324      * the default is _next.
3325      * @private
3326      */
3327     _track = function(type, n, id, url, win, qlength, trackfn) {
3328         var f = trackfn || _next;
3329
3330         // IE supports the readystatechange event for script and css nodes
3331         // Opera only for script nodes.  Opera support onload for script
3332         // nodes, but this doesn't fire when there is a load failure.
3333         // The onreadystatechange appears to be a better way to respond
3334         // to both success and failure.
3335         if (ua.ie) {
3336             n.onreadystatechange = function() {
3337                 var rs = this.readyState;
3338                 if ('loaded' === rs || 'complete' === rs) {
3339                     n.onreadystatechange = null;
3340                     f(id, url);
3341                 }
3342             };
3343
3344         // webkit prior to 3.x is no longer supported
3345         } else if (ua.webkit) {
3346             if (type === 'script') {
3347                 // Safari 3.x supports the load event for script nodes (DOM2)
3348                 n.addEventListener('load', function() {
3349                     f(id, url);
3350                 });
3351             }
3352
3353         // FireFox and Opera support onload (but not DOM2 in FF) handlers for
3354         // script nodes.  Opera, but not FF, supports the onload event for link
3355         // nodes.
3356         } else {
3357             n.onload = function() {
3358                 f(id, url);
3359             };
3360
3361             n.onerror = function(e) {
3362                 _fail(id, e + ': ' + url);
3363             };
3364         }
3365     };
3366
3367     _get = function(nId, tId) {
3368         var q = queues[tId],
3369             n = (L.isString(nId)) ? q.win.document.getElementById(nId) : nId;
3370         if (!n) {
3371             _fail(tId, 'target node not found: ' + nId);
3372         }
3373
3374         return n;
3375     };
3376
3377     /**
3378      * Removes the nodes for the specified queue
3379      * @method _purge
3380      * @param {string} tId the transaction id.
3381      * @private
3382      */
3383     _purge = function(tId) {
3384         var n, l, d, h, s, i, node, attr, insertBefore,
3385             q = queues[tId];
3386
3387         if (q) {
3388             n = q.nodes;
3389             l = n.length;
3390             d = q.win.document;
3391             h = d.getElementsByTagName('head')[0];
3392
3393             insertBefore = q.insertBefore ||
3394                            d.getElementsByTagName('base')[0];
3395
3396             if (insertBefore) {
3397                 s = _get(insertBefore, tId);
3398                 if (s) {
3399                     h = s.parentNode;
3400                 }
3401             }
3402
3403             for (i = 0; i < l; i = i + 1) {
3404                 node = n[i];
3405                 if (node.clearAttributes) {
3406                     node.clearAttributes();
3407                 } else {
3408                     for (attr in node) {
3409                         if (node.hasOwnProperty(attr)) {
3410                             delete node[attr];
3411                         }
3412                     }
3413                 }
3414
3415                 h.removeChild(node);
3416             }
3417         }
3418         q.nodes = [];
3419     };
3420
3421     return {
3422
3423         /**
3424          * The number of request required before an automatic purge.
3425          * Can be configured via the 'purgethreshold' config
3426          * property PURGE_THRESH
3427          * @static
3428          * @type int
3429          * @default 20
3430          * @private
3431          */
3432         PURGE_THRESH: 20,
3433
3434         /**
3435          * Called by the the helper for detecting script load in Safari
3436          * @method _finalize
3437          * @static
3438          * @param {string} id the transaction id.
3439          * @private
3440          */
3441         _finalize: function(id) {
3442             setTimeout(function() {
3443                 _finish(id);
3444             }, 0);
3445         },
3446
3447         /**
3448          * Abort a transaction
3449          * @method abort
3450          * @static
3451          * @param {string|object} o Either the tId or the object returned from
3452          * script() or css().
3453          */
3454         abort: function(o) {
3455             var id = (L.isString(o)) ? o : o.tId,
3456                 q = queues[id];
3457             if (q) {
3458                 q.aborted = true;
3459             }
3460         },
3461
3462         /**
3463          * Fetches and inserts one or more script nodes into the head
3464          * of the current document or the document in a specified window.
3465          *
3466          * @method script
3467          * @static
3468          * @param {string|string[]} url the url or urls to the script(s).
3469          * @param {object} opts Options:
3470          * <dl>
3471          * <dt>onSuccess</dt>
3472          * <dd>
3473          * callback to execute when the script(s) are finished loading
3474          * The callback receives an object back with the following
3475          * data:
3476          * <dl>
3477          * <dt>win</dt>
3478          * <dd>the window the script(s) were inserted into</dd>
3479          * <dt>data</dt>
3480          * <dd>the data object passed in when the request was made</dd>
3481          * <dt>nodes</dt>
3482          * <dd>An array containing references to the nodes that were
3483          * inserted</dd>
3484          * <dt>purge</dt>
3485          * <dd>A function that, when executed, will remove the nodes
3486          * that were inserted</dd>
3487          * <dt>
3488          * </dl>
3489          * </dd>
3490          * <dt>onTimeout</dt>
3491          * <dd>
3492          * callback to execute when a timeout occurs.
3493          * The callback receives an object back with the following
3494          * data:
3495          * <dl>
3496          * <dt>win</dt>
3497          * <dd>the window the script(s) were inserted into</dd>
3498          * <dt>data</dt>
3499          * <dd>the data object passed in when the request was made</dd>
3500          * <dt>nodes</dt>
3501          * <dd>An array containing references to the nodes that were
3502          * inserted</dd>
3503          * <dt>purge</dt>
3504          * <dd>A function that, when executed, will remove the nodes
3505          * that were inserted</dd>
3506          * <dt>
3507          * </dl>
3508          * </dd>
3509          * <dt>onEnd</dt>
3510          * <dd>a function that executes when the transaction finishes,
3511          * regardless of the exit path</dd>
3512          * <dt>onFailure</dt>
3513          * <dd>
3514          * callback to execute when the script load operation fails
3515          * The callback receives an object back with the following
3516          * data:
3517          * <dl>
3518          * <dt>win</dt>
3519          * <dd>the window the script(s) were inserted into</dd>
3520          * <dt>data</dt>
3521          * <dd>the data object passed in when the request was made</dd>
3522          * <dt>nodes</dt>
3523          * <dd>An array containing references to the nodes that were
3524          * inserted successfully</dd>
3525          * <dt>purge</dt>
3526          * <dd>A function that, when executed, will remove any nodes
3527          * that were inserted</dd>
3528          * <dt>
3529          * </dl>
3530          * </dd>
3531          * <dt>context</dt>
3532          * <dd>the execution context for the callbacks</dd>
3533          * <dt>win</dt>
3534          * <dd>a window other than the one the utility occupies</dd>
3535          * <dt>autopurge</dt>
3536          * <dd>
3537          * setting to true will let the utilities cleanup routine purge
3538          * the script once loaded
3539          * </dd>
3540          * <dt>purgethreshold</dt>
3541          * <dd>
3542          * The number of transaction before autopurge should be initiated
3543          * </dd>
3544          * <dt>data</dt>
3545          * <dd>
3546          * data that is supplied to the callback when the script(s) are
3547          * loaded.
3548          * </dd>
3549          * <dt>insertBefore</dt>
3550          * <dd>node or node id that will become the new node's nextSibling.
3551          * If this is not specified, nodes will be inserted before a base
3552          * tag should it exist.  Otherwise, the nodes will be appended to the
3553          * end of the document head.</dd>
3554          * </dl>
3555          * <dt>charset</dt>
3556          * <dd>Node charset, default utf-8 (deprecated, use the attributes
3557          * config)</dd>
3558          * <dt>attributes</dt>
3559          * <dd>An object literal containing additional attributes to add to
3560          * the link tags</dd>
3561          * <dt>timeout</dt>
3562          * <dd>Number of milliseconds to wait before aborting and firing
3563          * the timeout event</dd>
3564          * <pre>
3565          * &nbsp; Y.Get.script(
3566          * &nbsp; ["http://yui.yahooapis.com/2.5.2/build/yahoo/yahoo-min.js",
3567          * &nbsp;  "http://yui.yahooapis.com/2.5.2/build/event/event-min.js"],
3568          * &nbsp; &#123;
3569          * &nbsp;   onSuccess: function(o) &#123;
3570          * &nbsp;     this.log("won't cause error because Y is the context");
3571          * &nbsp;                   // immediately
3572          * &nbsp;   &#125;,
3573          * &nbsp;   onFailure: function(o) &#123;
3574          * &nbsp;   &#125;,
3575          * &nbsp;   onTimeout: function(o) &#123;
3576          * &nbsp;   &#125;,
3577          * &nbsp;   data: "foo",
3578          * &nbsp;   timeout: 10000, // 10 second timeout
3579          * &nbsp;   context: Y, // make the YUI instance
3580          * &nbsp;   // win: otherframe // target another window/frame
3581          * &nbsp;   autopurge: true // allow the utility to choose when to
3582          * &nbsp;                   // remove the nodes
3583          * &nbsp;   purgetheshold: 1 // purge previous transaction before
3584          * &nbsp;                    // next transaction
3585          * &nbsp; &#125;);.
3586          * </pre>
3587          * @return {tId: string} an object containing info about the
3588          * transaction.
3589          */
3590         script: function(url, opts) {
3591             return _queue('script', url, opts);
3592         },
3593
3594         /**
3595          * Fetches and inserts one or more css link nodes into the
3596          * head of the current document or the document in a specified
3597          * window.
3598          * @method css
3599          * @static
3600          * @param {string} url the url or urls to the css file(s).
3601          * @param {object} opts Options:
3602          * <dl>
3603          * <dt>onSuccess</dt>
3604          * <dd>
3605          * callback to execute when the css file(s) are finished loading
3606          * The callback receives an object back with the following
3607          * data:
3608          * <dl>win</dl>
3609          * <dd>the window the link nodes(s) were inserted into</dd>
3610          * <dt>data</dt>
3611          * <dd>the data object passed in when the request was made</dd>
3612          * <dt>nodes</dt>
3613          * <dd>An array containing references to the nodes that were
3614          * inserted</dd>
3615          * <dt>purge</dt>
3616          * <dd>A function that, when executed, will remove the nodes
3617          * that were inserted</dd>
3618          * <dt>
3619          * </dl>
3620          * </dd>
3621          * <dt>context</dt>
3622          * <dd>the execution context for the callbacks</dd>
3623          * <dt>win</dt>
3624          * <dd>a window other than the one the utility occupies</dd>
3625          * <dt>data</dt>
3626          * <dd>
3627          * data that is supplied to the callbacks when the nodes(s) are
3628          * loaded.
3629          * </dd>
3630          * <dt>insertBefore</dt>
3631          * <dd>node or node id that will become the new node's nextSibling</dd>
3632          * <dt>charset</dt>
3633          * <dd>Node charset, default utf-8 (deprecated, use the attributes
3634          * config)</dd>
3635          * <dt>attributes</dt>
3636          * <dd>An object literal containing additional attributes to add to
3637          * the link tags</dd>
3638          * </dl>
3639          * <pre>
3640          * Y.Get.css("http://localhost/css/menu.css");
3641          * </pre>
3642          * <pre>
3643          * &nbsp; Y.Get.css(
3644          * &nbsp; ["http://localhost/css/menu.css",
3645          * &nbsp;   insertBefore: 'custom-styles' // nodes will be inserted
3646          * &nbsp;                                 // before the specified node
3647          * &nbsp; &#125;);.
3648          * </pre>
3649          * @return {tId: string} an object containing info about the
3650          * transaction.
3651          */
3652         css: function(url, opts) {
3653             return _queue('css', url, opts);
3654         }
3655     };
3656 }();
3657
3658
3659
3660 }, '3.3.0' ,{requires:['yui-base']});
3661 YUI.add('features', function(Y) {
3662
3663 var feature_tests = {};
3664
3665 Y.mix(Y.namespace('Features'), {
3666
3667     tests: feature_tests,
3668
3669     add: function(cat, name, o) {
3670         feature_tests[cat] = feature_tests[cat] || {};
3671         feature_tests[cat][name] = o;
3672     },
3673
3674     all: function(cat, args) {
3675         var cat_o = feature_tests[cat],
3676             // results = {};
3677             result = '';
3678         if (cat_o) {
3679             Y.Object.each(cat_o, function(v, k) {
3680                 // results[k] = Y.Features.test(cat, k, args);
3681                 result += k + ':' +
3682                        (Y.Features.test(cat, k, args) ? 1 : 0) + ';';
3683             });
3684         }
3685
3686         return result;
3687     },
3688
3689     test: function(cat, name, args) {
3690         args = args || [];
3691         var result, ua, test,
3692             cat_o = feature_tests[cat],
3693             feature = cat_o && cat_o[name];
3694
3695         if (!feature) {
3696         } else {
3697
3698             result = feature.result;
3699
3700             if (Y.Lang.isUndefined(result)) {
3701
3702                 ua = feature.ua;
3703                 if (ua) {
3704                     result = (Y.UA[ua]);
3705                 }
3706
3707                 test = feature.test;
3708                 if (test && ((!ua) || result)) {
3709                     result = test.apply(Y, args);
3710                 }
3711
3712                 feature.result = result;
3713             }
3714         }
3715
3716         return result;
3717     }
3718 });
3719
3720 // Y.Features.add("load", "1", {});
3721 // Y.Features.test("load", "1");
3722 // caps=1:1;2:0;3:1;
3723
3724 /* This file is auto-generated by src/loader/meta_join.py */
3725 var add = Y.Features.add;
3726 // autocomplete-list-keys-sniff.js
3727 add('load', '0', {
3728     "test": function (Y) {
3729     // Only add keyboard support to autocomplete-list if this doesn't appear to
3730     // be an iOS or Android-based mobile device.
3731     //
3732     // There's currently no feasible way to actually detect whether a device has
3733     // a hardware keyboard, so this sniff will have to do. It can easily be
3734     // overridden by manually loading the autocomplete-list-keys module.
3735     //
3736     // Worth noting: even though iOS supports bluetooth keyboards, Mobile Safari
3737     // doesn't fire the keyboard events used by AutoCompleteList, so there's
3738     // no point loading the -keys module even when a bluetooth keyboard may be
3739     // available.
3740     return !(Y.UA.ios || Y.UA.android);
3741 }, 
3742     "trigger": "autocomplete-list"
3743 });
3744 // ie-style-test.js
3745 add('load', '1', {
3746     "test": function (Y) {
3747
3748     var testFeature = Y.Features.test,
3749         addFeature = Y.Features.add,
3750         WINDOW = Y.config.win,
3751         DOCUMENT = Y.config.doc,
3752         DOCUMENT_ELEMENT = 'documentElement',
3753         ret = false;
3754
3755     addFeature('style', 'computedStyle', {
3756         test: function() {
3757             return WINDOW && 'getComputedStyle' in WINDOW;
3758         }
3759     });
3760
3761     addFeature('style', 'opacity', {
3762         test: function() {
3763             return DOCUMENT && 'opacity' in DOCUMENT[DOCUMENT_ELEMENT].style;
3764         }
3765     });
3766
3767     ret =  (!testFeature('style', 'opacity') &&
3768             !testFeature('style', 'computedStyle'));
3769
3770     return ret;
3771 }, 
3772     "trigger": "dom-style"
3773 });
3774 // 0
3775 add('load', '2', {
3776     "trigger": "widget-base", 
3777     "ua": "ie"
3778 });
3779 // ie-base-test.js
3780 add('load', '3', {
3781     "test": function(Y) {
3782     var imp = Y.config.doc && Y.config.doc.implementation;
3783     return (imp && (!imp.hasFeature('Events', '2.0')));
3784 }, 
3785     "trigger": "node-base"
3786 });
3787 // dd-gestures-test.js
3788 add('load', '4', {
3789     "test": function(Y) {
3790     return (Y.config.win && ('ontouchstart' in Y.config.win && !Y.UA.chrome));
3791 }, 
3792     "trigger": "dd-drag"
3793 });
3794 // history-hash-ie-test.js
3795 add('load', '5', {
3796     "test": function (Y) {
3797     var docMode = Y.config.doc.documentMode;
3798
3799     return Y.UA.ie && (!('onhashchange' in Y.config.win) ||
3800             !docMode || docMode < 8);
3801 }, 
3802     "trigger": "history-hash"
3803 });
3804
3805
3806 }, '3.3.0' ,{requires:['yui-base']});
3807 YUI.add('rls', function(Y) {
3808
3809 /**
3810  * Implentation for building the remote loader service url.
3811  * @method _rls
3812  * @param {Array} what the requested modules.
3813  * @since 3.2.0
3814  * @return {string} the url for the remote loader service call.
3815  */
3816 Y._rls = function(what) {
3817
3818     var config = Y.config,
3819
3820         // the configuration
3821         rls = config.rls || {
3822             m: 1, // required in the template
3823             v: Y.version,
3824             gv: config.gallery,
3825             env: 1, // required in the template
3826             lang: config.lang,
3827             '2in3v': config['2in3'],
3828             '2v': config.yui2,
3829             filt: config.filter,
3830             filts: config.filters,
3831             tests: 1 // required in the template
3832         },
3833
3834         // The rls base path
3835         rls_base = config.rls_base || 'load?',
3836
3837         // the template
3838         rls_tmpl = config.rls_tmpl || function() {
3839             var s = '', param;
3840             for (param in rls) {
3841                 if (param in rls && rls[param]) {
3842                     s += param + '={' + param + '}&';
3843                 }
3844             }
3845             // console.log('rls_tmpl: ' + s);
3846             return s;
3847         }(),
3848
3849         url;
3850
3851     // update the request
3852     rls.m = what;
3853     rls.env = Y.Object.keys(YUI.Env.mods);
3854     rls.tests = Y.Features.all('load', [Y]);
3855
3856     url = Y.Lang.sub(rls_base + rls_tmpl, rls);
3857
3858     config.rls = rls;
3859     config.rls_tmpl = rls_tmpl;
3860
3861     // console.log(url);
3862     return url;
3863 };
3864
3865
3866
3867 }, '3.3.0' ,{requires:['get','features']});
3868 YUI.add('intl-base', function(Y) {
3869
3870 /**
3871  * The Intl utility provides a central location for managing sets of
3872  * localized resources (strings and formatting patterns).
3873  *
3874  * @class Intl
3875  * @uses EventTarget
3876  * @static
3877  */
3878
3879 var SPLIT_REGEX = /[, ]/;
3880
3881 Y.mix(Y.namespace('Intl'), {
3882
3883  /**
3884     * Returns the language among those available that
3885     * best matches the preferred language list, using the Lookup
3886     * algorithm of BCP 47.
3887     * If none of the available languages meets the user's preferences,
3888     * then "" is returned.
3889     * Extended language ranges are not supported.
3890     *
3891     * @method lookupBestLang
3892     * @param {String[] | String} preferredLanguages The list of preferred
3893     * languages in descending preference order, represented as BCP 47
3894     * language tags. A string array or a comma-separated list.
3895     * @param {String[]} availableLanguages The list of languages
3896     * that the application supports, represented as BCP 47 language
3897     * tags.
3898     *
3899     * @return {String} The available language that best matches the
3900     * preferred language list, or "".
3901     * @since 3.1.0
3902     */
3903     lookupBestLang: function(preferredLanguages, availableLanguages) {
3904
3905         var i, language, result, index;
3906
3907         // check whether the list of available languages contains language;
3908         // if so return it
3909         function scan(language) {
3910             var i;
3911             for (i = 0; i < availableLanguages.length; i += 1) {
3912                 if (language.toLowerCase() ===
3913                             availableLanguages[i].toLowerCase()) {
3914                     return availableLanguages[i];
3915                 }
3916             }
3917         }
3918
3919         if (Y.Lang.isString(preferredLanguages)) {
3920             preferredLanguages = preferredLanguages.split(SPLIT_REGEX);
3921         }
3922
3923         for (i = 0; i < preferredLanguages.length; i += 1) {
3924             language = preferredLanguages[i];
3925             if (!language || language === '*') {
3926                 continue;
3927             }
3928             // check the fallback sequence for one language
3929             while (language.length > 0) {
3930                 result = scan(language);
3931                 if (result) {
3932                     return result;
3933                 } else {
3934                     index = language.lastIndexOf('-');
3935                     if (index >= 0) {
3936                         language = language.substring(0, index);
3937                         // one-character subtags get cut along with the
3938                         // following subtag
3939                         if (index >= 2 && language.charAt(index - 2) === '-') {
3940                             language = language.substring(0, index - 2);
3941                         }
3942                     } else {
3943                         // nothing available for this language
3944                         break;
3945                     }
3946                 }
3947             }
3948         }
3949
3950         return '';
3951     }
3952 });
3953
3954
3955 }, '3.3.0' ,{requires:['yui-base']});
3956 YUI.add('yui-log', function(Y) {
3957
3958 /**
3959  * Provides console log capability and exposes a custom event for
3960  * console implementations.
3961  * @module yui
3962  * @submodule yui-log
3963  */
3964
3965 var INSTANCE = Y,
3966     LOGEVENT = 'yui:log',
3967     UNDEFINED = 'undefined',
3968     LEVELS = { debug: 1,
3969                info: 1,
3970                warn: 1,
3971                error: 1 };
3972
3973 /**
3974  * If the 'debug' config is true, a 'yui:log' event will be
3975  * dispatched, which the Console widget and anything else
3976  * can consume.  If the 'useBrowserConsole' config is true, it will
3977  * write to the browser console if available.  YUI-specific log
3978  * messages will only be present in the -debug versions of the
3979  * JS files.  The build system is supposed to remove log statements
3980  * from the raw and minified versions of the files.
3981  *
3982  * @method log
3983  * @for YUI
3984  * @param  {String}  msg  The message to log.
3985  * @param  {String}  cat  The log category for the message.  Default
3986  *                        categories are "info", "warn", "error", time".
3987  *                        Custom categories can be used as well. (opt).
3988  * @param  {String}  src  The source of the the message (opt).
3989  * @param  {boolean} silent If true, the log event won't fire.
3990  * @return {YUI}      YUI instance.
3991  */
3992 INSTANCE.log = function(msg, cat, src, silent) {
3993     var bail, excl, incl, m, f,
3994         Y = INSTANCE,
3995         c = Y.config,
3996         publisher = (Y.fire) ? Y : YUI.Env.globalEvents;
3997     // suppress log message if the config is off or the event stack
3998     // or the event call stack contains a consumer of the yui:log event
3999     if (c.debug) {
4000         // apply source filters
4001         if (src) {
4002             excl = c.logExclude;
4003             incl = c.logInclude;
4004             if (incl && !(src in incl)) {
4005                 bail = 1;
4006             } else if (excl && (src in excl)) {
4007                 bail = 1;
4008             }
4009         }
4010         if (!bail) {
4011             if (c.useBrowserConsole) {
4012                 m = (src) ? src + ': ' + msg : msg;
4013                 if (Y.Lang.isFunction(c.logFn)) {
4014                     c.logFn.call(Y, msg, cat, src);
4015                 } else if (typeof console != UNDEFINED && console.log) {
4016                     f = (cat && console[cat] && (cat in LEVELS)) ? cat : 'log';
4017                     console[f](m);
4018                 } else if (typeof opera != UNDEFINED) {
4019                     opera.postError(m);
4020                 }
4021             }
4022
4023             if (publisher && !silent) {
4024
4025                 if (publisher == Y && (!publisher.getEvent(LOGEVENT))) {
4026                     publisher.publish(LOGEVENT, {
4027                         broadcast: 2
4028                     });
4029                 }
4030
4031                 publisher.fire(LOGEVENT, {
4032                     msg: msg,
4033                     cat: cat,
4034                     src: src
4035                 });
4036             }
4037         }
4038     }
4039
4040     return Y;
4041 };
4042
4043 /**
4044  * Write a system message.  This message will be preserved in the
4045  * minified and raw versions of the YUI files, unlike log statements.
4046  * @method message
4047  * @for YUI
4048  * @param  {String}  msg  The message to log.
4049  * @param  {String}  cat  The log category for the message.  Default
4050  *                        categories are "info", "warn", "error", time".
4051  *                        Custom categories can be used as well. (opt).
4052  * @param  {String}  src  The source of the the message (opt).
4053  * @param  {boolean} silent If true, the log event won't fire.
4054  * @return {YUI}      YUI instance.
4055  */
4056 INSTANCE.message = function() {
4057     return INSTANCE.log.apply(INSTANCE, arguments);
4058 };
4059
4060
4061 }, '3.3.0' ,{requires:['yui-base']});
4062 YUI.add('yui-later', function(Y) {
4063
4064 /**
4065  * Provides a setTimeout/setInterval wrapper
4066  * @module yui
4067  * @submodule yui-later
4068  */
4069
4070 /**
4071  * Executes the supplied function in the context of the supplied
4072  * object 'when' milliseconds later.  Executes the function a
4073  * single time unless periodic is set to true.
4074  * @method later
4075  * @for YUI
4076  * @param when {int} the number of milliseconds to wait until the fn
4077  * is executed.
4078  * @param o the context object.
4079  * @param fn {Function|String} the function to execute or the name of
4080  * the method in the 'o' object to execute.
4081  * @param data [Array] data that is provided to the function.  This
4082  * accepts either a single item or an array.  If an array is provided,
4083  * the function is executed with one parameter for each array item.
4084  * If you need to pass a single array parameter, it needs to be wrapped
4085  * in an array [myarray].
4086  * @param periodic {boolean} if true, executes continuously at supplied
4087  * interval until canceled.
4088  * @return {object} a timer object. Call the cancel() method on this
4089  * object to stop the timer.
4090  */
4091 Y.later = function(when, o, fn, data, periodic) {
4092     when = when || 0;
4093
4094     var m = fn, f, id;
4095
4096     if (o && Y.Lang.isString(fn)) {
4097         m = o[fn];
4098     }
4099
4100     f = !Y.Lang.isUndefined(data) ? function() {
4101         m.apply(o, Y.Array(data));
4102     } : function() {
4103         m.call(o);
4104     };
4105
4106     id = (periodic) ? setInterval(f, when) : setTimeout(f, when);
4107
4108     return {
4109         id: id,
4110         interval: periodic,
4111         cancel: function() {
4112             if (this.interval) {
4113                 clearInterval(id);
4114             } else {
4115                 clearTimeout(id);
4116             }
4117         }
4118     };
4119 };
4120
4121 Y.Lang.later = Y.later;
4122
4123
4124
4125 }, '3.3.0' ,{requires:['yui-base']});
4126 YUI.add('yui-throttle', function(Y) {
4127
4128 /**
4129  * Provides a throttle/limiter for function calls
4130  * @module yui
4131  * @submodule yui-throttle
4132  */
4133
4134 /*! Based on work by Simon Willison: http://gist.github.com/292562 */
4135 /**
4136  * Throttles a call to a method based on the time between calls.
4137  * @method throttle
4138  * @for YUI
4139  * @param fn {function} The function call to throttle.
4140  * @param ms {int} The number of milliseconds to throttle the method call.
4141  * Can set globally with Y.config.throttleTime or by call. Passing a -1 will
4142  * disable the throttle. Defaults to 150.
4143  * @return {function} Returns a wrapped function that calls fn throttled.
4144  * @since 3.1.0
4145  */
4146 Y.throttle = function(fn, ms) {
4147     ms = (ms) ? ms : (Y.config.throttleTime || 150);
4148
4149     if (ms === -1) {
4150         return (function() {
4151             fn.apply(null, arguments);
4152         });
4153     }
4154
4155     var last = Y.Lang.now();
4156
4157     return (function() {
4158         var now = Y.Lang.now();
4159         if (now - last > ms) {
4160             last = now;
4161             fn.apply(null, arguments);
4162         }
4163     });
4164 };
4165
4166
4167 }, '3.3.0' ,{requires:['yui-base']});
4168
4169
4170 YUI.add('yui', function(Y){}, '3.3.0' ,{use:['yui-base','get','features','rls','intl-base','yui-log','yui-later','yui-throttle']});
4171
4172 YUI.add('oop', function(Y) {
4173
4174 /**
4175  * Supplies object inheritance and manipulation utilities.  This adds
4176  * additional functionaity to what is provided in yui-base, and the
4177  * methods are applied directly to the YUI instance.  This module
4178  * is required for most YUI components.
4179  * @module oop
4180  */
4181
4182 /**
4183  * The following methods are added to the YUI instance
4184  * @class YUI~oop
4185  */
4186
4187     var L = Y.Lang,
4188         A = Y.Array,
4189         OP = Object.prototype,
4190         CLONE_MARKER = '_~yuim~_',
4191         EACH = 'each',
4192         SOME = 'some',
4193
4194         dispatch = function(o, f, c, proto, action) {
4195             if (o && o[action] && o !== Y) {
4196                 return o[action].call(o, f, c);
4197             } else {
4198                 switch (A.test(o)) {
4199                     case 1:
4200                         return A[action](o, f, c);
4201                     case 2:
4202                         return A[action](Y.Array(o, 0, true), f, c);
4203                     default:
4204                         return Y.Object[action](o, f, c, proto);
4205                 }
4206             }
4207         };
4208
4209
4210     /**
4211      * Applies prototype properties from the supplier to the receiver.
4212      * The receiver can be a constructor or an instance.
4213      * @method augment
4214      * @param {function} r  the object to receive the augmentation.
4215      * @param {function} s  the object that supplies the properties to augment.
4216      * @param {boolean} ov if true, properties already on the receiver
4217      * will be overwritten if found on the supplier.
4218      * @param {string[]} wl  a whitelist.  If supplied, only properties in
4219      * this list will be applied to the receiver.
4220      * @param {Array | Any} args arg or arguments to apply to the supplier
4221      * constructor when initializing.
4222      * @return {object} the augmented object.
4223      *
4224      * @todo constructor optional?
4225      * @todo understanding what an instance is augmented with
4226      * @todo best practices for overriding sequestered methods.
4227      */
4228     Y.augment = function(r, s, ov, wl, args) {
4229         var sProto = s.prototype,
4230             newProto = null,
4231             construct = s,
4232             a = (args) ? Y.Array(args) : [],
4233             rProto = r.prototype,
4234             target = rProto || r,
4235             applyConstructor = false,
4236             sequestered, replacements;
4237
4238         // working on a class, so apply constructor infrastructure
4239         if (rProto && construct) {
4240             sequestered = {};
4241             replacements = {};
4242             newProto = {};
4243
4244             // sequester all of the functions in the supplier and replace with
4245             // one that will restore all of them.
4246             Y.Object.each(sProto, function(v, k) {
4247                 replacements[k] = function() {
4248
4249             // overwrite the prototype with all of the sequestered functions,
4250             // but only if it hasn't been overridden
4251                         for (var i in sequestered) {
4252                         if (sequestered.hasOwnProperty(i) &&
4253                                 (this[i] === replacements[i])) {
4254                             this[i] = sequestered[i];
4255                         }
4256                     }
4257
4258                     // apply the constructor
4259                     construct.apply(this, a);
4260
4261                     // apply the original sequestered function
4262                     return sequestered[k].apply(this, arguments);
4263                 };
4264
4265                 if ((!wl || (k in wl)) && (ov || !(k in this))) {
4266                     if (L.isFunction(v)) {
4267                         // sequester the function
4268                         sequestered[k] = v;
4269
4270 // replace the sequestered function with a function that will
4271 // restore all sequestered functions and exectue the constructor.
4272                         this[k] = replacements[k];
4273                     } else {
4274                         this[k] = v;
4275                     }
4276                 }
4277
4278             }, newProto, true);
4279
4280         // augmenting an instance, so apply the constructor immediately
4281         } else {
4282             applyConstructor = true;
4283         }
4284
4285         Y.mix(target, newProto || sProto, ov, wl);
4286
4287         if (applyConstructor) {
4288             s.apply(target, a);
4289         }
4290
4291         return r;
4292     };
4293
4294     /**
4295      * Applies object properties from the supplier to the receiver.  If
4296      * the target has the property, and the property is an object, the target
4297      * object will be augmented with the supplier's value.  If the property
4298      * is an array, the suppliers value will be appended to the target.
4299      * @method aggregate
4300      * @param {function} r  the object to receive the augmentation.
4301      * @param {function} s  the object that supplies the properties to augment.
4302      * @param {boolean} ov if true, properties already on the receiver
4303      * will be overwritten if found on the supplier.
4304      * @param {string[]} wl a whitelist.  If supplied, only properties in
4305      * this list will be applied to the receiver.
4306      * @return {object} the extended object.
4307      */
4308     Y.aggregate = function(r, s, ov, wl) {
4309         return Y.mix(r, s, ov, wl, 0, true);
4310     };
4311
4312     /**
4313      * Utility to set up the prototype, constructor and superclass properties to
4314      * support an inheritance strategy that can chain constructors and methods.
4315      * Static members will not be inherited.
4316      *
4317      * @method extend
4318      * @param {function} r   the object to modify.
4319      * @param {function} s the object to inherit.
4320      * @param {object} px prototype properties to add/override.
4321      * @param {object} sx static properties to add/override.
4322      * @return {object} the extended object.
4323      */
4324     Y.extend = function(r, s, px, sx) {
4325         if (!s || !r) {
4326             Y.error('extend failed, verify dependencies');
4327         }
4328
4329         var sp = s.prototype, rp = Y.Object(sp);
4330         r.prototype = rp;
4331
4332         rp.constructor = r;
4333         r.superclass = sp;
4334
4335         // assign constructor property
4336         if (s != Object && sp.constructor == OP.constructor) {
4337             sp.constructor = s;
4338         }
4339
4340         // add prototype overrides
4341         if (px) {
4342             Y.mix(rp, px, true);
4343         }
4344
4345         // add object overrides
4346         if (sx) {
4347             Y.mix(r, sx, true);
4348         }
4349
4350         return r;
4351     };
4352
4353     /**
4354      * Executes the supplied function for each item in
4355      * a collection.  Supports arrays, objects, and
4356      * Y.NodeLists
4357      * @method each
4358      * @param {object} o the object to iterate.
4359      * @param {function} f the function to execute.  This function
4360      * receives the value, key, and object as parameters.
4361      * @param {object} c the execution context for the function.
4362      * @param {boolean} proto if true, prototype properties are
4363      * iterated on objects.
4364      * @return {YUI} the YUI instance.
4365      */
4366     Y.each = function(o, f, c, proto) {
4367         return dispatch(o, f, c, proto, EACH);
4368     };
4369
4370     /**
4371      * Executes the supplied function for each item in
4372      * a collection.  The operation stops if the function
4373      * returns true. Supports arrays, objects, and
4374      * Y.NodeLists.
4375      * @method some
4376      * @param {object} o the object to iterate.
4377      * @param {function} f the function to execute.  This function
4378      * receives the value, key, and object as parameters.
4379      * @param {object} c the execution context for the function.
4380      * @param {boolean} proto if true, prototype properties are
4381      * iterated on objects.
4382      * @return {boolean} true if the function ever returns true,
4383      * false otherwise.
4384      */
4385     Y.some = function(o, f, c, proto) {
4386         return dispatch(o, f, c, proto, SOME);
4387     };
4388
4389     /**
4390      * Deep obj/array copy.  Function clones are actually
4391      * wrappers around the original function.
4392      * Array-like objects are treated as arrays.
4393      * Primitives are returned untouched.  Optionally, a
4394      * function can be provided to handle other data types,
4395      * filter keys, validate values, etc.
4396      *
4397      * @method clone
4398      * @param {object} o what to clone.
4399      * @param {boolean} safe if true, objects will not have prototype
4400      * items from the source.  If false, they will.  In this case, the
4401      * original is initially protected, but the clone is not completely
4402      * immune from changes to the source object prototype.  Also, cloned
4403      * prototype items that are deleted from the clone will result
4404      * in the value of the source prototype being exposed.  If operating
4405      * on a non-safe clone, items should be nulled out rather than deleted.
4406      * @param {function} f optional function to apply to each item in a
4407      * collection; it will be executed prior to applying the value to
4408      * the new object.  Return false to prevent the copy.
4409      * @param {object} c optional execution context for f.
4410      * @param {object} owner Owner object passed when clone is iterating
4411      * an object.  Used to set up context for cloned functions.
4412      * @param {object} cloned hash of previously cloned objects to avoid
4413      * multiple clones.
4414      * @return {Array|Object} the cloned object.
4415      */
4416     Y.clone = function(o, safe, f, c, owner, cloned) {
4417
4418         if (!L.isObject(o)) {
4419             return o;
4420         }
4421
4422         // @todo cloning YUI instances doesn't currently work
4423         if (Y.instanceOf(o, YUI)) {
4424             return o;
4425         }
4426
4427         var o2, marked = cloned || {}, stamp,
4428             yeach = Y.each;
4429
4430         switch (L.type(o)) {
4431             case 'date':
4432                 return new Date(o);
4433             case 'regexp':
4434                 // if we do this we need to set the flags too
4435                 // return new RegExp(o.source);
4436                 return o;
4437             case 'function':
4438                 // o2 = Y.bind(o, owner);
4439                 // break;
4440                 return o;
4441             case 'array':
4442                 o2 = [];
4443                 break;
4444             default:
4445
4446                 // #2528250 only one clone of a given object should be created.
4447                 if (o[CLONE_MARKER]) {
4448                     return marked[o[CLONE_MARKER]];
4449                 }
4450
4451                 stamp = Y.guid();
4452
4453                 o2 = (safe) ? {} : Y.Object(o);
4454
4455                 o[CLONE_MARKER] = stamp;
4456                 marked[stamp] = o;
4457         }
4458
4459         // #2528250 don't try to clone element properties
4460         if (!o.addEventListener && !o.attachEvent) {
4461             yeach(o, function(v, k) {
4462 if ((k || k === 0) && (!f || (f.call(c || this, v, k, this, o) !== false))) {
4463                     if (k !== CLONE_MARKER) {
4464                         if (k == 'prototype') {
4465                             // skip the prototype
4466                         // } else if (o[k] === o) {
4467                         //     this[k] = this;
4468                         } else {
4469                             this[k] =
4470                                 Y.clone(v, safe, f, c, owner || o, marked);
4471                         }
4472                     }
4473                 }
4474             }, o2);
4475         }
4476
4477         if (!cloned) {
4478             Y.Object.each(marked, function(v, k) {
4479                 if (v[CLONE_MARKER]) {
4480                     try {
4481                         delete v[CLONE_MARKER];
4482                     } catch (e) {
4483                         v[CLONE_MARKER] = null;
4484                     }
4485                 }
4486             }, this);
4487             marked = null;
4488         }
4489
4490         return o2;
4491     };
4492
4493
4494     /**
4495      * Returns a function that will execute the supplied function in the
4496      * supplied object's context, optionally adding any additional
4497      * supplied parameters to the beginning of the arguments collection the
4498      * supplied to the function.
4499      *
4500      * @method bind
4501      * @param {Function|String} f the function to bind, or a function name
4502      * to execute on the context object.
4503      * @param {object} c the execution context.
4504      * @param {any} args* 0..n arguments to include before the arguments the
4505      * function is executed with.
4506      * @return {function} the wrapped function.
4507      */
4508     Y.bind = function(f, c) {
4509         var xargs = arguments.length > 2 ?
4510                 Y.Array(arguments, 2, true) : null;
4511         return function() {
4512             var fn = L.isString(f) ? c[f] : f,
4513                 args = (xargs) ?
4514                     xargs.concat(Y.Array(arguments, 0, true)) : arguments;
4515             return fn.apply(c || fn, args);
4516         };
4517     };
4518
4519     /**
4520      * Returns a function that will execute the supplied function in the
4521      * supplied object's context, optionally adding any additional
4522      * supplied parameters to the end of the arguments the function
4523      * is executed with.
4524      *
4525      * @method rbind
4526      * @param {Function|String} f the function to bind, or a function name
4527      * to execute on the context object.
4528      * @param {object} c the execution context.
4529      * @param {any} args* 0..n arguments to append to the end of
4530      * arguments collection supplied to the function.
4531      * @return {function} the wrapped function.
4532      */
4533     Y.rbind = function(f, c) {
4534         var xargs = arguments.length > 2 ? Y.Array(arguments, 2, true) : null;
4535         return function() {
4536             var fn = L.isString(f) ? c[f] : f,
4537                 args = (xargs) ?
4538                     Y.Array(arguments, 0, true).concat(xargs) : arguments;
4539             return fn.apply(c || fn, args);
4540         };
4541     };
4542
4543
4544
4545 }, '3.3.0' );
4546 YUI.add('dom-base', function(Y) {
4547
4548 (function(Y) {
4549 /** 
4550  * The DOM utility provides a cross-browser abtraction layer
4551  * normalizing DOM tasks, and adds extra helper functionality
4552  * for other common tasks. 
4553  * @module dom
4554  * @submodule dom-base
4555  * @for DOM
4556  *
4557  */
4558
4559 /**
4560  * Provides DOM helper methods.
4561  * @class DOM
4562  *
4563  */
4564 var NODE_TYPE = 'nodeType',
4565     OWNER_DOCUMENT = 'ownerDocument',
4566     DOCUMENT_ELEMENT = 'documentElement',
4567     DEFAULT_VIEW = 'defaultView',
4568     PARENT_WINDOW = 'parentWindow',
4569     TAG_NAME = 'tagName',
4570     PARENT_NODE = 'parentNode',
4571     FIRST_CHILD = 'firstChild',
4572     PREVIOUS_SIBLING = 'previousSibling',
4573     NEXT_SIBLING = 'nextSibling',
4574     CONTAINS = 'contains',
4575     COMPARE_DOCUMENT_POSITION = 'compareDocumentPosition',
4576     EMPTY_STRING = '',
4577     EMPTY_ARRAY = [],
4578
4579     documentElement = Y.config.doc.documentElement,
4580
4581     re_tag = /<([a-z]+)/i,
4582
4583     createFromDIV = function(html, tag) {
4584         var div = Y.config.doc.createElement('div'),
4585             ret = true;
4586
4587         div.innerHTML = html;
4588         if (!div.firstChild || div.firstChild.tagName !== tag.toUpperCase()) {
4589             ret = false;
4590         }
4591
4592         return ret;
4593     },
4594
4595     addFeature = Y.Features.add,
4596     testFeature = Y.Features.test,
4597     
4598 Y_DOM = {
4599     /**
4600      * Returns the HTMLElement with the given ID (Wrapper for document.getElementById).
4601      * @method byId         
4602      * @param {String} id the id attribute 
4603      * @param {Object} doc optional The document to search. Defaults to current document 
4604      * @return {HTMLElement | null} The HTMLElement with the id, or null if none found. 
4605      */
4606     byId: function(id, doc) {
4607         // handle dupe IDs and IE name collision
4608         return Y_DOM.allById(id, doc)[0] || null;
4609     },
4610
4611     /**
4612      * Returns the text content of the HTMLElement. 
4613      * @method getText         
4614      * @param {HTMLElement} element The html element. 
4615      * @return {String} The text content of the element (includes text of any descending elements).
4616      */
4617     getText: (documentElement.textContent !== undefined) ?
4618         function(element) {
4619             var ret = '';
4620             if (element) {
4621                 ret = element.textContent;
4622             }
4623             return ret || '';
4624         } : function(element) {
4625             var ret = '';
4626             if (element) {
4627                 ret = element.innerText || element.nodeValue; // might be a textNode
4628             }
4629             return ret || '';
4630         },
4631
4632     /**
4633      * Sets the text content of the HTMLElement. 
4634      * @method setText         
4635      * @param {HTMLElement} element The html element. 
4636      * @param {String} content The content to add. 
4637      */
4638     setText: (documentElement.textContent !== undefined) ?
4639         function(element, content) {
4640             if (element) {
4641                 element.textContent = content;
4642             }
4643         } : function(element, content) {
4644             if ('innerText' in element) {
4645                 element.innerText = content;
4646             } else if ('nodeValue' in element) {
4647                 element.nodeValue = content;
4648             }
4649
4650         },
4651
4652     /*
4653      * Finds the ancestor of the element.
4654      * @method ancestor
4655      * @param {HTMLElement} element The html element.
4656      * @param {Function} fn optional An optional boolean test to apply.
4657      * The optional function is passed the current DOM node being tested as its only argument.
4658      * If no function is given, the parentNode is returned.
4659      * @param {Boolean} testSelf optional Whether or not to include the element in the scan 
4660      * @return {HTMLElement | null} The matching DOM node or null if none found. 
4661      */
4662     ancestor: function(element, fn, testSelf) {
4663         var ret = null;
4664         if (testSelf) {
4665             ret = (!fn || fn(element)) ? element : null;
4666
4667         }
4668         return ret || Y_DOM.elementByAxis(element, PARENT_NODE, fn, null);
4669     },
4670
4671     /*
4672      * Finds the ancestors of the element.
4673      * @method ancestors
4674      * @param {HTMLElement} element The html element.
4675      * @param {Function} fn optional An optional boolean test to apply.
4676      * The optional function is passed the current DOM node being tested as its only argument.
4677      * If no function is given, all ancestors are returned.
4678      * @param {Boolean} testSelf optional Whether or not to include the element in the scan 
4679      * @return {Array} An array containing all matching DOM nodes.
4680      */
4681     ancestors: function(element, fn, testSelf) {
4682         var ancestor = Y_DOM.ancestor.apply(Y_DOM, arguments),
4683             ret = (ancestor) ? [ancestor] : [];
4684
4685         while ((ancestor = Y_DOM.ancestor(ancestor, fn))) {
4686             if (ancestor) {
4687                 ret.unshift(ancestor);
4688             }
4689         }
4690
4691         return ret;
4692     },
4693
4694     /**
4695      * Searches the element by the given axis for the first matching element.
4696      * @method elementByAxis
4697      * @param {HTMLElement} element The html element.
4698      * @param {String} axis The axis to search (parentNode, nextSibling, previousSibling).
4699      * @param {Function} fn optional An optional boolean test to apply.
4700      * @param {Boolean} all optional Whether all node types should be returned, or just element nodes.
4701      * The optional function is passed the current HTMLElement being tested as its only argument.
4702      * If no function is given, the first element is returned.
4703      * @return {HTMLElement | null} The matching element or null if none found.
4704      */
4705     elementByAxis: function(element, axis, fn, all) {
4706         while (element && (element = element[axis])) { // NOTE: assignment
4707                 if ( (all || element[TAG_NAME]) && (!fn || fn(element)) ) {
4708                     return element;
4709                 }
4710         }
4711         return null;
4712     },
4713
4714     /**
4715      * Determines whether or not one HTMLElement is or contains another HTMLElement.
4716      * @method contains
4717      * @param {HTMLElement} element The containing html element.
4718      * @param {HTMLElement} needle The html element that may be contained.
4719      * @return {Boolean} Whether or not the element is or contains the needle.
4720      */
4721     contains: function(element, needle) {
4722         var ret = false;
4723
4724         if ( !needle || !element || !needle[NODE_TYPE] || !element[NODE_TYPE]) {
4725             ret = false;
4726         } else if (element[CONTAINS])  {
4727             if (Y.UA.opera || needle[NODE_TYPE] === 1) { // IE & SAF contains fail if needle not an ELEMENT_NODE
4728                 ret = element[CONTAINS](needle);
4729             } else {
4730                 ret = Y_DOM._bruteContains(element, needle); 
4731             }
4732         } else if (element[COMPARE_DOCUMENT_POSITION]) { // gecko
4733             if (element === needle || !!(element[COMPARE_DOCUMENT_POSITION](needle) & 16)) { 
4734                 ret = true;
4735             }
4736         }
4737
4738         return ret;
4739     },
4740
4741     /**
4742      * Determines whether or not the HTMLElement is part of the document.
4743      * @method inDoc
4744      * @param {HTMLElement} element The containing html element.
4745      * @param {HTMLElement} doc optional The document to check.
4746      * @return {Boolean} Whether or not the element is attached to the document. 
4747      */
4748     inDoc: function(element, doc) {
4749         var ret = false,
4750             rootNode;
4751
4752         if (element && element.nodeType) {
4753             (doc) || (doc = element[OWNER_DOCUMENT]);
4754
4755             rootNode = doc[DOCUMENT_ELEMENT];
4756
4757             // contains only works with HTML_ELEMENT
4758             if (rootNode && rootNode.contains && element.tagName) {
4759                 ret = rootNode.contains(element);
4760             } else {
4761                 ret = Y_DOM.contains(rootNode, element);
4762             }
4763         }
4764
4765         return ret;
4766
4767     },
4768
4769    allById: function(id, root) {
4770         root = root || Y.config.doc;
4771         var nodes = [],
4772             ret = [],
4773             i,
4774             node;
4775
4776         if (root.querySelectorAll) {
4777             ret = root.querySelectorAll('[id="' + id + '"]');
4778         } else if (root.all) {
4779             nodes = root.all(id);
4780
4781             if (nodes) {
4782                 // root.all may return HTMLElement or HTMLCollection.
4783                 // some elements are also HTMLCollection (FORM, SELECT).
4784                 if (nodes.nodeName) {
4785                     if (nodes.id === id) { // avoid false positive on name
4786                         ret.push(nodes);
4787                         nodes = EMPTY_ARRAY; // done, no need to filter
4788                     } else { //  prep for filtering
4789                         nodes = [nodes];
4790                     }
4791                 }
4792
4793                 if (nodes.length) {
4794                     // filter out matches on node.name
4795                     // and element.id as reference to element with id === 'id'
4796                     for (i = 0; node = nodes[i++];) {
4797                         if (node.id === id  || 
4798                                 (node.attributes && node.attributes.id &&
4799                                 node.attributes.id.value === id)) { 
4800                             ret.push(node);
4801                         }
4802                     }
4803                 }
4804             }
4805         } else {
4806             ret = [Y_DOM._getDoc(root).getElementById(id)];
4807         }
4808     
4809         return ret;
4810    },
4811
4812     /**
4813      * Creates a new dom node using the provided markup string. 
4814      * @method create
4815      * @param {String} html The markup used to create the element
4816      * @param {HTMLDocument} doc An optional document context 
4817      * @return {HTMLElement|DocumentFragment} returns a single HTMLElement 
4818      * when creating one node, and a documentFragment when creating
4819      * multiple nodes.
4820      */
4821     create: function(html, doc) {
4822         if (typeof html === 'string') {
4823             html = Y.Lang.trim(html); // match IE which trims whitespace from innerHTML
4824
4825         }
4826
4827         doc = doc || Y.config.doc;
4828         var m = re_tag.exec(html),
4829             create = Y_DOM._create,
4830             custom = Y_DOM.creators,
4831             ret = null,
4832             creator,
4833             tag, nodes;
4834
4835         if (html != undefined) { // not undefined or null
4836             if (m && m[1]) {
4837                 creator = custom[m[1].toLowerCase()];
4838                 if (typeof creator === 'function') {
4839                     create = creator; 
4840                 } else {
4841                     tag = creator;
4842                 }
4843             }
4844
4845             nodes = create(html, doc, tag).childNodes;
4846
4847             if (nodes.length === 1) { // return single node, breaking parentNode ref from "fragment"
4848                 ret = nodes[0].parentNode.removeChild(nodes[0]);
4849             } else if (nodes[0] && nodes[0].className === 'yui3-big-dummy') { // using dummy node to preserve some attributes (e.g. OPTION not selected)
4850                 if (nodes.length === 2) {
4851                     ret = nodes[0].nextSibling;
4852                 } else {
4853                     nodes[0].parentNode.removeChild(nodes[0]); 
4854                      ret = Y_DOM._nl2frag(nodes, doc);
4855                 }
4856             } else { // return multiple nodes as a fragment
4857                  ret = Y_DOM._nl2frag(nodes, doc);
4858             }
4859         }
4860
4861         return ret;
4862     },
4863
4864     _nl2frag: function(nodes, doc) {
4865         var ret = null,
4866             i, len;
4867
4868         if (nodes && (nodes.push || nodes.item) && nodes[0]) {
4869             doc = doc || nodes[0].ownerDocument; 
4870             ret = doc.createDocumentFragment();
4871
4872             if (nodes.item) { // convert live list to static array
4873                 nodes = Y.Array(nodes, 0, true);
4874             }
4875
4876             for (i = 0, len = nodes.length; i < len; i++) {
4877                 ret.appendChild(nodes[i]); 
4878             }
4879         } // else inline with log for minification
4880         return ret;
4881     },
4882
4883
4884     CUSTOM_ATTRIBUTES: (!documentElement.hasAttribute) ? { // IE < 8
4885         'for': 'htmlFor',
4886         'class': 'className'
4887     } : { // w3c
4888         'htmlFor': 'for',
4889         'className': 'class'
4890     },
4891
4892     /**
4893      * Provides a normalized attribute interface. 
4894      * @method setAttibute
4895      * @param {HTMLElement} el The target element for the attribute.
4896      * @param {String} attr The attribute to set.
4897      * @param {String} val The value of the attribute.
4898      */
4899     setAttribute: function(el, attr, val, ieAttr) {
4900         if (el && attr && el.setAttribute) {
4901             attr = Y_DOM.CUSTOM_ATTRIBUTES[attr] || attr;
4902             el.setAttribute(attr, val, ieAttr);
4903         }
4904     },
4905
4906
4907     /**
4908      * Provides a normalized attribute interface. 
4909      * @method getAttibute
4910      * @param {HTMLElement} el The target element for the attribute.
4911      * @param {String} attr The attribute to get.
4912      * @return {String} The current value of the attribute. 
4913      */
4914     getAttribute: function(el, attr, ieAttr) {
4915         ieAttr = (ieAttr !== undefined) ? ieAttr : 2;
4916         var ret = '';
4917         if (el && attr && el.getAttribute) {
4918             attr = Y_DOM.CUSTOM_ATTRIBUTES[attr] || attr;
4919             ret = el.getAttribute(attr, ieAttr);
4920
4921             if (ret === null) {
4922                 ret = ''; // per DOM spec
4923             }
4924         }
4925         return ret;
4926     },
4927
4928     isWindow: function(obj) {
4929         return !!(obj && obj.alert && obj.document);
4930     },
4931
4932     _fragClones: {},
4933
4934     _create: function(html, doc, tag) {
4935         tag = tag || 'div';
4936
4937         var frag = Y_DOM._fragClones[tag];
4938         if (frag) {
4939             frag = frag.cloneNode(false);
4940         } else {
4941             frag = Y_DOM._fragClones[tag] = doc.createElement(tag);
4942         }
4943         frag.innerHTML = html;
4944         return frag;
4945     },
4946
4947     _removeChildNodes: function(node) {
4948         while (node.firstChild) {
4949             node.removeChild(node.firstChild);
4950         }
4951     },
4952
4953     /**
4954      * Inserts content in a node at the given location 
4955      * @method addHTML
4956      * @param {HTMLElement} node The node to insert into
4957      * @param {HTMLElement | Array | HTMLCollection} content The content to be inserted 
4958      * @param {HTMLElement} where Where to insert the content
4959      * If no "where" is given, content is appended to the node
4960      * Possible values for "where"
4961      * <dl>
4962      * <dt>HTMLElement</dt>
4963      * <dd>The element to insert before</dd>
4964      * <dt>"replace"</dt>
4965      * <dd>Replaces the existing HTML</dd>
4966      * <dt>"before"</dt>
4967      * <dd>Inserts before the existing HTML</dd>
4968      * <dt>"before"</dt>
4969      * <dd>Inserts content before the node</dd>
4970      * <dt>"after"</dt>
4971      * <dd>Inserts content after the node</dd>
4972      * </dl>
4973      */
4974     addHTML: function(node, content, where) {
4975         var nodeParent = node.parentNode,
4976             i = 0,
4977             item,
4978             ret = content,
4979             newNode;
4980             
4981
4982         if (content != undefined) { // not null or undefined (maybe 0)
4983             if (content.nodeType) { // DOM node, just add it
4984                 newNode = content;
4985             } else if (typeof content == 'string' || typeof content == 'number') {
4986                 ret = newNode = Y_DOM.create(content);
4987             } else if (content[0] && content[0].nodeType) { // array or collection 
4988                 newNode = Y.config.doc.createDocumentFragment();
4989                 while ((item = content[i++])) {
4990                     newNode.appendChild(item); // append to fragment for insertion
4991                 }
4992             }
4993         }
4994
4995         if (where) {
4996             if (where.nodeType) { // insert regardless of relationship to node
4997                 where.parentNode.insertBefore(newNode, where);
4998             } else {
4999                 switch (where) {
5000                     case 'replace':
5001                         while (node.firstChild) {
5002                             node.removeChild(node.firstChild);
5003                         }
5004                         if (newNode) { // allow empty content to clear node
5005                             node.appendChild(newNode);
5006                         }
5007                         break;
5008                     case 'before':
5009                         nodeParent.insertBefore(newNode, node);
5010                         break;
5011                     case 'after':
5012                         if (node.nextSibling) { // IE errors if refNode is null
5013                             nodeParent.insertBefore(newNode, node.nextSibling);
5014                         } else {
5015                             nodeParent.appendChild(newNode);
5016                         }
5017                         break;
5018                     default:
5019                         node.appendChild(newNode);
5020                 }
5021             }
5022         } else if (newNode) {
5023             node.appendChild(newNode);
5024         }
5025
5026         return ret;
5027     },
5028
5029     VALUE_SETTERS: {},
5030
5031     VALUE_GETTERS: {},
5032
5033     getValue: function(node) {
5034         var ret = '', // TODO: return null?
5035             getter;
5036
5037         if (node && node[TAG_NAME]) {
5038             getter = Y_DOM.VALUE_GETTERS[node[TAG_NAME].toLowerCase()];
5039
5040             if (getter) {
5041                 ret = getter(node);
5042             } else {
5043                 ret = node.value;
5044             }
5045         }
5046
5047         // workaround for IE8 JSON stringify bug
5048         // which converts empty string values to null
5049         if (ret === EMPTY_STRING) {
5050             ret = EMPTY_STRING; // for real
5051         }
5052
5053         return (typeof ret === 'string') ? ret : '';
5054     },
5055
5056     setValue: function(node, val) {
5057         var setter;
5058
5059         if (node && node[TAG_NAME]) {
5060             setter = Y_DOM.VALUE_SETTERS[node[TAG_NAME].toLowerCase()];
5061
5062             if (setter) {
5063                 setter(node, val);
5064             } else {
5065                 node.value = val;
5066             }
5067         }
5068     },
5069
5070     siblings: function(node, fn) {
5071         var nodes = [],
5072             sibling = node;
5073
5074         while ((sibling = sibling[PREVIOUS_SIBLING])) {
5075             if (sibling[TAG_NAME] && (!fn || fn(sibling))) {
5076                 nodes.unshift(sibling);
5077             }
5078         }
5079
5080         sibling = node;
5081         while ((sibling = sibling[NEXT_SIBLING])) {
5082             if (sibling[TAG_NAME] && (!fn || fn(sibling))) {
5083                 nodes.push(sibling);
5084             }
5085         }
5086
5087         return nodes;
5088     },
5089
5090     /**
5091      * Brute force version of contains.
5092      * Used for browsers without contains support for non-HTMLElement Nodes (textNodes, etc).
5093      * @method _bruteContains
5094      * @private
5095      * @param {HTMLElement} element The containing html element.
5096      * @param {HTMLElement} needle The html element that may be contained.
5097      * @return {Boolean} Whether or not the element is or contains the needle.
5098      */
5099     _bruteContains: function(element, needle) {
5100         while (needle) {
5101             if (element === needle) {
5102                 return true;
5103             }
5104             needle = needle.parentNode;
5105         }
5106         return false;
5107     },
5108
5109 // TODO: move to Lang?
5110     /**
5111      * Memoizes dynamic regular expressions to boost runtime performance. 
5112      * @method _getRegExp
5113      * @private
5114      * @param {String} str The string to convert to a regular expression.
5115      * @param {String} flags optional An optinal string of flags.
5116      * @return {RegExp} An instance of RegExp
5117      */
5118     _getRegExp: function(str, flags) {
5119         flags = flags || '';
5120         Y_DOM._regexCache = Y_DOM._regexCache || {};
5121         if (!Y_DOM._regexCache[str + flags]) {
5122             Y_DOM._regexCache[str + flags] = new RegExp(str, flags);
5123         }
5124         return Y_DOM._regexCache[str + flags];
5125     },
5126
5127 // TODO: make getDoc/Win true privates?
5128     /**
5129      * returns the appropriate document.
5130      * @method _getDoc
5131      * @private
5132      * @param {HTMLElement} element optional Target element.
5133      * @return {Object} The document for the given element or the default document. 
5134      */
5135     _getDoc: function(element) {
5136         var doc = Y.config.doc;
5137         if (element) {
5138             doc = (element[NODE_TYPE] === 9) ? element : // element === document
5139                 element[OWNER_DOCUMENT] || // element === DOM node
5140                 element.document || // element === window
5141                 Y.config.doc; // default
5142         }
5143
5144         return doc;
5145     },
5146
5147     /**
5148      * returns the appropriate window.
5149      * @method _getWin
5150      * @private
5151      * @param {HTMLElement} element optional Target element.
5152      * @return {Object} The window for the given element or the default window. 
5153      */
5154     _getWin: function(element) {
5155         var doc = Y_DOM._getDoc(element);
5156         return doc[DEFAULT_VIEW] || doc[PARENT_WINDOW] || Y.config.win;
5157     },
5158
5159     _batch: function(nodes, fn, arg1, arg2, arg3, etc) {
5160         fn = (typeof fn === 'string') ? Y_DOM[fn] : fn;
5161         var result,
5162             args = Array.prototype.slice.call(arguments, 2),
5163             i = 0,
5164             node,
5165             ret;
5166
5167         if (fn && nodes) {
5168             while ((node = nodes[i++])) {
5169                 result = result = fn.call(Y_DOM, node, arg1, arg2, arg3, etc);
5170                 if (typeof result !== 'undefined') {
5171                     (ret) || (ret = []);
5172                     ret.push(result);
5173                 }
5174             }
5175         }
5176
5177         return (typeof ret !== 'undefined') ? ret : nodes;
5178     },
5179
5180     wrap: function(node, html) {
5181         var parent = Y.DOM.create(html),
5182             nodes = parent.getElementsByTagName('*');
5183
5184         if (nodes.length) {
5185             parent = nodes[nodes.length - 1];
5186         }
5187
5188         if (node.parentNode) { 
5189             node.parentNode.replaceChild(parent, node);
5190         }
5191         parent.appendChild(node);
5192     },
5193
5194     unwrap: function(node) {
5195         var parent = node.parentNode,
5196             lastChild = parent.lastChild,
5197             node = parent.firstChild,
5198             next = node,
5199             grandparent;
5200
5201         if (parent) {
5202             grandparent = parent.parentNode;
5203             if (grandparent) {
5204                 while (node !== lastChild) {
5205                     next = node.nextSibling;
5206                     grandparent.insertBefore(node, parent);
5207                     node = next;
5208                 }
5209                 grandparent.replaceChild(lastChild, parent);
5210             } else {
5211                 parent.removeChild(node);
5212             }
5213         }
5214     },
5215
5216     generateID: function(el) {
5217         var id = el.id;
5218
5219         if (!id) {
5220             id = Y.stamp(el);
5221             el.id = id; 
5222         }   
5223
5224         return id; 
5225     },
5226
5227     creators: {}
5228 };
5229
5230 addFeature('innerhtml', 'table', {
5231     test: function() {
5232         var node = Y.config.doc.createElement('table');
5233         try {
5234             node.innerHTML = '<tbody></tbody>';
5235         } catch(e) {
5236             return false;
5237         }
5238         return (node.firstChild && node.firstChild.nodeName === 'TBODY');
5239     }
5240 });
5241
5242 addFeature('innerhtml-div', 'tr', {
5243     test: function() {
5244         return createFromDIV('<tr></tr>', 'tr');
5245     }
5246 });
5247
5248 addFeature('innerhtml-div', 'script', {
5249     test: function() {
5250         return createFromDIV('<script></script>', 'script');
5251     }
5252 });
5253
5254 addFeature('value-set', 'select', {
5255     test: function() {
5256         var node = Y.config.doc.createElement('select');
5257         node.innerHTML = '<option>1</option><option>2</option>';
5258         node.value = '2';
5259         return (node.value && node.value === '2');
5260     }
5261 });
5262
5263 (function(Y) {
5264     var creators = Y_DOM.creators,
5265         create = Y_DOM.create,
5266         re_tbody = /(?:\/(?:thead|tfoot|tbody|caption|col|colgroup)>)+\s*<tbody/,
5267
5268         TABLE_OPEN = '<table>',
5269         TABLE_CLOSE = '</table>';
5270
5271     if (!testFeature('innerhtml', 'table')) {
5272         // TODO: thead/tfoot with nested tbody
5273             // IE adds TBODY when creating TABLE elements (which may share this impl)
5274         creators.tbody = function(html, doc) {
5275             var frag = create(TABLE_OPEN + html + TABLE_CLOSE, doc),
5276                 tb = frag.children.tags('tbody')[0];
5277
5278             if (frag.children.length > 1 && tb && !re_tbody.test(html)) {
5279                 tb[PARENT_NODE].removeChild(tb); // strip extraneous tbody
5280             }
5281             return frag;
5282         };
5283     }
5284
5285     if (!testFeature('innerhtml-div', 'script')) {
5286         creators.script = function(html, doc) {
5287             var frag = doc.createElement('div');
5288
5289             frag.innerHTML = '-' + html;
5290             frag.removeChild(frag[FIRST_CHILD]);
5291             return frag;
5292         }
5293
5294         Y_DOM.creators.link = Y_DOM.creators.style = Y_DOM.creators.script;
5295     }
5296
5297     
5298     if (!testFeature('value-set', 'select')) {
5299         Y_DOM.VALUE_SETTERS.select = function(node, val) {
5300             for (var i = 0, options = node.getElementsByTagName('option'), option;
5301                     option = options[i++];) {
5302                 if (Y_DOM.getValue(option) === val) {
5303                     option.selected = true;
5304                     //Y_DOM.setAttribute(option, 'selected', 'selected');
5305                     break;
5306                 }
5307             }
5308         }
5309     }
5310
5311     Y.mix(Y_DOM.VALUE_GETTERS, {
5312         button: function(node) {
5313             return (node.attributes && node.attributes.value) ? node.attributes.value.value : '';
5314         }
5315     });
5316
5317     Y.mix(Y_DOM.VALUE_SETTERS, {
5318         // IE: node.value changes the button text, which should be handled via innerHTML
5319         button: function(node, val) {
5320             var attr = node.attributes.value;
5321             if (!attr) {
5322                 attr = node[OWNER_DOCUMENT].createAttribute('value');
5323                 node.setAttributeNode(attr);
5324             }
5325
5326             attr.value = val;
5327         }
5328     });
5329
5330
5331     if (!testFeature('innerhtml-div', 'tr')) {
5332         Y.mix(creators, {
5333             option: function(html, doc) {
5334                 return create('<select><option class="yui3-big-dummy" selected></option>' + html + '</select>', doc);
5335             },
5336
5337             tr: function(html, doc) {
5338                 return create('<tbody>' + html + '</tbody>', doc);
5339             },
5340
5341             td: function(html, doc) {
5342                 return create('<tr>' + html + '</tr>', doc);
5343             }, 
5344
5345             col: function(html, doc) {
5346                 return create('<colgroup>' + html + '</colgroup>', doc);
5347             }, 
5348
5349             tbody: 'table'
5350         });
5351
5352         Y.mix(creators, {
5353             legend: 'fieldset',
5354             th: creators.td,
5355             thead: creators.tbody,
5356             tfoot: creators.tbody,
5357             caption: creators.tbody,
5358             colgroup: creators.tbody,
5359             optgroup: creators.option
5360         });
5361     }
5362
5363     Y.mix(Y_DOM.VALUE_GETTERS, {
5364         option: function(node) {
5365             var attrs = node.attributes;
5366             return (attrs.value && attrs.value.specified) ? node.value : node.text;
5367         },
5368
5369         select: function(node) {
5370             var val = node.value,
5371                 options = node.options;
5372
5373             if (options && options.length) {
5374                 // TODO: implement multipe select
5375                 if (node.multiple) {
5376                 } else {
5377                     val = Y_DOM.getValue(options[node.selectedIndex]);
5378                 }
5379             }
5380
5381             return val;
5382         }
5383     });
5384 })(Y);
5385
5386 Y.DOM = Y_DOM;
5387 })(Y);
5388 var addClass, hasClass, removeClass;
5389
5390 Y.mix(Y.DOM, {
5391     /**
5392      * Determines whether a DOM element has the given className.
5393      * @method hasClass
5394      * @for DOM
5395      * @param {HTMLElement} element The DOM element. 
5396      * @param {String} className the class name to search for
5397      * @return {Boolean} Whether or not the element has the given class. 
5398      */
5399     hasClass: function(node, className) {
5400         var re = Y.DOM._getRegExp('(?:^|\\s+)' + className + '(?:\\s+|$)');
5401         return re.test(node.className);
5402     },
5403
5404     /**
5405      * Adds a class name to a given DOM element.
5406      * @method addClass         
5407      * @for DOM
5408      * @param {HTMLElement} element The DOM element. 
5409      * @param {String} className the class name to add to the class attribute
5410      */
5411     addClass: function(node, className) {
5412         if (!Y.DOM.hasClass(node, className)) { // skip if already present 
5413             node.className = Y.Lang.trim([node.className, className].join(' '));
5414         }
5415     },
5416
5417     /**
5418      * Removes a class name from a given element.
5419      * @method removeClass         
5420      * @for DOM
5421      * @param {HTMLElement} element The DOM element. 
5422      * @param {String} className the class name to remove from the class attribute
5423      */
5424     removeClass: function(node, className) {
5425         if (className && hasClass(node, className)) {
5426             node.className = Y.Lang.trim(node.className.replace(Y.DOM._getRegExp('(?:^|\\s+)' +
5427                             className + '(?:\\s+|$)'), ' '));
5428
5429             if ( hasClass(node, className) ) { // in case of multiple adjacent
5430                 removeClass(node, className);
5431             }
5432         }                 
5433     },
5434
5435     /**
5436      * Replace a class with another class for a given element.
5437      * If no oldClassName is present, the newClassName is simply added.
5438      * @method replaceClass  
5439      * @for DOM
5440      * @param {HTMLElement} element The DOM element 
5441      * @param {String} oldClassName the class name to be replaced
5442      * @param {String} newClassName the class name that will be replacing the old class name
5443      */
5444     replaceClass: function(node, oldC, newC) {
5445         removeClass(node, oldC); // remove first in case oldC === newC
5446         addClass(node, newC);
5447     },
5448
5449     /**
5450      * If the className exists on the node it is removed, if it doesn't exist it is added.
5451      * @method toggleClass  
5452      * @for DOM
5453      * @param {HTMLElement} element The DOM element
5454      * @param {String} className the class name to be toggled
5455      * @param {Boolean} addClass optional boolean to indicate whether class
5456      * should be added or removed regardless of current state
5457      */
5458     toggleClass: function(node, className, force) {
5459         var add = (force !== undefined) ? force :
5460                 !(hasClass(node, className));
5461
5462         if (add) {
5463             addClass(node, className);
5464         } else {
5465             removeClass(node, className);
5466         }
5467     }
5468 });
5469
5470 hasClass = Y.DOM.hasClass;
5471 removeClass = Y.DOM.removeClass;
5472 addClass = Y.DOM.addClass;
5473
5474 Y.mix(Y.DOM, {
5475     /**
5476      * Sets the width of the element to the given size, regardless
5477      * of box model, border, padding, etc.
5478      * @method setWidth
5479      * @param {HTMLElement} element The DOM element. 
5480      * @param {String|Int} size The pixel height to size to
5481      */
5482
5483     setWidth: function(node, size) {
5484         Y.DOM._setSize(node, 'width', size);
5485     },
5486
5487     /**
5488      * Sets the height of the element to the given size, regardless
5489      * of box model, border, padding, etc.
5490      * @method setHeight
5491      * @param {HTMLElement} element The DOM element. 
5492      * @param {String|Int} size The pixel height to size to
5493      */
5494
5495     setHeight: function(node, size) {
5496         Y.DOM._setSize(node, 'height', size);
5497     },
5498
5499     _setSize: function(node, prop, val) {
5500         val = (val > 0) ? val : 0;
5501         var size = 0;
5502
5503         node.style[prop] = val + 'px';
5504         size = (prop === 'height') ? node.offsetHeight : node.offsetWidth;
5505
5506         if (size > val) {
5507             val = val - (size - val);
5508
5509             if (val < 0) {
5510                 val = 0;
5511             }
5512
5513             node.style[prop] = val + 'px';
5514         }
5515     }
5516 });
5517
5518
5519 }, '3.3.0' ,{requires:['oop']});
5520 YUI.add('dom-style', function(Y) {
5521
5522 (function(Y) {
5523 /** 
5524  * Add style management functionality to DOM.
5525  * @module dom
5526  * @submodule dom-style
5527  * @for DOM
5528  */
5529
5530 var DOCUMENT_ELEMENT = 'documentElement',
5531     DEFAULT_VIEW = 'defaultView',
5532     OWNER_DOCUMENT = 'ownerDocument',
5533     STYLE = 'style',
5534     FLOAT = 'float',
5535     CSS_FLOAT = 'cssFloat',
5536     STYLE_FLOAT = 'styleFloat',
5537     TRANSPARENT = 'transparent',
5538     GET_COMPUTED_STYLE = 'getComputedStyle',
5539     GET_BOUNDING_CLIENT_RECT = 'getBoundingClientRect',
5540
5541     WINDOW = Y.config.win,
5542     DOCUMENT = Y.config.doc,
5543     UNDEFINED = undefined,
5544
5545     Y_DOM = Y.DOM,
5546
5547     TRANSFORM = 'transform',
5548     VENDOR_TRANSFORM = [
5549         'WebkitTransform',
5550         'MozTransform',
5551         'OTransform'
5552     ],
5553
5554     re_color = /color$/i,
5555     re_unit = /width|height|top|left|right|bottom|margin|padding/i;
5556
5557 Y.Array.each(VENDOR_TRANSFORM, function(val) {
5558     if (val in DOCUMENT[DOCUMENT_ELEMENT].style) {
5559         TRANSFORM = val;
5560     }
5561 });
5562
5563 Y.mix(Y_DOM, {
5564     DEFAULT_UNIT: 'px',
5565
5566     CUSTOM_STYLES: {
5567     },
5568
5569
5570     /**
5571      * Sets a style property for a given element.
5572      * @method setStyle
5573      * @param {HTMLElement} An HTMLElement to apply the style to.
5574      * @param {String} att The style property to set. 
5575      * @param {String|Number} val The value. 
5576      */
5577     setStyle: function(node, att, val, style) {
5578         style = style || node.style;
5579         var CUSTOM_STYLES = Y_DOM.CUSTOM_STYLES;
5580
5581         if (style) {
5582             if (val === null || val === '') { // normalize unsetting
5583                 val = '';
5584             } else if (!isNaN(new Number(val)) && re_unit.test(att)) { // number values may need a unit
5585                 val += Y_DOM.DEFAULT_UNIT;
5586             }
5587
5588             if (att in CUSTOM_STYLES) {
5589                 if (CUSTOM_STYLES[att].set) {
5590                     CUSTOM_STYLES[att].set(node, val, style);
5591                     return; // NOTE: return
5592                 } else if (typeof CUSTOM_STYLES[att] === 'string') {
5593                     att = CUSTOM_STYLES[att];
5594                 }
5595             } else if (att === '') { // unset inline styles
5596                 att = 'cssText';
5597                 val = '';
5598             }
5599             style[att] = val; 
5600         }
5601     },
5602
5603     /**
5604      * Returns the current style value for the given property.
5605      * @method getStyle
5606      * @param {HTMLElement} An HTMLElement to get the style from.
5607      * @param {String} att The style property to get. 
5608      */
5609     getStyle: function(node, att, style) {
5610         style = style || node.style;
5611         var CUSTOM_STYLES = Y_DOM.CUSTOM_STYLES,
5612             val = '';
5613
5614         if (style) {
5615             if (att in CUSTOM_STYLES) {
5616                 if (CUSTOM_STYLES[att].get) {
5617                     return CUSTOM_STYLES[att].get(node, att, style); // NOTE: return
5618                 } else if (typeof CUSTOM_STYLES[att] === 'string') {
5619                     att = CUSTOM_STYLES[att];
5620                 }
5621             }
5622             val = style[att];
5623             if (val === '') { // TODO: is empty string sufficient?
5624                 val = Y_DOM[GET_COMPUTED_STYLE](node, att);
5625             }
5626         }
5627
5628         return val;
5629     },
5630
5631     /**
5632      * Sets multiple style properties.
5633      * @method setStyles
5634      * @param {HTMLElement} node An HTMLElement to apply the styles to. 
5635      * @param {Object} hash An object literal of property:value pairs. 
5636      */
5637     setStyles: function(node, hash) {
5638         var style = node.style;
5639         Y.each(hash, function(v, n) {
5640             Y_DOM.setStyle(node, n, v, style);
5641         }, Y_DOM);
5642     },
5643
5644     /**
5645      * Returns the computed style for the given node.
5646      * @method getComputedStyle
5647      * @param {HTMLElement} An HTMLElement to get the style from.
5648      * @param {String} att The style property to get. 
5649      * @return {String} The computed value of the style property. 
5650      */
5651     getComputedStyle: function(node, att) {
5652         var val = '',
5653             doc = node[OWNER_DOCUMENT];
5654
5655         if (node[STYLE] && doc[DEFAULT_VIEW] && doc[DEFAULT_VIEW][GET_COMPUTED_STYLE]) {
5656             val = doc[DEFAULT_VIEW][GET_COMPUTED_STYLE](node, null)[att];
5657         }
5658         return val;
5659     }
5660 });
5661
5662 // normalize reserved word float alternatives ("cssFloat" or "styleFloat")
5663 if (DOCUMENT[DOCUMENT_ELEMENT][STYLE][CSS_FLOAT] !== UNDEFINED) {
5664     Y_DOM.CUSTOM_STYLES[FLOAT] = CSS_FLOAT;
5665 } else if (DOCUMENT[DOCUMENT_ELEMENT][STYLE][STYLE_FLOAT] !== UNDEFINED) {
5666     Y_DOM.CUSTOM_STYLES[FLOAT] = STYLE_FLOAT;
5667 }
5668
5669 // fix opera computedStyle default color unit (convert to rgb)
5670 if (Y.UA.opera) {
5671     Y_DOM[GET_COMPUTED_STYLE] = function(node, att) {
5672         var view = node[OWNER_DOCUMENT][DEFAULT_VIEW],
5673             val = view[GET_COMPUTED_STYLE](node, '')[att];
5674
5675         if (re_color.test(att)) {
5676             val = Y.Color.toRGB(val);
5677         }
5678
5679         return val;
5680     };
5681
5682 }
5683
5684 // safari converts transparent to rgba(), others use "transparent"
5685 if (Y.UA.webkit) {
5686     Y_DOM[GET_COMPUTED_STYLE] = function(node, att) {
5687         var view = node[OWNER_DOCUMENT][DEFAULT_VIEW],
5688             val = view[GET_COMPUTED_STYLE](node, '')[att];
5689
5690         if (val === 'rgba(0, 0, 0, 0)') {
5691             val = TRANSPARENT; 
5692         }
5693
5694         return val;
5695     };
5696
5697 }
5698
5699 Y.DOM._getAttrOffset = function(node, attr) {
5700     var val = Y.DOM[GET_COMPUTED_STYLE](node, attr),
5701         offsetParent = node.offsetParent,
5702         position,
5703         parentOffset,
5704         offset;
5705
5706     if (val === 'auto') {
5707         position = Y.DOM.getStyle(node, 'position');
5708         if (position === 'static' || position === 'relative') {
5709             val = 0;    
5710         } else if (offsetParent && offsetParent[GET_BOUNDING_CLIENT_RECT]) {
5711             parentOffset = offsetParent[GET_BOUNDING_CLIENT_RECT]()[attr];
5712             offset = node[GET_BOUNDING_CLIENT_RECT]()[attr];
5713             if (attr === 'left' || attr === 'top') {
5714                 val = offset - parentOffset;
5715             } else {
5716                 val = parentOffset - node[GET_BOUNDING_CLIENT_RECT]()[attr];
5717             }
5718         }
5719     }
5720
5721     return val;
5722 };
5723
5724 Y.DOM._getOffset = function(node) {
5725     var pos,
5726         xy = null;
5727
5728     if (node) {
5729         pos = Y_DOM.getStyle(node, 'position');
5730         xy = [
5731             parseInt(Y_DOM[GET_COMPUTED_STYLE](node, 'left'), 10),
5732             parseInt(Y_DOM[GET_COMPUTED_STYLE](node, 'top'), 10)
5733         ];
5734
5735         if ( isNaN(xy[0]) ) { // in case of 'auto'
5736             xy[0] = parseInt(Y_DOM.getStyle(node, 'left'), 10); // try inline
5737             if ( isNaN(xy[0]) ) { // default to offset value
5738                 xy[0] = (pos === 'relative') ? 0 : node.offsetLeft || 0;
5739             }
5740         } 
5741
5742         if ( isNaN(xy[1]) ) { // in case of 'auto'
5743             xy[1] = parseInt(Y_DOM.getStyle(node, 'top'), 10); // try inline
5744             if ( isNaN(xy[1]) ) { // default to offset value
5745                 xy[1] = (pos === 'relative') ? 0 : node.offsetTop || 0;
5746             }
5747         } 
5748     }
5749
5750     return xy;
5751
5752 };
5753
5754 Y_DOM.CUSTOM_STYLES.transform = {
5755     set: function(node, val, style) {
5756         style[TRANSFORM] = val;
5757     },
5758
5759     get: function(node, style) {
5760         return Y_DOM[GET_COMPUTED_STYLE](node, TRANSFORM);
5761     }
5762 };
5763
5764
5765 })(Y);
5766 (function(Y) {
5767 var PARSE_INT = parseInt,
5768     RE = RegExp;
5769
5770 Y.Color = {
5771     KEYWORDS: {
5772         black: '000',
5773         silver: 'c0c0c0',
5774         gray: '808080',
5775         white: 'fff',
5776         maroon: '800000',
5777         red: 'f00',
5778         purple: '800080',
5779         fuchsia: 'f0f',
5780         green: '008000',
5781         lime: '0f0',
5782         olive: '808000',
5783         yellow: 'ff0',
5784         navy: '000080',
5785         blue: '00f',
5786         teal: '008080',
5787         aqua: '0ff'
5788     },
5789
5790     re_RGB: /^rgb\(([0-9]+)\s*,\s*([0-9]+)\s*,\s*([0-9]+)\)$/i,
5791     re_hex: /^#?([0-9A-F]{2})([0-9A-F]{2})([0-9A-F]{2})$/i,
5792     re_hex3: /([0-9A-F])/gi,
5793
5794     toRGB: function(val) {
5795         if (!Y.Color.re_RGB.test(val)) {
5796             val = Y.Color.toHex(val);
5797         }
5798
5799         if(Y.Color.re_hex.exec(val)) {
5800             val = 'rgb(' + [
5801                 PARSE_INT(RE.$1, 16),
5802                 PARSE_INT(RE.$2, 16),
5803                 PARSE_INT(RE.$3, 16)
5804             ].join(', ') + ')';
5805         }
5806         return val;
5807     },
5808
5809     toHex: function(val) {
5810         val = Y.Color.KEYWORDS[val] || val;
5811         if (Y.Color.re_RGB.exec(val)) {
5812             val = [
5813                 Number(RE.$1).toString(16),
5814                 Number(RE.$2).toString(16),
5815                 Number(RE.$3).toString(16)
5816             ];
5817
5818             for (var i = 0; i < val.length; i++) {
5819                 if (val[i].length < 2) {
5820                     val[i] = '0' + val[i];
5821                 }
5822             }
5823
5824             val = val.join('');
5825         }
5826
5827         if (val.length < 6) {
5828             val = val.replace(Y.Color.re_hex3, '$1$1');
5829         }
5830
5831         if (val !== 'transparent' && val.indexOf('#') < 0) {
5832             val = '#' + val;
5833         }
5834
5835         return val.toUpperCase();
5836     }
5837 };
5838 })(Y);
5839
5840
5841
5842 }, '3.3.0' ,{requires:['dom-base']});
5843 YUI.add('dom-screen', function(Y) {
5844
5845 (function(Y) {
5846
5847 /**
5848  * Adds position and region management functionality to DOM.
5849  * @module dom
5850  * @submodule dom-screen
5851  * @for DOM
5852  */
5853
5854 var DOCUMENT_ELEMENT = 'documentElement',
5855     COMPAT_MODE = 'compatMode',
5856     POSITION = 'position',
5857     FIXED = 'fixed',
5858     RELATIVE = 'relative',
5859     LEFT = 'left',
5860     TOP = 'top',
5861     _BACK_COMPAT = 'BackCompat',
5862     MEDIUM = 'medium',
5863     BORDER_LEFT_WIDTH = 'borderLeftWidth',
5864     BORDER_TOP_WIDTH = 'borderTopWidth',
5865     GET_BOUNDING_CLIENT_RECT = 'getBoundingClientRect',
5866     GET_COMPUTED_STYLE = 'getComputedStyle',
5867
5868     Y_DOM = Y.DOM,
5869
5870     // TODO: how about thead/tbody/tfoot/tr?
5871     // TODO: does caption matter?
5872     RE_TABLE = /^t(?:able|d|h)$/i,
5873
5874     SCROLL_NODE;
5875
5876 if (Y.UA.ie) {
5877     if (Y.config.doc[COMPAT_MODE] !== 'quirks') {
5878         SCROLL_NODE = DOCUMENT_ELEMENT; 
5879     } else {
5880         SCROLL_NODE = 'body';
5881     }
5882 }
5883
5884 Y.mix(Y_DOM, {
5885     /**
5886      * Returns the inner height of the viewport (exludes scrollbar). 
5887      * @method winHeight
5888      * @return {Number} The current height of the viewport.
5889      */
5890     winHeight: function(node) {
5891         var h = Y_DOM._getWinSize(node).height;
5892         return h;
5893     },
5894
5895     /**
5896      * Returns the inner width of the viewport (exludes scrollbar). 
5897      * @method winWidth
5898      * @return {Number} The current width of the viewport.
5899      */
5900     winWidth: function(node) {
5901         var w = Y_DOM._getWinSize(node).width;
5902         return w;
5903     },
5904
5905     /**
5906      * Document height 
5907      * @method docHeight
5908      * @return {Number} The current height of the document.
5909      */
5910     docHeight:  function(node) {
5911         var h = Y_DOM._getDocSize(node).height;
5912         return Math.max(h, Y_DOM._getWinSize(node).height);
5913     },
5914
5915     /**
5916      * Document width 
5917      * @method docWidth
5918      * @return {Number} The current width of the document.
5919      */
5920     docWidth:  function(node) {
5921         var w = Y_DOM._getDocSize(node).width;
5922         return Math.max(w, Y_DOM._getWinSize(node).width);
5923     },
5924
5925     /**
5926      * Amount page has been scroll horizontally 
5927      * @method docScrollX
5928      * @return {Number} The current amount the screen is scrolled horizontally.
5929      */
5930     docScrollX: function(node, doc) {
5931         doc = doc || (node) ? Y_DOM._getDoc(node) : Y.config.doc; // perf optimization
5932         var dv = doc.defaultView,
5933             pageOffset = (dv) ? dv.pageXOffset : 0;
5934         return Math.max(doc[DOCUMENT_ELEMENT].scrollLeft, doc.body.scrollLeft, pageOffset);
5935     },
5936
5937     /**
5938      * Amount page has been scroll vertically 
5939      * @method docScrollY
5940      * @return {Number} The current amount the screen is scrolled vertically.
5941      */
5942     docScrollY:  function(node, doc) {
5943         doc = doc || (node) ? Y_DOM._getDoc(node) : Y.config.doc; // perf optimization
5944         var dv = doc.defaultView,
5945             pageOffset = (dv) ? dv.pageYOffset : 0;
5946         return Math.max(doc[DOCUMENT_ELEMENT].scrollTop, doc.body.scrollTop, pageOffset);
5947     },
5948
5949     /**
5950      * Gets the current position of an element based on page coordinates. 
5951      * Element must be part of the DOM tree to have page coordinates
5952      * (display:none or elements not appended return false).
5953      * @method getXY
5954      * @param element The target element
5955      * @return {Array} The XY position of the element
5956
5957      TODO: test inDocument/display?
5958      */
5959     getXY: function() {
5960         if (Y.config.doc[DOCUMENT_ELEMENT][GET_BOUNDING_CLIENT_RECT]) {
5961             return function(node) {
5962                 var xy = null,
5963                     scrollLeft,
5964                     scrollTop,
5965                     box,
5966                     off1, off2,
5967                     bLeft, bTop,
5968                     mode,
5969                     doc,
5970                     inDoc,
5971                     rootNode;
5972
5973                 if (node && node.tagName) {
5974                     doc = node.ownerDocument;
5975                     rootNode = doc[DOCUMENT_ELEMENT];
5976
5977                     // inline inDoc check for perf
5978                     if (rootNode.contains) {
5979                         inDoc = rootNode.contains(node); 
5980                     } else {
5981                         inDoc = Y.DOM.contains(rootNode, node);
5982                     }
5983
5984                     if (inDoc) {
5985                         scrollLeft = (SCROLL_NODE) ? doc[SCROLL_NODE].scrollLeft : Y_DOM.docScrollX(node, doc);
5986                         scrollTop = (SCROLL_NODE) ? doc[SCROLL_NODE].scrollTop : Y_DOM.docScrollY(node, doc);
5987                         box = node[GET_BOUNDING_CLIENT_RECT]();
5988                         xy = [box.left, box.top];
5989
5990                             if (Y.UA.ie) {
5991                                 off1 = 2;
5992                                 off2 = 2;
5993                                 mode = doc[COMPAT_MODE];
5994                                 bLeft = Y_DOM[GET_COMPUTED_STYLE](doc[DOCUMENT_ELEMENT], BORDER_LEFT_WIDTH);
5995                                 bTop = Y_DOM[GET_COMPUTED_STYLE](doc[DOCUMENT_ELEMENT], BORDER_TOP_WIDTH);
5996
5997                                 if (Y.UA.ie === 6) {
5998                                     if (mode !== _BACK_COMPAT) {
5999                                         off1 = 0;
6000                                         off2 = 0;
6001                                     }
6002                                 }
6003                                 
6004                                 if ((mode == _BACK_COMPAT)) {
6005                                     if (bLeft !== MEDIUM) {
6006                                         off1 = parseInt(bLeft, 10);
6007                                     }
6008                                     if (bTop !== MEDIUM) {
6009                                         off2 = parseInt(bTop, 10);
6010                                     }
6011                                 }
6012                                 
6013                                 xy[0] -= off1;
6014                                 xy[1] -= off2;
6015
6016                             }
6017
6018                         if ((scrollTop || scrollLeft)) {
6019                             if (!Y.UA.ios) {
6020                                 xy[0] += scrollLeft;
6021                                 xy[1] += scrollTop;
6022                             }
6023                             
6024                         }
6025                     } else {
6026                         xy = Y_DOM._getOffset(node);       
6027                     }
6028                 }
6029                 return xy;                   
6030             }
6031         } else {
6032             return function(node) { // manually calculate by crawling up offsetParents
6033                 //Calculate the Top and Left border sizes (assumes pixels)
6034                 var xy = null,
6035                     doc,
6036                     parentNode,
6037                     bCheck,
6038                     scrollTop,
6039                     scrollLeft;
6040
6041                 if (node) {
6042                     if (Y_DOM.inDoc(node)) {
6043                         xy = [node.offsetLeft, node.offsetTop];
6044                         doc = node.ownerDocument;
6045                         parentNode = node;
6046                         // TODO: refactor with !! or just falsey
6047                         bCheck = ((Y.UA.gecko || Y.UA.webkit > 519) ? true : false);
6048
6049                         // TODO: worth refactoring for TOP/LEFT only?
6050                         while ((parentNode = parentNode.offsetParent)) {
6051                             xy[0] += parentNode.offsetLeft;
6052                             xy[1] += parentNode.offsetTop;
6053                             if (bCheck) {
6054                                 xy = Y_DOM._calcBorders(parentNode, xy);
6055                             }
6056                         }
6057
6058                         // account for any scrolled ancestors
6059                         if (Y_DOM.getStyle(node, POSITION) != FIXED) {
6060                             parentNode = node;
6061
6062                             while ((parentNode = parentNode.parentNode)) {
6063                                 scrollTop = parentNode.scrollTop;
6064                                 scrollLeft = parentNode.scrollLeft;
6065
6066                                 //Firefox does something funky with borders when overflow is not visible.
6067                                 if (Y.UA.gecko && (Y_DOM.getStyle(parentNode, 'overflow') !== 'visible')) {
6068                                         xy = Y_DOM._calcBorders(parentNode, xy);
6069                                 }
6070                                 
6071
6072                                 if (scrollTop || scrollLeft) {
6073                                     xy[0] -= scrollLeft;
6074                                     xy[1] -= scrollTop;
6075                                 }
6076                             }
6077                             xy[0] += Y_DOM.docScrollX(node, doc);
6078                             xy[1] += Y_DOM.docScrollY(node, doc);
6079
6080                         } else {
6081                             //Fix FIXED position -- add scrollbars
6082                             xy[0] += Y_DOM.docScrollX(node, doc);
6083                             xy[1] += Y_DOM.docScrollY(node, doc);
6084                         }
6085                     } else {
6086                         xy = Y_DOM._getOffset(node);
6087                     }
6088                 }
6089
6090                 return xy;                
6091             };
6092         }
6093     }(),// NOTE: Executing for loadtime branching
6094
6095     /**
6096      * Gets the current X position of an element based on page coordinates. 
6097      * Element must be part of the DOM tree to have page coordinates
6098      * (display:none or elements not appended return false).
6099      * @method getX
6100      * @param element The target element
6101      * @return {Int} The X position of the element
6102      */
6103
6104     getX: function(node) {
6105         return Y_DOM.getXY(node)[0];
6106     },
6107
6108     /**
6109      * Gets the current Y position of an element based on page coordinates. 
6110      * Element must be part of the DOM tree to have page coordinates
6111      * (display:none or elements not appended return false).
6112      * @method getY
6113      * @param element The target element
6114      * @return {Int} The Y position of the element
6115      */
6116
6117     getY: function(node) {
6118         return Y_DOM.getXY(node)[1];
6119     },
6120
6121     /**
6122      * Set the position of an html element in page coordinates.
6123      * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
6124      * @method setXY
6125      * @param element The target element
6126      * @param {Array} xy Contains X & Y values for new position (coordinates are page-based)
6127      * @param {Boolean} noRetry By default we try and set the position a second time if the first fails
6128      */
6129     setXY: function(node, xy, noRetry) {
6130         var setStyle = Y_DOM.setStyle,
6131             pos,
6132             delta,
6133             newXY,
6134             currentXY;
6135
6136         if (node && xy) {
6137             pos = Y_DOM.getStyle(node, POSITION);
6138
6139             delta = Y_DOM._getOffset(node);       
6140             if (pos == 'static') { // default to relative
6141                 pos = RELATIVE;
6142                 setStyle(node, POSITION, pos);
6143             }
6144             currentXY = Y_DOM.getXY(node);
6145
6146             if (xy[0] !== null) {
6147                 setStyle(node, LEFT, xy[0] - currentXY[0] + delta[0] + 'px');
6148             }
6149
6150             if (xy[1] !== null) {
6151                 setStyle(node, TOP, xy[1] - currentXY[1] + delta[1] + 'px');
6152             }
6153
6154             if (!noRetry) {
6155                 newXY = Y_DOM.getXY(node);
6156                 if (newXY[0] !== xy[0] || newXY[1] !== xy[1]) {
6157                     Y_DOM.setXY(node, xy, true); 
6158                 }
6159             }
6160           
6161         } else {
6162         }
6163     },
6164
6165     /**
6166      * Set the X position of an html element in page coordinates, regardless of how the element is positioned.
6167      * The element(s) must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
6168      * @method setX
6169      * @param element The target element
6170      * @param {Int} x The X values for new position (coordinates are page-based)
6171      */
6172     setX: function(node, x) {
6173         return Y_DOM.setXY(node, [x, null]);
6174     },
6175
6176     /**
6177      * Set the Y position of an html element in page coordinates, regardless of how the element is positioned.
6178      * The element(s) must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
6179      * @method setY
6180      * @param element The target element
6181      * @param {Int} y The Y values for new position (coordinates are page-based)
6182      */
6183     setY: function(node, y) {
6184         return Y_DOM.setXY(node, [null, y]);
6185     },
6186
6187     /**
6188      * @method swapXY
6189      * @description Swap the xy position with another node
6190      * @param {Node} node The node to swap with
6191      * @param {Node} otherNode The other node to swap with
6192      * @return {Node}
6193      */
6194     swapXY: function(node, otherNode) {
6195         var xy = Y_DOM.getXY(node);
6196         Y_DOM.setXY(node, Y_DOM.getXY(otherNode));
6197         Y_DOM.setXY(otherNode, xy);
6198     },
6199
6200     _calcBorders: function(node, xy2) {
6201         var t = parseInt(Y_DOM[GET_COMPUTED_STYLE](node, BORDER_TOP_WIDTH), 10) || 0,
6202             l = parseInt(Y_DOM[GET_COMPUTED_STYLE](node, BORDER_LEFT_WIDTH), 10) || 0;
6203         if (Y.UA.gecko) {
6204             if (RE_TABLE.test(node.tagName)) {
6205                 t = 0;
6206                 l = 0;
6207             }
6208         }
6209         xy2[0] += l;
6210         xy2[1] += t;
6211         return xy2;
6212     },
6213
6214     _getWinSize: function(node, doc) {
6215         doc  = doc || (node) ? Y_DOM._getDoc(node) : Y.config.doc;
6216         var win = doc.defaultView || doc.parentWindow,
6217             mode = doc[COMPAT_MODE],
6218             h = win.innerHeight,
6219             w = win.innerWidth,
6220             root = doc[DOCUMENT_ELEMENT];
6221
6222         if ( mode && !Y.UA.opera ) { // IE, Gecko
6223             if (mode != 'CSS1Compat') { // Quirks
6224                 root = doc.body; 
6225             }
6226             h = root.clientHeight;
6227             w = root.clientWidth;
6228         }
6229         return { height: h, width: w };
6230     },
6231
6232     _getDocSize: function(node) {
6233         var doc = (node) ? Y_DOM._getDoc(node) : Y.config.doc,
6234             root = doc[DOCUMENT_ELEMENT];
6235
6236         if (doc[COMPAT_MODE] != 'CSS1Compat') {
6237             root = doc.body;
6238         }
6239
6240         return { height: root.scrollHeight, width: root.scrollWidth };
6241     }
6242 });
6243
6244 })(Y);
6245 (function(Y) {
6246 var TOP = 'top',
6247     RIGHT = 'right',
6248     BOTTOM = 'bottom',
6249     LEFT = 'left',
6250
6251     getOffsets = function(r1, r2) {
6252         var t = Math.max(r1[TOP], r2[TOP]),
6253             r = Math.min(r1[RIGHT], r2[RIGHT]),
6254             b = Math.min(r1[BOTTOM], r2[BOTTOM]),
6255             l = Math.max(r1[LEFT], r2[LEFT]),
6256             ret = {};
6257         
6258         ret[TOP] = t;
6259         ret[RIGHT] = r;
6260         ret[BOTTOM] = b;
6261         ret[LEFT] = l;
6262         return ret;
6263     },
6264
6265     DOM = Y.DOM;
6266
6267 Y.mix(DOM, {
6268     /**
6269      * Returns an Object literal containing the following about this element: (top, right, bottom, left)
6270      * @for DOM
6271      * @method region
6272      * @param {HTMLElement} element The DOM element. 
6273      @return {Object} Object literal containing the following about this element: (top, right, bottom, left)
6274      */
6275     region: function(node) {
6276         var xy = DOM.getXY(node),
6277             ret = false;
6278         
6279         if (node && xy) {
6280             ret = DOM._getRegion(
6281                 xy[1], // top
6282                 xy[0] + node.offsetWidth, // right
6283                 xy[1] + node.offsetHeight, // bottom
6284                 xy[0] // left
6285             );
6286         }
6287
6288         return ret;
6289     },
6290
6291     /**
6292      * Find the intersect information for the passes nodes.
6293      * @method intersect
6294      * @for DOM
6295      * @param {HTMLElement} element The first element 
6296      * @param {HTMLElement | Object} element2 The element or region to check the interect with
6297      * @param {Object} altRegion An object literal containing the region for the first element if we already have the data (for performance i.e. DragDrop)
6298      @return {Object} Object literal containing the following intersection data: (top, right, bottom, left, area, yoff, xoff, inRegion)
6299      */
6300     intersect: function(node, node2, altRegion) {
6301         var r = altRegion || DOM.region(node), region = {},
6302             n = node2,
6303             off;
6304
6305         if (n.tagName) {
6306             region = DOM.region(n);
6307         } else if (Y.Lang.isObject(node2)) {
6308             region = node2;
6309         } else {
6310             return false;
6311         }
6312         
6313         off = getOffsets(region, r);
6314         return {
6315             top: off[TOP],
6316             right: off[RIGHT],
6317             bottom: off[BOTTOM],
6318             left: off[LEFT],
6319             area: ((off[BOTTOM] - off[TOP]) * (off[RIGHT] - off[LEFT])),
6320             yoff: ((off[BOTTOM] - off[TOP])),
6321             xoff: (off[RIGHT] - off[LEFT]),
6322             inRegion: DOM.inRegion(node, node2, false, altRegion)
6323         };
6324         
6325     },
6326     /**
6327      * Check if any part of this node is in the passed region
6328      * @method inRegion
6329      * @for DOM
6330      * @param {Object} node2 The node to get the region from or an Object literal of the region
6331      * $param {Boolean} all Should all of the node be inside the region
6332      * @param {Object} altRegion An object literal containing the region for this node if we already have the data (for performance i.e. DragDrop)
6333      * @return {Boolean} True if in region, false if not.
6334      */
6335     inRegion: function(node, node2, all, altRegion) {
6336         var region = {},
6337             r = altRegion || DOM.region(node),
6338             n = node2,
6339             off;
6340
6341         if (n.tagName) {
6342             region = DOM.region(n);
6343         } else if (Y.Lang.isObject(node2)) {
6344             region = node2;
6345         } else {
6346             return false;
6347         }
6348             
6349         if (all) {
6350             return (
6351                 r[LEFT]   >= region[LEFT]   &&
6352                 r[RIGHT]  <= region[RIGHT]  && 
6353                 r[TOP]    >= region[TOP]    && 
6354                 r[BOTTOM] <= region[BOTTOM]  );
6355         } else {
6356             off = getOffsets(region, r);
6357             if (off[BOTTOM] >= off[TOP] && off[RIGHT] >= off[LEFT]) {
6358                 return true;
6359             } else {
6360                 return false;
6361             }
6362             
6363         }
6364     },
6365
6366     /**
6367      * Check if any part of this element is in the viewport
6368      * @method inViewportRegion
6369      * @for DOM
6370      * @param {HTMLElement} element The DOM element. 
6371      * @param {Boolean} all Should all of the node be inside the region
6372      * @param {Object} altRegion An object literal containing the region for this node if we already have the data (for performance i.e. DragDrop)
6373      * @return {Boolean} True if in region, false if not.
6374      */
6375     inViewportRegion: function(node, all, altRegion) {
6376         return DOM.inRegion(node, DOM.viewportRegion(node), all, altRegion);
6377             
6378     },
6379
6380     _getRegion: function(t, r, b, l) {
6381         var region = {};
6382
6383         region[TOP] = region[1] = t;
6384         region[LEFT] = region[0] = l;
6385         region[BOTTOM] = b;
6386         region[RIGHT] = r;
6387         region.width = region[RIGHT] - region[LEFT];
6388         region.height = region[BOTTOM] - region[TOP];
6389
6390         return region;
6391     },
6392
6393     /**
6394      * Returns an Object literal containing the following about the visible region of viewport: (top, right, bottom, left)
6395      * @method viewportRegion
6396      * @for DOM
6397      * @return {Object} Object literal containing the following about the visible region of the viewport: (top, right, bottom, left)
6398      */
6399     viewportRegion: function(node) {
6400         node = node || Y.config.doc.documentElement;
6401         var ret = false,
6402             scrollX,
6403             scrollY;
6404
6405         if (node) {
6406             scrollX = DOM.docScrollX(node);
6407             scrollY = DOM.docScrollY(node);
6408
6409             ret = DOM._getRegion(scrollY, // top
6410                 DOM.winWidth(node) + scrollX, // right
6411                 scrollY + DOM.winHeight(node), // bottom
6412                 scrollX); // left
6413         }
6414
6415         return ret;
6416     }
6417 });
6418 })(Y);
6419
6420
6421 }, '3.3.0' ,{requires:['dom-base', 'dom-style', 'event-base']});
6422 YUI.add('selector-native', function(Y) {
6423
6424 (function(Y) {
6425 /**
6426  * The selector-native module provides support for native querySelector
6427  * @module dom
6428  * @submodule selector-native
6429  * @for Selector
6430  */
6431
6432 /**
6433  * Provides support for using CSS selectors to query the DOM 
6434  * @class Selector 
6435  * @static
6436  * @for Selector
6437  */
6438
6439 Y.namespace('Selector'); // allow native module to standalone
6440
6441 var COMPARE_DOCUMENT_POSITION = 'compareDocumentPosition',
6442     OWNER_DOCUMENT = 'ownerDocument';
6443
6444 var Selector = {
6445     _foundCache: [],
6446
6447     useNative: true,
6448
6449     _compare: ('sourceIndex' in Y.config.doc.documentElement) ?
6450         function(nodeA, nodeB) {
6451             var a = nodeA.sourceIndex,
6452                 b = nodeB.sourceIndex;
6453
6454             if (a === b) {
6455                 return 0;
6456             } else if (a > b) {
6457                 return 1;
6458             }
6459
6460             return -1;
6461
6462         } : (Y.config.doc.documentElement[COMPARE_DOCUMENT_POSITION] ?
6463         function(nodeA, nodeB) {
6464             if (nodeA[COMPARE_DOCUMENT_POSITION](nodeB) & 4) {
6465                 return -1;
6466             } else {
6467                 return 1;
6468             }
6469         } :
6470         function(nodeA, nodeB) {
6471             var rangeA, rangeB, compare;
6472             if (nodeA && nodeB) {
6473                 rangeA = nodeA[OWNER_DOCUMENT].createRange();
6474                 rangeA.setStart(nodeA, 0);
6475                 rangeB = nodeB[OWNER_DOCUMENT].createRange();
6476                 rangeB.setStart(nodeB, 0);
6477                 compare = rangeA.compareBoundaryPoints(1, rangeB); // 1 === Range.START_TO_END
6478             }
6479
6480             return compare;
6481         
6482     }),
6483
6484     _sort: function(nodes) {
6485         if (nodes) {
6486             nodes = Y.Array(nodes, 0, true);
6487             if (nodes.sort) {
6488                 nodes.sort(Selector._compare);
6489             }
6490         }
6491
6492         return nodes;
6493     },
6494
6495     _deDupe: function(nodes) {
6496         var ret = [],
6497             i, node;
6498
6499         for (i = 0; (node = nodes[i++]);) {
6500             if (!node._found) {
6501                 ret[ret.length] = node;
6502                 node._found = true;
6503             }
6504         }
6505
6506         for (i = 0; (node = ret[i++]);) {
6507             node._found = null;
6508             node.removeAttribute('_found');
6509         }
6510
6511         return ret;
6512     },
6513
6514     /**
6515      * Retrieves a set of nodes based on a given CSS selector. 
6516      * @method query
6517      *
6518      * @param {string} selector The CSS Selector to test the node against.
6519      * @param {HTMLElement} root optional An HTMLElement to start the query from. Defaults to Y.config.doc
6520      * @param {Boolean} firstOnly optional Whether or not to return only the first match.
6521      * @return {Array} An array of nodes that match the given selector.
6522      * @static
6523      */
6524     query: function(selector, root, firstOnly, skipNative) {
6525         root = root || Y.config.doc;
6526         var ret = [],
6527             useNative = (Y.Selector.useNative && Y.config.doc.querySelector && !skipNative),
6528             queries = [[selector, root]],
6529             query,
6530             result,
6531             i,
6532             fn = (useNative) ? Y.Selector._nativeQuery : Y.Selector._bruteQuery;
6533
6534         if (selector && fn) {
6535             // split group into seperate queries
6536             if (!skipNative && // already done if skipping
6537                     (!useNative || root.tagName)) { // split native when element scoping is needed
6538                 queries = Selector._splitQueries(selector, root);
6539             }
6540
6541             for (i = 0; (query = queries[i++]);) {
6542                 result = fn(query[0], query[1], firstOnly);
6543                 if (!firstOnly) { // coerce DOM Collection to Array
6544                     result = Y.Array(result, 0, true);
6545                 }
6546                 if (result) {
6547                     ret = ret.concat(result);
6548                 }
6549             }
6550
6551             if (queries.length > 1) { // remove dupes and sort by doc order 
6552                 ret = Selector._sort(Selector._deDupe(ret));
6553             }
6554         }
6555
6556         return (firstOnly) ? (ret[0] || null) : ret;
6557
6558     },
6559
6560     // allows element scoped queries to begin with combinator
6561     // e.g. query('> p', document.body) === query('body > p')
6562     _splitQueries: function(selector, node) {
6563         var groups = selector.split(','),
6564             queries = [],
6565             prefix = '',
6566             i, len;
6567
6568         if (node) {
6569             // enforce for element scoping
6570             if (node.tagName) {
6571                 node.id = node.id || Y.guid();
6572                 prefix = '[id="' + node.id + '"] ';
6573             }
6574
6575             for (i = 0, len = groups.length; i < len; ++i) {
6576                 selector =  prefix + groups[i];
6577                 queries.push([selector, node]);
6578             }
6579         }
6580
6581         return queries;
6582     },
6583
6584     _nativeQuery: function(selector, root, one) {
6585         if (Y.UA.webkit && selector.indexOf(':checked') > -1 &&
6586                 (Y.Selector.pseudos && Y.Selector.pseudos.checked)) { // webkit (chrome, safari) fails to find "selected"
6587             return Y.Selector.query(selector, root, one, true); // redo with skipNative true to try brute query
6588         }
6589         try {
6590             return root['querySelector' + (one ? '' : 'All')](selector);
6591         } catch(e) { // fallback to brute if available
6592             return Y.Selector.query(selector, root, one, true); // redo with skipNative true
6593         }
6594     },
6595
6596     filter: function(nodes, selector) {
6597         var ret = [],
6598             i, node;
6599
6600         if (nodes && selector) {
6601             for (i = 0; (node = nodes[i++]);) {
6602                 if (Y.Selector.test(node, selector)) {
6603                     ret[ret.length] = node;
6604                 }
6605             }
6606         } else {
6607         }
6608
6609         return ret;
6610     },
6611
6612     test: function(node, selector, root) {
6613         var ret = false,
6614             groups = selector.split(','),
6615             useFrag = false,
6616             parent,
6617             item,
6618             items,
6619             frag,
6620             i, j, group;
6621
6622         if (node && node.tagName) { // only test HTMLElements
6623
6624             // we need a root if off-doc
6625             if (!root && !Y.DOM.inDoc(node)) {
6626                 parent = node.parentNode;
6627                 if (parent) { 
6628                     root = parent;
6629                 } else { // only use frag when no parent to query
6630                     frag = node[OWNER_DOCUMENT].createDocumentFragment();
6631                     frag.appendChild(node);
6632                     root = frag;
6633                     useFrag = true;
6634                 }
6635             }
6636             root = root || node[OWNER_DOCUMENT];
6637
6638             if (!node.id) {
6639                 node.id = Y.guid();
6640             }
6641             for (i = 0; (group = groups[i++]);) { // TODO: off-dom test
6642                 group += '[id="' + node.id + '"]';
6643                 items = Y.Selector.query(group, root);
6644
6645                 for (j = 0; item = items[j++];) {
6646                     if (item === node) {
6647                         ret = true;
6648                         break;
6649                     }
6650                 }
6651                 if (ret) {
6652                     break;
6653                 }
6654             }
6655
6656             if (useFrag) { // cleanup
6657                 frag.removeChild(node);
6658             }
6659         }
6660
6661         return ret;
6662     },
6663
6664     /**
6665      * A convenience function to emulate Y.Node's aNode.ancestor(selector).
6666      * @param {HTMLElement} element An HTMLElement to start the query from.
6667      * @param {String} selector The CSS selector to test the node against.
6668      * @return {HTMLElement} The ancestor node matching the selector, or null.
6669      * @param {Boolean} testSelf optional Whether or not to include the element in the scan 
6670      * @static
6671      * @method ancestor
6672      */
6673     ancestor: function (element, selector, testSelf) {
6674         return Y.DOM.ancestor(element, function(n) {
6675             return Y.Selector.test(n, selector);
6676         }, testSelf);
6677     }
6678 };
6679
6680 Y.mix(Y.Selector, Selector, true);
6681
6682 })(Y);
6683
6684
6685 }, '3.3.0' ,{requires:['dom-base']});
6686 YUI.add('selector-css2', function(Y) {
6687
6688 /**
6689  * The selector module provides helper methods allowing CSS2 Selectors to be used with DOM elements.
6690  * @module dom
6691  * @submodule selector-css2
6692  * @for Selector
6693  */
6694
6695 /**
6696  * Provides helper methods for collecting and filtering DOM elements.
6697  */
6698
6699 var PARENT_NODE = 'parentNode',
6700     TAG_NAME = 'tagName',
6701     ATTRIBUTES = 'attributes',
6702     COMBINATOR = 'combinator',
6703     PSEUDOS = 'pseudos',
6704
6705     Selector = Y.Selector,
6706
6707     SelectorCSS2 = {
6708         _reRegExpTokens: /([\^\$\?\[\]\*\+\-\.\(\)\|\\])/, // TODO: move?
6709         SORT_RESULTS: true,
6710         _children: function(node, tag) {
6711             var ret = node.children,
6712                 i,
6713                 children = [],
6714                 childNodes,
6715                 child;
6716
6717             if (node.children && tag && node.children.tags) {
6718                 children = node.children.tags(tag);
6719             } else if ((!ret && node[TAG_NAME]) || (ret && tag)) { // only HTMLElements have children
6720                 childNodes = ret || node.childNodes;
6721                 ret = [];
6722                 for (i = 0; (child = childNodes[i++]);) {
6723                     if (child.tagName) {
6724                         if (!tag || tag === child.tagName) {
6725                             ret.push(child);
6726                         }
6727                     }
6728                 }
6729             }
6730
6731             return ret || [];
6732         },
6733
6734         _re: {
6735             //attr: /(\[.*\])/g,
6736             attr: /(\[[^\]]*\])/g,
6737             pseudos: /:([\-\w]+(?:\(?:['"]?(.+)['"]?\)))*/i
6738         },
6739
6740         /**
6741          * Mapping of shorthand tokens to corresponding attribute selector 
6742          * @property shorthand
6743          * @type object
6744          */
6745         shorthand: {
6746             '\\#(-?[_a-z]+[-\\w]*)': '[id=$1]',
6747             '\\.(-?[_a-z]+[-\\w]*)': '[className~=$1]'
6748         },
6749
6750         /**
6751          * List of operators and corresponding boolean functions. 
6752          * These functions are passed the attribute and the current node's value of the attribute.
6753          * @property operators
6754          * @type object
6755          */
6756         operators: {
6757             '': function(node, attr) { return Y.DOM.getAttribute(node, attr) !== ''; }, // Just test for existence of attribute
6758             //'': '.+',
6759             //'=': '^{val}$', // equality
6760             '~=': '(?:^|\\s+){val}(?:\\s+|$)', // space-delimited
6761             '|=': '^{val}-?' // optional hyphen-delimited
6762         },
6763
6764         pseudos: {
6765            'first-child': function(node) { 
6766                 return Y.Selector._children(node[PARENT_NODE])[0] === node; 
6767             } 
6768         },
6769
6770         _bruteQuery: function(selector, root, firstOnly) {
6771             var ret = [],
6772                 nodes = [],
6773                 tokens = Selector._tokenize(selector),
6774                 token = tokens[tokens.length - 1],
6775                 rootDoc = Y.DOM._getDoc(root),
6776                 child,
6777                 id,
6778                 className,
6779                 tagName;
6780
6781
6782             // if we have an initial ID, set to root when in document
6783             /*
6784             if (tokens[0] && rootDoc === root &&  
6785                     (id = tokens[0].id) &&
6786                     rootDoc.getElementById(id)) {
6787                 root = rootDoc.getElementById(id);
6788             }
6789             */
6790
6791             if (token) {
6792                 // prefilter nodes
6793                 id = token.id;
6794                 className = token.className;
6795                 tagName = token.tagName || '*';
6796
6797                 if (root.getElementsByTagName) { // non-IE lacks DOM api on doc frags
6798                     // try ID first, unless no root.all && root not in document
6799                     // (root.all works off document, but not getElementById)
6800                     // TODO: move to allById?
6801                     if (id && (root.all || (root.nodeType === 9 || Y.DOM.inDoc(root)))) {
6802                         nodes = Y.DOM.allById(id, root);
6803                     // try className
6804                     } else if (className) {
6805                         nodes = root.getElementsByClassName(className);
6806                     } else { // default to tagName
6807                         nodes = root.getElementsByTagName(tagName);
6808                     }
6809
6810                 } else { // brute getElementsByTagName('*')
6811                     child = root.firstChild;
6812                     while (child) {
6813                         if (child.tagName) { // only collect HTMLElements
6814                             nodes.push(child);
6815                         }
6816                         child = child.nextSilbing || child.firstChild;
6817                     }
6818                 }
6819                 if (nodes.length) {
6820                     ret = Selector._filterNodes(nodes, tokens, firstOnly);
6821                 }
6822             }
6823
6824             return ret;
6825         },
6826         
6827         _filterNodes: function(nodes, tokens, firstOnly) {
6828             var i = 0,
6829                 j,
6830                 len = tokens.length,
6831                 n = len - 1,
6832                 result = [],
6833                 node = nodes[0],
6834                 tmpNode = node,
6835                 getters = Y.Selector.getters,
6836                 operator,
6837                 combinator,
6838                 token,
6839                 path,
6840                 pass,
6841                 //FUNCTION = 'function',
6842                 value,
6843                 tests,
6844                 test;
6845
6846             //do {
6847             for (i = 0; (tmpNode = node = nodes[i++]);) {
6848                 n = len - 1;
6849                 path = null;
6850                 
6851                 testLoop:
6852                 while (tmpNode && tmpNode.tagName) {
6853                     token = tokens[n];
6854                     tests = token.tests;
6855                     j = tests.length;
6856                     if (j && !pass) {
6857                         while ((test = tests[--j])) {
6858                             operator = test[1];
6859                             if (getters[test[0]]) {
6860                                 value = getters[test[0]](tmpNode, test[0]);
6861                             } else {
6862                                 value = tmpNode[test[0]];
6863                                 // use getAttribute for non-standard attributes
6864                                 if (value === undefined && tmpNode.getAttribute) {
6865                                     value = tmpNode.getAttribute(test[0]);
6866                                 }
6867                             }
6868
6869                             if ((operator === '=' && value !== test[2]) ||  // fast path for equality
6870                                 (typeof operator !== 'string' && // protect against String.test monkey-patch (Moo)
6871                                 operator.test && !operator.test(value)) ||  // regex test
6872                                 (!operator.test && // protect against RegExp as function (webkit)
6873                                         typeof operator === 'function' && !operator(tmpNode, test[0]))) { // function test
6874
6875                                 // skip non element nodes or non-matching tags
6876                                 if ((tmpNode = tmpNode[path])) {
6877                                     while (tmpNode &&
6878                                         (!tmpNode.tagName ||
6879                                             (token.tagName && token.tagName !== tmpNode.tagName))
6880                                     ) {
6881                                         tmpNode = tmpNode[path]; 
6882                                     }
6883                                 }
6884                                 continue testLoop;
6885                             }
6886                         }
6887                     }
6888
6889                     n--; // move to next token
6890                     // now that we've passed the test, move up the tree by combinator
6891                     if (!pass && (combinator = token.combinator)) {
6892                         path = combinator.axis;
6893                         tmpNode = tmpNode[path];
6894
6895                         // skip non element nodes
6896                         while (tmpNode && !tmpNode.tagName) {
6897                             tmpNode = tmpNode[path]; 
6898                         }
6899
6900                         if (combinator.direct) { // one pass only
6901                             path = null; 
6902                         }
6903
6904                     } else { // success if we made it this far
6905                         result.push(node);
6906                         if (firstOnly) {
6907                             return result;
6908                         }
6909                         break;
6910                     }
6911                 }
6912             }// while (tmpNode = node = nodes[++i]);
6913             node = tmpNode = null;
6914             return result;
6915         },
6916
6917         combinators: {
6918             ' ': {
6919                 axis: 'parentNode'
6920             },
6921
6922             '>': {
6923                 axis: 'parentNode',
6924                 direct: true
6925             },
6926
6927
6928             '+': {
6929                 axis: 'previousSibling',
6930                 direct: true
6931             }
6932         },
6933
6934         _parsers: [
6935             {
6936                 name: ATTRIBUTES,
6937                 re: /^\[(-?[a-z]+[\w\-]*)+([~\|\^\$\*!=]=?)?['"]?([^\]]*?)['"]?\]/i,
6938                 fn: function(match, token) {
6939                     var operator = match[2] || '',
6940                         operators = Y.Selector.operators,
6941                         test;
6942
6943                     // add prefiltering for ID and CLASS
6944                     if ((match[1] === 'id' && operator === '=') ||
6945                             (match[1] === 'className' &&
6946                             Y.config.doc.documentElement.getElementsByClassName &&
6947                             (operator === '~=' || operator === '='))) {
6948                         token.prefilter = match[1];
6949                         token[match[1]] = match[3];
6950                     }
6951
6952                     // add tests
6953                     if (operator in operators) {
6954                         test = operators[operator];
6955                         if (typeof test === 'string') {
6956                             match[3] = match[3].replace(Y.Selector._reRegExpTokens, '\\$1');
6957                             test = Y.DOM._getRegExp(test.replace('{val}', match[3]));
6958                         }
6959                         match[2] = test;
6960                     }
6961                     if (!token.last || token.prefilter !== match[1]) {
6962                         return match.slice(1);
6963                     }
6964                 }
6965
6966             },
6967             {
6968                 name: TAG_NAME,
6969                 re: /^((?:-?[_a-z]+[\w-]*)|\*)/i,
6970                 fn: function(match, token) {
6971                     var tag = match[1].toUpperCase();
6972                     token.tagName = tag;
6973
6974                     if (tag !== '*' && (!token.last || token.prefilter)) {
6975                         return [TAG_NAME, '=', tag];
6976                     }
6977                     if (!token.prefilter) {
6978                         token.prefilter = 'tagName';
6979                     }
6980                 }
6981             },
6982             {
6983                 name: COMBINATOR,
6984                 re: /^\s*([>+~]|\s)\s*/,
6985                 fn: function(match, token) {
6986                 }
6987             },
6988             {
6989                 name: PSEUDOS,
6990                 re: /^:([\-\w]+)(?:\(['"]?(.+)['"]?\))*/i,
6991                 fn: function(match, token) {
6992                     var test = Selector[PSEUDOS][match[1]];
6993                     if (test) { // reorder match array
6994                         return [match[2], test];
6995                     } else { // selector token not supported (possibly missing CSS3 module)
6996                         return false;
6997                     }
6998                 }
6999             }
7000             ],
7001
7002         _getToken: function(token) {
7003             return {
7004                 tagName: null,
7005                 id: null,
7006                 className: null,
7007                 attributes: {},
7008                 combinator: null,
7009                 tests: []
7010             };
7011         },
7012
7013         /**
7014             Break selector into token units per simple selector.
7015             Combinator is attached to the previous token.
7016          */
7017         _tokenize: function(selector) {
7018             selector = selector || '';
7019             selector = Selector._replaceShorthand(Y.Lang.trim(selector)); 
7020             var token = Selector._getToken(),     // one token per simple selector (left selector holds combinator)
7021                 query = selector, // original query for debug report
7022                 tokens = [],    // array of tokens
7023                 found = false,  // whether or not any matches were found this pass
7024                 match,         // the regex match
7025                 test,
7026                 i, parser;
7027
7028             /*
7029                 Search for selector patterns, store, and strip them from the selector string
7030                 until no patterns match (invalid selector) or we run out of chars.
7031
7032                 Multiple attributes and pseudos are allowed, in any order.
7033                 for example:
7034                     'form:first-child[type=button]:not(button)[lang|=en]'
7035             */
7036             outer:
7037             do {
7038                 found = false; // reset after full pass
7039                 for (i = 0; (parser = Selector._parsers[i++]);) {
7040                     if ( (match = parser.re.exec(selector)) ) { // note assignment
7041                         if (parser.name !== COMBINATOR ) {
7042                             token.selector = selector;
7043                         }
7044                         selector = selector.replace(match[0], ''); // strip current match from selector
7045                         if (!selector.length) {
7046                             token.last = true;
7047                         }
7048
7049                         if (Selector._attrFilters[match[1]]) { // convert class to className, etc.
7050                             match[1] = Selector._attrFilters[match[1]];
7051                         }
7052
7053                         test = parser.fn(match, token);
7054                         if (test === false) { // selector not supported
7055                             found = false;
7056                             break outer;
7057                         } else if (test) {
7058                             token.tests.push(test);
7059                         }
7060
7061                         if (!selector.length || parser.name === COMBINATOR) {
7062                             tokens.push(token);
7063                             token = Selector._getToken(token);
7064                             if (parser.name === COMBINATOR) {
7065                                 token.combinator = Y.Selector.combinators[match[1]];
7066                             }
7067                         }
7068                         found = true;
7069                     }
7070                 }
7071             } while (found && selector.length);
7072
7073             if (!found || selector.length) { // not fully parsed
7074                 tokens = [];
7075             }
7076             return tokens;
7077         },
7078
7079         _replaceShorthand: function(selector) {
7080             var shorthand = Selector.shorthand,
7081                 attrs = selector.match(Selector._re.attr), // pull attributes to avoid false pos on "." and "#"
7082                 pseudos = selector.match(Selector._re.pseudos), // pull attributes to avoid false pos on "." and "#"
7083                 re, i, len;
7084
7085             if (pseudos) {
7086                 selector = selector.replace(Selector._re.pseudos, '!!REPLACED_PSEUDO!!');
7087             }
7088
7089             if (attrs) {
7090                 selector = selector.replace(Selector._re.attr, '!!REPLACED_ATTRIBUTE!!');
7091             }
7092
7093             for (re in shorthand) {
7094                 if (shorthand.hasOwnProperty(re)) {
7095                     selector = selector.replace(Y.DOM._getRegExp(re, 'gi'), shorthand[re]);
7096                 }
7097             }
7098
7099             if (attrs) {
7100                 for (i = 0, len = attrs.length; i < len; ++i) {
7101                     selector = selector.replace('!!REPLACED_ATTRIBUTE!!', attrs[i]);
7102                 }
7103             }
7104             if (pseudos) {
7105                 for (i = 0, len = pseudos.length; i < len; ++i) {
7106                     selector = selector.replace('!!REPLACED_PSEUDO!!', pseudos[i]);
7107                 }
7108             }
7109             return selector;
7110         },
7111
7112         _attrFilters: {
7113             'class': 'className',
7114             'for': 'htmlFor'
7115         },
7116
7117         getters: {
7118             href: function(node, attr) {
7119                 return Y.DOM.getAttribute(node, attr);
7120             }
7121         }
7122     };
7123
7124 Y.mix(Y.Selector, SelectorCSS2, true);
7125 Y.Selector.getters.src = Y.Selector.getters.rel = Y.Selector.getters.href;
7126
7127 // IE wants class with native queries
7128 if (Y.Selector.useNative && Y.config.doc.querySelector) {
7129     Y.Selector.shorthand['\\.(-?[_a-z]+[-\\w]*)'] = '[class~=$1]';
7130 }
7131
7132
7133
7134 }, '3.3.0' ,{requires:['selector-native']});
7135
7136
7137 YUI.add('selector', function(Y){}, '3.3.0' ,{use:['selector-native', 'selector-css2']});
7138
7139
7140
7141 YUI.add('dom', function(Y){}, '3.3.0' ,{use:['dom-base', 'dom-style', 'dom-screen', 'selector']});
7142
7143 YUI.add('event-custom-base', function(Y) {
7144
7145 /**
7146  * Custom event engine, DOM event listener abstraction layer, synthetic DOM
7147  * events.
7148  * @module event-custom
7149  */
7150
7151 Y.Env.evt = {
7152     handles: {},
7153     plugins: {}
7154 };
7155
7156
7157 /**
7158  * Custom event engine, DOM event listener abstraction layer, synthetic DOM
7159  * events.
7160  * @module event-custom
7161  * @submodule event-custom-base
7162  */
7163
7164 /**
7165  * Allows for the insertion of methods that are executed before or after
7166  * a specified method
7167  * @class Do
7168  * @static
7169  */
7170
7171 var DO_BEFORE = 0,
7172     DO_AFTER = 1,
7173
7174 DO = {
7175
7176     /**
7177      * Cache of objects touched by the utility
7178      * @property objs
7179      * @static
7180      */
7181     objs: {},
7182
7183     /**
7184      * Execute the supplied method before the specified function
7185      * @method before
7186      * @param fn {Function} the function to execute
7187      * @param obj the object hosting the method to displace
7188      * @param sFn {string} the name of the method to displace
7189      * @param c The execution context for fn
7190      * @param arg* {mixed} 0..n additional arguments to supply to the subscriber
7191      * when the event fires.
7192      * @return {string} handle for the subscription
7193      * @static
7194      */
7195     before: function(fn, obj, sFn, c) {
7196         var f = fn, a;
7197         if (c) {
7198             a = [fn, c].concat(Y.Array(arguments, 4, true));
7199             f = Y.rbind.apply(Y, a);
7200         }
7201
7202         return this._inject(DO_BEFORE, f, obj, sFn);
7203     },
7204
7205     /**
7206      * Execute the supplied method after the specified function
7207      * @method after
7208      * @param fn {Function} the function to execute
7209      * @param obj the object hosting the method to displace
7210      * @param sFn {string} the name of the method to displace
7211      * @param c The execution context for fn
7212      * @param arg* {mixed} 0..n additional arguments to supply to the subscriber
7213      * @return {string} handle for the subscription
7214      * @static
7215      */
7216     after: function(fn, obj, sFn, c) {
7217         var f = fn, a;
7218         if (c) {
7219             a = [fn, c].concat(Y.Array(arguments, 4, true));
7220             f = Y.rbind.apply(Y, a);
7221         }
7222
7223         return this._inject(DO_AFTER, f, obj, sFn);
7224     },
7225
7226     /**
7227      * Execute the supplied method after the specified function
7228      * @method _inject
7229      * @param when {string} before or after
7230      * @param fn {Function} the function to execute
7231      * @param obj the object hosting the method to displace
7232      * @param sFn {string} the name of the method to displace
7233      * @param c The execution context for fn
7234      * @return {string} handle for the subscription
7235      * @private
7236      * @static
7237      */
7238     _inject: function(when, fn, obj, sFn) {
7239
7240         // object id
7241         var id = Y.stamp(obj), o, sid;
7242
7243         if (! this.objs[id]) {
7244             // create a map entry for the obj if it doesn't exist
7245             this.objs[id] = {};
7246         }
7247
7248         o = this.objs[id];
7249
7250         if (! o[sFn]) {
7251             // create a map entry for the method if it doesn't exist
7252             o[sFn] = new Y.Do.Method(obj, sFn);
7253
7254             // re-route the method to our wrapper
7255             obj[sFn] =
7256                 function() {
7257                     return o[sFn].exec.apply(o[sFn], arguments);
7258                 };
7259         }
7260
7261         // subscriber id
7262         sid = id + Y.stamp(fn) + sFn;
7263
7264         // register the callback
7265         o[sFn].register(sid, fn, when);
7266
7267         return new Y.EventHandle(o[sFn], sid);
7268
7269     },
7270
7271     /**
7272      * Detach a before or after subscription
7273      * @method detach
7274      * @param handle {string} the subscription handle
7275      */
7276     detach: function(handle) {
7277
7278         if (handle.detach) {
7279             handle.detach();
7280         }
7281
7282     },
7283
7284     _unload: function(e, me) {
7285
7286     }
7287 };
7288
7289 Y.Do = DO;
7290
7291 //////////////////////////////////////////////////////////////////////////
7292
7293 /**
7294  * Contains the return value from the wrapped method, accessible
7295  * by 'after' event listeners.
7296  *
7297  * @property Do.originalRetVal
7298  * @static
7299  * @since 2.3.0
7300  */
7301
7302 /**
7303  * Contains the current state of the return value, consumable by
7304  * 'after' event listeners, and updated if an after subscriber
7305  * changes the return value generated by the wrapped function.
7306  *
7307  * @property Do.currentRetVal
7308  * @static
7309  * @since 2.3.0
7310  */
7311
7312 //////////////////////////////////////////////////////////////////////////
7313
7314 /**
7315  * Wrapper for a displaced method with aop enabled
7316  * @class Do.Method
7317  * @constructor
7318  * @param obj The object to operate on
7319  * @param sFn The name of the method to displace
7320  */
7321 DO.Method = function(obj, sFn) {
7322     this.obj = obj;
7323     this.methodName = sFn;
7324     this.method = obj[sFn];
7325     this.before = {};
7326     this.after = {};
7327 };
7328
7329 /**
7330  * Register a aop subscriber
7331  * @method register
7332  * @param sid {string} the subscriber id
7333  * @param fn {Function} the function to execute
7334  * @param when {string} when to execute the function
7335  */
7336 DO.Method.prototype.register = function (sid, fn, when) {
7337     if (when) {
7338         this.after[sid] = fn;
7339     } else {
7340         this.before[sid] = fn;
7341     }
7342 };
7343
7344 /**
7345  * Unregister a aop subscriber
7346  * @method delete
7347  * @param sid {string} the subscriber id
7348  * @param fn {Function} the function to execute
7349  * @param when {string} when to execute the function
7350  */
7351 DO.Method.prototype._delete = function (sid) {
7352     delete this.before[sid];
7353     delete this.after[sid];
7354 };
7355
7356 /**
7357  * Execute the wrapped method
7358  * @method exec
7359  */
7360 DO.Method.prototype.exec = function () {
7361
7362     var args = Y.Array(arguments, 0, true),
7363         i, ret, newRet,
7364         bf = this.before,
7365         af = this.after,
7366         prevented = false;
7367
7368     // execute before
7369     for (i in bf) {
7370         if (bf.hasOwnProperty(i)) {
7371             ret = bf[i].apply(this.obj, args);
7372             if (ret) {
7373                 switch (ret.constructor) {
7374                     case DO.Halt:
7375                         return ret.retVal;
7376                     case DO.AlterArgs:
7377                         args = ret.newArgs;
7378                         break;
7379                     case DO.Prevent:
7380                         prevented = true;
7381                         break;
7382                     default:
7383                 }
7384             }
7385         }
7386     }
7387
7388     // execute method
7389     if (!prevented) {
7390         ret = this.method.apply(this.obj, args);
7391     }
7392
7393     DO.originalRetVal = ret;
7394     DO.currentRetVal = ret;
7395
7396     // execute after methods.
7397     for (i in af) {
7398         if (af.hasOwnProperty(i)) {
7399             newRet = af[i].apply(this.obj, args);
7400             // Stop processing if a Halt object is returned
7401             if (newRet && newRet.constructor == DO.Halt) {
7402                 return newRet.retVal;
7403             // Check for a new return value
7404             } else if (newRet && newRet.constructor == DO.AlterReturn) {
7405                 ret = newRet.newRetVal;
7406                 // Update the static retval state
7407                 DO.currentRetVal = ret;
7408             }
7409         }
7410     }
7411
7412     return ret;
7413 };
7414
7415 //////////////////////////////////////////////////////////////////////////
7416
7417 /**
7418  * Return an AlterArgs object when you want to change the arguments that
7419  * were passed into the function.  An example would be a service that scrubs
7420  * out illegal characters prior to executing the core business logic.
7421  * @class Do.AlterArgs
7422  */
7423 DO.AlterArgs = function(msg, newArgs) {
7424     this.msg = msg;
7425     this.newArgs = newArgs;
7426 };
7427
7428 /**
7429  * Return an AlterReturn object when you want to change the result returned
7430  * from the core method to the caller
7431  * @class Do.AlterReturn
7432  */
7433 DO.AlterReturn = function(msg, newRetVal) {
7434     this.msg = msg;
7435     this.newRetVal = newRetVal;
7436 };
7437
7438 /**
7439  * Return a Halt object when you want to terminate the execution
7440  * of all subsequent subscribers as well as the wrapped method
7441  * if it has not exectued yet.
7442  * @class Do.Halt
7443  */
7444 DO.Halt = function(msg, retVal) {
7445     this.msg = msg;
7446     this.retVal = retVal;
7447 };
7448
7449 /**
7450  * Return a Prevent object when you want to prevent the wrapped function
7451  * from executing, but want the remaining listeners to execute
7452  * @class Do.Prevent
7453  */
7454 DO.Prevent = function(msg) {
7455     this.msg = msg;
7456 };
7457
7458 /**
7459  * Return an Error object when you want to terminate the execution
7460  * of all subsequent method calls.
7461  * @class Do.Error
7462  * @deprecated use Y.Do.Halt or Y.Do.Prevent
7463  */
7464 DO.Error = DO.Halt;
7465
7466
7467 //////////////////////////////////////////////////////////////////////////
7468
7469 // Y["Event"] && Y.Event.addListener(window, "unload", Y.Do._unload, Y.Do);
7470
7471
7472 /**
7473  * Custom event engine, DOM event listener abstraction layer, synthetic DOM
7474  * events.
7475  * @module event-custom
7476  * @submodule event-custom-base
7477  */
7478
7479
7480 // var onsubscribeType = "_event:onsub",
7481 var AFTER = 'after',
7482     CONFIGS = [
7483         'broadcast',
7484         'monitored',
7485         'bubbles',
7486         'context',
7487         'contextFn',
7488         'currentTarget',
7489         'defaultFn',
7490         'defaultTargetOnly',
7491         'details',
7492         'emitFacade',
7493         'fireOnce',
7494         'async',
7495         'host',
7496         'preventable',
7497         'preventedFn',
7498         'queuable',
7499         'silent',
7500         'stoppedFn',
7501         'target',
7502         'type'
7503     ],
7504
7505     YUI3_SIGNATURE = 9,
7506     YUI_LOG = 'yui:log';
7507
7508 /**
7509  * Return value from all subscribe operations
7510  * @class EventHandle
7511  * @constructor
7512  * @param {CustomEvent} evt the custom event.
7513  * @param {Subscriber} sub the subscriber.
7514  */
7515 Y.EventHandle = function(evt, sub) {
7516
7517     /**
7518      * The custom event
7519      * @type CustomEvent
7520      */
7521     this.evt = evt;
7522
7523     /**
7524      * The subscriber object
7525      * @type Subscriber
7526      */
7527     this.sub = sub;
7528 };
7529
7530 Y.EventHandle.prototype = {
7531     batch: function(f, c) {
7532         f.call(c || this, this);
7533         if (Y.Lang.isArray(this.evt)) {
7534             Y.Array.each(this.evt, function(h) {
7535                 h.batch.call(c || h, f);
7536             });
7537         }
7538     },
7539
7540     /**
7541      * Detaches this subscriber
7542      * @method detach
7543      * @return {int} the number of detached listeners
7544      */
7545     detach: function() {
7546         var evt = this.evt, detached = 0, i;
7547         if (evt) {
7548             if (Y.Lang.isArray(evt)) {
7549                 for (i = 0; i < evt.length; i++) {
7550                     detached += evt[i].detach();
7551                 }
7552             } else {
7553                 evt._delete(this.sub);
7554                 detached = 1;
7555             }
7556
7557         }
7558
7559         return detached;
7560     },
7561
7562     /**
7563      * Monitor the event state for the subscribed event.  The first parameter
7564      * is what should be monitored, the rest are the normal parameters when
7565      * subscribing to an event.
7566      * @method monitor
7567      * @param what {string} what to monitor ('attach', 'detach', 'publish').
7568      * @return {EventHandle} return value from the monitor event subscription.
7569      */
7570     monitor: function(what) {
7571         return this.evt.monitor.apply(this.evt, arguments);
7572     }
7573 };
7574
7575 /**
7576  * The CustomEvent class lets you define events for your application
7577  * that can be subscribed to by one or more independent component.
7578  *
7579  * @param {String} type The type of event, which is passed to the callback
7580  * when the event fires.
7581  * @param {object} o configuration object.
7582  * @class CustomEvent
7583  * @constructor
7584  */
7585 Y.CustomEvent = function(type, o) {
7586
7587     // if (arguments.length > 2) {
7588 // this.log('CustomEvent context and silent are now in the config', 'warn', 'Event');
7589     // }
7590
7591     o = o || {};
7592
7593     this.id = Y.stamp(this);
7594
7595     /**
7596      * The type of event, returned to subscribers when the event fires
7597      * @property type
7598      * @type string
7599      */
7600     this.type = type;
7601
7602     /**
7603      * The context the the event will fire from by default.  Defaults to the YUI
7604      * instance.
7605      * @property context
7606      * @type object
7607      */
7608     this.context = Y;
7609
7610     /**
7611      * Monitor when an event is attached or detached.
7612      *
7613      * @property monitored
7614      * @type boolean
7615      */
7616     // this.monitored = false;
7617
7618     this.logSystem = (type == YUI_LOG);
7619
7620     /**
7621      * If 0, this event does not broadcast.  If 1, the YUI instance is notified
7622      * every time this event fires.  If 2, the YUI instance and the YUI global
7623      * (if event is enabled on the global) are notified every time this event
7624      * fires.
7625      * @property broadcast
7626      * @type int
7627      */
7628     // this.broadcast = 0;
7629
7630     /**
7631      * By default all custom events are logged in the debug build, set silent
7632      * to true to disable debug outpu for this event.
7633      * @property silent
7634      * @type boolean
7635      */
7636     this.silent = this.logSystem;
7637
7638     /**
7639      * Specifies whether this event should be queued when the host is actively
7640      * processing an event.  This will effect exectution order of the callbacks
7641      * for the various events.
7642      * @property queuable
7643      * @type boolean
7644      * @default false
7645      */
7646     // this.queuable = false;
7647
7648     /**
7649      * The subscribers to this event
7650      * @property subscribers
7651      * @type Subscriber {}
7652      */
7653     this.subscribers = {};
7654
7655     /**
7656      * 'After' subscribers
7657      * @property afters
7658      * @type Subscriber {}
7659      */
7660     this.afters = {};
7661
7662     /**
7663      * This event has fired if true
7664      *
7665      * @property fired
7666      * @type boolean
7667      * @default false;
7668      */
7669     // this.fired = false;
7670
7671     /**
7672      * An array containing the arguments the custom event
7673      * was last fired with.
7674      * @property firedWith
7675      * @type Array
7676      */
7677     // this.firedWith;
7678
7679     /**
7680      * This event should only fire one time if true, and if
7681      * it has fired, any new subscribers should be notified
7682      * immediately.
7683      *
7684      * @property fireOnce
7685      * @type boolean
7686      * @default false;
7687      */
7688     // this.fireOnce = false;
7689
7690     /**
7691      * fireOnce listeners will fire syncronously unless async
7692      * is set to true
7693      * @property async
7694      * @type boolean
7695      * @default false
7696      */
7697     //this.async = false;
7698
7699     /**
7700      * Flag for stopPropagation that is modified during fire()
7701      * 1 means to stop propagation to bubble targets.  2 means
7702      * to also stop additional subscribers on this target.
7703      * @property stopped
7704      * @type int
7705      */
7706     // this.stopped = 0;
7707
7708     /**
7709      * Flag for preventDefault that is modified during fire().
7710      * if it is not 0, the default behavior for this event
7711      * @property prevented
7712      * @type int
7713      */
7714     // this.prevented = 0;
7715
7716     /**
7717      * Specifies the host for this custom event.  This is used
7718      * to enable event bubbling
7719      * @property host
7720      * @type EventTarget
7721      */
7722     // this.host = null;
7723
7724     /**
7725      * The default function to execute after event listeners
7726      * have fire, but only if the default action was not
7727      * prevented.
7728      * @property defaultFn
7729      * @type Function
7730      */
7731     // this.defaultFn = null;
7732
7733     /**
7734      * The function to execute if a subscriber calls
7735      * stopPropagation or stopImmediatePropagation
7736      * @property stoppedFn
7737      * @type Function
7738      */
7739     // this.stoppedFn = null;
7740
7741     /**
7742      * The function to execute if a subscriber calls
7743      * preventDefault
7744      * @property preventedFn
7745      * @type Function
7746      */
7747     // this.preventedFn = null;
7748
7749     /**
7750      * Specifies whether or not this event's default function
7751      * can be cancelled by a subscriber by executing preventDefault()
7752      * on the event facade
7753      * @property preventable
7754      * @type boolean
7755      * @default true
7756      */
7757     this.preventable = true;
7758
7759     /**
7760      * Specifies whether or not a subscriber can stop the event propagation
7761      * via stopPropagation(), stopImmediatePropagation(), or halt()
7762      *
7763      * Events can only bubble if emitFacade is true.
7764      *
7765      * @property bubbles
7766      * @type boolean
7767      * @default true
7768      */
7769     this.bubbles = true;
7770
7771     /**
7772      * Supports multiple options for listener signatures in order to
7773      * port YUI 2 apps.
7774      * @property signature
7775      * @type int
7776      * @default 9
7777      */
7778     this.signature = YUI3_SIGNATURE;
7779
7780     this.subCount = 0;
7781     this.afterCount = 0;
7782
7783     // this.hasSubscribers = false;
7784
7785     // this.hasAfters = false;
7786
7787     /**
7788      * If set to true, the custom event will deliver an EventFacade object
7789      * that is similar to a DOM event object.
7790      * @property emitFacade
7791      * @type boolean
7792      * @default false
7793      */
7794     // this.emitFacade = false;
7795
7796     this.applyConfig(o, true);
7797
7798     // this.log("Creating " + this.type);
7799
7800 };
7801
7802 Y.CustomEvent.prototype = {
7803
7804     hasSubs: function(when) {
7805         var s = this.subCount, a = this.afterCount, sib = this.sibling;
7806
7807         if (sib) {
7808             s += sib.subCount;
7809             a += sib.afterCount;
7810         }
7811
7812         if (when) {
7813             return (when == 'after') ? a : s;
7814         }
7815
7816         return (s + a);
7817     },
7818
7819     /**
7820      * Monitor the event state for the subscribed event.  The first parameter
7821      * is what should be monitored, the rest are the normal parameters when
7822      * subscribing to an event.
7823      * @method monitor
7824      * @param what {string} what to monitor ('detach', 'attach', 'publish').
7825      * @return {EventHandle} return value from the monitor event subscription.
7826      */
7827     monitor: function(what) {
7828         this.monitored = true;
7829         var type = this.id + '|' + this.type + '_' + what,
7830             args = Y.Array(arguments, 0, true);
7831         args[0] = type;
7832         return this.host.on.apply(this.host, args);
7833     },
7834
7835     /**
7836      * Get all of the subscribers to this event and any sibling event
7837      * @method getSubs
7838      * @return {Array} first item is the on subscribers, second the after.
7839      */
7840     getSubs: function() {
7841         var s = Y.merge(this.subscribers), a = Y.merge(this.afters), sib = this.sibling;
7842
7843         if (sib) {
7844             Y.mix(s, sib.subscribers);
7845             Y.mix(a, sib.afters);
7846         }
7847
7848         return [s, a];
7849     },
7850
7851     /**
7852      * Apply configuration properties.  Only applies the CONFIG whitelist
7853      * @method applyConfig
7854      * @param o hash of properties to apply.
7855      * @param force {boolean} if true, properties that exist on the event
7856      * will be overwritten.
7857      */
7858     applyConfig: function(o, force) {
7859         if (o) {
7860             Y.mix(this, o, force, CONFIGS);
7861         }
7862     },
7863
7864     _on: function(fn, context, args, when) {
7865
7866         if (!fn) {
7867             this.log('Invalid callback for CE: ' + this.type);
7868         }
7869
7870         var s = new Y.Subscriber(fn, context, args, when);
7871
7872         if (this.fireOnce && this.fired) {
7873             if (this.async) {
7874                 setTimeout(Y.bind(this._notify, this, s, this.firedWith), 0);
7875             } else {
7876                 this._notify(s, this.firedWith);
7877             }
7878         }
7879
7880         if (when == AFTER) {
7881             this.afters[s.id] = s;
7882             this.afterCount++;
7883         } else {
7884             this.subscribers[s.id] = s;
7885             this.subCount++;
7886         }
7887
7888         return new Y.EventHandle(this, s);
7889
7890     },
7891
7892     /**
7893      * Listen for this event
7894      * @method subscribe
7895      * @param {Function} fn The function to execute.
7896      * @return {EventHandle} Unsubscribe handle.
7897      * @deprecated use on.
7898      */
7899     subscribe: function(fn, context) {
7900         var a = (arguments.length > 2) ? Y.Array(arguments, 2, true) : null;
7901         return this._on(fn, context, a, true);
7902     },
7903
7904     /**
7905      * Listen for this event
7906      * @method on
7907      * @param {Function} fn The function to execute.
7908      * @param {object} context optional execution context.
7909      * @param {mixed} arg* 0..n additional arguments to supply to the subscriber
7910      * when the event fires.
7911      * @return {EventHandle} An object with a detach method to detch the handler(s).
7912      */
7913     on: function(fn, context) {
7914         var a = (arguments.length > 2) ? Y.Array(arguments, 2, true) : null;
7915         if (this.host) {
7916             this.host._monitor('attach', this.type, {
7917                 args: arguments
7918             });
7919         }
7920         return this._on(fn, context, a, true);
7921     },
7922
7923     /**
7924      * Listen for this event after the normal subscribers have been notified and
7925      * the default behavior has been applied.  If a normal subscriber prevents the
7926      * default behavior, it also prevents after listeners from firing.
7927      * @method after
7928      * @param {Function} fn The function to execute.
7929      * @param {object} context optional execution context.
7930      * @param {mixed} arg* 0..n additional arguments to supply to the subscriber
7931      * when the event fires.
7932      * @return {EventHandle} handle Unsubscribe handle.
7933      */
7934     after: function(fn, context) {
7935         var a = (arguments.length > 2) ? Y.Array(arguments, 2, true) : null;
7936         return this._on(fn, context, a, AFTER);
7937     },
7938
7939     /**
7940      * Detach listeners.
7941      * @method detach
7942      * @param {Function} fn  The subscribed function to remove, if not supplied
7943      *                       all will be removed.
7944      * @param {Object}   context The context object passed to subscribe.
7945      * @return {int} returns the number of subscribers unsubscribed.
7946      */
7947     detach: function(fn, context) {
7948         // unsubscribe handle
7949         if (fn && fn.detach) {
7950             return fn.detach();
7951         }
7952
7953         var i, s,
7954             found = 0,
7955             subs = Y.merge(this.subscribers, this.afters);
7956
7957         for (i in subs) {
7958             if (subs.hasOwnProperty(i)) {
7959                 s = subs[i];
7960                 if (s && (!fn || fn === s.fn)) {
7961                     this._delete(s);
7962                     found++;
7963                 }
7964             }
7965         }
7966
7967         return found;
7968     },
7969
7970     /**
7971      * Detach listeners.
7972      * @method unsubscribe
7973      * @param {Function} fn  The subscribed function to remove, if not supplied
7974      *                       all will be removed.
7975      * @param {Object}   context The context object passed to subscribe.
7976      * @return {int|undefined} returns the number of subscribers unsubscribed.
7977      * @deprecated use detach.
7978      */
7979     unsubscribe: function() {
7980         return this.detach.apply(this, arguments);
7981     },
7982
7983     /**
7984      * Notify a single subscriber
7985      * @method _notify
7986      * @param {Subscriber} s the subscriber.
7987      * @param {Array} args the arguments array to apply to the listener.
7988      * @private
7989      */
7990     _notify: function(s, args, ef) {
7991
7992         this.log(this.type + '->' + 'sub: ' + s.id);
7993
7994         var ret;
7995
7996         ret = s.notify(args, this);
7997
7998         if (false === ret || this.stopped > 1) {
7999             this.log(this.type + ' cancelled by subscriber');
8000             return false;
8001         }
8002
8003         return true;
8004     },
8005
8006     /**
8007      * Logger abstraction to centralize the application of the silent flag
8008      * @method log
8009      * @param {string} msg message to log.
8010      * @param {string} cat log category.
8011      */
8012     log: function(msg, cat) {
8013         if (!this.silent) {
8014         }
8015     },
8016
8017     /**
8018      * Notifies the subscribers.  The callback functions will be executed
8019      * from the context specified when the event was created, and with the
8020      * following parameters:
8021      *   <ul>
8022      *   <li>The type of event</li>
8023      *   <li>All of the arguments fire() was executed with as an array</li>
8024      *   <li>The custom object (if any) that was passed into the subscribe()
8025      *       method</li>
8026      *   </ul>
8027      * @method fire
8028      * @param {Object*} arguments an arbitrary set of parameters to pass to
8029      *                            the handler.
8030      * @return {boolean} false if one of the subscribers returned false,
8031      *                   true otherwise.
8032      *
8033      */
8034     fire: function() {
8035         if (this.fireOnce && this.fired) {
8036             this.log('fireOnce event: ' + this.type + ' already fired');
8037             return true;
8038         } else {
8039
8040             var args = Y.Array(arguments, 0, true);
8041
8042             // this doesn't happen if the event isn't published
8043             // this.host._monitor('fire', this.type, args);
8044
8045             this.fired = true;
8046             this.firedWith = args;
8047
8048             if (this.emitFacade) {
8049                 return this.fireComplex(args);
8050             } else {
8051                 return this.fireSimple(args);
8052             }
8053         }
8054     },
8055
8056     fireSimple: function(args) {
8057         this.stopped = 0;
8058         this.prevented = 0;
8059         if (this.hasSubs()) {
8060             // this._procSubs(Y.merge(this.subscribers, this.afters), args);
8061             var subs = this.getSubs();
8062             this._procSubs(subs[0], args);
8063             this._procSubs(subs[1], args);
8064         }
8065         this._broadcast(args);
8066         return this.stopped ? false : true;
8067     },
8068
8069     // Requires the event-custom-complex module for full funcitonality.
8070     fireComplex: function(args) {
8071         args[0] = args[0] || {};
8072         return this.fireSimple(args);
8073     },
8074
8075     _procSubs: function(subs, args, ef) {
8076         var s, i;
8077         for (i in subs) {
8078             if (subs.hasOwnProperty(i)) {
8079                 s = subs[i];
8080                 if (s && s.fn) {
8081                     if (false === this._notify(s, args, ef)) {
8082                         this.stopped = 2;
8083                     }
8084                     if (this.stopped == 2) {
8085                         return false;
8086                     }
8087                 }
8088             }
8089         }
8090
8091         return true;
8092     },
8093
8094     _broadcast: function(args) {
8095         if (!this.stopped && this.broadcast) {
8096
8097             var a = Y.Array(args);
8098             a.unshift(this.type);
8099
8100             if (this.host !== Y) {
8101                 Y.fire.apply(Y, a);
8102             }
8103
8104             if (this.broadcast == 2) {
8105                 Y.Global.fire.apply(Y.Global, a);
8106             }
8107         }
8108     },
8109
8110     /**
8111      * Removes all listeners
8112      * @method unsubscribeAll
8113      * @return {int} The number of listeners unsubscribed.
8114      * @deprecated use detachAll.
8115      */
8116     unsubscribeAll: function() {
8117         return this.detachAll.apply(this, arguments);
8118     },
8119
8120     /**
8121      * Removes all listeners
8122      * @method detachAll
8123      * @return {int} The number of listeners unsubscribed.
8124      */
8125     detachAll: function() {
8126         return this.detach();
8127     },
8128
8129     /**
8130      * @method _delete
8131      * @param subscriber object.
8132      * @private
8133      */
8134     _delete: function(s) {
8135         if (s) {
8136             if (this.subscribers[s.id]) {
8137                 delete this.subscribers[s.id];
8138                 this.subCount--;
8139             }
8140             if (this.afters[s.id]) {
8141                 delete this.afters[s.id];
8142                 this.afterCount--;
8143             }
8144         }
8145
8146         if (this.host) {
8147             this.host._monitor('detach', this.type, {
8148                 ce: this,
8149                 sub: s
8150             });
8151         }
8152
8153         if (s) {
8154             // delete s.fn;
8155             // delete s.context;
8156             s.deleted = true;
8157         }
8158     }
8159 };
8160
8161 /////////////////////////////////////////////////////////////////////
8162
8163 /**
8164  * Stores the subscriber information to be used when the event fires.
8165  * @param {Function} fn       The wrapped function to execute.
8166  * @param {Object}   context  The value of the keyword 'this' in the listener.
8167  * @param {Array} args*       0..n additional arguments to supply the listener.
8168  *
8169  * @class Subscriber
8170  * @constructor
8171  */
8172 Y.Subscriber = function(fn, context, args) {
8173
8174     /**
8175      * The callback that will be execute when the event fires
8176      * This is wrapped by Y.rbind if obj was supplied.
8177      * @property fn
8178      * @type Function
8179      */
8180     this.fn = fn;
8181
8182     /**
8183      * Optional 'this' keyword for the listener
8184      * @property context
8185      * @type Object
8186      */
8187     this.context = context;
8188
8189     /**
8190      * Unique subscriber id
8191      * @property id
8192      * @type String
8193      */
8194     this.id = Y.stamp(this);
8195
8196     /**
8197      * Additional arguments to propagate to the subscriber
8198      * @property args
8199      * @type Array
8200      */
8201     this.args = args;
8202
8203     /**
8204      * Custom events for a given fire transaction.
8205      * @property events
8206      * @type {EventTarget}
8207      */
8208     // this.events = null;
8209
8210     /**
8211      * This listener only reacts to the event once
8212      * @property once
8213      */
8214     // this.once = false;
8215
8216 };
8217
8218 Y.Subscriber.prototype = {
8219
8220     _notify: function(c, args, ce) {
8221         if (this.deleted && !this.postponed) {
8222             if (this.postponed) {
8223                 delete this.fn;
8224                 delete this.context;
8225             } else {
8226                 delete this.postponed;
8227                 return null;
8228             }
8229         }
8230         var a = this.args, ret;
8231         switch (ce.signature) {
8232             case 0:
8233                 ret = this.fn.call(c, ce.type, args, c);
8234                 break;
8235             case 1:
8236                 ret = this.fn.call(c, args[0] || null, c);
8237                 break;
8238             default:
8239                 if (a || args) {
8240                     args = args || [];
8241                     a = (a) ? args.concat(a) : args;
8242                     ret = this.fn.apply(c, a);
8243                 } else {
8244                     ret = this.fn.call(c);
8245                 }
8246         }
8247
8248         if (this.once) {
8249             ce._delete(this);
8250         }
8251
8252         return ret;
8253     },
8254
8255     /**
8256      * Executes the subscriber.
8257      * @method notify
8258      * @param args {Array} Arguments array for the subscriber.
8259      * @param ce {CustomEvent} The custom event that sent the notification.
8260      */
8261     notify: function(args, ce) {
8262         var c = this.context,
8263             ret = true;
8264
8265         if (!c) {
8266             c = (ce.contextFn) ? ce.contextFn() : ce.context;
8267         }
8268
8269         // only catch errors if we will not re-throw them.
8270         if (Y.config.throwFail) {
8271             ret = this._notify(c, args, ce);
8272         } else {
8273             try {
8274                 ret = this._notify(c, args, ce);
8275             } catch (e) {
8276                 Y.error(this + ' failed: ' + e.message, e);
8277             }
8278         }
8279
8280         return ret;
8281     },
8282
8283     /**
8284      * Returns true if the fn and obj match this objects properties.
8285      * Used by the unsubscribe method to match the right subscriber.
8286      *
8287      * @method contains
8288      * @param {Function} fn the function to execute.
8289      * @param {Object} context optional 'this' keyword for the listener.
8290      * @return {boolean} true if the supplied arguments match this
8291      *                   subscriber's signature.
8292      */
8293     contains: function(fn, context) {
8294         if (context) {
8295             return ((this.fn == fn) && this.context == context);
8296         } else {
8297             return (this.fn == fn);
8298         }
8299     }
8300
8301 };
8302
8303 /**
8304  * Custom event engine, DOM event listener abstraction layer, synthetic DOM
8305  * events.
8306  * @module event-custom
8307  * @submodule event-custom-base
8308  */
8309
8310 /**
8311  * EventTarget provides the implementation for any object to
8312  * publish, subscribe and fire to custom events, and also
8313  * alows other EventTargets to target the object with events
8314  * sourced from the other object.
8315  * EventTarget is designed to be used with Y.augment to wrap
8316  * EventCustom in an interface that allows events to be listened to
8317  * and fired by name.  This makes it possible for implementing code to
8318  * subscribe to an event that either has not been created yet, or will
8319  * not be created at all.
8320  * @class EventTarget
8321  * @param opts a configuration object
8322  * @config emitFacade {boolean} if true, all events will emit event
8323  * facade payloads by default (default false)
8324  * @config prefix {string} the prefix to apply to non-prefixed event names
8325  * @config chain {boolean} if true, on/after/detach return the host to allow
8326  * chaining, otherwise they return an EventHandle (default false)
8327  */
8328
8329 var L = Y.Lang,
8330     PREFIX_DELIMITER = ':',
8331     CATEGORY_DELIMITER = '|',
8332     AFTER_PREFIX = '~AFTER~',
8333     YArray = Y.Array,
8334
8335     _wildType = Y.cached(function(type) {
8336         return type.replace(/(.*)(:)(.*)/, "*$2$3");
8337     }),
8338
8339     /**
8340      * If the instance has a prefix attribute and the
8341      * event type is not prefixed, the instance prefix is
8342      * applied to the supplied type.
8343      * @method _getType
8344      * @private
8345      */
8346     _getType = Y.cached(function(type, pre) {
8347
8348         if (!pre || !L.isString(type) || type.indexOf(PREFIX_DELIMITER) > -1) {
8349             return type;
8350         }
8351
8352         return pre + PREFIX_DELIMITER + type;
8353     }),
8354
8355     /**
8356      * Returns an array with the detach key (if provided),
8357      * and the prefixed event name from _getType
8358      * Y.on('detachcategory| menu:click', fn)
8359      * @method _parseType
8360      * @private
8361      */
8362     _parseType = Y.cached(function(type, pre) {
8363
8364         var t = type, detachcategory, after, i;
8365
8366         if (!L.isString(t)) {
8367             return t;
8368         }
8369
8370         i = t.indexOf(AFTER_PREFIX);
8371
8372         if (i > -1) {
8373             after = true;
8374             t = t.substr(AFTER_PREFIX.length);
8375         }
8376
8377         i = t.indexOf(CATEGORY_DELIMITER);
8378
8379         if (i > -1) {
8380             detachcategory = t.substr(0, (i));
8381             t = t.substr(i+1);
8382             if (t == '*') {
8383                 t = null;
8384             }
8385         }
8386
8387         // detach category, full type with instance prefix, is this an after listener, short type
8388         return [detachcategory, (pre) ? _getType(t, pre) : t, after, t];
8389     }),
8390
8391     ET = function(opts) {
8392
8393
8394         var o = (L.isObject(opts)) ? opts : {};
8395
8396         this._yuievt = this._yuievt || {
8397
8398             id: Y.guid(),
8399
8400             events: {},
8401
8402             targets: {},
8403
8404             config: o,
8405
8406             chain: ('chain' in o) ? o.chain : Y.config.chain,
8407
8408             bubbling: false,
8409
8410             defaults: {
8411                 context: o.context || this,
8412                 host: this,
8413                 emitFacade: o.emitFacade,
8414                 fireOnce: o.fireOnce,
8415                 queuable: o.queuable,
8416                 monitored: o.monitored,
8417                 broadcast: o.broadcast,
8418                 defaultTargetOnly: o.defaultTargetOnly,
8419                 bubbles: ('bubbles' in o) ? o.bubbles : true
8420             }
8421         };
8422
8423     };
8424
8425
8426 ET.prototype = {
8427
8428     /**
8429      * Listen to a custom event hosted by this object one time.
8430      * This is the equivalent to <code>on</code> except the
8431      * listener is immediatelly detached when it is executed.
8432      * @method once
8433      * @param type    {string}   The type of the event
8434      * @param fn {Function} The callback
8435      * @param context {object} optional execution context.
8436      * @param arg* {mixed} 0..n additional arguments to supply to the subscriber
8437      * @return the event target or a detach handle per 'chain' config
8438      */
8439     once: function() {
8440         var handle = this.on.apply(this, arguments);
8441         handle.batch(function(hand) {
8442             if (hand.sub) {
8443                 hand.sub.once = true;
8444             }
8445         });
8446         return handle;
8447     },
8448
8449     /**
8450      * Takes the type parameter passed to 'on' and parses out the
8451      * various pieces that could be included in the type.  If the
8452      * event type is passed without a prefix, it will be expanded
8453      * to include the prefix one is supplied or the event target
8454      * is configured with a default prefix.
8455      * @method parseType
8456      * @param {string} type the type
8457      * @param {string} [pre=this._yuievt.config.prefix] the prefix
8458      * @since 3.3.0
8459      * @return {Array} an array containing:
8460      *  * the detach category, if supplied,
8461      *  * the prefixed event type,
8462      *  * whether or not this is an after listener,
8463      *  * the supplied event type
8464      */
8465     parseType: function(type, pre) {
8466         return _parseType(type, pre || this._yuievt.config.prefix);
8467     },
8468
8469     /**
8470      * Subscribe to a custom event hosted by this object
8471      * @method on
8472      * @param type    {string}   The type of the event
8473      * @param fn {Function} The callback
8474      * @param context {object} optional execution context.
8475      * @param arg* {mixed} 0..n additional arguments to supply to the subscriber
8476      * @return the event target or a detach handle per 'chain' config
8477      */
8478     on: function(type, fn, context) {
8479
8480         var parts = _parseType(type, this._yuievt.config.prefix), f, c, args, ret, ce,
8481             detachcategory, handle, store = Y.Env.evt.handles, after, adapt, shorttype,
8482             Node = Y.Node, n, domevent, isArr;
8483
8484         // full name, args, detachcategory, after
8485         this._monitor('attach', parts[1], {
8486             args: arguments,
8487             category: parts[0],
8488             after: parts[2]
8489         });
8490
8491         if (L.isObject(type)) {
8492
8493             if (L.isFunction(type)) {
8494                 return Y.Do.before.apply(Y.Do, arguments);
8495             }
8496
8497             f = fn;
8498             c = context;
8499             args = YArray(arguments, 0, true);
8500             ret = [];
8501
8502             if (L.isArray(type)) {
8503                 isArr = true;
8504             }
8505
8506             after = type._after;
8507             delete type._after;
8508
8509             Y.each(type, function(v, k) {
8510
8511                 if (L.isObject(v)) {
8512                     f = v.fn || ((L.isFunction(v)) ? v : f);
8513                     c = v.context || c;
8514                 }
8515
8516                 var nv = (after) ? AFTER_PREFIX : '';
8517
8518                 args[0] = nv + ((isArr) ? v : k);
8519                 args[1] = f;
8520                 args[2] = c;
8521
8522                 ret.push(this.on.apply(this, args));
8523
8524             }, this);
8525
8526             return (this._yuievt.chain) ? this : new Y.EventHandle(ret);
8527
8528         }
8529
8530         detachcategory = parts[0];
8531         after = parts[2];
8532         shorttype = parts[3];
8533
8534         // extra redirection so we catch adaptor events too.  take a look at this.
8535         if (Node && Y.instanceOf(this, Node) && (shorttype in Node.DOM_EVENTS)) {
8536             args = YArray(arguments, 0, true);
8537             args.splice(2, 0, Node.getDOMNode(this));
8538             return Y.on.apply(Y, args);
8539         }
8540
8541         type = parts[1];
8542
8543         if (Y.instanceOf(this, YUI)) {
8544
8545             adapt = Y.Env.evt.plugins[type];
8546             args  = YArray(arguments, 0, true);
8547             args[0] = shorttype;
8548
8549             if (Node) {
8550                 n = args[2];
8551
8552                 if (Y.instanceOf(n, Y.NodeList)) {
8553                     n = Y.NodeList.getDOMNodes(n);
8554                 } else if (Y.instanceOf(n, Node)) {
8555                     n = Node.getDOMNode(n);
8556                 }
8557
8558                 domevent = (shorttype in Node.DOM_EVENTS);
8559
8560                 // Captures both DOM events and event plugins.
8561                 if (domevent) {
8562                     args[2] = n;
8563                 }
8564             }
8565
8566             // check for the existance of an event adaptor
8567             if (adapt) {
8568                 handle = adapt.on.apply(Y, args);
8569             } else if ((!type) || domevent) {
8570                 handle = Y.Event._attach(args);
8571             }
8572
8573         }
8574
8575         if (!handle) {
8576             ce = this._yuievt.events[type] || this.publish(type);
8577             handle = ce._on(fn, context, (arguments.length > 3) ? YArray(arguments, 3, true) : null, (after) ? 'after' : true);
8578         }
8579
8580         if (detachcategory) {
8581             store[detachcategory] = store[detachcategory] || {};
8582             store[detachcategory][type] = store[detachcategory][type] || [];
8583             store[detachcategory][type].push(handle);
8584         }
8585
8586         return (this._yuievt.chain) ? this : handle;
8587
8588     },
8589
8590     /**
8591      * subscribe to an event
8592      * @method subscribe
8593      * @deprecated use on
8594      */
8595     subscribe: function() {
8596         return this.on.apply(this, arguments);
8597     },
8598
8599     /**
8600      * Detach one or more listeners the from the specified event
8601      * @method detach
8602      * @param type {string|Object}   Either the handle to the subscriber or the
8603      *                        type of event.  If the type
8604      *                        is not specified, it will attempt to remove
8605      *                        the listener from all hosted events.
8606      * @param fn   {Function} The subscribed function to unsubscribe, if not
8607      *                          supplied, all subscribers will be removed.
8608      * @param context  {Object}   The custom object passed to subscribe.  This is
8609      *                        optional, but if supplied will be used to
8610      *                        disambiguate multiple listeners that are the same
8611      *                        (e.g., you subscribe many object using a function
8612      *                        that lives on the prototype)
8613      * @return {EventTarget} the host
8614      */
8615     detach: function(type, fn, context) {
8616         var evts = this._yuievt.events, i,
8617             Node = Y.Node, isNode = Node && (Y.instanceOf(this, Node));
8618
8619         // detachAll disabled on the Y instance.
8620         if (!type && (this !== Y)) {
8621             for (i in evts) {
8622                 if (evts.hasOwnProperty(i)) {
8623                     evts[i].detach(fn, context);
8624                 }
8625             }
8626             if (isNode) {
8627                 Y.Event.purgeElement(Node.getDOMNode(this));
8628             }
8629
8630             return this;
8631         }
8632
8633         var parts = _parseType(type, this._yuievt.config.prefix),
8634         detachcategory = L.isArray(parts) ? parts[0] : null,
8635         shorttype = (parts) ? parts[3] : null,
8636         adapt, store = Y.Env.evt.handles, detachhost, cat, args,
8637         ce,
8638
8639         keyDetacher = function(lcat, ltype, host) {
8640             var handles = lcat[ltype], ce, i;
8641             if (handles) {
8642                 for (i = handles.length - 1; i >= 0; --i) {
8643                     ce = handles[i].evt;
8644                     if (ce.host === host || ce.el === host) {
8645                         handles[i].detach();
8646                     }
8647                 }
8648             }
8649         };
8650
8651         if (detachcategory) {
8652
8653             cat = store[detachcategory];
8654             type = parts[1];
8655             detachhost = (isNode) ? Y.Node.getDOMNode(this) : this;
8656
8657             if (cat) {
8658                 if (type) {
8659                     keyDetacher(cat, type, detachhost);
8660                 } else {
8661                     for (i in cat) {
8662                         if (cat.hasOwnProperty(i)) {
8663                             keyDetacher(cat, i, detachhost);
8664                         }
8665                     }
8666                 }
8667
8668                 return this;
8669             }
8670
8671         // If this is an event handle, use it to detach
8672         } else if (L.isObject(type) && type.detach) {
8673             type.detach();
8674             return this;
8675         // extra redirection so we catch adaptor events too.  take a look at this.
8676         } else if (isNode && ((!shorttype) || (shorttype in Node.DOM_EVENTS))) {
8677             args = YArray(arguments, 0, true);
8678             args[2] = Node.getDOMNode(this);
8679             Y.detach.apply(Y, args);
8680             return this;
8681         }
8682
8683         adapt = Y.Env.evt.plugins[shorttype];
8684
8685         // The YUI instance handles DOM events and adaptors
8686         if (Y.instanceOf(this, YUI)) {
8687             args = YArray(arguments, 0, true);
8688             // use the adaptor specific detach code if
8689             if (adapt && adapt.detach) {
8690                 adapt.detach.apply(Y, args);
8691                 return this;
8692             // DOM event fork
8693             } else if (!type || (!adapt && Node && (type in Node.DOM_EVENTS))) {
8694                 args[0] = type;
8695                 Y.Event.detach.apply(Y.Event, args);
8696                 return this;
8697             }
8698         }
8699
8700         // ce = evts[type];
8701         ce = evts[parts[1]];
8702         if (ce) {
8703             ce.detach(fn, context);
8704         }
8705
8706         return this;
8707     },
8708
8709     /**
8710      * detach a listener
8711      * @method unsubscribe
8712      * @deprecated use detach
8713      */
8714     unsubscribe: function() {
8715         return this.detach.apply(this, arguments);
8716     },
8717
8718     /**
8719      * Removes all listeners from the specified event.  If the event type
8720      * is not specified, all listeners from all hosted custom events will
8721      * be removed.
8722      * @method detachAll
8723      * @param type {string}   The type, or name of the event
8724      */
8725     detachAll: function(type) {
8726         return this.detach(type);
8727     },
8728
8729     /**
8730      * Removes all listeners from the specified event.  If the event type
8731      * is not specified, all listeners from all hosted custom events will
8732      * be removed.
8733      * @method unsubscribeAll
8734      * @param type {string}   The type, or name of the event
8735      * @deprecated use detachAll
8736      */
8737     unsubscribeAll: function() {
8738         return this.detachAll.apply(this, arguments);
8739     },
8740
8741     /**
8742      * Creates a new custom event of the specified type.  If a custom event
8743      * by that name already exists, it will not be re-created.  In either
8744      * case the custom event is returned.
8745      *
8746      * @method publish
8747      *
8748      * @param type {string} the type, or name of the event
8749      * @param opts {object} optional config params.  Valid properties are:
8750      *
8751      *  <ul>
8752      *    <li>
8753      *   'broadcast': whether or not the YUI instance and YUI global are notified when the event is fired (false)
8754      *    </li>
8755      *    <li>
8756      *   'bubbles': whether or not this event bubbles (true)
8757      *              Events can only bubble if emitFacade is true.
8758      *    </li>
8759      *    <li>
8760      *   'context': the default execution context for the listeners (this)
8761      *    </li>
8762      *    <li>
8763      *   'defaultFn': the default function to execute when this event fires if preventDefault was not called
8764      *    </li>
8765      *    <li>
8766      *   'emitFacade': whether or not this event emits a facade (false)
8767      *    </li>
8768      *    <li>
8769      *   'prefix': the prefix for this targets events, e.g., 'menu' in 'menu:click'
8770      *    </li>
8771      *    <li>
8772      *   'fireOnce': if an event is configured to fire once, new subscribers after
8773      *   the fire will be notified immediately.
8774      *    </li>
8775      *    <li>
8776      *   'async': fireOnce event listeners will fire synchronously if the event has already
8777      *    fired unless async is true.
8778      *    </li>
8779      *    <li>
8780      *   'preventable': whether or not preventDefault() has an effect (true)
8781      *    </li>
8782      *    <li>
8783      *   'preventedFn': a function that is executed when preventDefault is called
8784      *    </li>
8785      *    <li>
8786      *   'queuable': whether or not this event can be queued during bubbling (false)
8787      *    </li>
8788      *    <li>
8789      *   'silent': if silent is true, debug messages are not provided for this event.
8790      *    </li>
8791      *    <li>
8792      *   'stoppedFn': a function that is executed when stopPropagation is called
8793      *    </li>
8794      *
8795      *    <li>
8796      *   'monitored': specifies whether or not this event should send notifications about
8797      *   when the event has been attached, detached, or published.
8798      *    </li>
8799      *    <li>
8800      *   'type': the event type (valid option if not provided as the first parameter to publish)
8801      *    </li>
8802      *  </ul>
8803      *
8804      *  @return {CustomEvent} the custom event
8805      *
8806      */
8807     publish: function(type, opts) {
8808         var events, ce, ret, defaults,
8809             edata    = this._yuievt,
8810             pre      = edata.config.prefix;
8811
8812         type = (pre) ? _getType(type, pre) : type;
8813
8814         this._monitor('publish', type, {
8815             args: arguments
8816         });
8817
8818         if (L.isObject(type)) {
8819             ret = {};
8820             Y.each(type, function(v, k) {
8821                 ret[k] = this.publish(k, v || opts);
8822             }, this);
8823
8824             return ret;
8825         }
8826
8827         events = edata.events;
8828         ce = events[type];
8829
8830         if (ce) {
8831 // ce.log("publish applying new config to published event: '"+type+"' exists", 'info', 'event');
8832             if (opts) {
8833                 ce.applyConfig(opts, true);
8834             }
8835         } else {
8836
8837             defaults = edata.defaults;
8838
8839             // apply defaults
8840             ce = new Y.CustomEvent(type,
8841                                   (opts) ? Y.merge(defaults, opts) : defaults);
8842             events[type] = ce;
8843         }
8844
8845         // make sure we turn the broadcast flag off if this
8846         // event was published as a result of bubbling
8847         // if (opts instanceof Y.CustomEvent) {
8848           //   events[type].broadcast = false;
8849         // }
8850
8851         return events[type];
8852     },
8853
8854     /**
8855      * This is the entry point for the event monitoring system.
8856      * You can monitor 'attach', 'detach', 'fire', and 'publish'.
8857      * When configured, these events generate an event.  click ->
8858      * click_attach, click_detach, click_publish -- these can
8859      * be subscribed to like other events to monitor the event
8860      * system.  Inividual published events can have monitoring
8861      * turned on or off (publish can't be turned off before it
8862      * it published) by setting the events 'monitor' config.
8863      *
8864      * @private
8865      */
8866     _monitor: function(what, type, o) {
8867         var monitorevt, ce = this.getEvent(type);
8868         if ((this._yuievt.config.monitored && (!ce || ce.monitored)) || (ce && ce.monitored)) {
8869             monitorevt = type + '_' + what;
8870             o.monitored = what;
8871             this.fire.call(this, monitorevt, o);
8872         }
8873     },
8874
8875    /**
8876      * Fire a custom event by name.  The callback functions will be executed
8877      * from the context specified when the event was created, and with the
8878      * following parameters.
8879      *
8880      * If the custom event object hasn't been created, then the event hasn't
8881      * been published and it has no subscribers.  For performance sake, we
8882      * immediate exit in this case.  This means the event won't bubble, so
8883      * if the intention is that a bubble target be notified, the event must
8884      * be published on this object first.
8885      *
8886      * The first argument is the event type, and any additional arguments are
8887      * passed to the listeners as parameters.  If the first of these is an
8888      * object literal, and the event is configured to emit an event facade,
8889      * that object is mixed into the event facade and the facade is provided
8890      * in place of the original object.
8891      *
8892      * @method fire
8893      * @param type {String|Object} The type of the event, or an object that contains
8894      * a 'type' property.
8895      * @param arguments {Object*} an arbitrary set of parameters to pass to
8896      * the handler.  If the first of these is an object literal and the event is
8897      * configured to emit an event facade, the event facade will replace that
8898      * parameter after the properties the object literal contains are copied to
8899      * the event facade.
8900      * @return {EventTarget} the event host
8901      *
8902      */
8903     fire: function(type) {
8904
8905         var typeIncluded = L.isString(type),
8906             t = (typeIncluded) ? type : (type && type.type),
8907             ce, ret, pre = this._yuievt.config.prefix, ce2,
8908             args = (typeIncluded) ? YArray(arguments, 1, true) : arguments;
8909
8910         t = (pre) ? _getType(t, pre) : t;
8911
8912         this._monitor('fire', t, {
8913             args: args
8914         });
8915
8916         ce = this.getEvent(t, true);
8917         ce2 = this.getSibling(t, ce);
8918
8919         if (ce2 && !ce) {
8920             ce = this.publish(t);
8921         }
8922
8923         // this event has not been published or subscribed to
8924         if (!ce) {
8925             if (this._yuievt.hasTargets) {
8926                 return this.bubble({ type: t }, args, this);
8927             }
8928
8929             // otherwise there is nothing to be done
8930             ret = true;
8931         } else {
8932             ce.sibling = ce2;
8933             ret = ce.fire.apply(ce, args);
8934         }
8935
8936         return (this._yuievt.chain) ? this : ret;
8937     },
8938
8939     getSibling: function(type, ce) {
8940         var ce2;
8941         // delegate to *:type events if there are subscribers
8942         if (type.indexOf(PREFIX_DELIMITER) > -1) {
8943             type = _wildType(type);
8944             // console.log(type);
8945             ce2 = this.getEvent(type, true);
8946             if (ce2) {
8947                 // console.log("GOT ONE: " + type);
8948                 ce2.applyConfig(ce);
8949                 ce2.bubbles = false;
8950                 ce2.broadcast = 0;
8951                 // ret = ce2.fire.apply(ce2, a);
8952             }
8953         }
8954
8955         return ce2;
8956     },
8957
8958     /**
8959      * Returns the custom event of the provided type has been created, a
8960      * falsy value otherwise
8961      * @method getEvent
8962      * @param type {string} the type, or name of the event
8963      * @param prefixed {string} if true, the type is prefixed already
8964      * @return {CustomEvent} the custom event or null
8965      */
8966     getEvent: function(type, prefixed) {
8967         var pre, e;
8968         if (!prefixed) {
8969             pre = this._yuievt.config.prefix;
8970             type = (pre) ? _getType(type, pre) : type;
8971         }
8972         e = this._yuievt.events;
8973         return e[type] || null;
8974     },
8975
8976     /**
8977      * Subscribe to a custom event hosted by this object.  The
8978      * supplied callback will execute after any listeners add
8979      * via the subscribe method, and after the default function,
8980      * if configured for the event, has executed.
8981      * @method after
8982      * @param type    {string}   The type of the event
8983      * @param fn {Function} The callback
8984      * @param context {object} optional execution context.
8985      * @param arg* {mixed} 0..n additional arguments to supply to the subscriber
8986      * @return the event target or a detach handle per 'chain' config
8987      */
8988     after: function(type, fn) {
8989
8990         var a = YArray(arguments, 0, true);
8991
8992         switch (L.type(type)) {
8993             case 'function':
8994                 return Y.Do.after.apply(Y.Do, arguments);
8995             case 'array':
8996             //     YArray.each(a[0], function(v) {
8997             //         v = AFTER_PREFIX + v;
8998             //     });
8999             //     break;
9000             case 'object':
9001                 a[0]._after = true;
9002                 break;
9003             default:
9004                 a[0] = AFTER_PREFIX + type;
9005         }
9006
9007         return this.on.apply(this, a);
9008
9009     },
9010
9011     /**
9012      * Executes the callback before a DOM event, custom event
9013      * or method.  If the first argument is a function, it
9014      * is assumed the target is a method.  For DOM and custom
9015      * events, this is an alias for Y.on.
9016      *
9017      * For DOM and custom events:
9018      * type, callback, context, 0-n arguments
9019      *
9020      * For methods:
9021      * callback, object (method host), methodName, context, 0-n arguments
9022      *
9023      * @method before
9024      * @return detach handle
9025      */
9026     before: function() {
9027         return this.on.apply(this, arguments);
9028     }
9029
9030 };
9031
9032 Y.EventTarget = ET;
9033
9034 // make Y an event target
9035 Y.mix(Y, ET.prototype, false, false, {
9036     bubbles: false
9037 });
9038
9039 ET.call(Y);
9040
9041 YUI.Env.globalEvents = YUI.Env.globalEvents || new ET();
9042
9043 /**
9044  * Hosts YUI page level events.  This is where events bubble to
9045  * when the broadcast config is set to 2.  This property is
9046  * only available if the custom event module is loaded.
9047  * @property Global
9048  * @type EventTarget
9049  * @for YUI
9050  */
9051 Y.Global = YUI.Env.globalEvents;
9052
9053 // @TODO implement a global namespace function on Y.Global?
9054
9055 /**
9056  * <code>YUI</code>'s <code>on</code> method is a unified interface for subscribing to
9057  * most events exposed by YUI.  This includes custom events, DOM events, and
9058  * function events.  <code>detach</code> is also provided to remove listeners
9059  * serviced by this function.
9060  *
9061  * The signature that <code>on</code> accepts varies depending on the type
9062  * of event being consumed.  Refer to the specific methods that will
9063  * service a specific request for additional information about subscribing
9064  * to that type of event.
9065  *
9066  * <ul>
9067  * <li>Custom events.  These events are defined by various
9068  * modules in the library.  This type of event is delegated to
9069  * <code>EventTarget</code>'s <code>on</code> method.
9070  *   <ul>
9071  *     <li>The type of the event</li>
9072  *     <li>The callback to execute</li>
9073  *     <li>An optional context object</li>
9074  *     <li>0..n additional arguments to supply the callback.</li>
9075  *   </ul>
9076  *   Example:
9077  *   <code>Y.on('drag:drophit', function() { // start work });</code>
9078  * </li>
9079  * <li>DOM events.  These are moments reported by the browser related
9080  * to browser functionality and user interaction.
9081  * This type of event is delegated to <code>Event</code>'s
9082  * <code>attach</code> method.
9083  *   <ul>
9084  *     <li>The type of the event</li>
9085  *     <li>The callback to execute</li>
9086  *     <li>The specification for the Node(s) to attach the listener
9087  *     to.  This can be a selector, collections, or Node/Element
9088  *     refereces.</li>
9089  *     <li>An optional context object</li>
9090  *     <li>0..n additional arguments to supply the callback.</li>
9091  *   </ul>
9092  *   Example:
9093  *   <code>Y.on('click', function(e) { // something was clicked }, '#someelement');</code>
9094  * </li>
9095  * <li>Function events.  These events can be used to react before or after a
9096  * function is executed.  This type of event is delegated to <code>Event.Do</code>'s
9097  * <code>before</code> method.
9098  *   <ul>
9099  *     <li>The callback to execute</li>
9100  *     <li>The object that has the function that will be listened for.</li>
9101  *     <li>The name of the function to listen for.</li>
9102  *     <li>An optional context object</li>
9103  *     <li>0..n additional arguments to supply the callback.</li>
9104  *   </ul>
9105  *   Example <code>Y.on(function(arg1, arg2, etc) { // obj.methodname was executed }, obj 'methodname');</code>
9106  * </li>
9107  * </ul>
9108  *
9109  * <code>on</code> corresponds to the moment before any default behavior of
9110  * the event.  <code>after</code> works the same way, but these listeners
9111  * execute after the event's default behavior.  <code>before</code> is an
9112  * alias for <code>on</code>.
9113  *
9114  * @method on
9115  * @param type event type (this parameter does not apply for function events)
9116  * @param fn the callback
9117  * @param context optionally change the value of 'this' in the callback
9118  * @param args* 0..n additional arguments to pass to the callback.
9119  * @return the event target or a detach handle per 'chain' config
9120  * @for YUI
9121  */
9122
9123  /**
9124   * Listen for an event one time.  Equivalent to <code>on</code>, except that
9125   * the listener is immediately detached when executed.
9126   * @see on
9127   * @method once
9128   * @param type event type (this parameter does not apply for function events)
9129   * @param fn the callback
9130   * @param context optionally change the value of 'this' in the callback
9131   * @param args* 0..n additional arguments to pass to the callback.
9132   * @return the event target or a detach handle per 'chain' config
9133   * @for YUI
9134   */
9135
9136 /**
9137  * after() is a unified interface for subscribing to
9138  * most events exposed by YUI.  This includes custom events,
9139  * DOM events, and AOP events.  This works the same way as
9140  * the on() function, only it operates after any default
9141  * behavior for the event has executed. @see <code>on</code> for more
9142  * information.
9143  * @method after
9144  * @param type event type (this parameter does not apply for function events)
9145  * @param fn the callback
9146  * @param context optionally change the value of 'this' in the callback
9147  * @param args* 0..n additional arguments to pass to the callback.
9148  * @return the event target or a detach handle per 'chain' config
9149  * @for YUI
9150  */
9151
9152
9153 }, '3.3.0' ,{requires:['oop']});
9154 var GLOBAL_ENV = YUI.Env;
9155
9156 if (!GLOBAL_ENV._ready) {
9157     GLOBAL_ENV._ready = function() {
9158         GLOBAL_ENV.DOMReady = true;
9159         GLOBAL_ENV.remove(YUI.config.doc, 'DOMContentLoaded', GLOBAL_ENV._ready);
9160     };
9161
9162     // if (!YUI.UA.ie) {
9163         GLOBAL_ENV.add(YUI.config.doc, 'DOMContentLoaded', GLOBAL_ENV._ready);
9164     // }
9165 }
9166
9167 YUI.add('event-base', function(Y) {
9168
9169 /*
9170  * DOM event listener abstraction layer
9171  * @module event
9172  * @submodule event-base
9173  */
9174
9175 /**
9176  * The domready event fires at the moment the browser's DOM is
9177  * usable. In most cases, this is before images are fully
9178  * downloaded, allowing you to provide a more responsive user
9179  * interface.
9180  *
9181  * In YUI 3, domready subscribers will be notified immediately if
9182  * that moment has already passed when the subscription is created.
9183  *
9184  * One exception is if the yui.js file is dynamically injected into
9185  * the page.  If this is done, you must tell the YUI instance that
9186  * you did this in order for DOMReady (and window load events) to
9187  * fire normally.  That configuration option is 'injected' -- set
9188  * it to true if the yui.js script is not included inline.
9189  *
9190  * This method is part of the 'event-ready' module, which is a
9191  * submodule of 'event'.
9192  *
9193  * @event domready
9194  * @for YUI
9195  */
9196 Y.publish('domready', {
9197     fireOnce: true,
9198     async: true
9199 });
9200
9201 if (GLOBAL_ENV.DOMReady) {
9202     Y.fire('domready');
9203 } else {
9204     Y.Do.before(function() { Y.fire('domready'); }, YUI.Env, '_ready');
9205 }
9206
9207 /**
9208  * Custom event engine, DOM event listener abstraction layer, synthetic DOM
9209  * events.
9210  * @module event
9211  * @submodule event-base
9212  */
9213
9214 /**
9215  * Wraps a DOM event, properties requiring browser abstraction are
9216  * fixed here.  Provids a security layer when required.
9217  * @class DOMEventFacade
9218  * @param ev {Event} the DOM event
9219  * @param currentTarget {HTMLElement} the element the listener was attached to
9220  * @param wrapper {Event.Custom} the custom event wrapper for this DOM event
9221  */
9222
9223     var ua = Y.UA,
9224
9225     EMPTY = {},
9226
9227     /**
9228      * webkit key remapping required for Safari < 3.1
9229      * @property webkitKeymap
9230      * @private
9231      */
9232     webkitKeymap = {
9233         63232: 38, // up
9234         63233: 40, // down
9235         63234: 37, // left
9236         63235: 39, // right
9237         63276: 33, // page up
9238         63277: 34, // page down
9239         25:     9, // SHIFT-TAB (Safari provides a different key code in
9240                    // this case, even though the shiftKey modifier is set)
9241         63272: 46, // delete
9242         63273: 36, // home
9243         63275: 35  // end
9244     },
9245
9246     /**
9247      * Returns a wrapped node.  Intended to be used on event targets,
9248      * so it will return the node's parent if the target is a text
9249      * node.
9250      *
9251      * If accessing a property of the node throws an error, this is
9252      * probably the anonymous div wrapper Gecko adds inside text
9253      * nodes.  This likely will only occur when attempting to access
9254      * the relatedTarget.  In this case, we now return null because
9255      * the anonymous div is completely useless and we do not know
9256      * what the related target was because we can't even get to
9257      * the element's parent node.
9258      *
9259      * @method resolve
9260      * @private
9261      */
9262     resolve = function(n) {
9263         if (!n) {
9264             return n;
9265         }
9266         try {
9267             if (n && 3 == n.nodeType) {
9268                 n = n.parentNode;
9269             }
9270         } catch(e) {
9271             return null;
9272         }
9273
9274         return Y.one(n);
9275     },
9276
9277     DOMEventFacade = function(ev, currentTarget, wrapper) {
9278         this._event = ev;
9279         this._currentTarget = currentTarget;
9280         this._wrapper = wrapper || EMPTY;
9281
9282         // if not lazy init
9283         this.init();
9284     };
9285
9286 Y.extend(DOMEventFacade, Object, {
9287
9288     init: function() {
9289
9290         var e = this._event,
9291             overrides = this._wrapper.overrides,
9292             x = e.pageX,
9293             y = e.pageY,
9294             c,
9295             currentTarget = this._currentTarget;
9296
9297         this.altKey   = e.altKey;
9298         this.ctrlKey  = e.ctrlKey;
9299         this.metaKey  = e.metaKey;
9300         this.shiftKey = e.shiftKey;
9301         this.type     = (overrides && overrides.type) || e.type;
9302         this.clientX  = e.clientX;
9303         this.clientY  = e.clientY;
9304
9305         this.pageX = x;
9306         this.pageY = y;
9307
9308         c = e.keyCode || e.charCode;
9309
9310         if (ua.webkit && (c in webkitKeymap)) {
9311             c = webkitKeymap[c];
9312         }
9313
9314         this.keyCode = c;
9315         this.charCode = c;
9316         this.which = e.which || e.charCode || c;
9317         // this.button = e.button;
9318         this.button = this.which;
9319
9320         this.target = resolve(e.target);
9321         this.currentTarget = resolve(currentTarget);
9322         this.relatedTarget = resolve(e.relatedTarget);
9323
9324         if (e.type == "mousewheel" || e.type == "DOMMouseScroll") {
9325             this.wheelDelta = (e.detail) ? (e.detail * -1) : Math.round(e.wheelDelta / 80) || ((e.wheelDelta < 0) ? -1 : 1);
9326         }
9327
9328         if (this._touch) {
9329             this._touch(e, currentTarget, this._wrapper);
9330         }
9331     },
9332
9333     stopPropagation: function() {
9334         this._event.stopPropagation();
9335         this._wrapper.stopped = 1;
9336         this.stopped = 1;
9337     },
9338
9339     stopImmediatePropagation: function() {
9340         var e = this._event;
9341         if (e.stopImmediatePropagation) {
9342             e.stopImmediatePropagation();
9343         } else {
9344             this.stopPropagation();
9345         }
9346         this._wrapper.stopped = 2;
9347         this.stopped = 2;
9348     },
9349
9350     preventDefault: function(returnValue) {
9351         var e = this._event;
9352         e.preventDefault();
9353         e.returnValue = returnValue || false;
9354         this._wrapper.prevented = 1;
9355         this.prevented = 1;
9356     },
9357
9358     halt: function(immediate) {
9359         if (immediate) {
9360             this.stopImmediatePropagation();
9361         } else {
9362             this.stopPropagation();
9363         }
9364
9365         this.preventDefault();
9366     }
9367
9368 });
9369
9370 DOMEventFacade.resolve = resolve;
9371 Y.DOM2EventFacade = DOMEventFacade;
9372 Y.DOMEventFacade = DOMEventFacade;
9373
9374     /**
9375      * The native event
9376      * @property _event
9377      */
9378
9379     /**
9380      * The X location of the event on the page (including scroll)
9381      * @property pageX
9382      * @type int
9383      */
9384
9385     /**
9386      * The Y location of the event on the page (including scroll)
9387      * @property pageY
9388      * @type int
9389      */
9390
9391     /**
9392      * The keyCode for key events.  Uses charCode if keyCode is not available
9393      * @property keyCode
9394      * @type int
9395      */
9396
9397     /**
9398      * The charCode for key events.  Same as keyCode
9399      * @property charCode
9400      * @type int
9401      */
9402
9403     /**
9404      * The button that was pushed.
9405      * @property button
9406      * @type int
9407      */
9408
9409     /**
9410      * The button that was pushed.  Same as button.
9411      * @property which
9412      * @type int
9413      */
9414
9415     /**
9416      * Node reference for the targeted element
9417      * @propery target
9418      * @type Node
9419      */
9420
9421     /**
9422      * Node reference for the element that the listener was attached to.
9423      * @propery currentTarget
9424      * @type Node
9425      */
9426
9427     /**
9428      * Node reference to the relatedTarget
9429      * @propery relatedTarget
9430      * @type Node
9431      */
9432
9433     /**
9434      * Number representing the direction and velocity of the movement of the mousewheel.
9435      * Negative is down, the higher the number, the faster.  Applies to the mousewheel event.
9436      * @property wheelDelta
9437      * @type int
9438      */
9439
9440     /**
9441      * Stops the propagation to the next bubble target
9442      * @method stopPropagation
9443      */
9444
9445     /**
9446      * Stops the propagation to the next bubble target and
9447      * prevents any additional listeners from being exectued
9448      * on the current target.
9449      * @method stopImmediatePropagation
9450      */
9451
9452     /**
9453      * Prevents the event's default behavior
9454      * @method preventDefault
9455      * @param returnValue {string} sets the returnValue of the event to this value
9456      * (rather than the default false value).  This can be used to add a customized
9457      * confirmation query to the beforeunload event).
9458      */
9459
9460     /**
9461      * Stops the event propagation and prevents the default
9462      * event behavior.
9463      * @method halt
9464      * @param immediate {boolean} if true additional listeners
9465      * on the current target will not be executed
9466      */
9467 (function() {
9468 /**
9469  * DOM event listener abstraction layer
9470  * @module event
9471  * @submodule event-base
9472  */
9473
9474 /**
9475  * The event utility provides functions to add and remove event listeners,
9476  * event cleansing.  It also tries to automatically remove listeners it
9477  * registers during the unload event.
9478  *
9479  * @class Event
9480  * @static
9481  */
9482
9483 Y.Env.evt.dom_wrappers = {};
9484 Y.Env.evt.dom_map = {};
9485
9486 var _eventenv = Y.Env.evt,
9487     config = Y.config,
9488     win = config.win,
9489     add = YUI.Env.add,
9490     remove = YUI.Env.remove,
9491
9492     onLoad = function() {
9493         YUI.Env.windowLoaded = true;
9494         Y.Event._load();
9495         remove(win, "load", onLoad);
9496     },
9497
9498     onUnload = function() {
9499         Y.Event._unload();
9500     },
9501
9502     EVENT_READY = 'domready',
9503
9504     COMPAT_ARG = '~yui|2|compat~',
9505
9506     shouldIterate = function(o) {
9507         try {
9508             return (o && typeof o !== "string" && Y.Lang.isNumber(o.length) &&
9509                     !o.tagName && !o.alert);
9510         } catch(ex) {
9511             return false;
9512         }
9513
9514     },
9515
9516 Event = function() {
9517
9518     /**
9519      * True after the onload event has fired
9520      * @property _loadComplete
9521      * @type boolean
9522      * @static
9523      * @private
9524      */
9525     var _loadComplete =  false,
9526
9527     /**
9528      * The number of times to poll after window.onload.  This number is
9529      * increased if additional late-bound handlers are requested after
9530      * the page load.
9531      * @property _retryCount
9532      * @static
9533      * @private
9534      */
9535     _retryCount = 0,
9536
9537     /**
9538      * onAvailable listeners
9539      * @property _avail
9540      * @static
9541      * @private
9542      */
9543     _avail = [],
9544
9545     /**
9546      * Custom event wrappers for DOM events.  Key is
9547      * 'event:' + Element uid stamp + event type
9548      * @property _wrappers
9549      * @type Y.Event.Custom
9550      * @static
9551      * @private
9552      */
9553     _wrappers = _eventenv.dom_wrappers,
9554
9555     _windowLoadKey = null,
9556
9557     /**
9558      * Custom event wrapper map DOM events.  Key is
9559      * Element uid stamp.  Each item is a hash of custom event
9560      * wrappers as provided in the _wrappers collection.  This
9561      * provides the infrastructure for getListeners.
9562      * @property _el_events
9563      * @static
9564      * @private
9565      */
9566     _el_events = _eventenv.dom_map;
9567
9568     return {
9569
9570         /**
9571          * The number of times we should look for elements that are not
9572          * in the DOM at the time the event is requested after the document
9573          * has been loaded.  The default is 1000@amp;40 ms, so it will poll
9574          * for 40 seconds or until all outstanding handlers are bound
9575          * (whichever comes first).
9576          * @property POLL_RETRYS
9577          * @type int
9578          * @static
9579          * @final
9580          */
9581         POLL_RETRYS: 1000,
9582
9583         /**
9584          * The poll interval in milliseconds
9585          * @property POLL_INTERVAL
9586          * @type int
9587          * @static
9588          * @final
9589          */
9590         POLL_INTERVAL: 40,
9591
9592         /**
9593          * addListener/removeListener can throw errors in unexpected scenarios.
9594          * These errors are suppressed, the method returns false, and this property
9595          * is set
9596          * @property lastError
9597          * @static
9598          * @type Error
9599          */
9600         lastError: null,
9601
9602
9603         /**
9604          * poll handle
9605          * @property _interval
9606          * @static
9607          * @private
9608          */
9609         _interval: null,
9610
9611         /**
9612          * document readystate poll handle
9613          * @property _dri
9614          * @static
9615          * @private
9616          */
9617          _dri: null,
9618
9619         /**
9620          * True when the document is initially usable
9621          * @property DOMReady
9622          * @type boolean
9623          * @static
9624          */
9625         DOMReady: false,
9626
9627         /**
9628          * @method startInterval
9629          * @static
9630          * @private
9631          */
9632         startInterval: function() {
9633             if (!Event._interval) {
9634 Event._interval = setInterval(Event._poll, Event.POLL_INTERVAL);
9635             }
9636         },
9637
9638         /**
9639          * Executes the supplied callback when the item with the supplied
9640          * id is found.  This is meant to be used to execute behavior as
9641          * soon as possible as the page loads.  If you use this after the
9642          * initial page load it will poll for a fixed time for the element.
9643          * The number of times it will poll and the frequency are
9644          * configurable.  By default it will poll for 10 seconds.
9645          *
9646          * <p>The callback is executed with a single parameter:
9647          * the custom object parameter, if provided.</p>
9648          *
9649          * @method onAvailable
9650          *
9651          * @param {string||string[]}   id the id of the element, or an array
9652          * of ids to look for.
9653          * @param {function} fn what to execute when the element is found.
9654          * @param {object}   p_obj an optional object to be passed back as
9655          *                   a parameter to fn.
9656          * @param {boolean|object}  p_override If set to true, fn will execute
9657          *                   in the context of p_obj, if set to an object it
9658          *                   will execute in the context of that object
9659          * @param checkContent {boolean} check child node readiness (onContentReady)
9660          * @static
9661          * @deprecated Use Y.on("available")
9662          */
9663         // @TODO fix arguments
9664         onAvailable: function(id, fn, p_obj, p_override, checkContent, compat) {
9665
9666             var a = Y.Array(id), i, availHandle;
9667
9668
9669             for (i=0; i<a.length; i=i+1) {
9670                 _avail.push({
9671                     id:         a[i],
9672                     fn:         fn,
9673                     obj:        p_obj,
9674                     override:   p_override,
9675                     checkReady: checkContent,
9676                     compat:     compat
9677                 });
9678             }
9679             _retryCount = this.POLL_RETRYS;
9680
9681             // We want the first test to be immediate, but async
9682             setTimeout(Event._poll, 0);
9683
9684             availHandle = new Y.EventHandle({
9685
9686                 _delete: function() {
9687                     // set by the event system for lazy DOM listeners
9688                     if (availHandle.handle) {
9689                         availHandle.handle.detach();
9690                         return;
9691                     }
9692
9693                     var i, j;
9694
9695                     // otherwise try to remove the onAvailable listener(s)
9696                     for (i = 0; i < a.length; i++) {
9697                         for (j = 0; j < _avail.length; j++) {
9698                             if (a[i] === _avail[j].id) {
9699                                 _avail.splice(j, 1);
9700                             }
9701                         }
9702                     }
9703                 }
9704
9705             });
9706
9707             return availHandle;
9708         },
9709
9710         /**
9711          * Works the same way as onAvailable, but additionally checks the
9712          * state of sibling elements to determine if the content of the
9713          * available element is safe to modify.
9714          *
9715          * <p>The callback is executed with a single parameter:
9716          * the custom object parameter, if provided.</p>
9717          *
9718          * @method onContentReady
9719          *
9720          * @param {string}   id the id of the element to look for.
9721          * @param {function} fn what to execute when the element is ready.
9722          * @param {object}   obj an optional object to be passed back as
9723          *                   a parameter to fn.
9724          * @param {boolean|object}  override If set to true, fn will execute
9725          *                   in the context of p_obj.  If an object, fn will
9726          *                   exectute in the context of that object
9727          *
9728          * @static
9729          * @deprecated Use Y.on("contentready")
9730          */
9731         // @TODO fix arguments
9732         onContentReady: function(id, fn, obj, override, compat) {
9733             return Event.onAvailable(id, fn, obj, override, true, compat);
9734         },
9735
9736         /**
9737          * Adds an event listener
9738          *
9739          * @method attach
9740          *
9741          * @param {String}   type     The type of event to append
9742          * @param {Function} fn        The method the event invokes
9743          * @param {String|HTMLElement|Array|NodeList} el An id, an element
9744          *  reference, or a collection of ids and/or elements to assign the
9745          *  listener to.
9746          * @param {Object}   context optional context object
9747          * @param {Boolean|object}  args 0..n arguments to pass to the callback
9748          * @return {EventHandle} an object to that can be used to detach the listener
9749          *
9750          * @static
9751          */
9752
9753         attach: function(type, fn, el, context) {
9754             return Event._attach(Y.Array(arguments, 0, true));
9755         },
9756
9757         _createWrapper: function (el, type, capture, compat, facade) {
9758
9759             var cewrapper,
9760                 ek  = Y.stamp(el),
9761                 key = 'event:' + ek + type;
9762
9763             if (false === facade) {
9764                 key += 'native';
9765             }
9766             if (capture) {
9767                 key += 'capture';
9768             }
9769
9770
9771             cewrapper = _wrappers[key];
9772
9773
9774             if (!cewrapper) {
9775                 // create CE wrapper
9776                 cewrapper = Y.publish(key, {
9777                     silent: true,
9778                     bubbles: false,
9779                     contextFn: function() {
9780                         if (compat) {
9781                             return cewrapper.el;
9782                         } else {
9783                             cewrapper.nodeRef = cewrapper.nodeRef || Y.one(cewrapper.el);
9784                             return cewrapper.nodeRef;
9785                         }
9786                     }
9787                 });
9788
9789                 cewrapper.overrides = {};
9790
9791                 // for later removeListener calls
9792                 cewrapper.el = el;
9793                 cewrapper.key = key;
9794                 cewrapper.domkey = ek;
9795                 cewrapper.type = type;
9796                 cewrapper.fn = function(e) {
9797                     cewrapper.fire(Event.getEvent(e, el, (compat || (false === facade))));
9798                 };
9799                 cewrapper.capture = capture;
9800
9801                 if (el == win && type == "load") {
9802                     // window load happens once
9803                     cewrapper.fireOnce = true;
9804                     _windowLoadKey = key;
9805                 }
9806
9807                 _wrappers[key] = cewrapper;
9808                 _el_events[ek] = _el_events[ek] || {};
9809                 _el_events[ek][key] = cewrapper;
9810
9811                 add(el, type, cewrapper.fn, capture);
9812             }
9813
9814             return cewrapper;
9815
9816         },
9817
9818         _attach: function(args, conf) {
9819
9820             var compat,
9821                 handles, oEl, cewrapper, context,
9822                 fireNow = false, ret,
9823                 type = args[0],
9824                 fn = args[1],
9825                 el = args[2] || win,
9826                 facade = conf && conf.facade,
9827                 capture = conf && conf.capture,
9828                 overrides = conf && conf.overrides;
9829
9830             if (args[args.length-1] === COMPAT_ARG) {
9831                 compat = true;
9832                 // trimmedArgs.pop();
9833             }
9834
9835             if (!fn || !fn.call) {
9836 // throw new TypeError(type + " attach call failed, callback undefined");
9837                 return false;
9838             }
9839
9840             // The el argument can be an array of elements or element ids.
9841             if (shouldIterate(el)) {
9842
9843                 handles=[];
9844
9845                 Y.each(el, function(v, k) {
9846                     args[2] = v;
9847                     handles.push(Event._attach(args, conf));
9848                 });
9849
9850                 // return (handles.length === 1) ? handles[0] : handles;
9851                 return new Y.EventHandle(handles);
9852
9853             // If the el argument is a string, we assume it is
9854             // actually the id of the element.  If the page is loaded
9855             // we convert el to the actual element, otherwise we
9856             // defer attaching the event until the element is
9857             // ready
9858             } else if (Y.Lang.isString(el)) {
9859
9860                 // oEl = (compat) ? Y.DOM.byId(el) : Y.Selector.query(el);
9861
9862                 if (compat) {
9863                     oEl = Y.DOM.byId(el);
9864                 } else {
9865
9866                     oEl = Y.Selector.query(el);
9867
9868                     switch (oEl.length) {
9869                         case 0:
9870                             oEl = null;
9871                             break;
9872                         case 1:
9873                             oEl = oEl[0];
9874                             break;
9875                         default:
9876                             args[2] = oEl;
9877                             return Event._attach(args, conf);
9878                     }
9879                 }
9880
9881                 if (oEl) {
9882
9883                     el = oEl;
9884
9885                 // Not found = defer adding the event until the element is available
9886                 } else {
9887
9888                     ret = Event.onAvailable(el, function() {
9889
9890                         ret.handle = Event._attach(args, conf);
9891
9892                     }, Event, true, false, compat);
9893
9894                     return ret;
9895
9896                 }
9897             }
9898
9899             // Element should be an html element or node
9900             if (!el) {
9901                 return false;
9902             }
9903
9904             if (Y.Node && Y.instanceOf(el, Y.Node)) {
9905                 el = Y.Node.getDOMNode(el);
9906             }
9907
9908             cewrapper = Event._createWrapper(el, type, capture, compat, facade);
9909             if (overrides) {
9910                 Y.mix(cewrapper.overrides, overrides);
9911             }
9912
9913             if (el == win && type == "load") {
9914
9915                 // if the load is complete, fire immediately.
9916                 // all subscribers, including the current one
9917                 // will be notified.
9918                 if (YUI.Env.windowLoaded) {
9919                     fireNow = true;
9920                 }
9921             }
9922
9923             if (compat) {
9924                 args.pop();
9925             }
9926
9927             context = args[3];
9928
9929             // set context to the Node if not specified
9930             // ret = cewrapper.on.apply(cewrapper, trimmedArgs);
9931             ret = cewrapper._on(fn, context, (args.length > 4) ? args.slice(4) : null);
9932
9933             if (fireNow) {
9934                 cewrapper.fire();
9935             }
9936
9937             return ret;
9938
9939         },
9940
9941         /**
9942          * Removes an event listener.  Supports the signature the event was bound
9943          * with, but the preferred way to remove listeners is using the handle
9944          * that is returned when using Y.on
9945          *
9946          * @method detach
9947          *
9948          * @param {String} type the type of event to remove.
9949          * @param {Function} fn the method the event invokes.  If fn is
9950          * undefined, then all event handlers for the type of event are
9951          * removed.
9952          * @param {String|HTMLElement|Array|NodeList|EventHandle} el An
9953          * event handle, an id, an element reference, or a collection
9954          * of ids and/or elements to remove the listener from.
9955          * @return {boolean} true if the unbind was successful, false otherwise.
9956          * @static
9957          */
9958         detach: function(type, fn, el, obj) {
9959
9960             var args=Y.Array(arguments, 0, true), compat, l, ok, i,
9961                 id, ce;
9962
9963             if (args[args.length-1] === COMPAT_ARG) {
9964                 compat = true;
9965                 // args.pop();
9966             }
9967
9968             if (type && type.detach) {
9969                 return type.detach();
9970             }
9971
9972             // The el argument can be a string
9973             if (typeof el == "string") {
9974
9975                 // el = (compat) ? Y.DOM.byId(el) : Y.all(el);
9976                 if (compat) {
9977                     el = Y.DOM.byId(el);
9978                 } else {
9979                     el = Y.Selector.query(el);
9980                     l = el.length;
9981                     if (l < 1) {
9982                         el = null;
9983                     } else if (l == 1) {
9984                         el = el[0];
9985                     }
9986                 }
9987                 // return Event.detach.apply(Event, args);
9988             }
9989
9990             if (!el) {
9991                 return false;
9992             }
9993
9994             if (el.detach) {
9995                 args.splice(2, 1);
9996                 return el.detach.apply(el, args);
9997             // The el argument can be an array of elements or element ids.
9998             } else if (shouldIterate(el)) {
9999                 ok = true;
10000                 for (i=0, l=el.length; i<l; ++i) {
10001                     args[2] = el[i];
10002                     ok = ( Y.Event.detach.apply(Y.Event, args) && ok );
10003                 }
10004
10005                 return ok;
10006             }
10007
10008             if (!type || !fn || !fn.call) {
10009                 return Event.purgeElement(el, false, type);
10010             }
10011
10012             id = 'event:' + Y.stamp(el) + type;
10013             ce = _wrappers[id];
10014
10015             if (ce) {
10016                 return ce.detach(fn);
10017             } else {
10018                 return false;
10019             }
10020
10021         },
10022
10023         /**
10024          * Finds the event in the window object, the caller's arguments, or
10025          * in the arguments of another method in the callstack.  This is
10026          * executed automatically for events registered through the event
10027          * manager, so the implementer should not normally need to execute
10028          * this function at all.
10029          * @method getEvent
10030          * @param {Event} e the event parameter from the handler
10031          * @param {HTMLElement} el the element the listener was attached to
10032          * @return {Event} the event
10033          * @static
10034          */
10035         getEvent: function(e, el, noFacade) {
10036             var ev = e || win.event;
10037
10038             return (noFacade) ? ev :
10039                 new Y.DOMEventFacade(ev, el, _wrappers['event:' + Y.stamp(el) + e.type]);
10040         },
10041
10042         /**
10043          * Generates an unique ID for the element if it does not already
10044          * have one.
10045          * @method generateId
10046          * @param el the element to create the id for
10047          * @return {string} the resulting id of the element
10048          * @static
10049          */
10050         generateId: function(el) {
10051             return Y.DOM.generateID(el);
10052         },
10053
10054         /**
10055          * We want to be able to use getElementsByTagName as a collection
10056          * to attach a group of events to.  Unfortunately, different
10057          * browsers return different types of collections.  This function
10058          * tests to determine if the object is array-like.  It will also
10059          * fail if the object is an array, but is empty.
10060          * @method _isValidCollection
10061          * @param o the object to test
10062          * @return {boolean} true if the object is array-like and populated
10063          * @deprecated was not meant to be used directly
10064          * @static
10065          * @private
10066          */
10067         _isValidCollection: shouldIterate,
10068
10069         /**
10070          * hook up any deferred listeners
10071          * @method _load
10072          * @static
10073          * @private
10074          */
10075         _load: function(e) {
10076             if (!_loadComplete) {
10077                 _loadComplete = true;
10078
10079                 // Just in case DOMReady did not go off for some reason
10080                 // E._ready();
10081                 if (Y.fire) {
10082                     Y.fire(EVENT_READY);
10083                 }
10084
10085                 // Available elements may not have been detected before the
10086                 // window load event fires. Try to find them now so that the
10087                 // the user is more likely to get the onAvailable notifications
10088                 // before the window load notification
10089                 Event._poll();
10090             }
10091         },
10092
10093         /**
10094          * Polling function that runs before the onload event fires,
10095          * attempting to attach to DOM Nodes as soon as they are
10096          * available
10097          * @method _poll
10098          * @static
10099          * @private
10100          */
10101         _poll: function() {
10102             if (Event.locked) {
10103                 return;
10104             }
10105
10106             if (Y.UA.ie && !YUI.Env.DOMReady) {
10107                 // Hold off if DOMReady has not fired and check current
10108                 // readyState to protect against the IE operation aborted
10109                 // issue.
10110                 Event.startInterval();
10111                 return;
10112             }
10113
10114             Event.locked = true;
10115
10116             // keep trying until after the page is loaded.  We need to
10117             // check the page load state prior to trying to bind the
10118             // elements so that we can be certain all elements have been
10119             // tested appropriately
10120             var i, len, item, el, notAvail, executeItem,
10121                 tryAgain = !_loadComplete;
10122
10123             if (!tryAgain) {
10124                 tryAgain = (_retryCount > 0);
10125             }
10126
10127             // onAvailable
10128             notAvail = [];
10129
10130             executeItem = function (el, item) {
10131                 var context, ov = item.override;
10132                 if (item.compat) {
10133                     if (item.override) {
10134                         if (ov === true) {
10135                             context = item.obj;
10136                         } else {
10137                             context = ov;
10138                         }
10139                     } else {
10140                         context = el;
10141                     }
10142                     item.fn.call(context, item.obj);
10143                 } else {
10144                     context = item.obj || Y.one(el);
10145                     item.fn.apply(context, (Y.Lang.isArray(ov)) ? ov : []);
10146                 }
10147             };
10148
10149             // onAvailable
10150             for (i=0,len=_avail.length; i<len; ++i) {
10151                 item = _avail[i];
10152                 if (item && !item.checkReady) {
10153
10154                     // el = (item.compat) ? Y.DOM.byId(item.id) : Y.one(item.id);
10155                     el = (item.compat) ? Y.DOM.byId(item.id) : Y.Selector.query(item.id, null, true);
10156
10157                     if (el) {
10158                         executeItem(el, item);
10159                         _avail[i] = null;
10160                     } else {
10161                         notAvail.push(item);
10162                     }
10163                 }
10164             }
10165
10166             // onContentReady
10167             for (i=0,len=_avail.length; i<len; ++i) {
10168                 item = _avail[i];
10169                 if (item && item.checkReady) {
10170
10171                     // el = (item.compat) ? Y.DOM.byId(item.id) : Y.one(item.id);
10172                     el = (item.compat) ? Y.DOM.byId(item.id) : Y.Selector.query(item.id, null, true);
10173
10174                     if (el) {
10175                         // The element is available, but not necessarily ready
10176                         // @todo should we test parentNode.nextSibling?
10177                         if (_loadComplete || (el.get && el.get('nextSibling')) || el.nextSibling) {
10178                             executeItem(el, item);
10179                             _avail[i] = null;
10180                         }
10181                     } else {
10182                         notAvail.push(item);
10183                     }
10184                 }
10185             }
10186
10187             _retryCount = (notAvail.length === 0) ? 0 : _retryCount - 1;
10188
10189             if (tryAgain) {
10190                 // we may need to strip the nulled out items here
10191                 Event.startInterval();
10192             } else {
10193                 clearInterval(Event._interval);
10194                 Event._interval = null;
10195             }
10196
10197             Event.locked = false;
10198
10199             return;
10200
10201         },
10202
10203         /**
10204          * Removes all listeners attached to the given element via addListener.
10205          * Optionally, the node's children can also be purged.
10206          * Optionally, you can specify a specific type of event to remove.
10207          * @method purgeElement
10208          * @param {HTMLElement} el the element to purge
10209          * @param {boolean} recurse recursively purge this element's children
10210          * as well.  Use with caution.
10211          * @param {string} type optional type of listener to purge. If
10212          * left out, all listeners will be removed
10213          * @static
10214          */
10215         purgeElement: function(el, recurse, type) {
10216             // var oEl = (Y.Lang.isString(el)) ? Y.one(el) : el,
10217             var oEl = (Y.Lang.isString(el)) ?  Y.Selector.query(el, null, true) : el,
10218                 lis = Event.getListeners(oEl, type), i, len, props, children, child;
10219
10220             if (recurse && oEl) {
10221                 lis = lis || [];
10222                 children = Y.Selector.query('*', oEl);
10223                 i = 0;
10224                 len = children.length;
10225                 for (; i < len; ++i) {
10226                     child = Event.getListeners(children[i], type);
10227                     if (child) {
10228                         lis = lis.concat(child);
10229                     }
10230                 }
10231             }
10232
10233             if (lis) {
10234                 i = 0;
10235                 len = lis.length;
10236                 for (; i < len; ++i) {
10237                     props = lis[i];
10238                     props.detachAll();
10239                     remove(props.el, props.type, props.fn, props.capture);
10240                     delete _wrappers[props.key];
10241                     delete _el_events[props.domkey][props.key];
10242                 }
10243             }
10244
10245         },
10246
10247
10248         /**
10249          * Returns all listeners attached to the given element via addListener.
10250          * Optionally, you can specify a specific type of event to return.
10251          * @method getListeners
10252          * @param el {HTMLElement|string} the element or element id to inspect
10253          * @param type {string} optional type of listener to return. If
10254          * left out, all listeners will be returned
10255          * @return {Y.Custom.Event} the custom event wrapper for the DOM event(s)
10256          * @static
10257          */
10258         getListeners: function(el, type) {
10259             var ek = Y.stamp(el, true), evts = _el_events[ek],
10260                 results=[] , key = (type) ? 'event:' + ek + type : null,
10261                 adapters = _eventenv.plugins;
10262
10263             if (!evts) {
10264                 return null;
10265             }
10266
10267             if (key) {
10268                 // look for synthetic events
10269                 if (adapters[type] && adapters[type].eventDef) {
10270                     key += '_synth';
10271                 }
10272
10273                 if (evts[key]) {
10274                     results.push(evts[key]);
10275                 }
10276
10277                 // get native events as well
10278                 key += 'native';
10279                 if (evts[key]) {
10280                     results.push(evts[key]);
10281                 }
10282
10283             } else {
10284                 Y.each(evts, function(v, k) {
10285                     results.push(v);
10286                 });
10287             }
10288
10289             return (results.length) ? results : null;
10290         },
10291
10292         /**
10293          * Removes all listeners registered by pe.event.  Called
10294          * automatically during the unload event.
10295          * @method _unload
10296          * @static
10297          * @private
10298          */
10299         _unload: function(e) {
10300             Y.each(_wrappers, function(v, k) {
10301                 v.detachAll();
10302                 remove(v.el, v.type, v.fn, v.capture);
10303                 delete _wrappers[k];
10304                 delete _el_events[v.domkey][k];
10305             });
10306             remove(win, "unload", onUnload);
10307         },
10308
10309         /**
10310          * Adds a DOM event directly without the caching, cleanup, context adj, etc
10311          *
10312          * @method nativeAdd
10313          * @param {HTMLElement} el      the element to bind the handler to
10314          * @param {string}      type   the type of event handler
10315          * @param {function}    fn      the callback to invoke
10316          * @param {boolen}      capture capture or bubble phase
10317          * @static
10318          * @private
10319          */
10320         nativeAdd: add,
10321
10322         /**
10323          * Basic remove listener
10324          *
10325          * @method nativeRemove
10326          * @param {HTMLElement} el      the element to bind the handler to
10327          * @param {string}      type   the type of event handler
10328          * @param {function}    fn      the callback to invoke
10329          * @param {boolen}      capture capture or bubble phase
10330          * @static
10331          * @private
10332          */
10333         nativeRemove: remove
10334     };
10335
10336 }();
10337
10338 Y.Event = Event;
10339
10340 if (config.injected || YUI.Env.windowLoaded) {
10341     onLoad();
10342 } else {
10343     add(win, "load", onLoad);
10344 }
10345
10346 // Process onAvailable/onContentReady items when when the DOM is ready in IE
10347 if (Y.UA.ie) {
10348     Y.on(EVENT_READY, Event._poll);
10349 }
10350
10351 add(win, "unload", onUnload);
10352
10353 Event.Custom = Y.CustomEvent;
10354 Event.Subscriber = Y.Subscriber;
10355 Event.Target = Y.EventTarget;
10356 Event.Handle = Y.EventHandle;
10357 Event.Facade = Y.EventFacade;
10358
10359 Event._poll();
10360
10361 })();
10362
10363 /**
10364  * DOM event listener abstraction layer
10365  * @module event
10366  * @submodule event-base
10367  */
10368
10369 /**
10370  * Executes the callback as soon as the specified element
10371  * is detected in the DOM.  This function expects a selector
10372  * string for the element(s) to detect.  If you already have
10373  * an element reference, you don't need this event.
10374  * @event available
10375  * @param type {string} 'available'
10376  * @param fn {function} the callback function to execute.
10377  * @param el {string} an selector for the element(s) to attach
10378  * @param context optional argument that specifies what 'this' refers to.
10379  * @param args* 0..n additional arguments to pass on to the callback function.
10380  * These arguments will be added after the event object.
10381  * @return {EventHandle} the detach handle
10382  * @for YUI
10383  */
10384 Y.Env.evt.plugins.available = {
10385     on: function(type, fn, id, o) {
10386         var a = arguments.length > 4 ?  Y.Array(arguments, 4, true) : null;
10387         return Y.Event.onAvailable.call(Y.Event, id, fn, o, a);
10388     }
10389 };
10390
10391 /**
10392  * Executes the callback as soon as the specified element
10393  * is detected in the DOM with a nextSibling property
10394  * (indicating that the element's children are available).
10395  * This function expects a selector
10396  * string for the element(s) to detect.  If you already have
10397  * an element reference, you don't need this event.
10398  * @event contentready
10399  * @param type {string} 'contentready'
10400  * @param fn {function} the callback function to execute.
10401  * @param el {string} an selector for the element(s) to attach.
10402  * @param context optional argument that specifies what 'this' refers to.
10403  * @param args* 0..n additional arguments to pass on to the callback function.
10404  * These arguments will be added after the event object.
10405  * @return {EventHandle} the detach handle
10406  * @for YUI
10407  */
10408 Y.Env.evt.plugins.contentready = {
10409     on: function(type, fn, id, o) {
10410         var a = arguments.length > 4 ? Y.Array(arguments, 4, true) : null;
10411         return Y.Event.onContentReady.call(Y.Event, id, fn, o, a);
10412     }
10413 };
10414
10415
10416 }, '3.3.0' ,{requires:['event-custom-base']});
10417 (function() {
10418
10419 var stateChangeListener,
10420     GLOBAL_ENV   = YUI.Env,
10421     config       = YUI.config,
10422     doc          = config.doc,
10423     docElement   = doc && doc.documentElement,
10424     EVENT_NAME   = 'onreadystatechange',
10425     pollInterval = config.pollInterval || 40;
10426
10427 if (docElement.doScroll && !GLOBAL_ENV._ieready) {
10428     GLOBAL_ENV._ieready = function() {
10429         GLOBAL_ENV._ready();
10430     };
10431
10432 /*! DOMReady: based on work by: Dean Edwards/John Resig/Matthias Miller/Diego Perini */
10433 // Internet Explorer: use the doScroll() method on the root element.
10434 // This isolates what appears to be a safe moment to manipulate the
10435 // DOM prior to when the document's readyState suggests it is safe to do so.
10436     if (self !== self.top) {
10437         stateChangeListener = function() {
10438             if (doc.readyState == 'complete') {
10439                 GLOBAL_ENV.remove(doc, EVENT_NAME, stateChangeListener);
10440                 GLOBAL_ENV.ieready();
10441             }
10442         };
10443         GLOBAL_ENV.add(doc, EVENT_NAME, stateChangeListener);
10444     } else {
10445         GLOBAL_ENV._dri = setInterval(function() {
10446             try {
10447                 docElement.doScroll('left');
10448                 clearInterval(GLOBAL_ENV._dri);
10449                 GLOBAL_ENV._dri = null;
10450                 GLOBAL_ENV._ieready();
10451             } catch (domNotReady) { }
10452         }, pollInterval);
10453     }
10454 }
10455
10456 })();
10457 YUI.add('event-base-ie', function(Y) {
10458
10459 /*
10460  * Custom event engine, DOM event listener abstraction layer, synthetic DOM
10461  * events.
10462  * @module event
10463  * @submodule event-base
10464  */
10465
10466 var IEEventFacade = function() {
10467         // IEEventFacade.superclass.constructor.apply(this, arguments);
10468         Y.DOM2EventFacade.apply(this, arguments);
10469     };
10470
10471 Y.extend(IEEventFacade, Y.DOM2EventFacade, {
10472
10473     init: function() {
10474
10475         IEEventFacade.superclass.init.apply(this, arguments);
10476
10477         var e = this._event,
10478             resolve = Y.DOM2EventFacade.resolve,
10479             x, y, d, b, de, t;
10480
10481         this.target = resolve(e.srcElement);
10482
10483         if (('clientX' in e) && (!x) && (0 !== x)) {
10484             x = e.clientX;
10485             y = e.clientY;
10486
10487             d = Y.config.doc;
10488             b = d.body;
10489             de = d.documentElement;
10490
10491             x += (de.scrollLeft || (b && b.scrollLeft) || 0);
10492             y += (de.scrollTop  || (b && b.scrollTop)  || 0);
10493
10494             this.pageX = x;
10495             this.pageY = y;
10496         }
10497
10498         if (e.type == "mouseout") {
10499             t = e.toElement;
10500         } else if (e.type == "mouseover") {
10501             t = e.fromElement;
10502         }
10503
10504         this.relatedTarget = resolve(t);
10505
10506         // which should contain the unicode key code if this is a key event
10507         // if (e.charCode) {
10508         //     this.which = e.charCode;
10509         // }
10510
10511         // for click events, which is normalized for which mouse button was
10512         // clicked.
10513         if (e.button) {
10514             switch (e.button) {
10515                 case 2:
10516                     this.which = 3;
10517                     break;
10518                 case 4:
10519                     this.which = 2;
10520                     break;
10521                 default:
10522                     this.which = e.button;
10523             }
10524
10525             this.button = this.which;
10526         }
10527
10528     },
10529
10530     stopPropagation: function() {
10531         var e = this._event;
10532         e.cancelBubble = true;
10533         this._wrapper.stopped = 1;
10534         this.stopped = 1;
10535     },
10536
10537     stopImmediatePropagation: function() {
10538         this.stopPropagation();
10539         this._wrapper.stopped = 2;
10540         this.stopped = 2;
10541     },
10542
10543     preventDefault: function(returnValue) {
10544         this._event.returnValue = returnValue || false;
10545         this._wrapper.prevented = 1;
10546         this.prevented = 1;
10547     }
10548
10549 });
10550
10551 var imp = Y.config.doc && Y.config.doc.implementation;
10552
10553 if (imp && (!imp.hasFeature('Events', '2.0'))) {
10554     Y.DOMEventFacade = IEEventFacade;
10555 }
10556
10557
10558
10559 }, '3.3.0' );
10560 YUI.add('pluginhost-base', function(Y) {
10561
10562     /**
10563      * Provides the augmentable PluginHost interface, which can be added to any class.
10564      * @module pluginhost
10565      */
10566
10567     /**
10568      * Provides the augmentable PluginHost interface, which can be added to any class.
10569      * @module pluginhost-base
10570      */
10571
10572     /**
10573      * <p>
10574      * An augmentable class, which provides the augmented class with the ability to host plugins.
10575      * It adds <a href="#method_plug">plug</a> and <a href="#method_unplug">unplug</a> methods to the augmented class, which can 
10576      * be used to add or remove plugins from instances of the class.
10577      * </p>
10578      *
10579      * <p>Plugins can also be added through the constructor configuration object passed to the host class' constructor using
10580      * the "plugins" property. Supported values for the "plugins" property are those defined by the <a href="#method_plug">plug</a> method. 
10581      * 
10582      * For example the following code would add the AnimPlugin and IOPlugin to Overlay (the plugin host):
10583      * <xmp>
10584      * var o = new Overlay({plugins: [ AnimPlugin, {fn:IOPlugin, cfg:{section:"header"}}]});
10585      * </xmp>
10586      * </p>
10587      * <p>
10588      * Plug.Host's protected <a href="#method_initPlugins">_initPlugins</a> and <a href="#method_destroyPlugins">_destroyPlugins</a> 
10589      * methods should be invoked by the host class at the appropriate point in the host's lifecyle.  
10590      * </p>
10591      *
10592      * @class Plugin.Host
10593      */
10594
10595     var L = Y.Lang;
10596
10597     function PluginHost() {
10598         this._plugins = {};
10599     }
10600
10601     PluginHost.prototype = {
10602
10603         /**
10604          * Adds a plugin to the host object. This will instantiate the 
10605          * plugin and attach it to the configured namespace on the host object.
10606          *
10607          * @method plug
10608          * @chainable
10609          * @param P {Function | Object |Array} Accepts the plugin class, or an 
10610          * object with a "fn" property specifying the plugin class and 
10611          * a "cfg" property specifying the configuration for the Plugin.
10612          * <p>
10613          * Additionally an Array can also be passed in, with the above function or 
10614          * object values, allowing the user to add multiple plugins in a single call.
10615          * </p>
10616          * @param config (Optional) If the first argument is the plugin class, the second argument
10617          * can be the configuration for the plugin.
10618          * @return {Base} A reference to the host object
10619          */
10620         plug: function(Plugin, config) {
10621             var i, ln, ns;
10622
10623             if (L.isArray(Plugin)) {
10624                 for (i = 0, ln = Plugin.length; i < ln; i++) {
10625                     this.plug(Plugin[i]);
10626                 }
10627             } else {
10628                 if (Plugin && !L.isFunction(Plugin)) {
10629                     config = Plugin.cfg;
10630                     Plugin = Plugin.fn;
10631                 }
10632
10633                 // Plugin should be fn by now
10634                 if (Plugin && Plugin.NS) {
10635                     ns = Plugin.NS;
10636         
10637                     config = config || {};
10638                     config.host = this;
10639         
10640                     if (this.hasPlugin(ns)) {
10641                         // Update config
10642                         this[ns].setAttrs(config);
10643                     } else {
10644                         // Create new instance
10645                         this[ns] = new Plugin(config);
10646                         this._plugins[ns] = Plugin;
10647                     }
10648                 }
10649             }
10650             return this;
10651         },
10652
10653         /**
10654          * Removes a plugin from the host object. This will destroy the 
10655          * plugin instance and delete the namepsace from the host object. 
10656          *
10657          * @method unplug
10658          * @param {String | Function} plugin The namespace of the plugin, or the plugin class with the static NS namespace property defined. If not provided,
10659          * all registered plugins are unplugged.
10660          * @return {Base} A reference to the host object
10661          * @chainable
10662          */
10663         unplug: function(plugin) {
10664             var ns = plugin, 
10665                 plugins = this._plugins;
10666             
10667             if (plugin) {
10668                 if (L.isFunction(plugin)) {
10669                     ns = plugin.NS;
10670                     if (ns && (!plugins[ns] || plugins[ns] !== plugin)) {
10671                         ns = null;
10672                     }
10673                 }
10674         
10675                 if (ns) {
10676                     if (this[ns]) {
10677                         this[ns].destroy();
10678                         delete this[ns];
10679                     }
10680                     if (plugins[ns]) {
10681                         delete plugins[ns];
10682                     }
10683                 }
10684             } else {
10685                 for (ns in this._plugins) {
10686                     if (this._plugins.hasOwnProperty(ns)) {
10687                         this.unplug(ns);
10688                     }
10689                 }
10690             }
10691             return this;
10692         },
10693
10694         /**
10695          * Determines if a plugin has plugged into this host.
10696          *
10697          * @method hasPlugin
10698          * @param {String} ns The plugin's namespace
10699          * @return {boolean} returns true, if the plugin has been plugged into this host, false otherwise.
10700          */
10701         hasPlugin : function(ns) {
10702             return (this._plugins[ns] && this[ns]);
10703         },
10704
10705         /**
10706          * Initializes static plugins registered on the host (using the
10707          * Base.plug static method) and any plugins passed to the 
10708          * instance through the "plugins" configuration property.
10709          *
10710          * @method _initPlugins
10711          * @param {Config} config The configuration object with property name/value pairs.
10712          * @private
10713          */
10714         
10715         _initPlugins: function(config) {
10716             this._plugins = this._plugins || {};
10717
10718             if (this._initConfigPlugins) {
10719                 this._initConfigPlugins(config);
10720             }
10721         },
10722
10723         /**
10724          * Unplugs and destroys all plugins on the host
10725          * @method _destroyPlugins
10726          * @private
10727          */
10728         _destroyPlugins: function() {
10729             this.unplug();
10730         }
10731     };
10732
10733     Y.namespace("Plugin").Host = PluginHost;
10734
10735
10736 }, '3.3.0' ,{requires:['yui-base']});
10737 YUI.add('pluginhost-config', function(Y) {
10738
10739     /**
10740      * Adds pluginhost constructor configuration and static configuration support
10741      * @submodule pluginhost-config
10742      */
10743
10744     /**
10745      * Constructor and static configuration support for plugins
10746      * 
10747      * @for Plugin.Host
10748      */
10749     var PluginHost = Y.Plugin.Host,
10750         L = Y.Lang;
10751
10752     PluginHost.prototype._initConfigPlugins = function(config) {
10753
10754         // Class Configuration
10755         var classes = (this._getClasses) ? this._getClasses() : [this.constructor],
10756             plug = [],
10757             unplug = {},
10758             constructor, i, classPlug, classUnplug, pluginClassName;
10759
10760         // TODO: Room for optimization. Can we apply statically/unplug in same pass?
10761         for (i = classes.length - 1; i >= 0; i--) {
10762             constructor = classes[i];
10763
10764             classUnplug = constructor._UNPLUG;
10765             if (classUnplug) {
10766                 // subclasses over-write
10767                 Y.mix(unplug, classUnplug, true);
10768             }
10769
10770             classPlug = constructor._PLUG;
10771             if (classPlug) {
10772                 // subclasses over-write
10773                 Y.mix(plug, classPlug, true);
10774             }
10775         }
10776
10777         for (pluginClassName in plug) {
10778             if (plug.hasOwnProperty(pluginClassName)) {
10779                 if (!unplug[pluginClassName]) {
10780                     this.plug(plug[pluginClassName]);
10781                 }
10782             }
10783         }
10784
10785         // User Configuration
10786         if (config && config.plugins) {
10787             this.plug(config.plugins);
10788         }
10789     };
10790     
10791     /**
10792      * Registers plugins to be instantiated at the class level (plugins 
10793      * which should be plugged into every instance of the class by default).
10794      *
10795      * @method Plugin.Host.plug
10796      * @static
10797      *
10798      * @param {Function} hostClass The host class on which to register the plugins
10799      * @param {Function | Array} plugin Either the plugin class, an array of plugin classes or an array of objects (with fn and cfg properties defined)
10800      * @param {Object} config (Optional) If plugin is the plugin class, the configuration for the plugin
10801      */
10802     PluginHost.plug = function(hostClass, plugin, config) {
10803         // Cannot plug into Base, since Plugins derive from Base [ will cause infinite recurrsion ]
10804         var p, i, l, name;
10805     
10806         if (hostClass !== Y.Base) {
10807             hostClass._PLUG = hostClass._PLUG || {};
10808     
10809             if (!L.isArray(plugin)) {
10810                 if (config) {
10811                     plugin = {fn:plugin, cfg:config};
10812                 }
10813                 plugin = [plugin];
10814             }
10815     
10816             for (i = 0, l = plugin.length; i < l;i++) {
10817                 p = plugin[i];
10818                 name = p.NAME || p.fn.NAME;
10819                 hostClass._PLUG[name] = p;
10820             }
10821         }
10822     };
10823
10824     /**
10825      * Unregisters any class level plugins which have been registered by the host class, or any
10826      * other class in the hierarchy.
10827      *
10828      * @method Plugin.Host.unplug
10829      * @static
10830      *
10831      * @param {Function} hostClass The host class from which to unregister the plugins
10832      * @param {Function | Array} plugin The plugin class, or an array of plugin classes
10833      */
10834     PluginHost.unplug = function(hostClass, plugin) {
10835         var p, i, l, name;
10836     
10837         if (hostClass !== Y.Base) {
10838             hostClass._UNPLUG = hostClass._UNPLUG || {};
10839     
10840             if (!L.isArray(plugin)) {
10841                 plugin = [plugin];
10842             }
10843     
10844             for (i = 0, l = plugin.length; i < l; i++) {
10845                 p = plugin[i];
10846                 name = p.NAME;
10847                 if (!hostClass._PLUG[name]) {
10848                     hostClass._UNPLUG[name] = p;
10849                 } else {
10850                     delete hostClass._PLUG[name];
10851                 }
10852             }
10853         }
10854     };
10855
10856
10857 }, '3.3.0' ,{requires:['pluginhost-base']});
10858
10859
10860 YUI.add('pluginhost', function(Y){}, '3.3.0' ,{use:['pluginhost-base', 'pluginhost-config']});
10861
10862 YUI.add('node-base', function(Y) {
10863
10864 /**
10865  * The Node Utility provides a DOM-like interface for interacting with DOM nodes.
10866  * @module node
10867  * @submodule node-base
10868  */
10869
10870 /**
10871  * The Node class provides a wrapper for manipulating DOM Nodes.
10872  * Node properties can be accessed via the set/get methods.
10873  * Use Y.get() to retrieve Node instances.
10874  *
10875  * <strong>NOTE:</strong> Node properties are accessed using
10876  * the <code>set</code> and <code>get</code> methods.
10877  *
10878  * @class Node
10879  * @constructor
10880  * @param {DOMNode} node the DOM node to be mapped to the Node instance.
10881  * @for Node
10882  */
10883
10884 // "globals"
10885 var DOT = '.',
10886     NODE_NAME = 'nodeName',
10887     NODE_TYPE = 'nodeType',
10888     OWNER_DOCUMENT = 'ownerDocument',
10889     TAG_NAME = 'tagName',
10890     UID = '_yuid',
10891
10892     _slice = Array.prototype.slice,
10893
10894     Y_DOM = Y.DOM,
10895
10896     Y_Node = function(node) {
10897         var uid = (node.nodeType !== 9) ? node.uniqueID : node[UID];
10898
10899         if (uid && Y_Node._instances[uid] && Y_Node._instances[uid]._node !== node) {
10900             node[UID] = null; // unset existing uid to prevent collision (via clone or hack)
10901         }
10902
10903         uid = uid || Y.stamp(node);
10904         if (!uid) { // stamp failed; likely IE non-HTMLElement
10905             uid = Y.guid();
10906         }
10907
10908         this[UID] = uid;
10909
10910         /**
10911          * The underlying DOM node bound to the Y.Node instance
10912          * @property _node
10913          * @private
10914          */
10915         this._node = node;
10916         Y_Node._instances[uid] = this;
10917
10918         this._stateProxy = node; // when augmented with Attribute
10919
10920         Y.EventTarget.call(this, {emitFacade:true});
10921
10922         if (this._initPlugins) { // when augmented with Plugin.Host
10923             this._initPlugins();
10924         }
10925
10926         this.SHOW_TRANSITION = Y_Node.SHOW_TRANSITION;
10927         this.HIDE_TRANSITION = Y_Node.HIDE_TRANSITION;
10928     },
10929
10930     // used with previous/next/ancestor tests
10931     _wrapFn = function(fn) {
10932         var ret = null;
10933         if (fn) {
10934             ret = (typeof fn == 'string') ?
10935             function(n) {
10936                 return Y.Selector.test(n, fn);
10937             } :
10938             function(n) {
10939                 return fn(Y.one(n));
10940             };
10941         }
10942
10943         return ret;
10944     };
10945 // end "globals"
10946
10947 /**
10948  * The name of the component
10949  * @static
10950  * @property NAME
10951  */
10952 Y_Node.NAME = 'node';
10953
10954 /*
10955  * The pattern used to identify ARIA attributes
10956  */
10957 Y_Node.re_aria = /^(?:role$|aria-)/;
10958
10959 Y_Node.SHOW_TRANSITION = 'fadeIn';
10960 Y_Node.HIDE_TRANSITION = 'fadeOut';
10961
10962 /**
10963  * List of events that route to DOM events
10964  * @static
10965  * @property DOM_EVENTS
10966  */
10967
10968 Y_Node.DOM_EVENTS = {
10969     abort: 1,
10970     beforeunload: 1,
10971     blur: 1,
10972     change: 1,
10973     click: 1,
10974     close: 1,
10975     command: 1,
10976     contextmenu: 1,
10977     dblclick: 1,
10978     DOMMouseScroll: 1,
10979     drag: 1,
10980     dragstart: 1,
10981     dragenter: 1,
10982     dragover: 1,
10983     dragleave: 1,
10984     dragend: 1,
10985     drop: 1,
10986     error: 1,
10987     focus: 1,
10988     key: 1,
10989     keydown: 1,
10990     keypress: 1,
10991     keyup: 1,
10992     load: 1,
10993     message: 1,
10994     mousedown: 1,
10995     mouseenter: 1,
10996     mouseleave: 1,
10997     mousemove: 1,
10998     mousemultiwheel: 1,
10999     mouseout: 1,
11000     mouseover: 1,
11001     mouseup: 1,
11002     mousewheel: 1,
11003     orientationchange: 1,
11004     reset: 1,
11005     resize: 1,
11006     select: 1,
11007     selectstart: 1,
11008     submit: 1,
11009     scroll: 1,
11010     textInput: 1,
11011     unload: 1
11012 };
11013
11014 // Add custom event adaptors to this list.  This will make it so
11015 // that delegate, key, available, contentready, etc all will
11016 // be available through Node.on
11017 Y.mix(Y_Node.DOM_EVENTS, Y.Env.evt.plugins);
11018
11019 /**
11020  * A list of Node instances that have been created
11021  * @private
11022  * @property _instances
11023  * @static
11024  *
11025  */
11026 Y_Node._instances = {};
11027
11028 /**
11029  * Retrieves the DOM node bound to a Node instance
11030  * @method getDOMNode
11031  * @static
11032  *
11033  * @param {Y.Node || HTMLNode} node The Node instance or an HTMLNode
11034  * @return {HTMLNode} The DOM node bound to the Node instance.  If a DOM node is passed
11035  * as the node argument, it is simply returned.
11036  */
11037 Y_Node.getDOMNode = function(node) {
11038     if (node) {
11039         return (node.nodeType) ? node : node._node || null;
11040     }
11041     return null;
11042 };
11043
11044 /**
11045  * Checks Node return values and wraps DOM Nodes as Y.Node instances
11046  * and DOM Collections / Arrays as Y.NodeList instances.
11047  * Other return values just pass thru.  If undefined is returned (e.g. no return)
11048  * then the Node instance is returned for chainability.
11049  * @method scrubVal
11050  * @static
11051  *
11052  * @param {any} node The Node instance or an HTMLNode
11053  * @return {Y.Node | Y.NodeList | any} Depends on what is returned from the DOM node.
11054  */
11055 Y_Node.scrubVal = function(val, node) {
11056     if (val) { // only truthy values are risky
11057          if (typeof val == 'object' || typeof val == 'function') { // safari nodeList === function
11058             if (NODE_TYPE in val || Y_DOM.isWindow(val)) {// node || window
11059                 val = Y.one(val);
11060             } else if ((val.item && !val._nodes) || // dom collection or Node instance
11061                     (val[0] && val[0][NODE_TYPE])) { // array of DOM Nodes
11062                 val = Y.all(val);
11063             }
11064         }
11065     } else if (typeof val === 'undefined') {
11066         val = node; // for chaining
11067     } else if (val === null) {
11068         val = null; // IE: DOM null not the same as null
11069     }
11070
11071     return val;
11072 };
11073
11074 /**
11075  * Adds methods to the Y.Node prototype, routing through scrubVal.
11076  * @method addMethod
11077  * @static
11078  *
11079  * @param {String} name The name of the method to add
11080  * @param {Function} fn The function that becomes the method
11081  * @param {Object} context An optional context to call the method with
11082  * (defaults to the Node instance)
11083  * @return {any} Depends on what is returned from the DOM node.
11084  */
11085 Y_Node.addMethod = function(name, fn, context) {
11086     if (name && fn && typeof fn == 'function') {
11087         Y_Node.prototype[name] = function() {
11088             var args = _slice.call(arguments),
11089                 node = this,
11090                 ret;
11091
11092             if (args[0] && Y.instanceOf(args[0], Y_Node)) {
11093                 args[0] = args[0]._node;
11094             }
11095
11096             if (args[1] && Y.instanceOf(args[1], Y_Node)) {
11097                 args[1] = args[1]._node;
11098             }
11099             args.unshift(node._node);
11100
11101             ret = fn.apply(node, args);
11102
11103             if (ret) { // scrub truthy
11104                 ret = Y_Node.scrubVal(ret, node);
11105             }
11106
11107             (typeof ret != 'undefined') || (ret = node);
11108             return ret;
11109         };
11110     } else {
11111     }
11112 };
11113
11114 /**
11115  * Imports utility methods to be added as Y.Node methods.
11116  * @method importMethod
11117  * @static
11118  *
11119  * @param {Object} host The object that contains the method to import.
11120  * @param {String} name The name of the method to import
11121  * @param {String} altName An optional name to use in place of the host name
11122  * @param {Object} context An optional context to call the method with
11123  */
11124 Y_Node.importMethod = function(host, name, altName) {
11125     if (typeof name == 'string') {
11126         altName = altName || name;
11127         Y_Node.addMethod(altName, host[name], host);
11128     } else {
11129         Y.Array.each(name, function(n) {
11130             Y_Node.importMethod(host, n);
11131         });
11132     }
11133 };
11134
11135 /**
11136  * Returns a single Node instance bound to the node or the
11137  * first element matching the given selector. Returns null if no match found.
11138  * <strong>Note:</strong> For chaining purposes you may want to
11139  * use <code>Y.all</code>, which returns a NodeList when no match is found.
11140  * @method Y.one
11141  * @static
11142  * @param {String | HTMLElement} node a node or Selector
11143  * @return {Y.Node | null} a Node instance or null if no match found.
11144  */
11145 Y_Node.one = function(node) {
11146     var instance = null,
11147         cachedNode,
11148         uid;
11149
11150     if (node) {
11151         if (typeof node == 'string') {
11152             if (node.indexOf('doc') === 0) { // doc OR document
11153                 node = Y.config.doc;
11154             } else if (node.indexOf('win') === 0) { // win OR window
11155                 node = Y.config.win;
11156             } else {
11157                 node = Y.Selector.query(node, null, true);
11158             }
11159             if (!node) {
11160                 return null;
11161             }
11162         } else if (Y.instanceOf(node, Y_Node)) {
11163             return node; // NOTE: return
11164         }
11165
11166         if (node.nodeType || Y.DOM.isWindow(node)) { // avoid bad input (numbers, boolean, etc)
11167             uid = (node.uniqueID && node.nodeType !== 9) ? node.uniqueID : node._yuid;
11168             instance = Y_Node._instances[uid]; // reuse exising instances
11169             cachedNode = instance ? instance._node : null;
11170             if (!instance || (cachedNode && node !== cachedNode)) { // new Node when nodes don't match
11171                 instance = new Y_Node(node);
11172             }
11173         }
11174     }
11175     return instance;
11176 };
11177
11178 /**
11179  * Returns a new dom node using the provided markup string.
11180  * @method create
11181  * @static
11182  * @param {String} html The markup used to create the element
11183  * @param {HTMLDocument} doc An optional document context
11184  * @return {Node} A Node instance bound to a DOM node or fragment
11185  */
11186 Y_Node.create = function(html, doc) {
11187     if (doc && doc._node) {
11188         doc = doc._node;
11189     }
11190     return Y.one(Y_DOM.create(html, doc));
11191 };
11192
11193 /**
11194  * Static collection of configuration attributes for special handling
11195  * @property ATTRS
11196  * @static
11197  * @type object
11198  */
11199 Y_Node.ATTRS = {
11200     /**
11201      * Allows for getting and setting the text of an element.
11202      * Formatting is preserved and special characters are treated literally.
11203      * @config text
11204      * @type String
11205      */
11206     text: {
11207         getter: function() {
11208             return Y_DOM.getText(this._node);
11209         },
11210
11211         setter: function(content) {
11212             Y_DOM.setText(this._node, content);
11213             return content;
11214         }
11215     },
11216
11217     'options': {
11218         getter: function() {
11219             return this._node.getElementsByTagName('option');
11220         }
11221     },
11222
11223     /**
11224      * Returns a NodeList instance of all HTMLElement children.
11225      * @readOnly
11226      * @config children
11227      * @type NodeList
11228      */
11229     'children': {
11230         getter: function() {
11231             var node = this._node,
11232                 children = node.children,
11233                 childNodes, i, len;
11234
11235             if (!children) {
11236                 childNodes = node.childNodes;
11237                 children = [];
11238
11239                 for (i = 0, len = childNodes.length; i < len; ++i) {
11240                     if (childNodes[i][TAG_NAME]) {
11241                         children[children.length] = childNodes[i];
11242                     }
11243                 }
11244             }
11245             return Y.all(children);
11246         }
11247     },
11248
11249     value: {
11250         getter: function() {
11251             return Y_DOM.getValue(this._node);
11252         },
11253
11254         setter: function(val) {
11255             Y_DOM.setValue(this._node, val);
11256             return val;
11257         }
11258     }
11259 };
11260
11261 /**
11262  * The default setter for DOM properties
11263  * Called with instance context (this === the Node instance)
11264  * @method DEFAULT_SETTER
11265  * @static
11266  * @param {String} name The attribute/property being set
11267  * @param {any} val The value to be set
11268  * @return {any} The value
11269  */
11270 Y_Node.DEFAULT_SETTER = function(name, val) {
11271     var node = this._stateProxy,
11272         strPath;
11273
11274     if (name.indexOf(DOT) > -1) {
11275         strPath = name;
11276         name = name.split(DOT);
11277         // only allow when defined on node
11278         Y.Object.setValue(node, name, val);
11279     } else if (typeof node[name] != 'undefined') { // pass thru DOM properties
11280         node[name] = val;
11281     }
11282
11283     return val;
11284 };
11285
11286 /**
11287  * The default getter for DOM properties
11288  * Called with instance context (this === the Node instance)
11289  * @method DEFAULT_GETTER
11290  * @static
11291  * @param {String} name The attribute/property to look up
11292  * @return {any} The current value
11293  */
11294 Y_Node.DEFAULT_GETTER = function(name) {
11295     var node = this._stateProxy,
11296         val;
11297
11298     if (name.indexOf && name.indexOf(DOT) > -1) {
11299         val = Y.Object.getValue(node, name.split(DOT));
11300     } else if (typeof node[name] != 'undefined') { // pass thru from DOM
11301         val = node[name];
11302     }
11303
11304     return val;
11305 };
11306
11307 // Basic prototype augment - no lazy constructor invocation.
11308 Y.mix(Y_Node, Y.EventTarget, false, null, 1);
11309
11310 Y.mix(Y_Node.prototype, {
11311 /**
11312  * The method called when outputting Node instances as strings
11313  * @method toString
11314  * @return {String} A string representation of the Node instance
11315  */
11316     toString: function() {
11317         var str = this[UID] + ': not bound to a node',
11318             node = this._node,
11319             attrs, id, className;
11320
11321         if (node) {
11322             attrs = node.attributes;
11323             id = (attrs && attrs.id) ? node.getAttribute('id') : null;
11324             className = (attrs && attrs.className) ? node.getAttribute('className') : null;
11325             str = node[NODE_NAME];
11326
11327             if (id) {
11328                 str += '#' + id;
11329             }
11330
11331             if (className) {
11332                 str += '.' + className.replace(' ', '.');
11333             }
11334
11335             // TODO: add yuid?
11336             str += ' ' + this[UID];
11337         }
11338         return str;
11339     },
11340
11341     /**
11342      * Returns an attribute value on the Node instance.
11343      * Unless pre-configured (via Node.ATTRS), get hands
11344      * off to the underlying DOM node.  Only valid
11345      * attributes/properties for the node will be set.
11346      * @method get
11347      * @param {String} attr The attribute
11348      * @return {any} The current value of the attribute
11349      */
11350     get: function(attr) {
11351         var val;
11352
11353         if (this._getAttr) { // use Attribute imple
11354             val = this._getAttr(attr);
11355         } else {
11356             val = this._get(attr);
11357         }
11358
11359         if (val) {
11360             val = Y_Node.scrubVal(val, this);
11361         } else if (val === null) {
11362             val = null; // IE: DOM null is not true null (even though they ===)
11363         }
11364         return val;
11365     },
11366
11367     /**
11368      * Helper method for get.
11369      * @method _get
11370      * @private
11371      * @param {String} attr The attribute
11372      * @return {any} The current value of the attribute
11373      */
11374     _get: function(attr) {
11375         var attrConfig = Y_Node.ATTRS[attr],
11376             val;
11377
11378         if (attrConfig && attrConfig.getter) {
11379             val = attrConfig.getter.call(this);
11380         } else if (Y_Node.re_aria.test(attr)) {
11381             val = this._node.getAttribute(attr, 2);
11382         } else {
11383             val = Y_Node.DEFAULT_GETTER.apply(this, arguments);
11384         }
11385
11386         return val;
11387     },
11388
11389     /**
11390      * Sets an attribute on the Node instance.
11391      * Unless pre-configured (via Node.ATTRS), set hands
11392      * off to the underlying DOM node.  Only valid
11393      * attributes/properties for the node will be set.
11394      * To set custom attributes use setAttribute.
11395      * @method set
11396      * @param {String} attr The attribute to be set.
11397      * @param {any} val The value to set the attribute to.
11398      * @chainable
11399      */
11400     set: function(attr, val) {
11401         var attrConfig = Y_Node.ATTRS[attr];
11402
11403         if (this._setAttr) { // use Attribute imple
11404             this._setAttr.apply(this, arguments);
11405         } else { // use setters inline
11406             if (attrConfig && attrConfig.setter) {
11407                 attrConfig.setter.call(this, val, attr);
11408             } else if (Y_Node.re_aria.test(attr)) { // special case Aria
11409                 this._node.setAttribute(attr, val);
11410             } else {
11411                 Y_Node.DEFAULT_SETTER.apply(this, arguments);
11412             }
11413         }
11414
11415         return this;
11416     },
11417
11418     /**
11419      * Sets multiple attributes.
11420      * @method setAttrs
11421      * @param {Object} attrMap an object of name/value pairs to set
11422      * @chainable
11423      */
11424     setAttrs: function(attrMap) {
11425         if (this._setAttrs) { // use Attribute imple
11426             this._setAttrs(attrMap);
11427         } else { // use setters inline
11428             Y.Object.each(attrMap, function(v, n) {
11429                 this.set(n, v);
11430             }, this);
11431         }
11432
11433         return this;
11434     },
11435
11436     /**
11437      * Returns an object containing the values for the requested attributes.
11438      * @method getAttrs
11439      * @param {Array} attrs an array of attributes to get values
11440      * @return {Object} An object with attribute name/value pairs.
11441      */
11442     getAttrs: function(attrs) {
11443         var ret = {};
11444         if (this._getAttrs) { // use Attribute imple
11445             this._getAttrs(attrs);
11446         } else { // use setters inline
11447             Y.Array.each(attrs, function(v, n) {
11448                 ret[v] = this.get(v);
11449             }, this);
11450         }
11451
11452         return ret;
11453     },
11454
11455     /**
11456      * Creates a new Node using the provided markup string.
11457      * @method create
11458      * @param {String} html The markup used to create the element
11459      * @param {HTMLDocument} doc An optional document context
11460      * @return {Node} A Node instance bound to a DOM node or fragment
11461      */
11462     create: Y_Node.create,
11463
11464     /**
11465      * Compares nodes to determine if they match.
11466      * Node instances can be compared to each other and/or HTMLElements.
11467      * @method compareTo
11468      * @param {HTMLElement | Node} refNode The reference node to compare to the node.
11469      * @return {Boolean} True if the nodes match, false if they do not.
11470      */
11471     compareTo: function(refNode) {
11472         var node = this._node;
11473
11474         if (Y.instanceOf(refNode, Y_Node)) {
11475             refNode = refNode._node;
11476         }
11477         return node === refNode;
11478     },
11479
11480     /**
11481      * Determines whether the node is appended to the document.
11482      * @method inDoc
11483      * @param {Node|HTMLElement} doc optional An optional document to check against.
11484      * Defaults to current document.
11485      * @return {Boolean} Whether or not this node is appended to the document.
11486      */
11487     inDoc: function(doc) {
11488         var node = this._node;
11489         doc = (doc) ? doc._node || doc : node[OWNER_DOCUMENT];
11490         if (doc.documentElement) {
11491             return Y_DOM.contains(doc.documentElement, node);
11492         }
11493     },
11494
11495     getById: function(id) {
11496         var node = this._node,
11497             ret = Y_DOM.byId(id, node[OWNER_DOCUMENT]);
11498         if (ret && Y_DOM.contains(node, ret)) {
11499             ret = Y.one(ret);
11500         } else {
11501             ret = null;
11502         }
11503         return ret;
11504     },
11505
11506    /**
11507      * Returns the nearest ancestor that passes the test applied by supplied boolean method.
11508      * @method ancestor
11509      * @param {String | Function} fn A selector string or boolean method for testing elements.
11510      * @param {Boolean} testSelf optional Whether or not to include the element in the scan
11511      * If a function is used, it receives the current node being tested as the only argument.
11512      * @return {Node} The matching Node instance or null if not found
11513      */
11514     ancestor: function(fn, testSelf) {
11515         return Y.one(Y_DOM.ancestor(this._node, _wrapFn(fn), testSelf));
11516     },
11517
11518    /**
11519      * Returns the ancestors that pass the test applied by supplied boolean method.
11520      * @method ancestors
11521      * @param {String | Function} fn A selector string or boolean method for testing elements.
11522      * @param {Boolean} testSelf optional Whether or not to include the element in the scan
11523      * If a function is used, it receives the current node being tested as the only argument.
11524      * @return {NodeList} A NodeList instance containing the matching elements 
11525      */
11526     ancestors: function(fn, testSelf) {
11527         return Y.all(Y_DOM.ancestors(this._node, _wrapFn(fn), testSelf));
11528     },
11529
11530     /**
11531      * Returns the previous matching sibling.
11532      * Returns the nearest element node sibling if no method provided.
11533      * @method previous
11534      * @param {String | Function} fn A selector or boolean method for testing elements.
11535      * If a function is used, it receives the current node being tested as the only argument.
11536      * @return {Node} Node instance or null if not found
11537      */
11538     previous: function(fn, all) {
11539         return Y.one(Y_DOM.elementByAxis(this._node, 'previousSibling', _wrapFn(fn), all));
11540     },
11541
11542     /**
11543      * Returns the next matching sibling.
11544      * Returns the nearest element node sibling if no method provided.
11545      * @method next
11546      * @param {String | Function} fn A selector or boolean method for testing elements.
11547      * If a function is used, it receives the current node being tested as the only argument.
11548      * @return {Node} Node instance or null if not found
11549      */
11550     next: function(fn, all) {
11551         return Y.one(Y_DOM.elementByAxis(this._node, 'nextSibling', _wrapFn(fn), all));
11552     },
11553
11554     /**
11555      * Returns all matching siblings.
11556      * Returns all siblings if no method provided.
11557      * @method siblings
11558      * @param {String | Function} fn A selector or boolean method for testing elements.
11559      * If a function is used, it receives the current node being tested as the only argument.
11560      * @return {NodeList} NodeList instance bound to found siblings
11561      */
11562     siblings: function(fn) {
11563         return Y.all(Y_DOM.siblings(this._node, _wrapFn(fn)));
11564     },
11565
11566     /**
11567      * Retrieves a Node instance of nodes based on the given CSS selector.
11568      * @method one
11569      *
11570      * @param {string} selector The CSS selector to test against.
11571      * @return {Node} A Node instance for the matching HTMLElement.
11572      */
11573     one: function(selector) {
11574         return Y.one(Y.Selector.query(selector, this._node, true));
11575     },
11576
11577     /**
11578      * Retrieves a nodeList based on the given CSS selector.
11579      * @method all
11580      *
11581      * @param {string} selector The CSS selector to test against.
11582      * @return {NodeList} A NodeList instance for the matching HTMLCollection/Array.
11583      */
11584     all: function(selector) {
11585         var nodelist = Y.all(Y.Selector.query(selector, this._node));
11586         nodelist._query = selector;
11587         nodelist._queryRoot = this._node;
11588         return nodelist;
11589     },
11590
11591     // TODO: allow fn test
11592     /**
11593      * Test if the supplied node matches the supplied selector.
11594      * @method test
11595      *
11596      * @param {string} selector The CSS selector to test against.
11597      * @return {boolean} Whether or not the node matches the selector.
11598      */
11599     test: function(selector) {
11600         return Y.Selector.test(this._node, selector);
11601     },
11602
11603     /**
11604      * Removes the node from its parent.
11605      * Shortcut for myNode.get('parentNode').removeChild(myNode);
11606      * @method remove
11607      * @param {Boolean} destroy whether or not to call destroy() on the node
11608      * after removal.
11609      * @chainable
11610      *
11611      */
11612     remove: function(destroy) {
11613         var node = this._node,
11614             parentNode = node.parentNode;
11615
11616         if (parentNode) {
11617             parentNode.removeChild(node);
11618         }
11619
11620         if (destroy) {
11621             this.destroy();
11622         }
11623
11624         return this;
11625     },
11626
11627     /**
11628      * Replace the node with the other node. This is a DOM update only
11629      * and does not change the node bound to the Node instance.
11630      * Shortcut for myNode.get('parentNode').replaceChild(newNode, myNode);
11631      * @method replace
11632      * @param {Y.Node || HTMLNode} newNode Node to be inserted
11633      * @chainable
11634      *
11635      */
11636     replace: function(newNode) {
11637         var node = this._node;
11638         if (typeof newNode == 'string') {
11639             newNode = Y_Node.create(newNode);
11640         }
11641         node.parentNode.replaceChild(Y_Node.getDOMNode(newNode), node);
11642         return this;
11643     },
11644
11645     /**
11646      * @method replaceChild
11647      * @for Node
11648      * @param {String | HTMLElement | Node} node Node to be inserted 
11649      * @param {HTMLElement | Node} refNode Node to be replaced 
11650      * @return {Node} The replaced node
11651      */
11652     replaceChild: function(node, refNode) {
11653         if (typeof node == 'string') {
11654             node = Y_DOM.create(node);
11655         }
11656
11657         return Y.one(this._node.replaceChild(Y_Node.getDOMNode(node), Y_Node.getDOMNode(refNode)));
11658     },
11659
11660     /**
11661      * @method appendChild
11662      * @param {String | HTMLElement | Node} node Node to be appended 
11663      * @return {Node} The appended node 
11664      */
11665     appendChild: function(node) {
11666         return Y_Node.scrubVal(this._insert(node));
11667     },
11668
11669     /**
11670      * @method insertBefore
11671      * @param {String | HTMLElement | Node} newNode Node to be appended 
11672      * @param {HTMLElement | Node} refNode Node to be inserted before 
11673      * @return {Node} The inserted node 
11674      */
11675     insertBefore: function(newNode, refNode) {
11676         return Y.Node.scrubVal(this._insert(newNode, refNode));
11677     },
11678
11679     /**
11680      * Removes event listeners from the node and (optionally) its subtree
11681      * @method purge
11682      * @param {Boolean} recurse (optional) Whether or not to remove listeners from the
11683      * node's subtree
11684      * @param {String} type (optional) Only remove listeners of the specified type
11685      * @chainable
11686      *
11687      */
11688     purge: function(recurse, type) {
11689         Y.Event.purgeElement(this._node, recurse, type);
11690         return this;
11691     },
11692
11693     /**
11694      * Nulls internal node references, removes any plugins and event listeners
11695      * @method destroy
11696      * @param {Boolean} recursivePurge (optional) Whether or not to remove listeners from the
11697      * node's subtree (default is false)
11698      *
11699      */
11700     destroy: function(recursive) {
11701         this.purge(); // TODO: only remove events add via this Node
11702
11703         if (this.unplug) { // may not be a PluginHost
11704             this.unplug();
11705         }
11706
11707         this.clearData();
11708
11709         if (recursive) {
11710             this.all('*').destroy();
11711         }
11712
11713         this._node = null;
11714         this._stateProxy = null;
11715
11716         delete Y_Node._instances[this[UID]];
11717     },
11718
11719     /**
11720      * Invokes a method on the Node instance
11721      * @method invoke
11722      * @param {String} method The name of the method to invoke
11723      * @param {Any}  a, b, c, etc. Arguments to invoke the method with.
11724      * @return Whatever the underly method returns.
11725      * DOM Nodes and Collections return values
11726      * are converted to Node/NodeList instances.
11727      *
11728      */
11729     invoke: function(method, a, b, c, d, e) {
11730         var node = this._node,
11731             ret;
11732
11733         if (a && Y.instanceOf(a, Y_Node)) {
11734             a = a._node;
11735         }
11736
11737         if (b && Y.instanceOf(b, Y_Node)) {
11738             b = b._node;
11739         }
11740
11741         ret = node[method](a, b, c, d, e);
11742         return Y_Node.scrubVal(ret, this);
11743     },
11744
11745     /**
11746      * Inserts the content before the reference node.
11747      * @method insert
11748      * @param {String | Y.Node | HTMLElement | Y.NodeList | HTMLCollection} content The content to insert
11749      * @param {Int | Y.Node | HTMLElement | String} where The position to insert at.
11750      * Possible "where" arguments
11751      * <dl>
11752      * <dt>Y.Node</dt>
11753      * <dd>The Node to insert before</dd>
11754      * <dt>HTMLElement</dt>
11755      * <dd>The element to insert before</dd>
11756      * <dt>Int</dt>
11757      * <dd>The index of the child element to insert before</dd>
11758      * <dt>"replace"</dt>
11759      * <dd>Replaces the existing HTML</dd>
11760      * <dt>"before"</dt>
11761      * <dd>Inserts before the existing HTML</dd>
11762      * <dt>"before"</dt>
11763      * <dd>Inserts content before the node</dd>
11764      * <dt>"after"</dt>
11765      * <dd>Inserts content after the node</dd>
11766      * </dl>
11767      * @chainable
11768      */
11769     insert: function(content, where) {
11770         this._insert(content, where);
11771         return this;
11772     },
11773
11774     _insert: function(content, where) {
11775         var node = this._node,
11776             ret = null;
11777
11778         if (typeof where == 'number') { // allow index
11779             where = this._node.childNodes[where];
11780         } else if (where && where._node) { // Node
11781             where = where._node;
11782         }
11783
11784         if (content && typeof content != 'string') { // allow Node or NodeList/Array instances
11785             content = content._node || content._nodes || content;
11786         }
11787         ret = Y_DOM.addHTML(node, content, where);
11788
11789         return ret;
11790     },
11791
11792     /**
11793      * Inserts the content as the firstChild of the node.
11794      * @method prepend
11795      * @param {String | Y.Node | HTMLElement} content The content to insert
11796      * @chainable
11797      */
11798     prepend: function(content) {
11799         return this.insert(content, 0);
11800     },
11801
11802     /**
11803      * Inserts the content as the lastChild of the node.
11804      * @method append
11805      * @param {String | Y.Node | HTMLElement} content The content to insert
11806      * @chainable
11807      */
11808     append: function(content) {
11809         return this.insert(content, null);
11810     },
11811
11812     /**
11813      * Appends the node to the given node. 
11814      * @method appendTo
11815      * @param {Y.Node | HTMLElement} node The node to append to
11816      * @chainable
11817      */
11818     appendTo: function(node) {
11819         Y.one(node).append(this);
11820     },
11821
11822     /**
11823      * Replaces the node's current content with the content.
11824      * @method setContent
11825      * @param {String | Y.Node | HTMLElement | Y.NodeList | HTMLCollection} content The content to insert
11826      * @chainable
11827      */
11828     setContent: function(content) {
11829         this._insert(content, 'replace');
11830         return this;
11831     },
11832
11833     /**
11834      * Returns the node's current content (e.g. innerHTML) 
11835      * @method getContent
11836      * @return {String} The current content
11837      */
11838     getContent: function(content) {
11839         return this.get('innerHTML');
11840     },
11841
11842     /**
11843     * @method swap
11844     * @description Swap DOM locations with the given node.
11845     * This does not change which DOM node each Node instance refers to.
11846     * @param {Node} otherNode The node to swap with
11847      * @chainable
11848     */
11849     swap: Y.config.doc.documentElement.swapNode ?
11850         function(otherNode) {
11851             this._node.swapNode(Y_Node.getDOMNode(otherNode));
11852         } :
11853         function(otherNode) {
11854             otherNode = Y_Node.getDOMNode(otherNode);
11855             var node = this._node,
11856                 parent = otherNode.parentNode,
11857                 nextSibling = otherNode.nextSibling;
11858
11859             if (nextSibling === node) {
11860                 parent.insertBefore(node, otherNode);
11861             } else if (otherNode === node.nextSibling) {
11862                 parent.insertBefore(otherNode, node);
11863             } else {
11864                 node.parentNode.replaceChild(otherNode, node);
11865                 Y_DOM.addHTML(parent, node, nextSibling);
11866             }
11867             return this;
11868         },
11869
11870
11871     /**
11872     * @method getData
11873     * @description Retrieves arbitrary data stored on a Node instance.
11874     * This is not stored with the DOM node.
11875     * @param {string} name Optional name of the data field to retrieve.
11876     * If no name is given, all data is returned.
11877     * @return {any | Object} Whatever is stored at the given field,
11878     * or an object hash of all fields.
11879     */
11880     getData: function(name) {
11881         var ret;
11882         this._data = this._data || {};
11883         if (arguments.length) {
11884             ret = this._data[name];
11885         } else {
11886             ret = this._data;
11887         }
11888
11889         return ret;
11890
11891     },
11892
11893     /**
11894     * @method setData
11895     * @description Stores arbitrary data on a Node instance.
11896     * This is not stored with the DOM node.
11897     * @param {string} name The name of the field to set. If no name
11898     * is given, name is treated as the data and overrides any existing data.
11899     * @param {any} val The value to be assigned to the field.
11900     * @chainable
11901     */
11902     setData: function(name, val) {
11903         this._data = this._data || {};
11904         if (arguments.length > 1) {
11905             this._data[name] = val;
11906         } else {
11907             this._data = name;
11908         }
11909
11910        return this;
11911     },
11912
11913     /**
11914     * @method clearData
11915     * @description Clears stored data.
11916     * @param {string} name The name of the field to clear. If no name
11917     * is given, all data is cleared.
11918     * @chainable
11919     */
11920     clearData: function(name) {
11921         if ('_data' in this) {
11922             if (name) {
11923                 delete this._data[name];
11924             } else {
11925                 delete this._data;
11926             }
11927         }
11928
11929         return this;
11930     },
11931
11932     hasMethod: function(method) {
11933         var node = this._node;
11934         return !!(node && method in node &&
11935                 typeof node[method] != 'unknown' &&
11936             (typeof node[method] == 'function' ||
11937                 String(node[method]).indexOf('function') === 1)); // IE reports as object, prepends space
11938     },
11939
11940     SHOW_TRANSITION: null,
11941     HIDE_TRANSITION: null,
11942
11943     /**
11944      * Makes the node visible.
11945      * If the "transition" module is loaded, show optionally
11946      * animates the showing of the node using either the default
11947      * transition effect ('fadeIn'), or the given named effect.
11948      * @method show
11949      * @param {String} name A named Transition effect to use as the show effect. 
11950      * @param {Object} config Options to use with the transition. 
11951      * @param {Function} callback An optional function to run after the transition completes. 
11952      * @chainable
11953      */
11954     show: function(callback) {
11955         callback = arguments[arguments.length - 1];
11956         this.toggleView(true, callback);
11957         return this;
11958     },
11959
11960     /**
11961      * The implementation for showing nodes.
11962      * Default is to toggle the style.display property.
11963      * @protected
11964      * @chainable
11965      */
11966     _show: function() {
11967         this.setStyle('display', '');
11968
11969     },
11970
11971     _isHidden: function() {
11972         return Y.DOM.getStyle(this._node, 'display') === 'none';
11973     },
11974
11975     toggleView: function(on, callback) {
11976         this._toggleView.apply(this, arguments);
11977     },
11978
11979     _toggleView: function(on, callback) {
11980         callback = arguments[arguments.length - 1];
11981
11982         // base on current state if not forcing 
11983         if (typeof on != 'boolean') {
11984             on = (this._isHidden()) ? 1 : 0;
11985         }
11986
11987         if (on) {
11988             this._show();
11989         }  else {
11990             this._hide();
11991         }
11992
11993         if (typeof callback == 'function') {
11994             callback.call(this);
11995         }
11996
11997         return this;
11998     },
11999
12000     /**
12001      * Hides the node.
12002      * If the "transition" module is loaded, hide optionally
12003      * animates the hiding of the node using either the default
12004      * transition effect ('fadeOut'), or the given named effect.
12005      * @method hide
12006      * @param {String} name A named Transition effect to use as the show effect. 
12007      * @param {Object} config Options to use with the transition. 
12008      * @param {Function} callback An optional function to run after the transition completes. 
12009      * @chainable
12010      */
12011     hide: function(callback) {
12012         callback = arguments[arguments.length - 1];
12013         this.toggleView(false, callback);
12014         return this;
12015     },
12016
12017     /**
12018      * The implementation for hiding nodes.
12019      * Default is to toggle the style.display property.
12020      * @protected
12021      * @chainable
12022      */
12023     _hide: function() {
12024         this.setStyle('display', 'none');
12025     },
12026
12027     isFragment: function() {
12028         return (this.get('nodeType') === 11);
12029     },
12030
12031     /**
12032      * Removes all of the child nodes from the node.
12033      * @param {Boolean} destroy Whether the nodes should also be destroyed. 
12034      * @chainable
12035      */
12036     empty: function(destroy) {
12037         this.get('childNodes').remove(destroy);
12038         return this;
12039     }
12040
12041 }, true);
12042
12043 Y.Node = Y_Node;
12044 Y.one = Y.Node.one;
12045 /**
12046  * The NodeList module provides support for managing collections of Nodes.
12047  * @module node
12048  * @submodule nodelist
12049  */
12050
12051 /**
12052  * The NodeList class provides a wrapper for manipulating DOM NodeLists.
12053  * NodeList properties can be accessed via the set/get methods.
12054  * Use Y.all() to retrieve NodeList instances.
12055  *
12056  * @class NodeList
12057  * @constructor
12058  */
12059
12060 var NodeList = function(nodes) {
12061     var tmp = [];
12062     if (typeof nodes === 'string') { // selector query
12063         this._query = nodes;
12064         nodes = Y.Selector.query(nodes);
12065     } else if (nodes.nodeType || Y_DOM.isWindow(nodes)) { // domNode || window
12066         nodes = [nodes];
12067     } else if (Y.instanceOf(nodes, Y.Node)) {
12068         nodes = [nodes._node];
12069     } else if (Y.instanceOf(nodes[0], Y.Node)) { // allow array of Y.Nodes
12070         Y.Array.each(nodes, function(node) {
12071             if (node._node) {
12072                 tmp.push(node._node);
12073             }
12074         });
12075         nodes = tmp;
12076     } else { // array of domNodes or domNodeList (no mixed array of Y.Node/domNodes)
12077         nodes = Y.Array(nodes, 0, true);
12078     }
12079
12080     /**
12081      * The underlying array of DOM nodes bound to the Y.NodeList instance
12082      * @property _nodes
12083      * @private
12084      */
12085     this._nodes = nodes;
12086 };
12087
12088 NodeList.NAME = 'NodeList';
12089
12090 /**
12091  * Retrieves the DOM nodes bound to a NodeList instance
12092  * @method NodeList.getDOMNodes
12093  * @static
12094  *
12095  * @param {Y.NodeList} nodelist The NodeList instance
12096  * @return {Array} The array of DOM nodes bound to the NodeList
12097  */
12098 NodeList.getDOMNodes = function(nodelist) {
12099     return (nodelist && nodelist._nodes) ? nodelist._nodes : nodelist;
12100 };
12101
12102 NodeList.each = function(instance, fn, context) {
12103     var nodes = instance._nodes;
12104     if (nodes && nodes.length) {
12105         Y.Array.each(nodes, fn, context || instance);
12106     } else {
12107     }
12108 };
12109
12110 NodeList.addMethod = function(name, fn, context) {
12111     if (name && fn) {
12112         NodeList.prototype[name] = function() {
12113             var ret = [],
12114                 args = arguments;
12115
12116             Y.Array.each(this._nodes, function(node) {
12117                 var UID = (node.uniqueID && node.nodeType !== 9 ) ? 'uniqueID' : '_yuid',
12118                     instance = Y.Node._instances[node[UID]],
12119                     ctx,
12120                     result;
12121
12122                 if (!instance) {
12123                     instance = NodeList._getTempNode(node);
12124                 }
12125                 ctx = context || instance;
12126                 result = fn.apply(ctx, args);
12127                 if (result !== undefined && result !== instance) {
12128                     ret[ret.length] = result;
12129                 }
12130             });
12131
12132             // TODO: remove tmp pointer
12133             return ret.length ? ret : this;
12134         };
12135     } else {
12136     }
12137 };
12138
12139 NodeList.importMethod = function(host, name, altName) {
12140     if (typeof name === 'string') {
12141         altName = altName || name;
12142         NodeList.addMethod(name, host[name]);
12143     } else {
12144         Y.Array.each(name, function(n) {
12145             NodeList.importMethod(host, n);
12146         });
12147     }
12148 };
12149
12150 NodeList._getTempNode = function(node) {
12151     var tmp = NodeList._tempNode;
12152     if (!tmp) {
12153         tmp = Y.Node.create('<div></div>');
12154         NodeList._tempNode = tmp;
12155     }
12156
12157     tmp._node = node;
12158     tmp._stateProxy = node;
12159     return tmp;
12160 };
12161
12162 Y.mix(NodeList.prototype, {
12163     /**
12164      * Retrieves the Node instance at the given index.
12165      * @method item
12166      *
12167      * @param {Number} index The index of the target Node.
12168      * @return {Node} The Node instance at the given index.
12169      */
12170     item: function(index) {
12171         return Y.one((this._nodes || [])[index]);
12172     },
12173
12174     /**
12175      * Applies the given function to each Node in the NodeList.
12176      * @method each
12177      * @param {Function} fn The function to apply. It receives 3 arguments:
12178      * the current node instance, the node's index, and the NodeList instance
12179      * @param {Object} context optional An optional context to apply the function with
12180      * Default context is the current Node instance
12181      * @chainable
12182      */
12183     each: function(fn, context) {
12184         var instance = this;
12185         Y.Array.each(this._nodes, function(node, index) {
12186             node = Y.one(node);
12187             return fn.call(context || node, node, index, instance);
12188         });
12189         return instance;
12190     },
12191
12192     batch: function(fn, context) {
12193         var nodelist = this;
12194
12195         Y.Array.each(this._nodes, function(node, index) {
12196             var instance = Y.Node._instances[node[UID]];
12197             if (!instance) {
12198                 instance = NodeList._getTempNode(node);
12199             }
12200
12201             return fn.call(context || instance, instance, index, nodelist);
12202         });
12203         return nodelist;
12204     },
12205
12206     /**
12207      * Executes the function once for each node until a true value is returned.
12208      * @method some
12209      * @param {Function} fn The function to apply. It receives 3 arguments:
12210      * the current node instance, the node's index, and the NodeList instance
12211      * @param {Object} context optional An optional context to execute the function from.
12212      * Default context is the current Node instance
12213      * @return {Boolean} Whether or not the function returned true for any node.
12214      */
12215     some: function(fn, context) {
12216         var instance = this;
12217         return Y.Array.some(this._nodes, function(node, index) {
12218             node = Y.one(node);
12219             context = context || node;
12220             return fn.call(context, node, index, instance);
12221         });
12222     },
12223
12224     /**
12225      * Creates a documenFragment from the nodes bound to the NodeList instance
12226      * @method toFrag
12227      * @return Node a Node instance bound to the documentFragment
12228      */
12229     toFrag: function() {
12230         return Y.one(Y.DOM._nl2frag(this._nodes));
12231     },
12232
12233     /**
12234      * Returns the index of the node in the NodeList instance
12235      * or -1 if the node isn't found.
12236      * @method indexOf
12237      * @param {Y.Node || DOMNode} node the node to search for
12238      * @return {Int} the index of the node value or -1 if not found
12239      */
12240     indexOf: function(node) {
12241         return Y.Array.indexOf(this._nodes, Y.Node.getDOMNode(node));
12242     },
12243
12244     /**
12245      * Filters the NodeList instance down to only nodes matching the given selector.
12246      * @method filter
12247      * @param {String} selector The selector to filter against
12248      * @return {NodeList} NodeList containing the updated collection
12249      * @see Selector
12250      */
12251     filter: function(selector) {
12252         return Y.all(Y.Selector.filter(this._nodes, selector));
12253     },
12254
12255
12256     /**
12257      * Creates a new NodeList containing all nodes at every n indices, where
12258      * remainder n % index equals r.
12259      * (zero-based index).
12260      * @method modulus
12261      * @param {Int} n The offset to use (return every nth node)
12262      * @param {Int} r An optional remainder to use with the modulus operation (defaults to zero)
12263      * @return {NodeList} NodeList containing the updated collection
12264      */
12265     modulus: function(n, r) {
12266         r = r || 0;
12267         var nodes = [];
12268         NodeList.each(this, function(node, i) {
12269             if (i % n === r) {
12270                 nodes.push(node);
12271             }
12272         });
12273
12274         return Y.all(nodes);
12275     },
12276
12277     /**
12278      * Creates a new NodeList containing all nodes at odd indices
12279      * (zero-based index).
12280      * @method odd
12281      * @return {NodeList} NodeList containing the updated collection
12282      */
12283     odd: function() {
12284         return this.modulus(2, 1);
12285     },
12286
12287     /**
12288      * Creates a new NodeList containing all nodes at even indices
12289      * (zero-based index), including zero.
12290      * @method even
12291      * @return {NodeList} NodeList containing the updated collection
12292      */
12293     even: function() {
12294         return this.modulus(2);
12295     },
12296
12297     destructor: function() {
12298     },
12299
12300     /**
12301      * Reruns the initial query, when created using a selector query
12302      * @method refresh
12303      * @chainable
12304      */
12305     refresh: function() {
12306         var doc,
12307             nodes = this._nodes,
12308             query = this._query,
12309             root = this._queryRoot;
12310
12311         if (query) {
12312             if (!root) {
12313                 if (nodes && nodes[0] && nodes[0].ownerDocument) {
12314                     root = nodes[0].ownerDocument;
12315                 }
12316             }
12317
12318             this._nodes = Y.Selector.query(query, root);
12319         }
12320
12321         return this;
12322     },
12323
12324     _prepEvtArgs: function(type, fn, context) {
12325         // map to Y.on/after signature (type, fn, nodes, context, arg1, arg2, etc)
12326         var args = Y.Array(arguments, 0, true);
12327
12328         if (args.length < 2) { // type only (event hash) just add nodes
12329             args[2] = this._nodes;
12330         } else {
12331             args.splice(2, 0, this._nodes);
12332         }
12333
12334         args[3] = context || this; // default to NodeList instance as context
12335
12336         return args;
12337     },
12338
12339     /**
12340      * Applies an event listener to each Node bound to the NodeList.
12341      * @method on
12342      * @param {String} type The event being listened for
12343      * @param {Function} fn The handler to call when the event fires
12344      * @param {Object} context The context to call the handler with.
12345      * Default is the NodeList instance.
12346      * @param {Object} context The context to call the handler with.
12347      * param {mixed} arg* 0..n additional arguments to supply to the subscriber
12348      * when the event fires.
12349      * @return {Object} Returns an event handle that can later be use to detach().
12350      * @see Event.on
12351      */
12352     on: function(type, fn, context) {
12353         return Y.on.apply(Y, this._prepEvtArgs.apply(this, arguments));
12354     },
12355
12356     /**
12357      * Applies an one-time event listener to each Node bound to the NodeList.
12358      * @method once
12359      * @param {String} type The event being listened for
12360      * @param {Function} fn The handler to call when the event fires
12361      * @param {Object} context The context to call the handler with.
12362      * Default is the NodeList instance.
12363      * @return {Object} Returns an event handle that can later be use to detach().
12364      * @see Event.on
12365      */
12366     once: function(type, fn, context) {
12367         return Y.once.apply(Y, this._prepEvtArgs.apply(this, arguments));
12368     },
12369
12370     /**
12371      * Applies an event listener to each Node bound to the NodeList.
12372      * The handler is called only after all on() handlers are called
12373      * and the event is not prevented.
12374      * @method after
12375      * @param {String} type The event being listened for
12376      * @param {Function} fn The handler to call when the event fires
12377      * @param {Object} context The context to call the handler with.
12378      * Default is the NodeList instance.
12379      * @return {Object} Returns an event handle that can later be use to detach().
12380      * @see Event.on
12381      */
12382     after: function(type, fn, context) {
12383         return Y.after.apply(Y, this._prepEvtArgs.apply(this, arguments));
12384     },
12385
12386     /**
12387      * Returns the current number of items in the NodeList.
12388      * @method size
12389      * @return {Int} The number of items in the NodeList.
12390      */
12391     size: function() {
12392         return this._nodes.length;
12393     },
12394
12395     /**
12396      * Determines if the instance is bound to any nodes
12397      * @method isEmpty
12398      * @return {Boolean} Whether or not the NodeList is bound to any nodes
12399      */
12400     isEmpty: function() {
12401         return this._nodes.length < 1;
12402     },
12403
12404     toString: function() {
12405         var str = '',
12406             errorMsg = this[UID] + ': not bound to any nodes',
12407             nodes = this._nodes,
12408             node;
12409
12410         if (nodes && nodes[0]) {
12411             node = nodes[0];
12412             str += node[NODE_NAME];
12413             if (node.id) {
12414                 str += '#' + node.id;
12415             }
12416
12417             if (node.className) {
12418                 str += '.' + node.className.replace(' ', '.');
12419             }
12420
12421             if (nodes.length > 1) {
12422                 str += '...[' + nodes.length + ' items]';
12423             }
12424         }
12425         return str || errorMsg;
12426     }
12427
12428 }, true);
12429
12430 NodeList.importMethod(Y.Node.prototype, [
12431     /**
12432      * Called on each Node instance
12433      * @for NodeList
12434      * @method append
12435      * @see Node.append
12436      */
12437     'append',
12438
12439     /** Called on each Node instance
12440       * @method destroy
12441       * @see Node.destroy
12442       */
12443     'destroy',
12444
12445     /**
12446       * Called on each Node instance
12447       * @method detach
12448       * @see Node.detach
12449       */
12450     'detach',
12451
12452     /** Called on each Node instance
12453       * @method detachAll
12454       * @see Node.detachAll
12455       */
12456     'detachAll',
12457
12458     /** Called on each Node instance
12459       * @method empty
12460       * @see Node.empty
12461       */
12462     'empty',
12463
12464     /** Called on each Node instance
12465       * @method insert
12466       * @see Node.insert
12467       */
12468     'insert',
12469
12470     /** Called on each Node instance
12471       * @method prepend
12472       * @see Node.prepend
12473       */
12474     'prepend',
12475
12476     /** Called on each Node instance
12477       * @method remove
12478       * @see Node.remove
12479       */
12480     'remove',
12481
12482     /** Called on each Node instance
12483       * @method set
12484       * @see Node.set
12485       */
12486     'set',
12487
12488     /** Called on each Node instance
12489       * @method setContent
12490       * @see Node.setContent
12491       */
12492     'setContent',
12493
12494     /**
12495      * Makes each node visible.
12496      * If the "transition" module is loaded, show optionally
12497      * animates the showing of the node using either the default
12498      * transition effect ('fadeIn'), or the given named effect.
12499      * @method show
12500      * @param {String} name A named Transition effect to use as the show effect. 
12501      * @param {Object} config Options to use with the transition. 
12502      * @param {Function} callback An optional function to run after the transition completes. 
12503      * @chainable
12504      */
12505     'show',
12506
12507     /**
12508      * Hides each node.
12509      * If the "transition" module is loaded, hide optionally
12510      * animates the hiding of the node using either the default
12511      * transition effect ('fadeOut'), or the given named effect.
12512      * @method hide
12513      * @param {String} name A named Transition effect to use as the show effect. 
12514      * @param {Object} config Options to use with the transition. 
12515      * @param {Function} callback An optional function to run after the transition completes. 
12516      * @chainable
12517      */
12518     'hide',
12519
12520     'toggleView'
12521 ]);
12522
12523 // one-off implementation to convert array of Nodes to NodeList
12524 // e.g. Y.all('input').get('parentNode');
12525
12526 /** Called on each Node instance
12527   * @method get
12528   * @see Node
12529   */
12530 NodeList.prototype.get = function(attr) {
12531     var ret = [],
12532         nodes = this._nodes,
12533         isNodeList = false,
12534         getTemp = NodeList._getTempNode,
12535         instance,
12536         val;
12537
12538     if (nodes[0]) {
12539         instance = Y.Node._instances[nodes[0]._yuid] || getTemp(nodes[0]);
12540         val = instance._get(attr);
12541         if (val && val.nodeType) {
12542             isNodeList = true;
12543         }
12544     }
12545
12546     Y.Array.each(nodes, function(node) {
12547         instance = Y.Node._instances[node._yuid];
12548
12549         if (!instance) {
12550             instance = getTemp(node);
12551         }
12552
12553         val = instance._get(attr);
12554         if (!isNodeList) { // convert array of Nodes to NodeList
12555             val = Y.Node.scrubVal(val, instance);
12556         }
12557
12558         ret.push(val);
12559     });
12560
12561     return (isNodeList) ? Y.all(ret) : ret;
12562 };
12563
12564 Y.NodeList = NodeList;
12565
12566 Y.all = function(nodes) {
12567     return new NodeList(nodes);
12568 };
12569
12570 Y.Node.all = Y.all;
12571 Y.Array.each([
12572     /**
12573      * Passes through to DOM method.
12574      * @for Node
12575      * @method removeChild
12576      * @param {HTMLElement | Node} node Node to be removed 
12577      * @return {Node} The removed node 
12578      */
12579     'removeChild',
12580
12581     /**
12582      * Passes through to DOM method.
12583      * @method hasChildNodes
12584      * @return {Boolean} Whether or not the node has any childNodes 
12585      */
12586     'hasChildNodes',
12587
12588     /**
12589      * Passes through to DOM method.
12590      * @method cloneNode
12591      * @param {Boolean} deep Whether or not to perform a deep clone, which includes
12592      * subtree and attributes
12593      * @return {Node} The clone 
12594      */
12595     'cloneNode',
12596
12597     /**
12598      * Passes through to DOM method.
12599      * @method hasAttribute
12600      * @param {String} attribute The attribute to test for 
12601      * @return {Boolean} Whether or not the attribute is present 
12602      */
12603     'hasAttribute',
12604
12605     /**
12606      * Passes through to DOM method.
12607      * @method removeAttribute
12608      * @param {String} attribute The attribute to be removed 
12609      * @chainable
12610      */
12611     'removeAttribute',
12612
12613     /**
12614      * Passes through to DOM method.
12615      * @method scrollIntoView
12616      * @chainable
12617      */
12618     'scrollIntoView',
12619
12620     /**
12621      * Passes through to DOM method.
12622      * @method getElementsByTagName
12623      * @param {String} tagName The tagName to collect 
12624      * @return {NodeList} A NodeList representing the HTMLCollection
12625      */
12626     'getElementsByTagName',
12627
12628     /**
12629      * Passes through to DOM method.
12630      * @method focus
12631      * @chainable
12632      */
12633     'focus',
12634
12635     /**
12636      * Passes through to DOM method.
12637      * @method blur
12638      * @chainable
12639      */
12640     'blur',
12641
12642     /**
12643      * Passes through to DOM method.
12644      * Only valid on FORM elements
12645      * @method submit
12646      * @chainable
12647      */
12648     'submit',
12649
12650     /**
12651      * Passes through to DOM method.
12652      * Only valid on FORM elements
12653      * @method reset
12654      * @chainable
12655      */
12656     'reset',
12657
12658     /**
12659      * Passes through to DOM method.
12660      * @method select
12661      * @chainable
12662      */
12663      'select',
12664
12665     /**
12666      * Passes through to DOM method.
12667      * Only valid on TABLE elements
12668      * @method createCaption
12669      * @chainable
12670      */
12671     'createCaption'
12672
12673 ], function(method) {
12674     Y.Node.prototype[method] = function(arg1, arg2, arg3) {
12675         var ret = this.invoke(method, arg1, arg2, arg3);
12676         return ret;
12677     };
12678 });
12679
12680 Y.Node.importMethod(Y.DOM, [
12681     /**
12682      * Determines whether the node is an ancestor of another HTML element in the DOM hierarchy.
12683      * @method contains
12684      * @param {Node | HTMLElement} needle The possible node or descendent
12685      * @return {Boolean} Whether or not this node is the needle its ancestor
12686      */
12687     'contains',
12688     /**
12689      * Allows setting attributes on DOM nodes, normalizing in some cases.
12690      * This passes through to the DOM node, allowing for custom attributes.
12691      * @method setAttribute
12692      * @for Node
12693      * @for NodeList
12694      * @chainable
12695      * @param {string} name The attribute name 
12696      * @param {string} value The value to set
12697      */
12698     'setAttribute',
12699     /**
12700      * Allows getting attributes on DOM nodes, normalizing in some cases.
12701      * This passes through to the DOM node, allowing for custom attributes.
12702      * @method getAttribute
12703      * @for Node
12704      * @for NodeList
12705      * @param {string} name The attribute name 
12706      * @return {string} The attribute value 
12707      */
12708     'getAttribute',
12709
12710     /**
12711      * Wraps the given HTML around the node.
12712      * @method wrap
12713      * @param {String} html The markup to wrap around the node. 
12714      * @chainable
12715      */
12716     'wrap',
12717
12718     /**
12719      * Removes the node's parent node. 
12720      * @method unwrap
12721      * @chainable
12722      */
12723     'unwrap',
12724
12725     /**
12726      * Applies a unique ID to the node if none exists
12727      * @method generateID
12728      * @return {String} The existing or generated ID
12729      */
12730     'generateID'
12731 ]);
12732
12733 Y.NodeList.importMethod(Y.Node.prototype, [
12734 /**
12735  * Allows getting attributes on DOM nodes, normalizing in some cases.
12736  * This passes through to the DOM node, allowing for custom attributes.
12737  * @method getAttribute
12738  * @see Node
12739  * @for NodeList
12740  * @param {string} name The attribute name 
12741  * @return {string} The attribute value 
12742  */
12743
12744     'getAttribute',
12745 /**
12746  * Allows setting attributes on DOM nodes, normalizing in some cases.
12747  * This passes through to the DOM node, allowing for custom attributes.
12748  * @method setAttribute
12749  * @see Node
12750  * @for NodeList
12751  * @chainable
12752  * @param {string} name The attribute name 
12753  * @param {string} value The value to set
12754  */
12755     'setAttribute',
12756  
12757 /**
12758  * Allows for removing attributes on DOM nodes.
12759  * This passes through to the DOM node, allowing for custom attributes.
12760  * @method removeAttribute
12761  * @see Node
12762  * @for NodeList
12763  * @param {string} name The attribute to remove 
12764  */
12765     'removeAttribute',
12766 /**
12767  * Removes the parent node from node in the list. 
12768  * @method unwrap
12769  * @chainable
12770  */
12771     'unwrap',
12772 /**
12773  * Wraps the given HTML around each node.
12774  * @method wrap
12775  * @param {String} html The markup to wrap around the node. 
12776  * @chainable
12777  */
12778     'wrap',
12779
12780 /**
12781  * Applies a unique ID to each node if none exists
12782  * @method generateID
12783  * @return {String} The existing or generated ID
12784  */
12785     'generateID'
12786 ]);
12787 (function(Y) {
12788     var methods = [
12789     /**
12790      * Determines whether each node has the given className.
12791      * @method hasClass
12792      * @for Node
12793      * @param {String} className the class name to search for
12794      * @return {Boolean} Whether or not the element has the specified class 
12795      */
12796      'hasClass',
12797
12798     /**
12799      * Adds a class name to each node.
12800      * @method addClass         
12801      * @param {String} className the class name to add to the node's class attribute
12802      * @chainable
12803      */
12804      'addClass',
12805
12806     /**
12807      * Removes a class name from each node.
12808      * @method removeClass         
12809      * @param {String} className the class name to remove from the node's class attribute
12810      * @chainable
12811      */
12812      'removeClass',
12813
12814     /**
12815      * Replace a class with another class for each node.
12816      * If no oldClassName is present, the newClassName is simply added.
12817      * @method replaceClass  
12818      * @param {String} oldClassName the class name to be replaced
12819      * @param {String} newClassName the class name that will be replacing the old class name
12820      * @chainable
12821      */
12822      'replaceClass',
12823
12824     /**
12825      * If the className exists on the node it is removed, if it doesn't exist it is added.
12826      * @method toggleClass  
12827      * @param {String} className the class name to be toggled
12828      * @param {Boolean} force Option to force adding or removing the class. 
12829      * @chainable
12830      */
12831      'toggleClass'
12832     ];
12833
12834     Y.Node.importMethod(Y.DOM, methods);
12835     /**
12836      * Determines whether each node has the given className.
12837      * @method hasClass
12838      * @see Node.hasClass
12839      * @for NodeList
12840      * @param {String} className the class name to search for
12841      * @return {Array} An array of booleans for each node bound to the NodeList. 
12842      */
12843
12844     /**
12845      * Adds a class name to each node.
12846      * @method addClass         
12847      * @see Node.addClass
12848      * @param {String} className the class name to add to the node's class attribute
12849      * @chainable
12850      */
12851
12852     /**
12853      * Removes a class name from each node.
12854      * @method removeClass         
12855      * @see Node.removeClass
12856      * @param {String} className the class name to remove from the node's class attribute
12857      * @chainable
12858      */
12859
12860     /**
12861      * Replace a class with another class for each node.
12862      * If no oldClassName is present, the newClassName is simply added.
12863      * @method replaceClass  
12864      * @see Node.replaceClass
12865      * @param {String} oldClassName the class name to be replaced
12866      * @param {String} newClassName the class name that will be replacing the old class name
12867      * @chainable
12868      */
12869
12870     /**
12871      * If the className exists on the node it is removed, if it doesn't exist it is added.
12872      * @method toggleClass  
12873      * @see Node.toggleClass
12874      * @param {String} className the class name to be toggled
12875      * @chainable
12876      */
12877     Y.NodeList.importMethod(Y.Node.prototype, methods);
12878 })(Y);
12879
12880 if (!Y.config.doc.documentElement.hasAttribute) { // IE < 8
12881     Y.Node.prototype.hasAttribute = function(attr) {
12882         if (attr === 'value') {
12883             if (this.get('value') !== "") { // IE < 8 fails to populate specified when set in HTML
12884                 return true;
12885             }
12886         }
12887         return !!(this._node.attributes[attr] &&
12888                 this._node.attributes[attr].specified);
12889     };
12890 }
12891
12892 // IE throws an error when calling focus() on an element that's invisible, not
12893 // displayed, or disabled.
12894 Y.Node.prototype.focus = function () {
12895     try {
12896         this._node.focus();
12897     } catch (e) {
12898     }
12899 };
12900
12901 // IE throws error when setting input.type = 'hidden',
12902 // input.setAttribute('type', 'hidden') and input.attributes.type.value = 'hidden'
12903 Y.Node.ATTRS.type = {
12904     setter: function(val) {
12905         if (val === 'hidden') {
12906             try {
12907                 this._node.type = 'hidden';
12908             } catch(e) {
12909                 this.setStyle('display', 'none');
12910                 this._inputType = 'hidden';
12911             }
12912         } else {
12913             try { // IE errors when changing the type from "hidden'
12914                 this._node.type = val;
12915             } catch (e) {
12916             }
12917         }
12918         return val;
12919     },
12920
12921     getter: function() {
12922         return this._inputType || this._node.type;
12923     },
12924
12925     _bypassProxy: true // don't update DOM when using with Attribute
12926 };
12927
12928 if (Y.config.doc.createElement('form').elements.nodeType) {
12929     // IE: elements collection is also FORM node which trips up scrubVal.
12930     Y.Node.ATTRS.elements = {
12931             getter: function() {
12932                 return this.all('input, textarea, button, select');
12933             }
12934     };
12935 }
12936
12937 Y.mix(Y.Node.ATTRS, {
12938     offsetHeight: {
12939         setter: function(h) {
12940             Y.DOM.setHeight(this._node, h);
12941             return h;
12942         },
12943
12944         getter: function() {
12945             return this._node.offsetHeight;
12946         }
12947     },
12948
12949     offsetWidth: {
12950         setter: function(w) {
12951             Y.DOM.setWidth(this._node, w);
12952             return w;
12953         },
12954
12955         getter: function() {
12956             return this._node.offsetWidth;
12957         }
12958     }
12959 });
12960
12961 Y.mix(Y.Node.prototype, {
12962     sizeTo: function(w, h) {
12963         var node;
12964         if (arguments.length < 2) {
12965             node = Y.one(w);
12966             w = node.get('offsetWidth');
12967             h = node.get('offsetHeight');
12968         }
12969
12970         this.setAttrs({
12971             offsetWidth: w,
12972             offsetHeight: h
12973         });
12974     }
12975 });
12976 var Y_NodeList = Y.NodeList,
12977     ArrayProto = Array.prototype,
12978     ArrayMethods = [
12979         /** Returns a new NodeList combining the given NodeList(s) 
12980           * @for NodeList
12981           * @method concat
12982           * @param {NodeList | Array} valueN Arrays/NodeLists and/or values to
12983           * concatenate to the resulting NodeList
12984           * @return {NodeList} A new NodeList comprised of this NodeList joined with the input.
12985           */
12986         'concat',
12987         /** Removes the first last from the NodeList and returns it.
12988           * @for NodeList
12989           * @method pop
12990           * @return {Node} The last item in the NodeList.
12991           */
12992         'pop',
12993         /** Adds the given Node(s) to the end of the NodeList. 
12994           * @for NodeList
12995           * @method push
12996           * @param {Node | DOMNode} nodeN One or more nodes to add to the end of the NodeList. 
12997           */
12998         'push',
12999         /** Removes the first item from the NodeList and returns it.
13000           * @for NodeList
13001           * @method shift
13002           * @return {Node} The first item in the NodeList.
13003           */
13004         'shift',
13005         /** Returns a new NodeList comprising the Nodes in the given range. 
13006           * @for NodeList
13007           * @method slice
13008           * @param {Number} begin Zero-based index at which to begin extraction.
13009           As a negative index, start indicates an offset from the end of the sequence. slice(-2) extracts the second-to-last element and the last element in the sequence.
13010           * @param {Number} end Zero-based index at which to end extraction. slice extracts up to but not including end.
13011           slice(1,4) extracts the second element through the fourth element (elements indexed 1, 2, and 3).
13012           As a negative index, end indicates an offset from the end of the sequence. slice(2,-1) extracts the third element through the second-to-last element in the sequence.
13013           If end is omitted, slice extracts to the end of the sequence.
13014           * @return {NodeList} A new NodeList comprised of this NodeList joined with the input.
13015           */
13016         'slice',
13017         /** Changes the content of the NodeList, adding new elements while removing old elements.
13018           * @for NodeList
13019           * @method splice
13020           * @param {Number} index Index at which to start changing the array. If negative, will begin that many elements from the end.
13021           * @param {Number} howMany An integer indicating the number of old array elements to remove. If howMany is 0, no elements are removed. In this case, you should specify at least one new element. If no howMany parameter is specified (second syntax above, which is a SpiderMonkey extension), all elements after index are removed.
13022           * {Node | DOMNode| element1, ..., elementN 
13023           The elements to add to the array. If you don't specify any elements, splice simply removes elements from the array.
13024           * @return {NodeList} The element(s) removed.
13025           */
13026         'splice',
13027         /** Adds the given Node(s) to the beginning of the NodeList. 
13028           * @for NodeList
13029           * @method push
13030           * @param {Node | DOMNode} nodeN One or more nodes to add to the NodeList. 
13031           */
13032         'unshift'
13033     ];
13034
13035
13036 Y.Array.each(ArrayMethods, function(name) {
13037     Y_NodeList.prototype[name] = function() {
13038         var args = [],
13039             i = 0,
13040             arg;
13041
13042         while ((arg = arguments[i++])) { // use DOM nodes/nodeLists 
13043             args.push(arg._node || arg._nodes || arg);
13044         }
13045         return Y.Node.scrubVal(ArrayProto[name].apply(this._nodes, args));
13046     };
13047 });
13048
13049
13050 }, '3.3.0' ,{requires:['dom-base', 'selector-css2', 'event-base']});
13051 YUI.add('node-style', function(Y) {
13052
13053 (function(Y) {
13054 /**
13055  * Extended Node interface for managing node styles.
13056  * @module node
13057  * @submodule node-style
13058  */
13059
13060 var methods = [
13061     /**
13062      * Returns the style's current value.
13063      * @method getStyle
13064      * @for Node
13065      * @param {String} attr The style attribute to retrieve. 
13066      * @return {String} The current value of the style property for the element.
13067      */
13068     'getStyle',
13069
13070     /**
13071      * Returns the computed value for the given style property.
13072      * @method getComputedStyle
13073      * @param {String} attr The style attribute to retrieve. 
13074      * @return {String} The computed value of the style property for the element.
13075      */
13076     'getComputedStyle',
13077
13078     /**
13079      * Sets a style property of the node.
13080      * @method setStyle
13081      * @param {String} attr The style attribute to set. 
13082      * @param {String|Number} val The value. 
13083      * @chainable
13084      */
13085     'setStyle',
13086
13087     /**
13088      * Sets multiple style properties on the node.
13089      * @method setStyles
13090      * @param {Object} hash An object literal of property:value pairs. 
13091      * @chainable
13092      */
13093     'setStyles'
13094 ];
13095 Y.Node.importMethod(Y.DOM, methods);
13096 /**
13097  * Returns an array of values for each node.
13098  * @method getStyle
13099  * @for NodeList
13100  * @see Node.getStyle
13101  * @param {String} attr The style attribute to retrieve. 
13102  * @return {Array} The current values of the style property for the element.
13103  */
13104
13105 /**
13106  * Returns an array of the computed value for each node.
13107  * @method getComputedStyle
13108  * @see Node.getComputedStyle
13109  * @param {String} attr The style attribute to retrieve. 
13110  * @return {Array} The computed values for each node.
13111  */
13112
13113 /**
13114  * Sets a style property on each node.
13115  * @method setStyle
13116  * @see Node.setStyle
13117  * @param {String} attr The style attribute to set. 
13118  * @param {String|Number} val The value. 
13119  * @chainable
13120  */
13121
13122 /**
13123  * Sets multiple style properties on each node.
13124  * @method setStyles
13125  * @see Node.setStyles
13126  * @param {Object} hash An object literal of property:value pairs. 
13127  * @chainable
13128  */
13129 Y.NodeList.importMethod(Y.Node.prototype, methods);
13130 })(Y);
13131
13132
13133 }, '3.3.0' ,{requires:['dom-style', 'node-base']});
13134 YUI.add('node-screen', function(Y) {
13135
13136 /**
13137  * Extended Node interface for managing regions and screen positioning.
13138  * Adds support for positioning elements and normalizes window size and scroll detection. 
13139  * @module node
13140  * @submodule node-screen
13141  */
13142
13143 // these are all "safe" returns, no wrapping required
13144 Y.each([
13145     /**
13146      * Returns the inner width of the viewport (exludes scrollbar). 
13147      * @config winWidth
13148      * @for Node
13149      * @type {Int}
13150      */
13151     'winWidth',
13152
13153     /**
13154      * Returns the inner height of the viewport (exludes scrollbar). 
13155      * @config winHeight
13156      * @type {Int}
13157      */
13158     'winHeight',
13159
13160     /**
13161      * Document width 
13162      * @config winHeight
13163      * @type {Int}
13164      */
13165     'docWidth',
13166
13167     /**
13168      * Document height 
13169      * @config docHeight
13170      * @type {Int}
13171      */
13172     'docHeight',
13173
13174     /**
13175      * Amount page has been scroll vertically 
13176      * @config docScrollX
13177      * @type {Int}
13178      */
13179     'docScrollX',
13180
13181     /**
13182      * Amount page has been scroll horizontally 
13183      * @config docScrollY
13184      * @type {Int}
13185      */
13186     'docScrollY'
13187     ],
13188     function(name) {
13189         Y.Node.ATTRS[name] = {
13190             getter: function() {
13191                 var args = Array.prototype.slice.call(arguments);
13192                 args.unshift(Y.Node.getDOMNode(this));
13193
13194                 return Y.DOM[name].apply(this, args);
13195             }
13196         };
13197     }
13198 );
13199
13200 Y.Node.ATTRS.scrollLeft = {
13201     getter: function() {
13202         var node = Y.Node.getDOMNode(this);
13203         return ('scrollLeft' in node) ? node.scrollLeft : Y.DOM.docScrollX(node);
13204     },
13205
13206     setter: function(val) {
13207         var node = Y.Node.getDOMNode(this);
13208         if (node) {
13209             if ('scrollLeft' in node) {
13210                 node.scrollLeft = val;
13211             } else if (node.document || node.nodeType === 9) {
13212                 Y.DOM._getWin(node).scrollTo(val, Y.DOM.docScrollY(node)); // scroll window if win or doc
13213             }
13214         } else {
13215         }
13216     }
13217 };
13218
13219 Y.Node.ATTRS.scrollTop = {
13220     getter: function() {
13221         var node = Y.Node.getDOMNode(this);
13222         return ('scrollTop' in node) ? node.scrollTop : Y.DOM.docScrollY(node);
13223     },
13224
13225     setter: function(val) {
13226         var node = Y.Node.getDOMNode(this);
13227         if (node) {
13228             if ('scrollTop' in node) {
13229                 node.scrollTop = val;
13230             } else if (node.document || node.nodeType === 9) {
13231                 Y.DOM._getWin(node).scrollTo(Y.DOM.docScrollX(node), val); // scroll window if win or doc
13232             }
13233         } else {
13234         }
13235     }
13236 };
13237
13238 Y.Node.importMethod(Y.DOM, [
13239 /**
13240  * Gets the current position of the node in page coordinates. 
13241  * @method getXY
13242  * @for Node
13243  * @return {Array} The XY position of the node
13244 */
13245     'getXY',
13246
13247 /**
13248  * Set the position of the node in page coordinates, regardless of how the node is positioned.
13249  * @method setXY
13250  * @param {Array} xy Contains X & Y values for new position (coordinates are page-based)
13251  * @chainable
13252  */
13253     'setXY',
13254
13255 /**
13256  * Gets the current position of the node in page coordinates. 
13257  * @method getX
13258  * @return {Int} The X position of the node
13259 */
13260     'getX',
13261
13262 /**
13263  * Set the position of the node in page coordinates, regardless of how the node is positioned.
13264  * @method setX
13265  * @param {Int} x X value for new position (coordinates are page-based)
13266  * @chainable
13267  */
13268     'setX',
13269
13270 /**
13271  * Gets the current position of the node in page coordinates. 
13272  * @method getY
13273  * @return {Int} The Y position of the node
13274 */
13275     'getY',
13276
13277 /**
13278  * Set the position of the node in page coordinates, regardless of how the node is positioned.
13279  * @method setY
13280  * @param {Int} y Y value for new position (coordinates are page-based)
13281  * @chainable
13282  */
13283     'setY',
13284
13285 /**
13286  * Swaps the XY position of this node with another node. 
13287  * @method swapXY
13288  * @param {Y.Node || HTMLElement} otherNode The node to swap with.
13289  * @chainable
13290  */
13291     'swapXY'
13292 ]);
13293
13294 /**
13295  * Returns a region object for the node
13296  * @config region
13297  * @for Node
13298  * @type Node
13299  */
13300 Y.Node.ATTRS.region = {
13301     getter: function() {
13302         var node = Y.Node.getDOMNode(this),
13303             region;
13304
13305         if (node && !node.tagName) {
13306             if (node.nodeType === 9) { // document
13307                 node = node.documentElement;
13308             }
13309         }
13310         if (node.alert) {
13311             region = Y.DOM.viewportRegion(node);
13312         } else {
13313             region = Y.DOM.region(node);
13314         }
13315         return region;
13316     }
13317 };
13318
13319 /**
13320  * Returns a region object for the node's viewport
13321  * @config viewportRegion
13322  * @type Node
13323  */
13324 Y.Node.ATTRS.viewportRegion = {
13325     getter: function() {
13326         return Y.DOM.viewportRegion(Y.Node.getDOMNode(this));
13327     }
13328 };
13329
13330 Y.Node.importMethod(Y.DOM, 'inViewportRegion');
13331
13332 // these need special treatment to extract 2nd node arg
13333 /**
13334  * Compares the intersection of the node with another node or region
13335  * @method intersect
13336  * @for Node
13337  * @param {Node|Object} node2 The node or region to compare with.
13338  * @param {Object} altRegion An alternate region to use (rather than this node's).
13339  * @return {Object} An object representing the intersection of the regions.
13340  */
13341 Y.Node.prototype.intersect = function(node2, altRegion) {
13342     var node1 = Y.Node.getDOMNode(this);
13343     if (Y.instanceOf(node2, Y.Node)) { // might be a region object
13344         node2 = Y.Node.getDOMNode(node2);
13345     }
13346     return Y.DOM.intersect(node1, node2, altRegion);
13347 };
13348
13349 /**
13350  * Determines whether or not the node is within the giving region.
13351  * @method inRegion
13352  * @param {Node|Object} node2 The node or region to compare with.
13353  * @param {Boolean} all Whether or not all of the node must be in the region.
13354  * @param {Object} altRegion An alternate region to use (rather than this node's).
13355  * @return {Object} An object representing the intersection of the regions.
13356  */
13357 Y.Node.prototype.inRegion = function(node2, all, altRegion) {
13358     var node1 = Y.Node.getDOMNode(this);
13359     if (Y.instanceOf(node2, Y.Node)) { // might be a region object
13360         node2 = Y.Node.getDOMNode(node2);
13361     }
13362     return Y.DOM.inRegion(node1, node2, all, altRegion);
13363 };
13364
13365
13366 }, '3.3.0' ,{requires:['dom-screen']});
13367 YUI.add('node-pluginhost', function(Y) {
13368
13369 /**
13370  * Registers plugins to be instantiated at the class level (plugins 
13371  * which should be plugged into every instance of Node by default).
13372  *
13373  * @method Node.plug
13374  * @static
13375  *
13376  * @param {Function | Array} plugin Either the plugin class, an array of plugin classes or an array of objects (with fn and cfg properties defined)
13377  * @param {Object} config (Optional) If plugin is the plugin class, the configuration for the plugin
13378  */
13379 Y.Node.plug = function() {
13380     var args = Y.Array(arguments);
13381     args.unshift(Y.Node);
13382     Y.Plugin.Host.plug.apply(Y.Base, args);
13383     return Y.Node;
13384 };
13385
13386 /**
13387  * Unregisters any class level plugins which have been registered by the Node
13388  *
13389  * @method Node.unplug
13390  * @static
13391  *
13392  * @param {Function | Array} plugin The plugin class, or an array of plugin classes
13393  */
13394 Y.Node.unplug = function() {
13395     var args = Y.Array(arguments);
13396     args.unshift(Y.Node);
13397     Y.Plugin.Host.unplug.apply(Y.Base, args);
13398     return Y.Node;
13399 };
13400
13401 Y.mix(Y.Node, Y.Plugin.Host, false, null, 1);
13402
13403 // allow batching of plug/unplug via NodeList
13404 // doesn't use NodeList.importMethod because we need real Nodes (not tmpNode)
13405 Y.NodeList.prototype.plug = function() {
13406     var args = arguments;
13407     Y.NodeList.each(this, function(node) {
13408         Y.Node.prototype.plug.apply(Y.one(node), args);
13409     });
13410 };
13411
13412 Y.NodeList.prototype.unplug = function() {
13413     var args = arguments;
13414     Y.NodeList.each(this, function(node) {
13415         Y.Node.prototype.unplug.apply(Y.one(node), args);
13416     });
13417 };
13418
13419
13420 }, '3.3.0' ,{requires:['node-base', 'pluginhost']});
13421 YUI.add('node-event-delegate', function(Y) {
13422
13423 /**
13424  * Functionality to make the node a delegated event container
13425  * @module node
13426  * @submodule node-event-delegate
13427  */
13428
13429 /**
13430  * <p>Sets up a delegation listener for an event occurring inside the Node.
13431  * The delegated event will be verified against a supplied selector or
13432  * filtering function to test if the event references at least one node that
13433  * should trigger the subscription callback.</p>
13434  *
13435  * <p>Selector string filters will trigger the callback if the event originated
13436  * from a node that matches it or is contained in a node that matches it.
13437  * Function filters are called for each Node up the parent axis to the
13438  * subscribing container node, and receive at each level the Node and the event
13439  * object.  The function should return true (or a truthy value) if that Node
13440  * should trigger the subscription callback.  Note, it is possible for filters
13441  * to match multiple Nodes for a single event.  In this case, the delegate
13442  * callback will be executed for each matching Node.</p>
13443  *
13444  * <p>For each matching Node, the callback will be executed with its 'this'
13445  * object set to the Node matched by the filter (unless a specific context was
13446  * provided during subscription), and the provided event's
13447  * <code>currentTarget</code> will also be set to the matching Node.  The
13448  * containing Node from which the subscription was originally made can be
13449  * referenced as <code>e.container</code>.
13450  *
13451  * @method delegate
13452  * @param type {String} the event type to delegate
13453  * @param fn {Function} the callback function to execute.  This function
13454  *              will be provided the event object for the delegated event.
13455  * @param spec {String|Function} a selector that must match the target of the
13456  *              event or a function to test target and its parents for a match
13457  * @param context {Object} optional argument that specifies what 'this' refers to.
13458  * @param args* {any} 0..n additional arguments to pass on to the callback function.
13459  *              These arguments will be added after the event object.
13460  * @return {EventHandle} the detach handle
13461  * @for Node
13462  */
13463 Y.Node.prototype.delegate = function(type) {
13464
13465     var args = Y.Array(arguments, 0, true),
13466         index = (Y.Lang.isObject(type) && !Y.Lang.isArray(type)) ? 1 : 2;
13467
13468     args.splice(index, 0, this._node);
13469
13470     return Y.delegate.apply(Y, args);
13471 };
13472
13473
13474 }, '3.3.0' ,{requires:['node-base', 'event-delegate']});
13475
13476
13477 YUI.add('node', function(Y){}, '3.3.0' ,{skinnable:false, requires:['dom', 'event-base', 'event-delegate', 'pluginhost'], use:['node-base', 'node-style', 'node-screen', 'node-pluginhost', 'node-event-delegate']});
13478
13479 YUI.add('event-delegate', function(Y) {
13480
13481 /**
13482  * Adds event delegation support to the library.
13483  * 
13484  * @module event
13485  * @submodule event-delegate
13486  */
13487
13488 var toArray          = Y.Array,
13489     YLang            = Y.Lang,
13490     isString         = YLang.isString,
13491     isObject         = YLang.isObject,
13492     isArray          = YLang.isArray,
13493     selectorTest     = Y.Selector.test,
13494     detachCategories = Y.Env.evt.handles;
13495
13496 /**
13497  * <p>Sets up event delegation on a container element.  The delegated event
13498  * will use a supplied selector or filtering function to test if the event
13499  * references at least one node that should trigger the subscription
13500  * callback.</p>
13501  *
13502  * <p>Selector string filters will trigger the callback if the event originated
13503  * from a node that matches it or is contained in a node that matches it.
13504  * Function filters are called for each Node up the parent axis to the
13505  * subscribing container node, and receive at each level the Node and the event
13506  * object.  The function should return true (or a truthy value) if that Node
13507  * should trigger the subscription callback.  Note, it is possible for filters
13508  * to match multiple Nodes for a single event.  In this case, the delegate
13509  * callback will be executed for each matching Node.</p>
13510  *
13511  * <p>For each matching Node, the callback will be executed with its 'this'
13512  * object set to the Node matched by the filter (unless a specific context was
13513  * provided during subscription), and the provided event's
13514  * <code>currentTarget</code> will also be set to the matching Node.  The
13515  * containing Node from which the subscription was originally made can be
13516  * referenced as <code>e.container</code>.
13517  *
13518  * @method delegate
13519  * @param type {String} the event type to delegate
13520  * @param fn {Function} the callback function to execute.  This function
13521  *              will be provided the event object for the delegated event.
13522  * @param el {String|node} the element that is the delegation container
13523  * @param spec {string|Function} a selector that must match the target of the
13524  *              event or a function to test target and its parents for a match
13525  * @param context optional argument that specifies what 'this' refers to.
13526  * @param args* 0..n additional arguments to pass on to the callback function.
13527  *              These arguments will be added after the event object.
13528  * @return {EventHandle} the detach handle
13529  * @for YUI
13530  */
13531 function delegate(type, fn, el, filter) {
13532     var args     = toArray(arguments, 0, true),
13533         query    = isString(el) ? el : null,
13534         typeBits, synth, container, categories, cat, i, len, handles, handle;
13535
13536     // Support Y.delegate({ click: fnA, key: fnB }, context, filter, ...);
13537     // and Y.delegate(['click', 'key'], fn, context, filter, ...);
13538     if (isObject(type)) {
13539         handles = [];
13540
13541         if (isArray(type)) {
13542             for (i = 0, len = type.length; i < len; ++i) {
13543                 args[0] = type[i];
13544                 handles.push(Y.delegate.apply(Y, args));
13545             }
13546         } else {
13547             // Y.delegate({'click', fn}, context, filter) =>
13548             // Y.delegate('click', fn, context, filter)
13549             args.unshift(null); // one arg becomes two; need to make space
13550
13551             for (i in type) {
13552                 if (type.hasOwnProperty(i)) {
13553                     args[0] = i;
13554                     args[1] = type[i];
13555                     handles.push(Y.delegate.apply(Y, args));
13556                 }
13557             }
13558         }
13559
13560         return new Y.EventHandle(handles);
13561     }
13562
13563     typeBits = type.split(/\|/);
13564
13565     if (typeBits.length > 1) {
13566         cat  = typeBits.shift();
13567         type = typeBits.shift();
13568     }
13569
13570     synth = Y.Node.DOM_EVENTS[type];
13571
13572     if (isObject(synth) && synth.delegate) {
13573         handle = synth.delegate.apply(synth, arguments);
13574     }
13575
13576     if (!handle) {
13577         if (!type || !fn || !el || !filter) {
13578             return;
13579         }
13580
13581         container = (query) ? Y.Selector.query(query, null, true) : el;
13582
13583         if (!container && isString(el)) {
13584             handle = Y.on('available', function () {
13585                 Y.mix(handle, Y.delegate.apply(Y, args), true);
13586             }, el);
13587         }
13588
13589         if (!handle && container) {
13590             args.splice(2, 2, container); // remove the filter
13591
13592             handle = Y.Event._attach(args, { facade: false });
13593             handle.sub.filter  = filter;
13594             handle.sub._notify = delegate.notifySub;
13595         }
13596     }
13597
13598     if (handle && cat) {
13599         categories = detachCategories[cat]  || (detachCategories[cat] = {});
13600         categories = categories[type] || (categories[type] = []);
13601         categories.push(handle);
13602     }
13603
13604     return handle;
13605 }
13606
13607 /**
13608  * Overrides the <code>_notify</code> method on the normal DOM subscription to
13609  * inject the filtering logic and only proceed in the case of a match.
13610  * 
13611  * @method delegate.notifySub
13612  * @param thisObj {Object} default 'this' object for the callback
13613  * @param args {Array} arguments passed to the event's <code>fire()</code>
13614  * @param ce {CustomEvent} the custom event managing the DOM subscriptions for
13615  *              the subscribed event on the subscribing node.
13616  * @return {Boolean} false if the event was stopped
13617  * @private
13618  * @static
13619  * @since 3.2.0
13620  */
13621 delegate.notifySub = function (thisObj, args, ce) {
13622     // Preserve args for other subscribers
13623     args = args.slice();
13624     if (this.args) {
13625         args.push.apply(args, this.args);
13626     }
13627
13628     // Only notify subs if the event occurred on a targeted element
13629     var currentTarget = delegate._applyFilter(this.filter, args, ce),
13630         //container     = e.currentTarget,
13631         e, i, len, ret;
13632
13633     if (currentTarget) {
13634         // Support multiple matches up the the container subtree
13635         currentTarget = toArray(currentTarget);
13636
13637         // The second arg is the currentTarget, but we'll be reusing this
13638         // facade, replacing the currentTarget for each use, so it doesn't
13639         // matter what element we seed it with.
13640         e = args[0] = new Y.DOMEventFacade(args[0], ce.el, ce);
13641
13642         e.container = Y.one(ce.el);
13643     
13644         for (i = 0, len = currentTarget.length; i < len && !e.stopped; ++i) {
13645             e.currentTarget = Y.one(currentTarget[i]);
13646
13647             ret = this.fn.apply(this.context || e.currentTarget, args);
13648
13649             if (ret === false) { // stop further notifications
13650                 break;
13651             }
13652         }
13653
13654         return ret;
13655     }
13656 };
13657
13658 /**
13659  * <p>Compiles a selector string into a filter function to identify whether
13660  * Nodes along the parent axis of an event's target should trigger event
13661  * notification.</p>
13662  *
13663  * <p>This function is memoized, so previously compiled filter functions are
13664  * returned if the same selector string is provided.</p>
13665  *
13666  * <p>This function may be useful when defining synthetic events for delegate
13667  * handling.</p>
13668  *
13669  * @method delegate.compileFilter
13670  * @param selector {String} the selector string to base the filtration on
13671  * @return {Function}
13672  * @since 3.2.0
13673  * @static
13674  */
13675 delegate.compileFilter = Y.cached(function (selector) {
13676     return function (target, e) {
13677         return selectorTest(target._node, selector, e.currentTarget._node);
13678     };
13679 });
13680
13681 /**
13682  * Walks up the parent axis of an event's target, and tests each element
13683  * against a supplied filter function.  If any Nodes, including the container,
13684  * satisfy the filter, the delegated callback will be triggered for each.
13685  *
13686  * @method delegate._applyFilter
13687  * @param filter {Function} boolean function to test for inclusion in event
13688  *                  notification
13689  * @param args {Array} the arguments that would be passed to subscribers
13690  * @param ce   {CustomEvent} the DOM event wrapper
13691  * @return {Node|Node[]|undefined} The Node or Nodes that satisfy the filter
13692  * @protected
13693  */
13694 delegate._applyFilter = function (filter, args, ce) {
13695     var e         = args[0],
13696         container = ce.el, // facadeless events in IE, have no e.currentTarget
13697         target    = e.target || e.srcElement,
13698         match     = [],
13699         isContainer = false;
13700
13701     // Resolve text nodes to their containing element
13702     if (target.nodeType === 3) {
13703         target = target.parentNode;
13704     }
13705
13706     // passing target as the first arg rather than leaving well enough alone
13707     // making 'this' in the filter function refer to the target.  This is to
13708     // support bound filter functions.
13709     args.unshift(target);
13710
13711     if (isString(filter)) {
13712         while (target) {
13713             isContainer = (target === container);
13714             if (selectorTest(target, filter, (isContainer ?null: container))) {
13715                 match.push(target);
13716             }
13717
13718             if (isContainer) {
13719                 break;
13720             }
13721
13722             target = target.parentNode;
13723         }
13724     } else {
13725         // filter functions are implementer code and should receive wrappers
13726         args[0] = Y.one(target);
13727         args[1] = new Y.DOMEventFacade(e, container, ce);
13728
13729         while (target) {
13730             // filter(target, e, extra args...) - this === target
13731             if (filter.apply(args[0], args)) {
13732                 match.push(target);
13733             }
13734
13735             if (target === container) {
13736                 break;
13737             }
13738
13739             target = target.parentNode;
13740             args[0] = Y.one(target);
13741         }
13742         args[1] = e; // restore the raw DOM event
13743     }
13744
13745     if (match.length <= 1) {
13746         match = match[0]; // single match or undefined
13747     }
13748
13749     // remove the target
13750     args.shift();
13751
13752     return match;
13753 };
13754
13755 /**
13756  * Sets up event delegation on a container element.  The delegated event
13757  * will use a supplied filter to test if the callback should be executed.
13758  * This filter can be either a selector string or a function that returns
13759  * a Node to use as the currentTarget for the event.
13760  *
13761  * The event object for the delegated event is supplied to the callback
13762  * function.  It is modified slightly in order to support all properties
13763  * that may be needed for event delegation.  'currentTarget' is set to
13764  * the element that matched the selector string filter or the Node returned
13765  * from the filter function.  'container' is set to the element that the
13766  * listener is delegated from (this normally would be the 'currentTarget').
13767  *
13768  * Filter functions will be called with the arguments that would be passed to
13769  * the callback function, including the event object as the first parameter.
13770  * The function should return false (or a falsey value) if the success criteria
13771  * aren't met, and the Node to use as the event's currentTarget and 'this'
13772  * object if they are.
13773  *
13774  * @method delegate
13775  * @param type {string} the event type to delegate
13776  * @param fn {function} the callback function to execute.  This function
13777  * will be provided the event object for the delegated event.
13778  * @param el {string|node} the element that is the delegation container
13779  * @param filter {string|function} a selector that must match the target of the
13780  * event or a function that returns a Node or false.
13781  * @param context optional argument that specifies what 'this' refers to.
13782  * @param args* 0..n additional arguments to pass on to the callback function.
13783  * These arguments will be added after the event object.
13784  * @return {EventHandle} the detach handle
13785  * @for YUI
13786  */
13787 Y.delegate = Y.Event.delegate = delegate;
13788
13789
13790 }, '3.3.0' ,{requires:['node-base']});
13791 YUI.add('io-base', function(Y) {
13792
13793    /**
13794     * Base IO functionality. Provides basic XHR transport support.
13795     * @module io
13796     * @submodule io-base
13797     */
13798
13799    /**
13800     * The io class is a utility that brokers HTTP requests through a simplified
13801     * interface.  Specifically, it allows JavaScript to make HTTP requests to
13802     * a resource without a page reload.  The underlying transport for making
13803     * same-domain requests is the XMLHttpRequest object.  YUI.io can also use
13804     * Flash, if specified as a transport, for cross-domain requests.
13805     *
13806     * @class io
13807     */
13808
13809    /**
13810     * @event io:start
13811     * @description This event is fired by YUI.io when a transaction is initiated.
13812     * @type Event Custom
13813     */
13814     var E_START = 'io:start',
13815
13816    /**
13817     * @event io:complete
13818     * @description This event is fired by YUI.io when a transaction is complete.
13819     * Response status and data are accessible, if available.
13820     * @type Event Custom
13821     */
13822     E_COMPLETE = 'io:complete',
13823
13824    /**
13825     * @event io:success
13826     * @description This event is fired by YUI.io when a transaction is complete, and
13827     * the HTTP status resolves to HTTP2xx.
13828     * @type Event Custom
13829     */
13830     E_SUCCESS = 'io:success',
13831
13832    /**
13833     * @event io:failure
13834     * @description This event is fired by YUI.io when a transaction is complete, and
13835     * the HTTP status resolves to HTTP4xx, 5xx and above.
13836     * @type Event Custom
13837     */
13838     E_FAILURE = 'io:failure',
13839
13840    /**
13841     * @event io:end
13842     * @description This event signifies the end of the transaction lifecycle.  The
13843     * transaction transport is destroyed.
13844     * @type Event Custom
13845     */
13846     E_END = 'io:end',
13847
13848     //--------------------------------------
13849     //  Properties
13850     //--------------------------------------
13851    /**
13852     * @description A transaction counter that increments for each transaction.
13853     *
13854     * @property transactionId
13855     * @private
13856     * @static
13857     * @type int
13858     */
13859     transactionId = 0,
13860
13861    /**
13862     * @description Object of default HTTP headers to be initialized and sent
13863     * for all transactions.
13864     *
13865     * @property _headers
13866     * @private
13867     * @static
13868     * @type object
13869     */
13870     _headers = {
13871         'X-Requested-With' : 'XMLHttpRequest'
13872     },
13873
13874    /**
13875     * @description Object that stores timeout values for any transaction with
13876     * a defined "timeout" configuration property.
13877     *
13878     * @property _timeout
13879     * @private
13880     * @static
13881     * @type object
13882     */
13883     _timeout = {},
13884
13885     // Window reference
13886     w = Y.config.win;
13887
13888     //--------------------------------------
13889     //  Methods
13890     //--------------------------------------
13891
13892    /**
13893     * @description Method that creates the XMLHttpRequest transport
13894     *
13895     * @method _xhr
13896     * @private
13897     * @static
13898     * @return object
13899     */
13900     function _xhr() {
13901         return w.XMLHttpRequest ? new XMLHttpRequest() : new ActiveXObject('Microsoft.XMLHTTP');
13902     }
13903
13904
13905    /**
13906     * @description Method that increments _transactionId for each transaction.
13907     *
13908     * @method _id
13909     * @private
13910     * @static
13911     * @return int
13912     */
13913     function _id() {
13914         var id = transactionId;
13915
13916         transactionId++;
13917
13918         return id;
13919     }
13920
13921    /**
13922     * @description Method that creates a unique transaction object for each
13923     * request.
13924     *
13925     * @method _create
13926     * @private
13927     * @static
13928     * @param {number} c - configuration object subset to determine if
13929     *                     the transaction is an XDR or file upload,
13930     *                     requiring an alternate transport.
13931     * @param {number} i - transaction id
13932     * @return object
13933     */
13934     function _create(c, i) {
13935         var o = {};
13936             o.id = Y.Lang.isNumber(i) ? i : _id();
13937             c = c || {};
13938
13939         if (!c.use && !c.upload) {
13940             o.c = _xhr();
13941         }
13942         else if (c.use) {
13943             if (c.use === 'native') {
13944                 if (w.XDomainRequest) {
13945                     o.c = new XDomainRequest();
13946                     o.t = c.use;
13947                 }
13948                 else {
13949                     o.c = _xhr();
13950                 }
13951             }
13952             else {
13953                 o.c = Y.io._transport[c.use];
13954                 o.t = c.use;
13955             }
13956         }
13957         else {
13958             o.c = {};
13959         }
13960
13961         return o;
13962     }
13963
13964
13965     function _destroy(o) {
13966         if (w) {
13967             if (o.c && w.XMLHttpRequest) {
13968                 o.c.onreadystatechange = null;
13969             }
13970                         else if (Y.UA.ie === 6 && !o.t) {
13971                                 // IE, when using XMLHttpRequest as an ActiveX Object, will throw
13972                                 // a "Type Mismatch" error if the event handler is set to "null".
13973                                 o.c.abort();
13974                         }
13975         }
13976
13977         o.c = null;
13978         o = null;
13979     }
13980
13981    /**
13982     * @description Method for creating and subscribing transaction events.
13983     *
13984     * @method _tE
13985     * @private
13986     * @static
13987     * @param {string} e - event to be published
13988     * @param {object} c - configuration data subset for event subscription.
13989     *
13990     * @return void
13991     */
13992     function _tE(e, c) {
13993         var eT = new Y.EventTarget().publish('transaction:' + e),
13994             a = c.arguments,
13995             cT = c.context || Y;
13996
13997         if (a) {
13998             eT.on(c.on[e], cT, a);
13999         }
14000         else {
14001             eT.on(c.on[e], cT);
14002         }
14003
14004         return eT;
14005     }
14006
14007    /**
14008     * @description Fires event "io:start" and creates, fires a
14009     * transaction-specific start event, if config.on.start is
14010     * defined.
14011     *
14012     * @method _ioStart
14013     * @private
14014     * @static
14015     * @param {number} id - transaction id
14016     * @param {object} c - configuration object for the transaction.
14017     *
14018     * @return void
14019     */
14020     function _ioStart(id, c) {
14021         var a = c.arguments;
14022
14023         if (a) {
14024             Y.fire(E_START, id, a);
14025         }
14026         else {
14027             Y.fire(E_START, id);
14028         }
14029
14030         if (c.on && c.on.start) {
14031             _tE('start', c).fire(id);
14032         }
14033     }
14034
14035
14036    /**
14037     * @description Fires event "io:complete" and creates, fires a
14038     * transaction-specific "complete" event, if config.on.complete is
14039     * defined.
14040     *
14041     * @method _ioComplete
14042     * @private
14043     * @static
14044     * @param {object} o - transaction object.
14045     * @param {object} c - configuration object for the transaction.
14046     *
14047     * @return void
14048     */
14049     function _ioComplete(o, c) {
14050         var r = o.e ? { status: 0, statusText: o.e } : o.c,
14051             a = c.arguments;
14052
14053         if (a) {
14054             Y.fire(E_COMPLETE, o.id, r, a);
14055         }
14056         else {
14057             Y.fire(E_COMPLETE, o.id, r);
14058         }
14059
14060         if (c.on && c.on.complete) {
14061             _tE('complete', c).fire(o.id, r);
14062         }
14063     }
14064
14065    /**
14066     * @description Fires event "io:end" and creates, fires a
14067     * transaction-specific "end" event, if config.on.end is
14068     * defined.
14069     *
14070     * @method _ioEnd
14071     * @private
14072     * @static
14073     * @param {object} o - transaction object.
14074     * @param {object} c - configuration object for the transaction.
14075     *
14076     * @return void
14077     */
14078     function _ioEnd(o, c) {
14079         var a = c.arguments;
14080
14081         if (a) {
14082             Y.fire(E_END, o.id, a);
14083         }
14084         else {
14085             Y.fire(E_END, o.id);
14086         }
14087
14088         if (c.on && c.on.end) {
14089             _tE('end', c).fire(o.id);
14090         }
14091
14092         _destroy(o);
14093     }
14094
14095    /**
14096     * @description Fires event "io:success" and creates, fires a
14097     * transaction-specific "success" event, if config.on.success is
14098     * defined.
14099     *
14100     * @method _ioSuccess
14101     * @private
14102     * @static
14103     * @param {object} o - transaction object.
14104     * @param {object} c - configuration object for the transaction.
14105     *
14106     * @return void
14107     */
14108     function _ioSuccess(o, c) {
14109         var a = c.arguments;
14110
14111         if (a) {
14112             Y.fire(E_SUCCESS, o.id, o.c, a);
14113         }
14114         else {
14115             Y.fire(E_SUCCESS, o.id, o.c);
14116         }
14117
14118         if (c.on && c.on.success) {
14119             _tE('success', c).fire(o.id, o.c);
14120         }
14121
14122         _ioEnd(o, c);
14123     }
14124
14125    /**
14126     * @description Fires event "io:failure" and creates, fires a
14127     * transaction-specific "failure" event, if config.on.failure is
14128     * defined.
14129     *
14130     * @method _ioFailure
14131     * @private
14132     * @static
14133     * @param {object} o - transaction object.
14134     * @param {object} c - configuration object for the transaction.
14135     *
14136     * @return void
14137     */
14138     function _ioFailure(o, c) {
14139         var r = o.e ? { status: 0, statusText: o.e } : o.c,
14140             a = c.arguments;
14141
14142         if (a) {
14143             Y.fire(E_FAILURE, o.id, r, a);
14144         }
14145         else {
14146             Y.fire(E_FAILURE, o.id, r);
14147         }
14148
14149         if (c.on && c.on.failure) {
14150             _tE('failure', c).fire(o.id, r);
14151         }
14152
14153         _ioEnd(o, c);
14154     }
14155
14156    /**
14157     * @description Resends an XDR transaction, using the Flash tranport,
14158     * if the native transport fails.
14159     *
14160     * @method _resend
14161     * @private
14162     * @static
14163
14164     * @param {object} o - Transaction object generated by _create().
14165     * @param {string} uri - qualified path to transaction resource.
14166     * @param {object} c - configuration object for the transaction.
14167     *
14168     * @return void
14169     */
14170     function _resend(o, uri, c, d) {
14171         _destroy(o);
14172         c.xdr.use = 'flash';
14173         // If the original request included serialized form data and
14174         // additional data are defined in configuration.data, it must
14175         // be reset to prevent data duplication.
14176         c.data = c.form && d ? d : null;
14177
14178         return Y.io(uri, c, o.id);
14179     }
14180
14181    /**
14182     * @description Method that concatenates string data for HTTP GET transactions.
14183     *
14184     * @method _concat
14185     * @private
14186     * @static
14187     * @param {string} s - URI or root data.
14188     * @param {string} d - data to be concatenated onto URI.
14189     * @return int
14190     */
14191     function _concat(s, d) {
14192         s += ((s.indexOf('?') == -1) ? '?' : '&') + d;
14193         return s;
14194     }
14195
14196    /**
14197     * @description Method that stores default client headers for all transactions.
14198     * If a label is passed with no value argument, the header will be deleted.
14199     *
14200     * @method _setHeader
14201     * @private
14202     * @static
14203     * @param {string} l - HTTP header
14204     * @param {string} v - HTTP header value
14205     * @return int
14206     */
14207     function _setHeader(l, v) {
14208         if (v) {
14209             _headers[l] = v;
14210         }
14211         else {
14212             delete _headers[l];
14213         }
14214     }
14215
14216    /**
14217     * @description Method that sets all HTTP headers to be sent in a transaction.
14218     *
14219     * @method _setHeaders
14220     * @private
14221     * @static
14222     * @param {object} o - XHR instance for the specific transaction.
14223     * @param {object} h - HTTP headers for the specific transaction, as defined
14224     *                     in the configuration object passed to YUI.io().
14225     * @return void
14226     */
14227     function _setHeaders(o, h) {
14228         var p;
14229             h = h || {};
14230
14231         for (p in _headers) {
14232             if (_headers.hasOwnProperty(p)) {
14233                                 /*
14234                 if (h[p]) {
14235                     // Configuration headers will supersede preset io headers,
14236                     // if headers match.
14237                     continue;
14238                 }
14239                 else {
14240                     h[p] = _headers[p];
14241                 }
14242                                 */
14243                                 if (!h[p]) {
14244                                         h[p] = _headers[p];
14245                                 }
14246             }
14247         }
14248
14249         for (p in h) {
14250             if (h.hasOwnProperty(p)) {
14251                                 if (h[p] !== 'disable') {
14252                         o.setRequestHeader(p, h[p]);
14253                                 }
14254                         }
14255         }
14256     }
14257
14258    /**
14259     * @description Terminates a transaction due to an explicit abort or
14260     * timeout.
14261     *
14262     * @method _ioCancel
14263     * @private
14264     * @static
14265     * @param {object} o - Transaction object generated by _create().
14266     * @param {string} s - Identifies timed out or aborted transaction.
14267     *
14268     * @return void
14269     */
14270     function _ioCancel(o, s) {
14271         if (o && o.c) {
14272             o.e = s;
14273             o.c.abort();
14274         }
14275     }
14276
14277    /**
14278     * @description Starts timeout count if the configuration object
14279     * has a defined timeout property.
14280     *
14281     * @method _startTimeout
14282     * @private
14283     * @static
14284     * @param {object} o - Transaction object generated by _create().
14285     * @param {object} t - Timeout in milliseconds.
14286     * @return void
14287     */
14288     function _startTimeout(o, t) {
14289         _timeout[o.id] = w.setTimeout(function() { _ioCancel(o, 'timeout'); }, t);
14290     }
14291
14292    /**
14293     * @description Clears the timeout interval started by _startTimeout().
14294     *
14295     * @method _clearTimeout
14296     * @private
14297     * @static
14298     * @param {number} id - Transaction id.
14299     * @return void
14300     */
14301     function _clearTimeout(id) {
14302         w.clearTimeout(_timeout[id]);
14303         delete _timeout[id];
14304     }
14305
14306    /**
14307     * @description Method that determines if a transaction response qualifies
14308     * as success or failure, based on the response HTTP status code, and
14309     * fires the appropriate success or failure events.
14310     *
14311     * @method _handleResponse
14312     * @private
14313     * @static
14314     * @param {object} o - Transaction object generated by _create().
14315     * @param {object} c - Configuration object passed to io().
14316     * @return void
14317     */
14318     function _handleResponse(o, c) {
14319         var status;
14320
14321         try {
14322                         status = (o.c.status && o.c.status !== 0) ? o.c.status : 0;
14323         }
14324         catch(e) {
14325             status = 0;
14326         }
14327
14328         // IE reports HTTP 204 as HTTP 1223.
14329         if (status >= 200 && status < 300 || status === 1223) {
14330             _ioSuccess(o, c);
14331         }
14332         else {
14333             _ioFailure(o, c);
14334         }
14335     }
14336
14337    /**
14338     * @description Event handler bound to onreadystatechange.
14339     *
14340     * @method _readyState
14341     * @private
14342     * @static
14343     * @param {object} o - Transaction object generated by _create().
14344     * @param {object} c - Configuration object passed to YUI.io().
14345     * @return void
14346     */
14347     function _readyState(o, c) {
14348         if (o.c.readyState === 4) {
14349             if (c.timeout) {
14350                 _clearTimeout(o.id);
14351             }
14352
14353             w.setTimeout(
14354                 function() {
14355                     _ioComplete(o, c);
14356                     _handleResponse(o, c);
14357                 }, 0);
14358         }
14359     }
14360
14361    /**
14362     * @description Method for requesting a transaction. _io() is implemented as
14363     * yui.io().  Each transaction may include a configuration object.  Its
14364     * properties are:
14365     *
14366     * method: HTTP method verb (e.g., GET or POST). If this property is not
14367     *         not defined, the default value will be GET.
14368     *
14369     * data: This is the name-value string that will be sent as the transaction
14370     *       data.  If the request is HTTP GET, the data become part of
14371     *       querystring. If HTTP POST, the data are sent in the message body.
14372     *
14373     * xdr: Defines the transport to be used for cross-domain requests.  By
14374     *      setting this property, the transaction will use the specified
14375     *      transport instead of XMLHttpRequest.
14376     *      The properties are:
14377     *      {
14378     *        use: Specify the transport to be used: 'flash' and 'native'
14379     *        dataType: Set the value to 'XML' if that is the expected
14380     *                  response content type.
14381     *      }
14382     *
14383     *
14384     * form: This is a defined object used to process HTML form as data.  The
14385     *       properties are:
14386     *       {
14387     *         id: Node object or id of HTML form.
14388     *         useDisabled: Boolean value to allow disabled HTML form field
14389     *                      values to be sent as part of the data.
14390     *       }
14391     *
14392     * on: This is a defined object used to create and handle specific
14393     *     events during a transaction lifecycle.  These events will fire in
14394     *     addition to the global io events. The events are:
14395     *     start - This event is fired when a request is sent to a resource.
14396     *     complete - This event fires when the transaction is complete.
14397     *     success - This event fires when the response status resolves to
14398     *               HTTP 2xx.
14399     *     failure - This event fires when the response status resolves to
14400     *               HTTP 4xx, 5xx; and, for all transaction exceptions,
14401     *               including aborted transactions and transaction timeouts.
14402     *     end -  This even is fired at the conclusion of the transaction
14403     *            lifecycle, after a success or failure resolution.
14404     *
14405     *     The properties are:
14406     *     {
14407     *       start: function(id, arguments){},
14408     *       complete: function(id, responseobject, arguments){},
14409     *       success: function(id, responseobject, arguments){},
14410     *       failure: function(id, responseobject, arguments){},
14411     *       end: function(id, arguments){}
14412     *     }
14413     *     Each property can reference a function or be written as an
14414     *     inline function.
14415     *
14416     * sync: To enable synchronous transactions, set the configuration property
14417     *       "sync" to true; the default behavior is false.  Synchronous
14418     *       transactions are limited to same-domain requests only.
14419     *
14420     * context: Object reference for all defined transaction event handlers
14421     *          when it is implemented as a method of a base object. Defining
14422     *          "context" will set the reference of "this," used in the
14423     *          event handlers, to the context value.  In the case where
14424     *          different event handlers all have different contexts,
14425     *          use Y.bind() to set the execution context, bypassing this
14426     *          configuration.
14427     *
14428     * headers: This is a defined object of client headers, as many as.
14429     *          desired for the transaction.  The object pattern is:
14430     *          { 'header': 'value' }.
14431     *
14432     * timeout: This value, defined as milliseconds, is a time threshold for the
14433     *          transaction. When this threshold is reached, and the transaction's
14434     *          Complete event has not yet fired, the transaction will be aborted.
14435     *
14436     * arguments: Object, array, string, or number passed to all registered
14437     *            event handlers.  This value is available as the second
14438     *            argument in the "start" and "abort" event handlers; and, it is
14439     *            the third argument in the "complete", "success", and "failure"
14440     *            event handlers.
14441     *
14442     * @method _io
14443     * @private
14444     * @static
14445     * @param {string} uri - qualified path to transaction resource.
14446     * @param {object} c - configuration object for the transaction.
14447     * @param {number} i - transaction id, if already set.
14448     * @return object
14449     */
14450     function _io(uri, c, i) {
14451         var f, o, d, m, r, s, oD, a, j,
14452             u = uri;
14453             c = Y.Object(c);
14454             o = _create(c.xdr || c.form, i);
14455             m = c.method ? c.method = c.method.toUpperCase() : c.method = 'GET';
14456             s = c.sync;
14457             oD = c.data;
14458
14459         //To serialize an object into a key-value string, add the
14460         //QueryString module to the YUI instance's 'use' method.
14461         if (Y.Lang.isObject(c.data) && Y.QueryString) {
14462             c.data = Y.QueryString.stringify(c.data);
14463         }
14464
14465         if (c.form) {
14466             if (c.form.upload) {
14467                 // This is a file upload transaction, calling
14468                 // upload() in io-upload-iframe.
14469                 return Y.io.upload(o, uri, c);
14470             }
14471             else {
14472                 // Serialize HTML form data.
14473                 f = Y.io._serialize(c.form, c.data);
14474                 if (m === 'POST' || m === 'PUT') {
14475                     c.data = f;
14476                 }
14477                 else if (m === 'GET') {
14478                     uri = _concat(uri, f);
14479                 }
14480             }
14481         }
14482
14483         if (c.data && m === 'GET') {
14484             uri = _concat(uri, c.data);
14485         }
14486
14487         if (c.data && m === 'POST') {
14488             c.headers = Y.merge({ 'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8' }, c.headers);
14489         }
14490
14491         if (o.t) {
14492             return Y.io.xdr(uri, o, c);
14493         }
14494
14495         if (!s) {
14496             o.c.onreadystatechange = function() { _readyState(o, c); };
14497         }
14498
14499         try {
14500             o.c.open(m, uri, s ? false : true);
14501             // Will work only in browsers that implement the
14502             // Cross-Origin Resource Sharing draft.
14503             if (c.xdr && c.xdr.credentials) {
14504                 o.c.withCredentials = true;
14505             }
14506         }
14507         catch(e1) {
14508             if (c.xdr) {
14509                 // This exception is usually thrown by browsers
14510                 // that do not support native XDR transactions.
14511                 return _resend(o, u, c, oD);
14512             }
14513         }
14514
14515         _setHeaders(o.c, c.headers);
14516         _ioStart(o.id, c);
14517         try {
14518             // Using "null" with HTTP POST will  result in a request
14519             // with no Content-Length header defined.
14520             o.c.send(c.data || '');
14521             if (s) {
14522                 d = o.c;
14523                 a  = ['status', 'statusText', 'responseText', 'responseXML'];
14524                 r = c.arguments ? { id: o.id, arguments: c.arguments } : { id: o.id };
14525
14526                 for (j = 0; j < 4; j++) {
14527                     r[a[j]] = o.c[a[j]];
14528                 }
14529
14530                 r.getAllResponseHeaders = function() { return d.getAllResponseHeaders(); };
14531                 r.getResponseHeader = function(h) { return d.getResponseHeader(h); };
14532                 _ioComplete(o, c);
14533                 _handleResponse(o, c);
14534
14535                 return r;
14536             }
14537         }
14538         catch(e2) {
14539             if (c.xdr) {
14540                 // This exception is usually thrown by browsers
14541                 // that do not support native XDR transactions.
14542                 return _resend(o, u, c, oD);
14543             }
14544         }
14545
14546         // If config.timeout is defined, and the request is standard XHR,
14547         // initialize timeout polling.
14548         if (c.timeout) {
14549             _startTimeout(o, c.timeout);
14550         }
14551
14552         return {
14553             id: o.id,
14554             abort: function() {
14555                 return o.c ? _ioCancel(o, 'abort') : false;
14556             },
14557             isInProgress: function() {
14558                 return o.c ? o.c.readyState !== 4 && o.c.readyState !== 0 : false;
14559             }
14560         };
14561     }
14562
14563     _io.start = _ioStart;
14564     _io.complete = _ioComplete;
14565     _io.success = _ioSuccess;
14566     _io.failure = _ioFailure;
14567     _io.end = _ioEnd;
14568     _io._id = _id;
14569     _io._timeout = _timeout;
14570
14571     //--------------------------------------
14572     //  Begin public interface definition
14573     //--------------------------------------
14574    /**
14575     * @description Method that stores default client headers for all transactions.
14576     * If a label is passed with no value argument, the header will be deleted.
14577     * This is the interface for _setHeader().
14578     *
14579     * @method header
14580     * @public
14581     * @static
14582     * @param {string} l - HTTP header
14583     * @param {string} v - HTTP header value
14584     * @return int
14585     */
14586     _io.header = _setHeader;
14587
14588    /**
14589     * @description Method for requesting a transaction. This
14590     * is the interface for _io().
14591     *
14592     * @method io
14593     * @public
14594     * @static
14595     * @param {string} uri - qualified path to transaction resource.
14596     * @param {object} c - configuration object for the transaction.
14597     * @return object
14598     */
14599     Y.io = _io;
14600     Y.io.http = _io;
14601
14602
14603
14604 }, '3.3.0' ,{requires:['event-custom-base', 'querystring-stringify-simple']});
14605 YUI.add('querystring-stringify-simple', function(Y) {
14606
14607 /*global Y */
14608 /**
14609  * <p>Provides Y.QueryString.stringify method for converting objects to Query Strings.
14610  * This is a subset implementation of the full querystring-stringify.</p>
14611  * <p>This module provides the bare minimum functionality (encoding a hash of simple values),
14612  * without the additional support for nested data structures.  Every key-value pair is
14613  * encoded by encodeURIComponent.</p>
14614  * <p>This module provides a minimalistic way for io to handle  single-level objects
14615  * as transaction data.</p>
14616  *
14617  * @module querystring
14618  * @submodule querystring-stringify-simple
14619  * @for QueryString
14620  * @static
14621  */
14622
14623 var QueryString = Y.namespace("QueryString"),
14624     EUC = encodeURIComponent;
14625
14626 /**
14627  * <p>Converts a simple object to a Query String representation.</p>
14628  * <p>Nested objects, Arrays, and so on, are not supported.</p>
14629  *
14630  * @method stringify
14631  * @for QueryString
14632  * @public
14633  * @submodule querystring-stringify-simple
14634  * @param obj {Object} A single-level object to convert to a querystring.
14635  * @param cfg {Object} (optional) Configuration object.  In the simple
14636  *                                module, only the arrayKey setting is
14637  *                                supported.  When set to true, the key of an
14638  *                                array will have the '[]' notation appended
14639  *                                to the key;.
14640  * @static
14641  */
14642 QueryString.stringify = function (obj, c) {
14643     var qs = [],
14644         // Default behavior is false; standard key notation.
14645         s = c && c.arrayKey ? true : false,
14646         key, i, l;
14647
14648     for (key in obj) {
14649         if (obj.hasOwnProperty(key)) {
14650             if (Y.Lang.isArray(obj[key])) {
14651                 for (i = 0, l = obj[key].length; i < l; i++) {
14652                     qs.push(EUC(s ? key + '[]' : key) + '=' + EUC(obj[key][i]));
14653                 }
14654             }
14655             else {
14656                 qs.push(EUC(key) + '=' + EUC(obj[key]));
14657             }
14658         }
14659     }
14660
14661     return qs.join('&');
14662 };
14663
14664
14665
14666 }, '3.3.0' );
14667 YUI.add('json-parse', function(Y) {
14668
14669 /**
14670  * <p>The JSON module adds support for serializing JavaScript objects into
14671  * JSON strings and parsing JavaScript objects from strings in JSON format.</p>
14672  *
14673  * <p>The JSON namespace is added to your YUI instance including static methods
14674  * Y.JSON.parse(..) and Y.JSON.stringify(..).</p>
14675  *
14676  * <p>The functionality and method signatures follow the ECMAScript 5
14677  * specification.  In browsers with native JSON support, the native
14678  * implementation is used.</p>
14679  *
14680  * <p>The <code>json</code> module is a rollup of <code>json-parse</code> and
14681  * <code>json-stringify</code>.</p>
14682  * 
14683  * <p>As their names suggest, <code>json-parse</code> adds support for parsing
14684  * JSON data (Y.JSON.parse) and <code>json-stringify</code> for serializing
14685  * JavaScript data into JSON strings (Y.JSON.stringify).  You may choose to
14686  * include either of the submodules individually if you don't need the
14687  * complementary functionality, or include the rollup for both.</p>
14688  *
14689  * @module json
14690  * @class JSON
14691  * @static
14692  */
14693
14694 /**
14695  * Provides Y.JSON.parse method to accept JSON strings and return native
14696  * JavaScript objects.
14697  *
14698  * @module json
14699  * @submodule json-parse
14700  * @for JSON
14701  * @static
14702  */
14703
14704
14705 // All internals kept private for security reasons
14706 function fromGlobal(ref) {
14707     return (Y.config.win || this || {})[ref];
14708 }
14709
14710
14711     /**
14712      * Alias to native browser implementation of the JSON object if available.
14713      *
14714      * @property Native
14715      * @type {Object}
14716      * @private
14717      */
14718 var _JSON  = fromGlobal('JSON'),
14719     // Create an indirect reference to eval to allow for minification
14720     _eval  = fromGlobal('eval'),
14721     Native = (Object.prototype.toString.call(_JSON) === '[object JSON]' && _JSON),
14722     useNative = !!Native,
14723
14724     /**
14725      * Replace certain Unicode characters that JavaScript may handle incorrectly
14726      * during eval--either by deleting them or treating them as line
14727      * endings--with escape sequences.
14728      * IMPORTANT NOTE: This regex will be used to modify the input if a match is
14729      * found.
14730      *
14731      * @property _UNICODE_EXCEPTIONS
14732      * @type {RegExp}
14733      * @private
14734      */
14735     _UNICODE_EXCEPTIONS = /[\u0000\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,
14736
14737
14738     /**
14739      * First step in the safety evaluation.  Regex used to replace all escape
14740      * sequences (i.e. "\\", etc) with '@' characters (a non-JSON character).
14741      *
14742      * @property _ESCAPES
14743      * @type {RegExp}
14744      * @private
14745      */
14746     _ESCAPES = /\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g,
14747
14748     /**
14749      * Second step in the safety evaluation.  Regex used to replace all simple
14750      * values with ']' characters.
14751      *
14752      * @property _VALUES
14753      * @type {RegExp}
14754      * @private
14755      */
14756     _VALUES  = /"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g,
14757
14758     /**
14759      * Third step in the safety evaluation.  Regex used to remove all open
14760      * square brackets following a colon, comma, or at the beginning of the
14761      * string.
14762      *
14763      * @property _BRACKETS
14764      * @type {RegExp}
14765      * @private
14766      */
14767     _BRACKETS = /(?:^|:|,)(?:\s*\[)+/g,
14768
14769     /**
14770      * Final step in the safety evaluation.  Regex used to test the string left
14771      * after all previous replacements for invalid characters.
14772      *
14773      * @property _UNSAFE
14774      * @type {RegExp}
14775      * @private
14776      */
14777     _UNSAFE = /[^\],:{}\s]/,
14778     
14779     /**
14780      * Replaces specific unicode characters with their appropriate \unnnn
14781      * format. Some browsers ignore certain characters during eval.
14782      *
14783      * @method escapeException
14784      * @param c {String} Unicode character
14785      * @return {String} the \unnnn escapement of the character
14786      * @private
14787      */
14788     _escapeException = function (c) {
14789         return '\\u'+('0000'+(+(c.charCodeAt(0))).toString(16)).slice(-4);
14790     },
14791
14792     /**
14793      * Traverses nested objects, applying a reviver function to each (key,value)
14794      * from the scope if the key:value's containing object.  The value returned
14795      * from the function will replace the original value in the key:value pair.
14796      * If the value returned is undefined, the key will be omitted from the
14797      * returned object.
14798      *
14799      * @method _revive
14800      * @param data {MIXED} Any JavaScript data
14801      * @param reviver {Function} filter or mutation function
14802      * @return {MIXED} The results of the filtered data
14803      * @private
14804      */
14805     _revive = function (data, reviver) {
14806         var walk = function (o,key) {
14807             var k,v,value = o[key];
14808             if (value && typeof value === 'object') {
14809                 for (k in value) {
14810                     if (value.hasOwnProperty(k)) {
14811                         v = walk(value, k);
14812                         if (v === undefined) {
14813                             delete value[k];
14814                         } else {
14815                             value[k] = v;
14816                         }
14817                     }
14818                 }
14819             }
14820             return reviver.call(o,key,value);
14821         };
14822
14823         return typeof reviver === 'function' ? walk({'':data},'') : data;
14824     },
14825
14826     /**
14827      * Parse a JSON string, returning the native JavaScript representation.
14828      *
14829      * @param s {string} JSON string data
14830      * @param reviver {function} (optional) function(k,v) passed each key value
14831      *          pair of object literals, allowing pruning or altering values
14832      * @return {MIXED} the native JavaScript representation of the JSON string
14833      * @throws SyntaxError
14834      * @method parse
14835      * @static
14836      */
14837     // JavaScript implementation in lieu of native browser support.  Based on
14838     // the json2.js library from http://json.org
14839     _parse = function (s,reviver) {
14840         // Replace certain Unicode characters that are otherwise handled
14841         // incorrectly by some browser implementations.
14842         // NOTE: This modifies the input if such characters are found!
14843         s = s.replace(_UNICODE_EXCEPTIONS, _escapeException);
14844         
14845         // Test for any remaining invalid characters
14846         if (!_UNSAFE.test(s.replace(_ESCAPES,'@').
14847                             replace(_VALUES,']').
14848                             replace(_BRACKETS,''))) {
14849
14850             // Eval the text into a JavaScript data structure, apply any
14851             // reviver function, and return
14852             return _revive( _eval('(' + s + ')'), reviver );
14853         }
14854
14855         throw new SyntaxError('JSON.parse');
14856     };
14857     
14858 Y.namespace('JSON').parse = function (s,reviver) {
14859         if (typeof s !== 'string') {
14860             s += '';
14861         }
14862
14863         return Native && Y.JSON.useNativeParse ?
14864             Native.parse(s,reviver) : _parse(s,reviver);
14865 };
14866
14867 function workingNative( k, v ) {
14868     return k === "ok" ? true : v;
14869 }
14870
14871 // Double check basic functionality.  This is mainly to catch early broken
14872 // implementations of the JSON API in Firefox 3.1 beta1 and beta2
14873 if ( Native ) {
14874     try {
14875         useNative = ( Native.parse( '{"ok":false}', workingNative ) ).ok;
14876     }
14877     catch ( e ) {
14878         useNative = false;
14879     }
14880 }
14881
14882 /**
14883  * Leverage native JSON parse if the browser has a native implementation.
14884  * In general, this is a good idea.  See the Known Issues section in the
14885  * JSON user guide for caveats.  The default value is true for browsers with
14886  * native JSON support.
14887  *
14888  * @property useNativeParse
14889  * @type Boolean
14890  * @default true
14891  * @static
14892  */
14893 Y.JSON.useNativeParse = useNative;
14894
14895
14896 }, '3.3.0' );
14897 YUI.add('transition-native', function(Y) {
14898
14899 /**
14900 * Provides the transition method for Node.
14901 * Transition has no API of its own, but adds the transition method to Node.
14902 *
14903 * @module transition
14904 * @requires node-style
14905 */
14906
14907 var TRANSITION = '-webkit-transition',
14908     TRANSITION_CAMEL = 'WebkitTransition',
14909     TRANSITION_PROPERTY_CAMEL = 'WebkitTransitionProperty',
14910     TRANSITION_PROPERTY = '-webkit-transition-property',
14911     TRANSITION_DURATION = '-webkit-transition-duration',
14912     TRANSITION_TIMING_FUNCTION = '-webkit-transition-timing-function',
14913     TRANSITION_DELAY = '-webkit-transition-delay',
14914     TRANSITION_END = 'webkitTransitionEnd',
14915     ON_TRANSITION_END = 'onwebkittransitionend',
14916     TRANSFORM_CAMEL = 'WebkitTransform',
14917
14918     EMPTY_OBJ = {},
14919
14920 /**
14921  * A class for constructing transition instances.
14922  * Adds the "transition" method to Node.
14923  * @class Transition
14924  * @constructor
14925  */
14926
14927 Transition = function() {
14928     this.init.apply(this, arguments);
14929 };
14930
14931 Transition.fx = {};
14932 Transition.toggles = {};
14933
14934 Transition._hasEnd = {};
14935
14936 Transition._toCamel = function(property) {
14937     property = property.replace(/-([a-z])/gi, function(m0, m1) {
14938         return m1.toUpperCase();
14939     });
14940
14941     return property;
14942 };
14943
14944 Transition._toHyphen = function(property) {
14945     property = property.replace(/([A-Z]?)([a-z]+)([A-Z]?)/g, function(m0, m1, m2, m3) {
14946         var str = '';
14947         if (m1) {
14948             str += '-' + m1.toLowerCase();
14949         }
14950         str += m2;
14951         
14952         if (m3) {
14953             str += '-' + m3.toLowerCase();
14954         }
14955
14956         return str;
14957     }); 
14958
14959     return property;
14960 };
14961
14962
14963 Transition._reKeywords = /^(?:node|duration|iterations|easing|delay|on|onstart|onend)$/i;
14964
14965 Transition.useNative = false;
14966
14967 if (TRANSITION in Y.config.doc.documentElement.style) {
14968     Transition.useNative = true;
14969     Transition.supported = true; // TODO: remove
14970 }
14971
14972 Y.Node.DOM_EVENTS[TRANSITION_END] = 1; 
14973
14974 Transition.NAME = 'transition';
14975
14976 Transition.DEFAULT_EASING = 'ease';
14977 Transition.DEFAULT_DURATION = 0.5;
14978 Transition.DEFAULT_DELAY = 0;
14979
14980 Transition._nodeAttrs = {};
14981
14982 Transition.prototype = {
14983     constructor: Transition,
14984     init: function(node, config) {
14985         var anim = this;
14986         anim._node = node;
14987         if (!anim._running && config) {
14988             anim._config = config;
14989             node._transition = anim; // cache for reuse
14990
14991             anim._duration = ('duration' in config) ?
14992                 config.duration: anim.constructor.DEFAULT_DURATION;
14993
14994             anim._delay = ('delay' in config) ?
14995                 config.delay: anim.constructor.DEFAULT_DELAY;
14996
14997             anim._easing = config.easing || anim.constructor.DEFAULT_EASING;
14998             anim._count = 0; // track number of animated properties
14999             anim._running = false;
15000
15001         }
15002
15003         return anim;
15004     },
15005
15006     addProperty: function(prop, config) {
15007         var anim = this,
15008             node = this._node,
15009             uid = Y.stamp(node),
15010             nodeInstance = Y.one(node),
15011             attrs = Transition._nodeAttrs[uid],
15012             computed,
15013             compareVal,
15014             dur,
15015             attr,
15016             val;
15017
15018         if (!attrs) {
15019             attrs = Transition._nodeAttrs[uid] = {};
15020         }
15021
15022         attr = attrs[prop];
15023
15024         // might just be a value
15025         if (config && config.value !== undefined) {
15026             val = config.value;
15027         } else if (config !== undefined) {
15028             val = config; 
15029             config = EMPTY_OBJ;
15030         }
15031
15032         if (typeof val === 'function') {
15033             val = val.call(nodeInstance, nodeInstance);
15034         }
15035
15036         if (attr && attr.transition) {
15037             // take control if another transition owns this property
15038             if (attr.transition !== anim) {
15039                 attr.transition._count--; // remapping attr to this transition
15040             }
15041         } 
15042
15043         anim._count++; // properties per transition
15044
15045         // make 0 async and fire events
15046         dur = ((typeof config.duration != 'undefined') ? config.duration :
15047                     anim._duration) || 0.0001;
15048
15049         attrs[prop] = {
15050             value: val,
15051             duration: dur,
15052             delay: (typeof config.delay != 'undefined') ? config.delay :
15053                     anim._delay,
15054
15055             easing: config.easing || anim._easing,
15056
15057             transition: anim
15058         };
15059
15060         // native end event doesnt fire when setting to same value
15061         // supplementing with timer
15062         // val may be a string or number (height: 0, etc), but computedStyle is always string
15063         computed = Y.DOM.getComputedStyle(node, prop);
15064         compareVal = (typeof val === 'string') ? computed : parseFloat(computed);
15065
15066         if (Transition.useNative && compareVal === val) {
15067             setTimeout(function() {
15068                 anim._onNativeEnd.call(node, {
15069                     propertyName: prop,
15070                     elapsedTime: dur
15071                 });
15072             }, dur * 1000);
15073         }
15074     },
15075
15076     removeProperty: function(prop) {
15077         var anim = this,
15078             attrs = Transition._nodeAttrs[Y.stamp(anim._node)];
15079
15080         if (attrs && attrs[prop]) {
15081             delete attrs[prop];
15082             anim._count--;
15083         }
15084
15085     },
15086
15087     initAttrs: function(config) {
15088         var attr,
15089             node = this._node;
15090
15091         if (config.transform && !config[TRANSFORM_CAMEL]) {
15092             config[TRANSFORM_CAMEL] = config.transform;
15093             delete config.transform; // TODO: copy
15094         }
15095
15096         for (attr in config) {
15097             if (config.hasOwnProperty(attr) && !Transition._reKeywords.test(attr)) {
15098                 this.addProperty(attr, config[attr]);
15099
15100                 // when size is auto or % webkit starts from zero instead of computed 
15101                 // (https://bugs.webkit.org/show_bug.cgi?id=16020)
15102                 // TODO: selective set
15103                 if (node.style[attr] === '') {
15104                     Y.DOM.setStyle(node, attr, Y.DOM.getComputedStyle(node, attr));
15105                 }
15106             }
15107         }
15108     },
15109
15110     /**
15111      * Starts or an animation.
15112      * @method run
15113      * @chainable
15114      * @private
15115      */    
15116     run: function(callback) {
15117         var anim = this,
15118             node = anim._node,
15119             config = anim._config,
15120             data = {
15121                 type: 'transition:start',
15122                 config: config
15123             };
15124
15125
15126         if (!anim._running) {
15127             anim._running = true;
15128
15129             //anim._node.fire('transition:start', data);
15130
15131             if (config.on && config.on.start) {
15132                 config.on.start.call(Y.one(node), data);
15133             }
15134
15135             anim.initAttrs(anim._config);
15136
15137             anim._callback = callback;
15138             anim._start();
15139         }
15140
15141
15142         return anim;
15143     },
15144
15145     _start: function() {
15146         this._runNative();
15147     },
15148
15149     _prepDur: function(dur) {
15150         dur = parseFloat(dur);
15151
15152         return dur + 's';
15153     },
15154
15155     _runNative: function(time) {
15156         var anim = this,
15157             node = anim._node,
15158             uid = Y.stamp(node),
15159             style = node.style,
15160             computed = getComputedStyle(node),
15161             attrs = Transition._nodeAttrs[uid],
15162             cssText = '',
15163             cssTransition = computed[TRANSITION_PROPERTY],
15164
15165             transitionText = TRANSITION_PROPERTY + ': ',
15166             duration = TRANSITION_DURATION + ': ',
15167             easing = TRANSITION_TIMING_FUNCTION + ': ',
15168             delay = TRANSITION_DELAY + ': ',
15169             hyphy,
15170             attr,
15171             name;
15172
15173         // preserve existing transitions
15174         if (cssTransition !== 'all') {
15175             transitionText += cssTransition + ',';
15176             duration += computed[TRANSITION_DURATION] + ',';
15177             easing += computed[TRANSITION_TIMING_FUNCTION] + ',';
15178             delay += computed[TRANSITION_DELAY] + ',';
15179
15180         }
15181
15182         // run transitions mapped to this instance
15183         for (name in attrs) {
15184             hyphy = Transition._toHyphen(name);
15185             attr = attrs[name];
15186             if (attrs.hasOwnProperty(name) && attr.transition === anim) {
15187                 if (name in node.style) { // only native styles allowed
15188                     duration += anim._prepDur(attr.duration) + ',';
15189                     delay += anim._prepDur(attr.delay) + ',';
15190                     easing += (attr.easing) + ',';
15191
15192                     transitionText += hyphy + ',';
15193                     cssText += hyphy + ': ' + attr.value + '; ';
15194                 } else {
15195                     this.removeProperty(name);
15196                 }
15197             }
15198         }
15199
15200         transitionText = transitionText.replace(/,$/, ';');
15201         duration = duration.replace(/,$/, ';');
15202         easing = easing.replace(/,$/, ';');
15203         delay = delay.replace(/,$/, ';');
15204
15205         // only one native end event per node
15206         if (!Transition._hasEnd[uid]) {
15207             //anim._detach = Y.on(TRANSITION_END, anim._onNativeEnd, node);
15208             //node[ON_TRANSITION_END] = anim._onNativeEnd;
15209             node.addEventListener(TRANSITION_END, anim._onNativeEnd, false);
15210             Transition._hasEnd[uid] = true;
15211
15212         }
15213         
15214         //setTimeout(function() { // allow updates to apply (size fix, onstart, etc)
15215             style.cssText += transitionText + duration + easing + delay + cssText;
15216         //}, 1);
15217
15218     },
15219
15220     _end: function(elapsed) {
15221         var anim = this,
15222             node = anim._node,
15223             callback = anim._callback,
15224             config = anim._config,
15225             data = {
15226                 type: 'transition:end',
15227                 config: config,
15228                 elapsedTime: elapsed 
15229             },
15230
15231             nodeInstance = Y.one(node); 
15232
15233         anim._running = false;
15234         anim._callback = null;
15235
15236         if (node) {
15237             if (config.on && config.on.end) {
15238                 setTimeout(function() { // IE: allow previous update to finish
15239                     config.on.end.call(nodeInstance, data);
15240
15241                     // nested to ensure proper fire order
15242                     if (callback) {
15243                         callback.call(nodeInstance, data);
15244                     }
15245
15246                 }, 1);
15247             } else if (callback) {
15248                 setTimeout(function() { // IE: allow previous update to finish
15249                     callback.call(nodeInstance, data);
15250                 }, 1);
15251             }
15252             //node.fire('transition:end', data);
15253         }
15254
15255     },
15256
15257     _endNative: function(name) {
15258         var node = this._node,
15259             value = node.ownerDocument.defaultView.getComputedStyle(node, '')[TRANSITION_PROPERTY];
15260
15261         if (typeof value === 'string') {
15262             value = value.replace(new RegExp('(?:^|,\\s)' + name + ',?'), ',');
15263             value = value.replace(/^,|,$/, '');
15264             node.style[TRANSITION_CAMEL] = value;
15265         }
15266     },
15267
15268     _onNativeEnd: function(e) {
15269         var node = this,
15270             uid = Y.stamp(node),
15271             event = e,//e._event,
15272             name = Transition._toCamel(event.propertyName),
15273             elapsed = event.elapsedTime,
15274             attrs = Transition._nodeAttrs[uid],
15275             attr = attrs[name],
15276             anim = (attr) ? attr.transition : null,
15277             data,
15278             config;
15279
15280         if (anim) {
15281             anim.removeProperty(name);
15282             anim._endNative(name);
15283             config = anim._config[name];
15284
15285             data = {
15286                 type: 'propertyEnd',
15287                 propertyName: name,
15288                 elapsedTime: elapsed,
15289                 config: config
15290             };
15291
15292             if (config && config.on && config.on.end) {
15293                 config.on.end.call(Y.one(node), data);
15294             }
15295
15296             //node.fire('transition:propertyEnd', data);
15297
15298             if (anim._count <= 0)  { // after propertyEnd fires
15299                 anim._end(elapsed);
15300             }
15301         }
15302     },
15303
15304     destroy: function() {
15305         var anim = this;
15306         /*
15307         if (anim._detach) {
15308             anim._detach.detach();
15309         }
15310         */
15311         //anim._node[ON_TRANSITION_END] = null;
15312         node.removeEventListener(TRANSITION_END, anim._onNativeEnd, false);
15313         anim._node = null;
15314     }
15315 };
15316
15317 Y.Transition = Transition;
15318 Y.TransitionNative = Transition; // TODO: remove
15319
15320 /** 
15321  *   Animate one or more css properties to a given value. Requires the "transition" module.
15322  *   <pre>example usage:
15323  *       Y.one('#demo').transition({
15324  *           duration: 1, // in seconds, default is 0.5
15325  *           easing: 'ease-out', // default is 'ease'
15326  *           delay: '1', // delay start for 1 second, default is 0
15327  *
15328  *           height: '10px',
15329  *           width: '10px',
15330  *
15331  *           opacity: { // per property
15332  *               value: 0,
15333  *               duration: 2,
15334  *               delay: 2,
15335  *               easing: 'ease-in'
15336  *           }
15337  *       });
15338  *   </pre>
15339  *   @for Node
15340  *   @method transition
15341  *   @param {Object} config An object containing one or more style properties, a duration and an easing.
15342  *   @param {Function} callback A function to run after the transition has completed. 
15343  *   @chainable
15344 */
15345 Y.Node.prototype.transition = function(name, config, callback) {
15346     var 
15347         transitionAttrs = Transition._nodeAttrs[Y.stamp(this._node)],
15348         anim = (transitionAttrs) ? transitionAttrs.transition || null : null,
15349         fxConfig,
15350         prop;
15351     
15352     if (typeof name === 'string') { // named effect, pull config from registry
15353         if (typeof config === 'function') {
15354             callback = config;
15355             config = null;
15356         }
15357
15358         fxConfig = Transition.fx[name];
15359
15360         if (config && typeof config !== 'boolean') {
15361             config = Y.clone(config);
15362
15363             for (prop in fxConfig) {
15364                 if (fxConfig.hasOwnProperty(prop)) {
15365                     if (! (prop in config)) {
15366                         config[prop] = fxConfig[prop]; 
15367                     }
15368                 }
15369             }
15370         } else {
15371             config = fxConfig;
15372         }
15373
15374     } else { // name is a config, config is a callback or undefined
15375         callback = config;
15376         config = name;
15377     }
15378
15379     if (anim && !anim._running) {
15380         anim.init(this, config);
15381     } else {
15382         anim = new Transition(this._node, config);
15383     }
15384
15385     anim.run(callback);
15386     return this;
15387 };
15388
15389 Y.Node.prototype.show = function(name, config, callback) {
15390     this._show(); // show prior to transition
15391     if (name && Y.Transition) {
15392         if (typeof name !== 'string' && !name.push) { // named effect or array of effects supercedes default
15393             if (typeof config === 'function') {
15394                 callback = config;
15395                 config = name;
15396             }
15397             name = this.SHOW_TRANSITION; 
15398         }    
15399         this.transition(name, config, callback);
15400     }    
15401     return this;
15402 };
15403
15404 var _wrapCallBack = function(anim, fn, callback) {
15405     return function() {
15406         if (fn) {
15407             fn.call(anim);
15408         }
15409         if (callback) {
15410             callback.apply(anim._node, arguments);
15411         }
15412     };
15413 };
15414
15415 Y.Node.prototype.hide = function(name, config, callback) {
15416     if (name && Y.Transition) {
15417         if (typeof config === 'function') {
15418             callback = config;
15419             config = null;
15420         }
15421
15422         callback = _wrapCallBack(this, this._hide, callback); // wrap with existing callback
15423         if (typeof name !== 'string' && !name.push) { // named effect or array of effects supercedes default
15424             if (typeof config === 'function') {
15425                 callback = config;
15426                 config = name;
15427             }
15428             name = this.HIDE_TRANSITION; 
15429         }    
15430         this.transition(name, config, callback);
15431     } else {
15432         this._hide();
15433     }    
15434     return this;
15435 }; 
15436
15437 /** 
15438  *   Animate one or more css properties to a given value. Requires the "transition" module.
15439  *   <pre>example usage:
15440  *       Y.all('.demo').transition({
15441  *           duration: 1, // in seconds, default is 0.5
15442  *           easing: 'ease-out', // default is 'ease'
15443  *           delay: '1', // delay start for 1 second, default is 0
15444  *
15445  *           height: '10px',
15446  *           width: '10px',
15447  *
15448  *           opacity: { // per property
15449  *               value: 0,
15450  *               duration: 2,
15451  *               delay: 2,
15452  *               easing: 'ease-in'
15453  *           }
15454  *       });
15455  *   </pre>
15456  *   @for NodeList
15457  *   @method transition
15458  *   @param {Object} config An object containing one or more style properties, a duration and an easing.
15459  *   @param {Function} callback A function to run after the transition has completed. The callback fires
15460  *       once per item in the NodeList.
15461  *   @chainable
15462 */
15463 Y.NodeList.prototype.transition = function(config, callback) {
15464     var nodes = this._nodes,
15465         i = 0,
15466         node;
15467
15468     while ((node = nodes[i++])) {
15469         Y.one(node).transition(config, callback);
15470     }
15471
15472     return this;
15473 };
15474
15475 Y.Node.prototype.toggleView = function(name, on) {
15476     var callback;
15477     this._toggles = this._toggles || [];
15478
15479     if (typeof name == 'boolean') { // no transition, just toggle
15480         on = name;
15481     }
15482     if (typeof on === 'undefined' && name in this._toggles) {
15483         on = ! this._toggles[name];
15484     }
15485
15486     on = (on) ? 1 : 0;
15487
15488     if (on) {
15489         this._show();
15490     }  else {
15491         callback = _wrapCallBack(anim, this._hide);
15492     }
15493
15494     this._toggles[name] = on;
15495     this.transition(Y.Transition.toggles[name][on], callback);
15496 };
15497
15498 Y.NodeList.prototype.toggleView = function(config, callback) {
15499     var nodes = this._nodes,
15500         i = 0,
15501         node;
15502
15503     while ((node = nodes[i++])) {
15504         Y.one(node).toggleView(config, callback);
15505     }
15506
15507     return this;
15508 };
15509
15510 Y.mix(Transition.fx, {
15511     fadeOut: {
15512         opacity: 0,
15513         duration: 0.5,
15514         easing: 'ease-out'
15515     },
15516
15517     fadeIn: {
15518         opacity: 1,
15519         duration: 0.5,
15520         easing: 'ease-in'
15521     },
15522
15523     sizeOut: {
15524         height: 0,
15525         width: 0,
15526         duration: 0.75,
15527         easing: 'ease-out'
15528     },
15529
15530     sizeIn: {
15531         height: function(node) {
15532             return node.get('scrollHeight') + 'px';
15533         },
15534         width: function(node) {
15535             return node.get('scrollWidth') + 'px';
15536         },
15537         duration: 0.5,
15538         easing: 'ease-in',
15539         
15540         on: {
15541             start: function() {
15542                 var overflow = this.getStyle('overflow');
15543                 if (overflow !== 'hidden') { // enable scrollHeight/Width
15544                     this.setStyle('overflow', 'hidden');
15545                     this._transitionOverflow = overflow;
15546                 }
15547             },
15548
15549             end: function() {
15550                 if (this._transitionOverflow) { // revert overridden value
15551                     this.setStyle('overflow', this._transitionOverflow);
15552                 }
15553             }
15554         } 
15555     }
15556 });
15557
15558 Y.mix(Transition.toggles, {
15559     size: ['sizeIn', 'sizeOut'],
15560     fade: ['fadeOut', 'fadeIn']
15561 });
15562
15563
15564 }, '3.3.0' ,{requires:['node-base']});
15565 YUI.add('transition-timer', function(Y) {
15566
15567 /*
15568 * The Transition Utility provides an API for creating advanced transitions.
15569 * @module transition
15570 */
15571
15572 /*
15573 * Provides the base Transition class, for animating numeric properties.
15574 *
15575 * @module transition
15576 * @submodule transition-timer
15577 */
15578
15579
15580 var Transition = Y.Transition;
15581
15582 Y.mix(Transition.prototype, {
15583     _start: function() {
15584         if (Transition.useNative) {
15585             this._runNative();
15586         } else {
15587             this._runTimer();
15588         }
15589     },
15590
15591     _runTimer: function() {
15592         var anim = this;
15593         anim._initAttrs();
15594
15595         Transition._running[Y.stamp(anim)] = anim;
15596         anim._startTime = new Date();
15597         Transition._startTimer();
15598     },
15599
15600     _endTimer: function() {
15601         var anim = this;
15602         delete Transition._running[Y.stamp(anim)];
15603         anim._startTime = null;
15604     },
15605
15606     _runFrame: function() {
15607         var t = new Date() - this._startTime;
15608         this._runAttrs(t);
15609     },
15610
15611     _runAttrs: function(time) {
15612         var anim = this,
15613             node = anim._node,
15614             config = anim._config,
15615             uid = Y.stamp(node),
15616             attrs = Transition._nodeAttrs[uid],
15617             customAttr = Transition.behaviors,
15618             done = false,
15619             allDone = false,
15620             data,
15621             name,
15622             attribute,
15623             setter,
15624             elapsed,
15625             delay,
15626             d,
15627             t,
15628             i;
15629
15630         for (name in attrs) {
15631             attribute = attrs[name];
15632             if ((attribute && attribute.transition === anim)) {
15633                 d = attribute.duration;
15634                 delay = attribute.delay;
15635                 elapsed = (time - delay) / 1000;
15636                 t = time;
15637                 data = {
15638                     type: 'propertyEnd',
15639                     propertyName: name,
15640                     config: config,
15641                     elapsedTime: elapsed
15642                 };
15643
15644                 setter = (i in customAttr && 'set' in customAttr[i]) ?
15645                         customAttr[i].set : Transition.DEFAULT_SETTER;
15646
15647                 done = (t >= d);
15648
15649                 if (t > d) {
15650                     t = d;
15651                 }
15652
15653                 if (!delay || time >= delay) {
15654                     setter(anim, name, attribute.from, attribute.to, t - delay, d - delay,
15655                         attribute.easing, attribute.unit); 
15656
15657                     if (done) {
15658                         delete attrs[name];
15659                         anim._count--;
15660
15661                         if (config[name] && config[name].on && config[name].on.end) {
15662                             config[name].on.end.call(Y.one(node), data);
15663                         }
15664
15665                         //node.fire('transition:propertyEnd', data);
15666
15667                         if (!allDone && anim._count <= 0) {
15668                             allDone = true;
15669                             anim._end(elapsed);
15670                             anim._endTimer();
15671                         }
15672                     }
15673                 }
15674
15675             }
15676         }
15677     },
15678
15679     _initAttrs: function() {
15680         var anim = this,
15681             customAttr = Transition.behaviors,
15682             uid = Y.stamp(anim._node),
15683             attrs = Transition._nodeAttrs[uid],
15684             attribute,
15685             duration,
15686             delay,
15687             easing,
15688             val,
15689             name,
15690             mTo,
15691             mFrom,
15692             unit, begin, end;
15693
15694         for (name in attrs) {
15695             attribute = attrs[name];
15696             if (attrs.hasOwnProperty(name) && (attribute && attribute.transition === anim)) {
15697                 duration = attribute.duration * 1000;
15698                 delay = attribute.delay * 1000;
15699                 easing = attribute.easing;
15700                 val = attribute.value;
15701
15702                 // only allow supported properties
15703                 if (name in anim._node.style || name in Y.DOM.CUSTOM_STYLES) {
15704                     begin = (name in customAttr && 'get' in customAttr[name])  ?
15705                             customAttr[name].get(anim, name) : Transition.DEFAULT_GETTER(anim, name);
15706
15707                     mFrom = Transition.RE_UNITS.exec(begin);
15708                     mTo = Transition.RE_UNITS.exec(val);
15709
15710                     begin = mFrom ? mFrom[1] : begin;
15711                     end = mTo ? mTo[1] : val;
15712                     unit = mTo ? mTo[2] : mFrom ?  mFrom[2] : ''; // one might be zero TODO: mixed units
15713
15714                     if (!unit && Transition.RE_DEFAULT_UNIT.test(name)) {
15715                         unit = Transition.DEFAULT_UNIT;
15716                     }
15717
15718                     if (typeof easing === 'string') {
15719                         if (easing.indexOf('cubic-bezier') > -1) {
15720                             easing = easing.substring(13, easing.length - 1).split(',');
15721                         } else if (Transition.easings[easing]) {
15722                             easing = Transition.easings[easing];
15723                         }
15724                     }
15725
15726                     attribute.from = Number(begin);
15727                     attribute.to = Number(end);
15728                     attribute.unit = unit;
15729                     attribute.easing = easing;
15730                     attribute.duration = duration + delay;
15731                     attribute.delay = delay;
15732                 } else {
15733                     delete attrs[name];
15734                     anim._count--;
15735                 }
15736             }
15737         }
15738     },
15739
15740     destroy: function() {
15741         this.detachAll();
15742         this._node = null;
15743     }
15744 }, true);
15745
15746 Y.mix(Y.Transition, {
15747     _runtimeAttrs: {},
15748     /*
15749      * Regex of properties that should use the default unit.
15750      *
15751      * @property RE_DEFAULT_UNIT
15752      * @static
15753      */
15754     RE_DEFAULT_UNIT: /^width|height|top|right|bottom|left|margin.*|padding.*|border.*$/i,
15755
15756     /*
15757      * The default unit to use with properties that pass the RE_DEFAULT_UNIT test.
15758      *
15759      * @property DEFAULT_UNIT
15760      * @static
15761      */
15762     DEFAULT_UNIT: 'px',
15763
15764     /*
15765      * Time in milliseconds passed to setInterval for frame processing 
15766      *
15767      * @property intervalTime
15768      * @default 20
15769      * @static
15770      */
15771     intervalTime: 20,
15772
15773     /*
15774      * Bucket for custom getters and setters
15775      *
15776      * @property behaviors
15777      * @static
15778      */
15779     behaviors: {
15780         left: {
15781             get: function(anim, attr) {
15782                 return Y.DOM._getAttrOffset(anim._node, attr);
15783             }
15784         }
15785     },
15786
15787     /*
15788      * The default setter to use when setting object properties.
15789      *
15790      * @property DEFAULT_SETTER
15791      * @static
15792      */
15793     DEFAULT_SETTER: function(anim, att, from, to, elapsed, duration, fn, unit) {
15794         from = Number(from);
15795         to = Number(to);
15796
15797         var node = anim._node,
15798             val = Transition.cubicBezier(fn, elapsed / duration);
15799
15800         val = from + val[0] * (to - from);
15801
15802         if (node) {
15803             if (att in node.style || att in Y.DOM.CUSTOM_STYLES) {
15804                 unit = unit || '';
15805                 Y.DOM.setStyle(node, att, val + unit);
15806             }
15807         } else {
15808             anim._end();
15809         }
15810     },
15811
15812     /*
15813      * The default getter to use when getting object properties.
15814      *
15815      * @property DEFAULT_GETTER
15816      * @static
15817      */
15818     DEFAULT_GETTER: function(anim, att) {
15819         var node = anim._node,
15820             val = '';
15821
15822         if (att in node.style || att in Y.DOM.CUSTOM_STYLES) {
15823             val = Y.DOM.getComputedStyle(node, att);
15824         }
15825
15826         return val;
15827     },
15828
15829     _startTimer: function() {
15830         if (!Transition._timer) {
15831             Transition._timer = setInterval(Transition._runFrame, Transition.intervalTime);
15832         }
15833     },
15834
15835     _stopTimer: function() {
15836         clearInterval(Transition._timer);
15837         Transition._timer = null;
15838     },
15839
15840     /*
15841      * Called per Interval to handle each animation frame.
15842      * @method _runFrame
15843      * @private
15844      * @static
15845      */    
15846     _runFrame: function() {
15847         var done = true,
15848             anim;
15849         for (anim in Transition._running) {
15850             if (Transition._running[anim]._runFrame) {
15851                 done = false;
15852                 Transition._running[anim]._runFrame();
15853             }
15854         }
15855
15856         if (done) {
15857             Transition._stopTimer();
15858         }
15859     },
15860
15861     cubicBezier: function(p, t) {
15862         var x0 = 0,
15863             y0 = 0,
15864             x1 = p[0],
15865             y1 = p[1],
15866             x2 = p[2],
15867             y2 = p[3],
15868             x3 = 1,
15869             y3 = 0,
15870
15871             A = x3 - 3 * x2 + 3 * x1 - x0,
15872             B = 3 * x2 - 6 * x1 + 3 * x0,
15873             C = 3 * x1 - 3 * x0,
15874             D = x0,
15875             E = y3 - 3 * y2 + 3 * y1 - y0,
15876             F = 3 * y2 - 6 * y1 + 3 * y0,
15877             G = 3 * y1 - 3 * y0,
15878             H = y0,
15879
15880             x = (((A*t) + B)*t + C)*t + D,
15881             y = (((E*t) + F)*t + G)*t + H;
15882
15883         return [x, y];
15884     },
15885
15886     easings: {
15887         ease: [0.25, 0, 1, 0.25],
15888         linear: [0, 0, 1, 1],
15889         'ease-in': [0.42, 0, 1, 1],
15890         'ease-out': [0, 0, 0.58, 1],
15891         'ease-in-out': [0.42, 0, 0.58, 1]
15892     },
15893
15894     _running: {},
15895     _timer: null,
15896
15897     RE_UNITS: /^(-?\d*\.?\d*){1}(em|ex|px|in|cm|mm|pt|pc|%)*$/
15898 }, true); 
15899
15900 Transition.behaviors.top = Transition.behaviors.bottom = Transition.behaviors.right = Transition.behaviors.left;
15901
15902 Y.Transition = Transition;
15903
15904
15905 }, '3.3.0' ,{requires:['transition-native', 'node-style']});
15906
15907
15908 YUI.add('transition', function(Y){}, '3.3.0' ,{use:['transition-native', 'transition-timer']});
15909
15910 YUI.add('selector-css3', function(Y) {
15911
15912 /**
15913  * The selector css3 module provides support for css3 selectors.
15914  * @module dom
15915  * @submodule selector-css3
15916  * @for Selector
15917  */
15918
15919 /*
15920     an+b = get every _a_th node starting at the _b_th
15921     0n+b = no repeat ("0" and "n" may both be omitted (together) , e.g. "0n+1" or "1", not "0+1"), return only the _b_th element
15922     1n+b =  get every element starting from b ("1" may may be omitted, e.g. "1n+0" or "n+0" or "n")
15923     an+0 = get every _a_th element, "0" may be omitted 
15924 */
15925
15926 Y.Selector._reNth = /^(?:([\-]?\d*)(n){1}|(odd|even)$)*([\-+]?\d*)$/;
15927
15928 Y.Selector._getNth = function(node, expr, tag, reverse) {
15929     Y.Selector._reNth.test(expr);
15930     var a = parseInt(RegExp.$1, 10), // include every _a_ elements (zero means no repeat, just first _a_)
15931         n = RegExp.$2, // "n"
15932         oddeven = RegExp.$3, // "odd" or "even"
15933         b = parseInt(RegExp.$4, 10) || 0, // start scan from element _b_
15934         result = [],
15935         siblings = Y.Selector._children(node.parentNode, tag),
15936         op;
15937
15938     if (oddeven) {
15939         a = 2; // always every other
15940         op = '+';
15941         n = 'n';
15942         b = (oddeven === 'odd') ? 1 : 0;
15943     } else if ( isNaN(a) ) {
15944         a = (n) ? 1 : 0; // start from the first or no repeat
15945     }
15946
15947     if (a === 0) { // just the first
15948         if (reverse) {
15949             b = siblings.length - b + 1; 
15950         }
15951
15952         if (siblings[b - 1] === node) {
15953             return true;
15954         } else {
15955             return false;
15956         }
15957
15958     } else if (a < 0) {
15959         reverse = !!reverse;
15960         a = Math.abs(a);
15961     }
15962
15963     if (!reverse) {
15964         for (var i = b - 1, len = siblings.length; i < len; i += a) {
15965             if ( i >= 0 && siblings[i] === node ) {
15966                 return true;
15967             }
15968         }
15969     } else {
15970         for (var i = siblings.length - b, len = siblings.length; i >= 0; i -= a) {
15971             if ( i < len && siblings[i] === node ) {
15972                 return true;
15973             }
15974         }
15975     }
15976     return false;
15977 };
15978
15979 Y.mix(Y.Selector.pseudos, {
15980     'root': function(node) {
15981         return node === node.ownerDocument.documentElement;
15982     },
15983
15984     'nth-child': function(node, expr) {
15985         return Y.Selector._getNth(node, expr);
15986     },
15987
15988     'nth-last-child': function(node, expr) {
15989         return Y.Selector._getNth(node, expr, null, true);
15990     },
15991
15992     'nth-of-type': function(node, expr) {
15993         return Y.Selector._getNth(node, expr, node.tagName);
15994     },
15995      
15996     'nth-last-of-type': function(node, expr) {
15997         return Y.Selector._getNth(node, expr, node.tagName, true);
15998     },
15999      
16000     'last-child': function(node) {
16001         var children = Y.Selector._children(node.parentNode);
16002         return children[children.length - 1] === node;
16003     },
16004
16005     'first-of-type': function(node) {
16006         return Y.Selector._children(node.parentNode, node.tagName)[0] === node;
16007     },
16008      
16009     'last-of-type': function(node) {
16010         var children = Y.Selector._children(node.parentNode, node.tagName);
16011         return children[children.length - 1] === node;
16012     },
16013      
16014     'only-child': function(node) {
16015         var children = Y.Selector._children(node.parentNode);
16016         return children.length === 1 && children[0] === node;
16017     },
16018
16019     'only-of-type': function(node) {
16020         var children = Y.Selector._children(node.parentNode, node.tagName);
16021         return children.length === 1 && children[0] === node;
16022     },
16023
16024     'empty': function(node) {
16025         return node.childNodes.length === 0;
16026     },
16027
16028     'not': function(node, expr) {
16029         return !Y.Selector.test(node, expr);
16030     },
16031
16032     'contains': function(node, expr) {
16033         var text = node.innerText || node.textContent || '';
16034         return text.indexOf(expr) > -1;
16035     },
16036
16037     'checked': function(node) {
16038         return (node.checked === true || node.selected === true);
16039     },
16040
16041     enabled: function(node) {
16042         return (node.disabled !== undefined && !node.disabled);
16043     },
16044
16045     disabled: function(node) {
16046         return (node.disabled);
16047     }
16048 });
16049
16050 Y.mix(Y.Selector.operators, {
16051     '^=': '^{val}', // Match starts with value
16052     '$=': '{val}$', // Match ends with value
16053     '*=': '{val}' // Match contains value as substring 
16054 });
16055
16056 Y.Selector.combinators['~'] = {
16057     axis: 'previousSibling'
16058 };
16059
16060
16061 }, '3.3.0' ,{requires:['dom-base', 'selector-native', 'selector-css2']});
16062 YUI.add('dom-style-ie', function(Y) {
16063
16064 (function(Y) {
16065 var HAS_LAYOUT = 'hasLayout',
16066     PX = 'px',
16067     FILTER = 'filter',
16068     FILTERS = 'filters',
16069     OPACITY = 'opacity',
16070     AUTO = 'auto',
16071
16072     BORDER_WIDTH = 'borderWidth',
16073     BORDER_TOP_WIDTH = 'borderTopWidth',
16074     BORDER_RIGHT_WIDTH = 'borderRightWidth',
16075     BORDER_BOTTOM_WIDTH = 'borderBottomWidth',
16076     BORDER_LEFT_WIDTH = 'borderLeftWidth',
16077     WIDTH = 'width',
16078     HEIGHT = 'height',
16079     TRANSPARENT = 'transparent',
16080     VISIBLE = 'visible',
16081     GET_COMPUTED_STYLE = 'getComputedStyle',
16082     UNDEFINED = undefined,
16083     documentElement = Y.config.doc.documentElement,
16084
16085     testFeature = Y.Features.test,
16086     addFeature = Y.Features.add,
16087
16088     // TODO: unit-less lineHeight (e.g. 1.22)
16089     re_unit = /^(\d[.\d]*)+(em|ex|px|gd|rem|vw|vh|vm|ch|mm|cm|in|pt|pc|deg|rad|ms|s|hz|khz|%){1}?/i,
16090
16091     isIE8 = (Y.UA.ie >= 8),
16092
16093     _getStyleObj = function(node) {
16094         return node.currentStyle || node.style;
16095     },
16096
16097     ComputedStyle = {
16098         CUSTOM_STYLES: {},
16099
16100         get: function(el, property) {
16101             var value = '',
16102                 current;
16103
16104             if (el) {
16105                     current = _getStyleObj(el)[property];
16106
16107                 if (property === OPACITY && Y.DOM.CUSTOM_STYLES[OPACITY]) {
16108                     value = Y.DOM.CUSTOM_STYLES[OPACITY].get(el);        
16109                 } else if (!current || (current.indexOf && current.indexOf(PX) > -1)) { // no need to convert
16110                     value = current;
16111                 } else if (Y.DOM.IE.COMPUTED[property]) { // use compute function
16112                     value = Y.DOM.IE.COMPUTED[property](el, property);
16113                 } else if (re_unit.test(current)) { // convert to pixel
16114                     value = ComputedStyle.getPixel(el, property) + PX;
16115                 } else {
16116                     value = current;
16117                 }
16118             }
16119
16120             return value;
16121         },
16122
16123         sizeOffsets: {
16124             width: ['Left', 'Right'],
16125             height: ['Top', 'Bottom'],
16126             top: ['Top'],
16127             bottom: ['Bottom']
16128         },
16129
16130         getOffset: function(el, prop) {
16131             var current = _getStyleObj(el)[prop],                     // value of "width", "top", etc.
16132                 capped = prop.charAt(0).toUpperCase() + prop.substr(1), // "Width", "Top", etc.
16133                 offset = 'offset' + capped,                             // "offsetWidth", "offsetTop", etc.
16134                 pixel = 'pixel' + capped,                               // "pixelWidth", "pixelTop", etc.
16135                 sizeOffsets = ComputedStyle.sizeOffsets[prop], 
16136                 mode = el.ownerDocument.compatMode,
16137                 value = '';
16138
16139             // IE pixelWidth incorrect for percent
16140             // manually compute by subtracting padding and border from offset size
16141             // NOTE: clientWidth/Height (size minus border) is 0 when current === AUTO so offsetHeight is used
16142             // reverting to auto from auto causes position stacking issues (old impl)
16143             if (current === AUTO || current.indexOf('%') > -1) {
16144                 value = el['offset' + capped];
16145
16146                 if (mode !== 'BackCompat') {
16147                     if (sizeOffsets[0]) {
16148                         value -= ComputedStyle.getPixel(el, 'padding' + sizeOffsets[0]);
16149                         value -= ComputedStyle.getBorderWidth(el, 'border' + sizeOffsets[0] + 'Width', 1);
16150                     }
16151
16152                     if (sizeOffsets[1]) {
16153                         value -= ComputedStyle.getPixel(el, 'padding' + sizeOffsets[1]);
16154                         value -= ComputedStyle.getBorderWidth(el, 'border' + sizeOffsets[1] + 'Width', 1);
16155                     }
16156                 }
16157
16158             } else { // use style.pixelWidth, etc. to convert to pixels
16159                 // need to map style.width to currentStyle (no currentStyle.pixelWidth)
16160                 if (!el.style[pixel] && !el.style[prop]) {
16161                     el.style[prop] = current;
16162                 }
16163                 value = el.style[pixel];
16164                 
16165             }
16166             return value + PX;
16167         },
16168
16169         borderMap: {
16170             thin: (isIE8) ? '1px' : '2px',
16171             medium: (isIE8) ? '3px': '4px', 
16172             thick: (isIE8) ? '5px' : '6px'
16173         },
16174
16175         getBorderWidth: function(el, property, omitUnit) {
16176             var unit = omitUnit ? '' : PX,
16177                 current = el.currentStyle[property];
16178
16179             if (current.indexOf(PX) < 0) { // look up keywords if a border exists
16180                 if (ComputedStyle.borderMap[current] &&
16181                         el.currentStyle.borderStyle !== 'none') {
16182                     current = ComputedStyle.borderMap[current];
16183                 } else { // otherwise no border (default is "medium")
16184                     current = 0;
16185                 }
16186             }
16187             return (omitUnit) ? parseFloat(current) : current;
16188         },
16189
16190         getPixel: function(node, att) {
16191             // use pixelRight to convert to px
16192             var val = null,
16193                 style = _getStyleObj(node),
16194                 styleRight = style.right,
16195                 current = style[att];
16196
16197             node.style.right = current;
16198             val = node.style.pixelRight;
16199             node.style.right = styleRight; // revert
16200
16201             return val;
16202         },
16203
16204         getMargin: function(node, att) {
16205             var val,
16206                 style = _getStyleObj(node);
16207
16208             if (style[att] == AUTO) {
16209                 val = 0;
16210             } else {
16211                 val = ComputedStyle.getPixel(node, att);
16212             }
16213             return val + PX;
16214         },
16215
16216         getVisibility: function(node, att) {
16217             var current;
16218             while ( (current = node.currentStyle) && current[att] == 'inherit') { // NOTE: assignment in test
16219                 node = node.parentNode;
16220             }
16221             return (current) ? current[att] : VISIBLE;
16222         },
16223
16224         getColor: function(node, att) {
16225             var current = _getStyleObj(node)[att];
16226
16227             if (!current || current === TRANSPARENT) {
16228                 Y.DOM.elementByAxis(node, 'parentNode', null, function(parent) {
16229                     current = _getStyleObj(parent)[att];
16230                     if (current && current !== TRANSPARENT) {
16231                         node = parent;
16232                         return true;
16233                     }
16234                 });
16235             }
16236
16237             return Y.Color.toRGB(current);
16238         },
16239
16240         getBorderColor: function(node, att) {
16241             var current = _getStyleObj(node),
16242                 val = current[att] || current.color;
16243             return Y.Color.toRGB(Y.Color.toHex(val));
16244         }
16245     },
16246
16247     //fontSize: getPixelFont,
16248     IEComputed = {};
16249
16250 addFeature('style', 'computedStyle', {
16251     test: function() {
16252         return 'getComputedStyle' in Y.config.win;
16253     }
16254 });
16255
16256 addFeature('style', 'opacity', {
16257     test: function() {
16258         return 'opacity' in documentElement.style;
16259     }
16260 });
16261
16262 addFeature('style', 'filter', {
16263     test: function() {
16264         return 'filters' in documentElement;
16265     }
16266 });
16267
16268 // use alpha filter for IE opacity
16269 if (!testFeature('style', 'opacity') && testFeature('style', 'filter')) {
16270     Y.DOM.CUSTOM_STYLES[OPACITY] = {
16271         get: function(node) {
16272             var val = 100;
16273             try { // will error if no DXImageTransform
16274                 val = node[FILTERS]['DXImageTransform.Microsoft.Alpha'][OPACITY];
16275
16276             } catch(e) {
16277                 try { // make sure its in the document
16278                     val = node[FILTERS]('alpha')[OPACITY];
16279                 } catch(err) {
16280                 }
16281             }
16282             return val / 100;
16283         },
16284
16285         set: function(node, val, style) {
16286             var current,
16287                 styleObj = _getStyleObj(node),
16288                 currentFilter = styleObj[FILTER];
16289
16290             style = style || node.style;
16291             if (val === '') { // normalize inline style behavior
16292                 current = (OPACITY in styleObj) ? styleObj[OPACITY] : 1; // revert to original opacity
16293                 val = current;
16294             }
16295
16296             if (typeof currentFilter == 'string') { // in case not appended
16297                 style[FILTER] = currentFilter.replace(/alpha([^)]*\))/gi, '') +
16298                         ((val < 1) ? 'alpha(' + OPACITY + '=' + val * 100 + ')' : '');
16299
16300                 if (!style[FILTER]) {
16301                     style.removeAttribute(FILTER);
16302                 }
16303
16304                 if (!styleObj[HAS_LAYOUT]) {
16305                     style.zoom = 1; // needs layout 
16306                 }
16307             }
16308         }
16309     };
16310 }
16311
16312 try {
16313     Y.config.doc.createElement('div').style.height = '-1px';
16314 } catch(e) { // IE throws error on invalid style set; trap common cases
16315     Y.DOM.CUSTOM_STYLES.height = {
16316         set: function(node, val, style) {
16317             var floatVal = parseFloat(val);
16318             if (floatVal >= 0 || val === 'auto' || val === '') {
16319                 style.height = val;
16320             } else {
16321             }
16322         }
16323     };
16324
16325     Y.DOM.CUSTOM_STYLES.width = {
16326         set: function(node, val, style) {
16327             var floatVal = parseFloat(val);
16328             if (floatVal >= 0 || val === 'auto' || val === '') {
16329                 style.width = val;
16330             } else {
16331             }
16332         }
16333     };
16334 }
16335
16336 if (!testFeature('style', 'computedStyle')) {
16337     // TODO: top, right, bottom, left
16338     IEComputed[WIDTH] = IEComputed[HEIGHT] = ComputedStyle.getOffset;
16339
16340     IEComputed.color = IEComputed.backgroundColor = ComputedStyle.getColor;
16341
16342     IEComputed[BORDER_WIDTH] = IEComputed[BORDER_TOP_WIDTH] = IEComputed[BORDER_RIGHT_WIDTH] =
16343             IEComputed[BORDER_BOTTOM_WIDTH] = IEComputed[BORDER_LEFT_WIDTH] =
16344             ComputedStyle.getBorderWidth;
16345
16346     IEComputed.marginTop = IEComputed.marginRight = IEComputed.marginBottom =
16347             IEComputed.marginLeft = ComputedStyle.getMargin;
16348
16349     IEComputed.visibility = ComputedStyle.getVisibility;
16350     IEComputed.borderColor = IEComputed.borderTopColor =
16351             IEComputed.borderRightColor = IEComputed.borderBottomColor =
16352             IEComputed.borderLeftColor = ComputedStyle.getBorderColor;
16353
16354     Y.DOM[GET_COMPUTED_STYLE] = ComputedStyle.get; 
16355
16356     Y.namespace('DOM.IE');
16357     Y.DOM.IE.COMPUTED = IEComputed;
16358     Y.DOM.IE.ComputedStyle = ComputedStyle;
16359 }
16360
16361 })(Y);
16362
16363
16364 }, '3.3.0' ,{requires:['dom-style']});
16365 YUI.add('simpleyui', function(Y) {
16366
16367 // empty
16368
16369
16370
16371 }, '3.3.0' ,{use:['yui','oop','dom','event-custom-base','event-base','pluginhost','node','event-delegate','io-base','json-parse','transition','selector-css3','dom-style-ie','querystring-stringify-simple']});
16372 var Y = YUI().use('*');