Bug 7356 - Fix various typos and mis-spellings
[koha.git] / koha-tmpl / intranet-tmpl / prog / en / lib / yui / yuiloader / yuiloader-debug.js
1 /*
2 Copyright (c) 2009, Yahoo! Inc. All rights reserved.
3 Code licensed under the BSD License:
4 http://developer.yahoo.net/yui/license.txt
5 version: 2.8.0r4
6 */
7 /**
8  * The YAHOO object is the single global object used by YUI Library.  It
9  * contains utility function for setting up namespaces, inheritance, and
10  * logging.  YAHOO.util, YAHOO.widget, and YAHOO.example are namespaces
11  * created automatically for and used by the library.
12  * @module yahoo
13  * @title  YAHOO Global
14  */
15
16 /**
17  * YAHOO_config is not included as part of the library.  Instead it is an 
18  * object that can be defined by the implementer immediately before 
19  * including the YUI library.  The properties included in this object
20  * will be used to configure global properties needed as soon as the 
21  * library begins to load.
22  * @class YAHOO_config
23  * @static
24  */
25
26 /**
27  * A reference to a function that will be executed every time a YAHOO module
28  * is loaded.  As parameter, this function will receive the version
29  * information for the module. See <a href="YAHOO.env.html#getVersion">
30  * YAHOO.env.getVersion</a> for the description of the version data structure.
31  * @property listener
32  * @type Function
33  * @static
34  * @default undefined
35  */
36
37 /**
38  * Set to true if the library will be dynamically loaded after window.onload.
39  * Defaults to false 
40  * @property injecting
41  * @type boolean
42  * @static
43  * @default undefined
44  */
45
46 /**
47  * Instructs the yuiloader component to dynamically load yui components and
48  * their dependencies.  See the yuiloader documentation for more information
49  * about dynamic loading
50  * @property load
51  * @static
52  * @default undefined
53  * @see yuiloader
54  */
55
56 /**
57  * Forces the use of the supplied locale where applicable in the library
58  * @property locale
59  * @type string
60  * @static
61  * @default undefined
62  */
63
64 if (typeof YAHOO == "undefined" || !YAHOO) {
65     /**
66      * The YAHOO global namespace object.  If YAHOO is already defined, the
67      * existing YAHOO object will not be overwritten so that defined
68      * namespaces are preserved.
69      * @class YAHOO
70      * @static
71      */
72     var YAHOO = {};
73 }
74
75 /**
76  * Returns the namespace specified and creates it if it doesn't exist
77  * <pre>
78  * YAHOO.namespace("property.package");
79  * YAHOO.namespace("YAHOO.property.package");
80  * </pre>
81  * Either of the above would create YAHOO.property, then
82  * YAHOO.property.package
83  *
84  * Be careful when naming packages. Reserved words may work in some browsers
85  * and not others. For instance, the following will fail in Safari:
86  * <pre>
87  * YAHOO.namespace("really.long.nested.namespace");
88  * </pre>
89  * This fails because "long" is a future reserved word in ECMAScript
90  *
91  * For implementation code that uses YUI, do not create your components
92  * in the namespaces defined by YUI (
93  * <code>YAHOO.util</code>, 
94  * <code>YAHOO.widget</code>, 
95  * <code>YAHOO.lang</code>, 
96  * <code>YAHOO.tool</code>, 
97  * <code>YAHOO.example</code>, 
98  * <code>YAHOO.env</code>) -- create your own namespace (e.g., 'companyname').
99  *
100  * @method namespace
101  * @static
102  * @param  {String*} arguments 1-n namespaces to create 
103  * @return {Object}  A reference to the last namespace object created
104  */
105 YAHOO.namespace = function() {
106     var a=arguments, o=null, i, j, d;
107     for (i=0; i<a.length; i=i+1) {
108         d=(""+a[i]).split(".");
109         o=YAHOO;
110
111         // YAHOO is implied, so it is ignored if it is included
112         for (j=(d[0] == "YAHOO") ? 1 : 0; j<d.length; j=j+1) {
113             o[d[j]]=o[d[j]] || {};
114             o=o[d[j]];
115         }
116     }
117
118     return o;
119 };
120
121 /**
122  * Uses YAHOO.widget.Logger to output a log message, if the widget is
123  * available.
124  *
125  * @method log
126  * @static
127  * @param  {String}  msg  The message to log.
128  * @param  {String}  cat  The log category for the message.  Default
129  *                        categories are "info", "warn", "error", time".
130  *                        Custom categories can be used as well. (opt)
131  * @param  {String}  src  The source of the message (opt)
132  * @return {Boolean}      True if the log operation was successful.
133  */
134 YAHOO.log = function(msg, cat, src) {
135     var l=YAHOO.widget.Logger;
136     if(l && l.log) {
137         return l.log(msg, cat, src);
138     } else {
139         return false;
140     }
141 };
142
143 /**
144  * Registers a module with the YAHOO object
145  * @method register
146  * @static
147  * @param {String}   name    the name of the module (event, slider, etc)
148  * @param {Function} mainClass a reference to class in the module.  This
149  *                             class will be tagged with the version info
150  *                             so that it will be possible to identify the
151  *                             version that is in use when multiple versions
152  *                             have loaded
153  * @param {Object}   data      metadata object for the module.  Currently it
154  *                             is expected to contain a "version" property
155  *                             and a "build" property at minimum.
156  */
157 YAHOO.register = function(name, mainClass, data) {
158     var mods = YAHOO.env.modules, m, v, b, ls, i;
159
160     if (!mods[name]) {
161         mods[name] = { 
162             versions:[], 
163             builds:[] 
164         };
165     }
166
167     m  = mods[name];
168     v  = data.version;
169     b  = data.build;
170     ls = YAHOO.env.listeners;
171
172     m.name = name;
173     m.version = v;
174     m.build = b;
175     m.versions.push(v);
176     m.builds.push(b);
177     m.mainClass = mainClass;
178
179     // fire the module load listeners
180     for (i=0;i<ls.length;i=i+1) {
181         ls[i](m);
182     }
183     // label the main class
184     if (mainClass) {
185         mainClass.VERSION = v;
186         mainClass.BUILD = b;
187     } else {
188         YAHOO.log("mainClass is undefined for module " + name, "warn");
189     }
190 };
191
192 /**
193  * YAHOO.env is used to keep track of what is known about the YUI library and
194  * the browsing environment
195  * @class YAHOO.env
196  * @static
197  */
198 YAHOO.env = YAHOO.env || {
199
200     /**
201      * Keeps the version info for all YUI modules that have reported themselves
202      * @property modules
203      * @type Object[]
204      */
205     modules: [],
206     
207     /**
208      * List of functions that should be executed every time a YUI module
209      * reports itself.
210      * @property listeners
211      * @type Function[]
212      */
213     listeners: []
214 };
215
216 /**
217  * Returns the version data for the specified module:
218  *      <dl>
219  *      <dt>name:</dt>      <dd>The name of the module</dd>
220  *      <dt>version:</dt>   <dd>The version in use</dd>
221  *      <dt>build:</dt>     <dd>The build number in use</dd>
222  *      <dt>versions:</dt>  <dd>All versions that were registered</dd>
223  *      <dt>builds:</dt>    <dd>All builds that were registered.</dd>
224  *      <dt>mainClass:</dt> <dd>An object that was was stamped with the
225  *                 current version and build. If 
226  *                 mainClass.VERSION != version or mainClass.BUILD != build,
227  *                 multiple versions of pieces of the library have been
228  *                 loaded, potentially causing issues.</dd>
229  *       </dl>
230  *
231  * @method getVersion
232  * @static
233  * @param {String}  name the name of the module (event, slider, etc)
234  * @return {Object} The version info
235  */
236 YAHOO.env.getVersion = function(name) {
237     return YAHOO.env.modules[name] || null;
238 };
239
240 /**
241  * Do not fork for a browser if it can be avoided.  Use feature detection when
242  * you can.  Use the user agent as a last resort.  YAHOO.env.ua stores a version
243  * number for the browser engine, 0 otherwise.  This value may or may not map
244  * to the version number of the browser using the engine.  The value is 
245  * presented as a float so that it can easily be used for boolean evaluation 
246  * as well as for looking for a particular range of versions.  Because of this, 
247  * some of the granularity of the version info may be lost (e.g., Gecko 1.8.0.9 
248  * reports 1.8).
249  * @class YAHOO.env.ua
250  * @static
251  */
252 YAHOO.env.ua = function() {
253
254         var numberfy = function(s) {
255             var c = 0;
256             return parseFloat(s.replace(/\./g, function() {
257                 return (c++ == 1) ? '' : '.';
258             }));
259         },
260
261         nav = navigator,
262
263         o = {
264
265         /**
266          * Internet Explorer version number or 0.  Example: 6
267          * @property ie
268          * @type float
269          */
270         ie: 0,
271
272         /**
273          * Opera version number or 0.  Example: 9.2
274          * @property opera
275          * @type float
276          */
277         opera: 0,
278
279         /**
280          * Gecko engine revision number.  Will evaluate to 1 if Gecko 
281          * is detected but the revision could not be found. Other browsers
282          * will be 0.  Example: 1.8
283          * <pre>
284          * Firefox 1.0.0.4: 1.7.8   <-- Reports 1.7
285          * Firefox 1.5.0.9: 1.8.0.9 <-- Reports 1.8
286          * Firefox 2.0.0.3: 1.8.1.3 <-- Reports 1.8
287          * Firefox 3 alpha: 1.9a4   <-- Reports 1.9
288          * </pre>
289          * @property gecko
290          * @type float
291          */
292         gecko: 0,
293
294         /**
295          * AppleWebKit version.  KHTML browsers that are not WebKit browsers 
296          * will evaluate to 1, other browsers 0.  Example: 418.9.1
297          * <pre>
298          * Safari 1.3.2 (312.6): 312.8.1 <-- Reports 312.8 -- currently the 
299          *                                   latest available for Mac OSX 10.3.
300          * Safari 2.0.2:         416     <-- hasOwnProperty introduced
301          * Safari 2.0.4:         418     <-- preventDefault fixed
302          * Safari 2.0.4 (419.3): 418.9.1 <-- One version of Safari may run
303          *                                   different versions of webkit
304          * Safari 2.0.4 (419.3): 419     <-- Tiger installations that have been
305          *                                   updated, but not updated
306          *                                   to the latest patch.
307          * Webkit 212 nightly:   522+    <-- Safari 3.0 precursor (with native SVG
308          *                                   and many major issues fixed).  
309          * 3.x yahoo.com, flickr:422     <-- Safari 3.x hacks the user agent
310          *                                   string when hitting yahoo.com and 
311          *                                   flickr.com.
312          * Safari 3.0.4 (523.12):523.12  <-- First Tiger release - automatic update
313          *                                   from 2.x via the 10.4.11 OS patch
314          * Webkit nightly 1/2008:525+    <-- Supports DOMContentLoaded event.
315          *                                   yahoo.com user agent hack removed.
316          *                                   
317          * </pre>
318          * http://developer.apple.com/internet/safari/uamatrix.html
319          * @property webkit
320          * @type float
321          */
322         webkit: 0,
323
324         /**
325          * The mobile property will be set to a string containing any relevant
326          * user agent information when a modern mobile browser is detected.
327          * Currently limited to Safari on the iPhone/iPod Touch, Nokia N-series
328          * devices with the WebKit-based browser, and Opera Mini.  
329          * @property mobile 
330          * @type string
331          */
332         mobile: null,
333
334         /**
335          * Adobe AIR version number or 0.  Only populated if webkit is detected.
336          * Example: 1.0
337          * @property air
338          * @type float
339          */
340         air: 0,
341
342         /**
343          * Google Caja version number or 0.
344          * @property caja
345          * @type float
346          */
347         caja: nav.cajaVersion,
348
349         /**
350          * Set to true if the page appears to be in SSL
351          * @property secure
352          * @type boolean
353          * @static
354          */
355         secure: false,
356
357         /**
358          * The operating system.  Currently only detecting windows or macintosh
359          * @property os
360          * @type string
361          * @static
362          */
363         os: null
364
365     },
366
367     ua = navigator && navigator.userAgent, 
368     
369     loc = window && window.location,
370
371     href = loc && loc.href,
372     
373     m;
374
375     o.secure = href && (href.toLowerCase().indexOf("https") === 0);
376
377     if (ua) {
378
379         if ((/windows|win32/i).test(ua)) {
380             o.os = 'windows';
381         } else if ((/macintosh/i).test(ua)) {
382             o.os = 'macintosh';
383         }
384     
385         // Modern KHTML browsers should qualify as Safari X-Grade
386         if ((/KHTML/).test(ua)) {
387             o.webkit=1;
388         }
389
390         // Modern WebKit browsers are at least X-Grade
391         m=ua.match(/AppleWebKit\/([^\s]*)/);
392         if (m&&m[1]) {
393             o.webkit=numberfy(m[1]);
394
395             // Mobile browser check
396             if (/ Mobile\//.test(ua)) {
397                 o.mobile = "Apple"; // iPhone or iPod Touch
398             } else {
399                 m=ua.match(/NokiaN[^\/]*/);
400                 if (m) {
401                     o.mobile = m[0]; // Nokia N-series, ex: NokiaN95
402                 }
403             }
404
405             m=ua.match(/AdobeAIR\/([^\s]*)/);
406             if (m) {
407                 o.air = m[0]; // Adobe AIR 1.0 or better
408             }
409
410         }
411
412         if (!o.webkit) { // not webkit
413             // @todo check Opera/8.01 (J2ME/MIDP; Opera Mini/2.0.4509/1316; fi; U; ssr)
414             m=ua.match(/Opera[\s\/]([^\s]*)/);
415             if (m&&m[1]) {
416                 o.opera=numberfy(m[1]);
417                 m=ua.match(/Opera Mini[^;]*/);
418                 if (m) {
419                     o.mobile = m[0]; // ex: Opera Mini/2.0.4509/1316
420                 }
421             } else { // not opera or webkit
422                 m=ua.match(/MSIE\s([^;]*)/);
423                 if (m&&m[1]) {
424                     o.ie=numberfy(m[1]);
425                 } else { // not opera, webkit, or ie
426                     m=ua.match(/Gecko\/([^\s]*)/);
427                     if (m) {
428                         o.gecko=1; // Gecko detected, look for revision
429                         m=ua.match(/rv:([^\s\)]*)/);
430                         if (m&&m[1]) {
431                             o.gecko=numberfy(m[1]);
432                         }
433                     }
434                 }
435             }
436         }
437     }
438
439     return o;
440 }();
441
442 /*
443  * Initializes the global by creating the default namespaces and applying
444  * any new configuration information that is detected.  This is the setup
445  * for env.
446  * @method init
447  * @static
448  * @private
449  */
450 (function() {
451     YAHOO.namespace("util", "widget", "example");
452     /*global YAHOO_config*/
453     if ("undefined" !== typeof YAHOO_config) {
454         var l=YAHOO_config.listener, ls=YAHOO.env.listeners,unique=true, i;
455         if (l) {
456             // if YAHOO is loaded multiple times we need to check to see if
457             // this is a new config object.  If it is, add the new component
458             // load listener to the stack
459             for (i=0; i<ls.length; i++) {
460                 if (ls[i] == l) {
461                     unique = false;
462                     break;
463                 }
464             }
465
466             if (unique) {
467                 ls.push(l);
468             }
469         }
470     }
471 })();
472 /**
473  * Provides the language utilites and extensions used by the library
474  * @class YAHOO.lang
475  */
476 YAHOO.lang = YAHOO.lang || {};
477
478 (function() {
479
480
481 var L = YAHOO.lang,
482
483     OP = Object.prototype,
484     ARRAY_TOSTRING = '[object Array]',
485     FUNCTION_TOSTRING = '[object Function]',
486     OBJECT_TOSTRING = '[object Object]',
487     NOTHING = [],
488
489     // ADD = ["toString", "valueOf", "hasOwnProperty"],
490     ADD = ["toString", "valueOf"],
491
492     OB = {
493
494     /**
495      * Determines wheather or not the provided object is an array.
496      * @method isArray
497      * @param {any} o The object being testing
498      * @return {boolean} the result
499      */
500     isArray: function(o) { 
501         return OP.toString.apply(o) === ARRAY_TOSTRING;
502     },
503
504     /**
505      * Determines whether or not the provided object is a boolean
506      * @method isBoolean
507      * @param {any} o The object being testing
508      * @return {boolean} the result
509      */
510     isBoolean: function(o) {
511         return typeof o === 'boolean';
512     },
513     
514     /**
515      * Determines whether or not the provided object is a function.
516      * Note: Internet Explorer thinks certain functions are objects:
517      *
518      * var obj = document.createElement("object");
519      * YAHOO.lang.isFunction(obj.getAttribute) // reports false in IE
520      *
521      * var input = document.createElement("input"); // append to body
522      * YAHOO.lang.isFunction(input.focus) // reports false in IE
523      *
524      * You will have to implement additional tests if these functions
525      * matter to you.
526      *
527      * @method isFunction
528      * @param {any} o The object being testing
529      * @return {boolean} the result
530      */
531     isFunction: function(o) {
532         return (typeof o === 'function') || OP.toString.apply(o) === FUNCTION_TOSTRING;
533     },
534         
535     /**
536      * Determines whether or not the provided object is null
537      * @method isNull
538      * @param {any} o The object being testing
539      * @return {boolean} the result
540      */
541     isNull: function(o) {
542         return o === null;
543     },
544         
545     /**
546      * Determines whether or not the provided object is a legal number
547      * @method isNumber
548      * @param {any} o The object being testing
549      * @return {boolean} the result
550      */
551     isNumber: function(o) {
552         return typeof o === 'number' && isFinite(o);
553     },
554       
555     /**
556      * Determines whether or not the provided object is of type object
557      * or function
558      * @method isObject
559      * @param {any} o The object being testing
560      * @return {boolean} the result
561      */  
562     isObject: function(o) {
563 return (o && (typeof o === 'object' || L.isFunction(o))) || false;
564     },
565         
566     /**
567      * Determines whether or not the provided object is a string
568      * @method isString
569      * @param {any} o The object being testing
570      * @return {boolean} the result
571      */
572     isString: function(o) {
573         return typeof o === 'string';
574     },
575         
576     /**
577      * Determines whether or not the provided object is undefined
578      * @method isUndefined
579      * @param {any} o The object being testing
580      * @return {boolean} the result
581      */
582     isUndefined: function(o) {
583         return typeof o === 'undefined';
584     },
585     
586  
587     /**
588      * IE will not enumerate native functions in a derived object even if the
589      * function was overridden.  This is a workaround for specific functions 
590      * we care about on the Object prototype. 
591      * @property _IEEnumFix
592      * @param {Function} r  the object to receive the augmentation
593      * @param {Function} s  the object that supplies the properties to augment
594      * @static
595      * @private
596      */
597     _IEEnumFix: (YAHOO.env.ua.ie) ? function(r, s) {
598             var i, fname, f;
599             for (i=0;i<ADD.length;i=i+1) {
600
601                 fname = ADD[i];
602                 f = s[fname];
603
604                 if (L.isFunction(f) && f!=OP[fname]) {
605                     r[fname]=f;
606                 }
607             }
608     } : function(){},
609        
610     /**
611      * Utility to set up the prototype, constructor and superclass properties to
612      * support an inheritance strategy that can chain constructors and methods.
613      * Static members will not be inherited.
614      *
615      * @method extend
616      * @static
617      * @param {Function} subc   the object to modify
618      * @param {Function} superc the object to inherit
619      * @param {Object} overrides  additional properties/methods to add to the
620      *                              subclass prototype.  These will override the
621      *                              matching items obtained from the superclass 
622      *                              if present.
623      */
624     extend: function(subc, superc, overrides) {
625         if (!superc||!subc) {
626             throw new Error("extend failed, please check that " +
627                             "all dependencies are included.");
628         }
629         var F = function() {}, i;
630         F.prototype=superc.prototype;
631         subc.prototype=new F();
632         subc.prototype.constructor=subc;
633         subc.superclass=superc.prototype;
634         if (superc.prototype.constructor == OP.constructor) {
635             superc.prototype.constructor=superc;
636         }
637     
638         if (overrides) {
639             for (i in overrides) {
640                 if (L.hasOwnProperty(overrides, i)) {
641                     subc.prototype[i]=overrides[i];
642                 }
643             }
644
645             L._IEEnumFix(subc.prototype, overrides);
646         }
647     },
648    
649     /**
650      * Applies all properties in the supplier to the receiver if the
651      * receiver does not have these properties yet.  Optionally, one or 
652      * more methods/properties can be specified (as additional 
653      * parameters).  This option will overwrite the property if receiver 
654      * has it already.  If true is passed as the third parameter, all 
655      * properties will be applied and _will_ overwrite properties in 
656      * the receiver.
657      *
658      * @method augmentObject
659      * @static
660      * @since 2.3.0
661      * @param {Function} r  the object to receive the augmentation
662      * @param {Function} s  the object that supplies the properties to augment
663      * @param {String*|boolean}  arguments zero or more properties methods 
664      *        to augment the receiver with.  If none specified, everything
665      *        in the supplier will be used unless it would
666      *        overwrite an existing property in the receiver. If true
667      *        is specified as the third parameter, all properties will
668      *        be applied and will overwrite an existing property in
669      *        the receiver
670      */
671     augmentObject: function(r, s) {
672         if (!s||!r) {
673             throw new Error("Absorb failed, verify dependencies.");
674         }
675         var a=arguments, i, p, overrideList=a[2];
676         if (overrideList && overrideList!==true) { // only absorb the specified properties
677             for (i=2; i<a.length; i=i+1) {
678                 r[a[i]] = s[a[i]];
679             }
680         } else { // take everything, overwriting only if the third parameter is true
681             for (p in s) { 
682                 if (overrideList || !(p in r)) {
683                     r[p] = s[p];
684                 }
685             }
686             
687             L._IEEnumFix(r, s);
688         }
689     },
690  
691     /**
692      * Same as YAHOO.lang.augmentObject, except it only applies prototype properties
693      * @see YAHOO.lang.augmentObject
694      * @method augmentProto
695      * @static
696      * @param {Function} r  the object to receive the augmentation
697      * @param {Function} s  the object that supplies the properties to augment
698      * @param {String*|boolean}  arguments zero or more properties methods 
699      *        to augment the receiver with.  If none specified, everything 
700      *        in the supplier will be used unless it would overwrite an existing 
701      *        property in the receiver.  if true is specified as the third 
702      *        parameter, all properties will be applied and will overwrite an 
703      *        existing property in the receiver
704      */
705     augmentProto: function(r, s) {
706         if (!s||!r) {
707             throw new Error("Augment failed, verify dependencies.");
708         }
709         //var a=[].concat(arguments);
710         var a=[r.prototype,s.prototype], i;
711         for (i=2;i<arguments.length;i=i+1) {
712             a.push(arguments[i]);
713         }
714         L.augmentObject.apply(this, a);
715     },
716
717       
718     /**
719      * Returns a simple string representation of the object or array.
720      * Other types of objects will be returned unprocessed.  Arrays
721      * are expected to be indexed.  Use object notation for
722      * associative arrays.
723      * @method dump
724      * @since 2.3.0
725      * @param o {Object} The object to dump
726      * @param d {int} How deep to recurse child objects, default 3
727      * @return {String} the dump result
728      */
729     dump: function(o, d) {
730         var i,len,s=[],OBJ="{...}",FUN="f(){...}",
731             COMMA=', ', ARROW=' => ';
732
733         // Cast non-objects to string
734         // Skip dates because the std toString is what we want
735         // Skip HTMLElement-like objects because trying to dump 
736         // an element will cause an unhandled exception in FF 2.x
737         if (!L.isObject(o)) {
738             return o + "";
739         } else if (o instanceof Date || ("nodeType" in o && "tagName" in o)) {
740             return o;
741         } else if  (L.isFunction(o)) {
742             return FUN;
743         }
744
745         // dig into child objects the depth specifed. Default 3
746         d = (L.isNumber(d)) ? d : 3;
747
748         // arrays [1, 2, 3]
749         if (L.isArray(o)) {
750             s.push("[");
751             for (i=0,len=o.length;i<len;i=i+1) {
752                 if (L.isObject(o[i])) {
753                     s.push((d > 0) ? L.dump(o[i], d-1) : OBJ);
754                 } else {
755                     s.push(o[i]);
756                 }
757                 s.push(COMMA);
758             }
759             if (s.length > 1) {
760                 s.pop();
761             }
762             s.push("]");
763         // objects {k1 => v1, k2 => v2}
764         } else {
765             s.push("{");
766             for (i in o) {
767                 if (L.hasOwnProperty(o, i)) {
768                     s.push(i + ARROW);
769                     if (L.isObject(o[i])) {
770                         s.push((d > 0) ? L.dump(o[i], d-1) : OBJ);
771                     } else {
772                         s.push(o[i]);
773                     }
774                     s.push(COMMA);
775                 }
776             }
777             if (s.length > 1) {
778                 s.pop();
779             }
780             s.push("}");
781         }
782
783         return s.join("");
784     },
785
786     /**
787      * Does variable substitution on a string. It scans through the string 
788      * looking for expressions enclosed in { } braces. If an expression 
789      * is found, it is used a key on the object.  If there is a space in
790      * the key, the first word is used for the key and the rest is provided
791      * to an optional function to be used to programatically determine the
792      * value (the extra information might be used for this decision). If 
793      * the value for the key in the object, or what is returned from the
794      * function has a string value, number value, or object value, it is 
795      * substituted for the bracket expression and it repeats.  If this
796      * value is an object, it uses the Object's toString() if this has
797      * been overridden, otherwise it does a shallow dump of the key/value
798      * pairs.
799      * @method substitute
800      * @since 2.3.0
801      * @param s {String} The string that will be modified.
802      * @param o {Object} An object containing the replacement values
803      * @param f {Function} An optional function that can be used to
804      *                     process each match.  It receives the key,
805      *                     value, and any extra metadata included with
806      *                     the key inside of the braces.
807      * @return {String} the substituted string
808      */
809     substitute: function (s, o, f) {
810         var i, j, k, key, v, meta, saved=[], token, 
811             DUMP='dump', SPACE=' ', LBRACE='{', RBRACE='}',
812             dump, objstr;
813
814
815         for (;;) {
816             i = s.lastIndexOf(LBRACE);
817             if (i < 0) {
818                 break;
819             }
820             j = s.indexOf(RBRACE, i);
821             if (i + 1 >= j) {
822                 break;
823             }
824
825             //Extract key and meta info 
826             token = s.substring(i + 1, j);
827             key = token;
828             meta = null;
829             k = key.indexOf(SPACE);
830             if (k > -1) {
831                 meta = key.substring(k + 1);
832                 key = key.substring(0, k);
833             }
834
835             // lookup the value
836             v = o[key];
837
838             // if a substitution function was provided, execute it
839             if (f) {
840                 v = f(key, v, meta);
841             }
842
843             if (L.isObject(v)) {
844                 if (L.isArray(v)) {
845                     v = L.dump(v, parseInt(meta, 10));
846                 } else {
847                     meta = meta || "";
848
849                     // look for the keyword 'dump', if found force obj dump
850                     dump = meta.indexOf(DUMP);
851                     if (dump > -1) {
852                         meta = meta.substring(4);
853                     }
854
855                     objstr = v.toString();
856
857                     // use the toString if it is not the Object toString 
858                     // and the 'dump' meta info was not found
859                     if (objstr === OBJECT_TOSTRING || dump > -1) {
860                         v = L.dump(v, parseInt(meta, 10));
861                     } else {
862                         v = objstr;
863                     }
864                 }
865             } else if (!L.isString(v) && !L.isNumber(v)) {
866                 // This {block} has no replace string. Save it for later.
867                 v = "~-" + saved.length + "-~";
868                 saved[saved.length] = token;
869
870                 // break;
871             }
872
873             s = s.substring(0, i) + v + s.substring(j + 1);
874
875
876         }
877
878         // restore saved {block}s
879         for (i=saved.length-1; i>=0; i=i-1) {
880             s = s.replace(new RegExp("~-" + i + "-~"), "{"  + saved[i] + "}", "g");
881         }
882
883         return s;
884     },
885
886
887     /**
888      * Returns a string without any leading or trailing whitespace.  If 
889      * the input is not a string, the input will be returned untouched.
890      * @method trim
891      * @since 2.3.0
892      * @param s {string} the string to trim
893      * @return {string} the trimmed string
894      */
895     trim: function(s){
896         try {
897             return s.replace(/^\s+|\s+$/g, "");
898         } catch(e) {
899             return s;
900         }
901     },
902
903     /**
904      * Returns a new object containing all of the properties of
905      * all the supplied objects.  The properties from later objects
906      * will overwrite those in earlier objects.
907      * @method merge
908      * @since 2.3.0
909      * @param arguments {Object*} the objects to merge
910      * @return the new merged object
911      */
912     merge: function() {
913         var o={}, a=arguments, l=a.length, i;
914         for (i=0; i<l; i=i+1) {
915             L.augmentObject(o, a[i], true);
916         }
917         return o;
918     },
919
920     /**
921      * Executes the supplied function in the context of the supplied 
922      * object 'when' milliseconds later.  Executes the function a 
923      * single time unless periodic is set to true.
924      * @method later
925      * @since 2.4.0
926      * @param when {int} the number of milliseconds to wait until the fn 
927      * is executed
928      * @param o the context object
929      * @param fn {Function|String} the function to execute or the name of 
930      * the method in the 'o' object to execute
931      * @param data [Array] data that is provided to the function.  This accepts
932      * either a single item or an array.  If an array is provided, the
933      * function is executed with one parameter for each array item.  If
934      * you need to pass a single array parameter, it needs to be wrapped in
935      * an array [myarray]
936      * @param periodic {boolean} if true, executes continuously at supplied 
937      * interval until canceled
938      * @return a timer object. Call the cancel() method on this object to 
939      * stop the timer.
940      */
941     later: function(when, o, fn, data, periodic) {
942         when = when || 0; 
943         o = o || {};
944         var m=fn, d=data, f, r;
945
946         if (L.isString(fn)) {
947             m = o[fn];
948         }
949
950         if (!m) {
951             throw new TypeError("method undefined");
952         }
953
954         if (d && !L.isArray(d)) {
955             d = [data];
956         }
957
958         f = function() {
959             m.apply(o, d || NOTHING);
960         };
961
962         r = (periodic) ? setInterval(f, when) : setTimeout(f, when);
963
964         return {
965             interval: periodic,
966             cancel: function() {
967                 if (this.interval) {
968                     clearInterval(r);
969                 } else {
970                     clearTimeout(r);
971                 }
972             }
973         };
974     },
975     
976     /**
977      * A convenience method for detecting a legitimate non-null value.
978      * Returns false for null/undefined/NaN, true for other values, 
979      * including 0/false/''
980      * @method isValue
981      * @since 2.3.0
982      * @param o {any} the item to test
983      * @return {boolean} true if it is not null/undefined/NaN || false
984      */
985     isValue: function(o) {
986         // return (o || o === false || o === 0 || o === ''); // Infinity fails
987 return (L.isObject(o) || L.isString(o) || L.isNumber(o) || L.isBoolean(o));
988     }
989
990 };
991
992 /**
993  * Determines whether or not the property was added
994  * to the object instance.  Returns false if the property is not present
995  * in the object, or was inherited from the prototype.
996  * This abstraction is provided to enable hasOwnProperty for Safari 1.3.x.
997  * There is a discrepancy between YAHOO.lang.hasOwnProperty and
998  * Object.prototype.hasOwnProperty when the property is a primitive added to
999  * both the instance AND prototype with the same value:
1000  * <pre>
1001  * var A = function() {};
1002  * A.prototype.foo = 'foo';
1003  * var a = new A();
1004  * a.foo = 'foo';
1005  * alert(a.hasOwnProperty('foo')); // true
1006  * alert(YAHOO.lang.hasOwnProperty(a, 'foo')); // false when using fallback
1007  * </pre>
1008  * @method hasOwnProperty
1009  * @param {any} o The object being testing
1010  * @param prop {string} the name of the property to test
1011  * @return {boolean} the result
1012  */
1013 L.hasOwnProperty = (OP.hasOwnProperty) ?
1014     function(o, prop) {
1015         return o && o.hasOwnProperty(prop);
1016     } : function(o, prop) {
1017         return !L.isUndefined(o[prop]) && 
1018                 o.constructor.prototype[prop] !== o[prop];
1019     };
1020
1021 // new lang wins
1022 OB.augmentObject(L, OB, true);
1023
1024 /*
1025  * An alias for <a href="YAHOO.lang.html">YAHOO.lang</a>
1026  * @class YAHOO.util.Lang
1027  */
1028 YAHOO.util.Lang = L;
1029  
1030 /**
1031  * Same as YAHOO.lang.augmentObject, except it only applies prototype 
1032  * properties.  This is an alias for augmentProto.
1033  * @see YAHOO.lang.augmentObject
1034  * @method augment
1035  * @static
1036  * @param {Function} r  the object to receive the augmentation
1037  * @param {Function} s  the object that supplies the properties to augment
1038  * @param {String*|boolean}  arguments zero or more properties methods to 
1039  *        augment the receiver with.  If none specified, everything
1040  *        in the supplier will be used unless it would
1041  *        overwrite an existing property in the receiver.  if true
1042  *        is specified as the third parameter, all properties will
1043  *        be applied and will overwrite an existing property in
1044  *        the receiver
1045  */
1046 L.augment = L.augmentProto;
1047
1048 /**
1049  * An alias for <a href="YAHOO.lang.html#augment">YAHOO.lang.augment</a>
1050  * @for YAHOO
1051  * @method augment
1052  * @static
1053  * @param {Function} r  the object to receive the augmentation
1054  * @param {Function} s  the object that supplies the properties to augment
1055  * @param {String*}  arguments zero or more properties methods to 
1056  *        augment the receiver with.  If none specified, everything
1057  *        in the supplier will be used unless it would
1058  *        overwrite an existing property in the receiver
1059  */
1060 YAHOO.augment = L.augmentProto;
1061        
1062 /**
1063  * An alias for <a href="YAHOO.lang.html#extend">YAHOO.lang.extend</a>
1064  * @method extend
1065  * @static
1066  * @param {Function} subc   the object to modify
1067  * @param {Function} superc the object to inherit
1068  * @param {Object} overrides  additional properties/methods to add to the
1069  *        subclass prototype.  These will override the
1070  *        matching items obtained from the superclass if present.
1071  */
1072 YAHOO.extend = L.extend;
1073
1074 })();
1075 YAHOO.register("yahoo", YAHOO, {version: "2.8.0r4", build: "2449"});
1076 /**
1077  * Provides a mechanism to fetch remote resources and
1078  * insert them into a document
1079  * @module get
1080  * @requires yahoo
1081  */
1082
1083 /**
1084  * Fetches and inserts one or more script or link nodes into the document 
1085  * @namespace YAHOO.util
1086  * @class YAHOO.util.Get
1087  */
1088 YAHOO.util.Get = function() {
1089
1090     /**
1091      * hash of queues to manage multiple requests
1092      * @property queues
1093      * @private
1094      */
1095     var queues={}, 
1096         
1097     /**
1098      * queue index used to generate transaction ids
1099      * @property qidx
1100      * @type int
1101      * @private
1102      */
1103         qidx=0, 
1104         
1105     /**
1106      * node index used to generate unique node ids
1107      * @property nidx
1108      * @type int
1109      * @private
1110      */
1111         nidx=0, 
1112
1113         // ridx=0,
1114
1115         // sandboxFrame=null,
1116
1117     /**
1118      * interal property used to prevent multiple simultaneous purge 
1119      * processes
1120      * @property purging
1121      * @type boolean
1122      * @private
1123      */
1124         purging=false,
1125
1126         ua=YAHOO.env.ua, 
1127         
1128         lang=YAHOO.lang;
1129     
1130     /** 
1131      * Generates an HTML element, this is not appended to a document
1132      * @method _node
1133      * @param type {string} the type of element
1134      * @param attr {string} the attributes
1135      * @param win {Window} optional window to create the element in
1136      * @return {HTMLElement} the generated node
1137      * @private
1138      */
1139     var _node = function(type, attr, win) {
1140         var w = win || window, d=w.document, n=d.createElement(type);
1141
1142         for (var i in attr) {
1143             if (attr[i] && YAHOO.lang.hasOwnProperty(attr, i)) {
1144                 n.setAttribute(i, attr[i]);
1145             }
1146         }
1147
1148         return n;
1149     };
1150
1151     /**
1152      * Generates a link node
1153      * @method _linkNode
1154      * @param url {string} the url for the css file
1155      * @param win {Window} optional window to create the node in
1156      * @return {HTMLElement} the generated node
1157      * @private
1158      */
1159     var _linkNode = function(url, win, attributes) {
1160
1161         var o = {
1162             id:   "yui__dyn_" + (nidx++),
1163             type: "text/css",
1164             rel:  "stylesheet",
1165             href: url
1166         };
1167
1168         if (attributes) {
1169             lang.augmentObject(o, attributes);
1170         }
1171
1172         return _node("link", o, win);
1173     };
1174
1175     /**
1176      * Generates a script node
1177      * @method _scriptNode
1178      * @param url {string} the url for the script file
1179      * @param win {Window} optional window to create the node in
1180      * @return {HTMLElement} the generated node
1181      * @private
1182      */
1183     var _scriptNode = function(url, win, attributes) {
1184         var o = {
1185             id:   "yui__dyn_" + (nidx++),
1186             type: "text/javascript",
1187             src:  url
1188         };
1189
1190         if (attributes) {
1191             lang.augmentObject(o, attributes);
1192         }
1193
1194         return _node("script", o, win);
1195     };
1196
1197     /**
1198      * Returns the data payload for callback functions
1199      * @method _returnData
1200      * @private
1201      */
1202     var _returnData = function(q, msg) {
1203         return {
1204                 tId: q.tId,
1205                 win: q.win,
1206                 data: q.data,
1207                 nodes: q.nodes,
1208                 msg: msg,
1209                 purge: function() {
1210                     _purge(this.tId);
1211                 }
1212             };
1213     };
1214
1215     var _get = function(nId, tId) {
1216         var q = queues[tId],
1217             n = (lang.isString(nId)) ? q.win.document.getElementById(nId) : nId;
1218         if (!n) {
1219             _fail(tId, "target node not found: " + nId);
1220         }
1221
1222         return n;
1223     };
1224
1225     /*
1226      * The request failed, execute fail handler with whatever
1227      * was accomplished.  There isn't a failure case at the
1228      * moment unless you count aborted transactions
1229      * @method _fail
1230      * @param id {string} the id of the request
1231      * @private
1232      */
1233     var _fail = function(id, msg) {
1234         var q = queues[id];
1235         // execute failure callback
1236         if (q.onFailure) {
1237             var sc=q.scope || q.win;
1238             q.onFailure.call(sc, _returnData(q, msg));
1239         }
1240     };
1241
1242     /**
1243      * The request is complete, so executing the requester's callback
1244      * @method _finish
1245      * @param id {string} the id of the request
1246      * @private
1247      */
1248     var _finish = function(id) {
1249         var q = queues[id];
1250         q.finished = true;
1251
1252         if (q.aborted) {
1253             var msg = "transaction " + id + " was aborted";
1254             _fail(id, msg);
1255             return;
1256         }
1257
1258         // execute success callback
1259         if (q.onSuccess) {
1260             var sc=q.scope || q.win;
1261             q.onSuccess.call(sc, _returnData(q));
1262         }
1263     };
1264
1265     /**
1266      * Timeout detected
1267      * @method _timeout
1268      * @param id {string} the id of the request
1269      * @private
1270      */
1271     var _timeout = function(id) {
1272         var q = queues[id];
1273         if (q.onTimeout) {
1274             var sc=q.scope || q;
1275             q.onTimeout.call(sc, _returnData(q));
1276         }
1277     };
1278
1279     /**
1280      * Loads the next item for a given request
1281      * @method _next
1282      * @param id {string} the id of the request
1283      * @param loaded {string} the url that was just loaded, if any
1284      * @private
1285      */
1286     var _next = function(id, loaded) {
1287         var q = queues[id];
1288
1289         if (q.timer) {
1290             // Y.log('cancel timer');
1291             q.timer.cancel();
1292         }
1293
1294         if (q.aborted) {
1295             var msg = "transaction " + id + " was aborted";
1296             _fail(id, msg);
1297             return;
1298         }
1299
1300         if (loaded) {
1301             q.url.shift(); 
1302             if (q.varName) {
1303                 q.varName.shift(); 
1304             }
1305         } else {
1306             // This is the first pass: make sure the url is an array
1307             q.url = (lang.isString(q.url)) ? [q.url] : q.url;
1308             if (q.varName) {
1309                 q.varName = (lang.isString(q.varName)) ? [q.varName] : q.varName;
1310             }
1311         }
1312
1313         var w=q.win, d=w.document, h=d.getElementsByTagName("head")[0], n;
1314
1315         if (q.url.length === 0) {
1316             // Safari 2.x workaround - There is no way to know when 
1317             // a script is ready in versions of Safari prior to 3.x.
1318             // Adding an extra node reduces the problem, but doesn't
1319             // eliminate it completely because the browser executes
1320             // them asynchronously. 
1321             if (q.type === "script" && ua.webkit && ua.webkit < 420 && 
1322                     !q.finalpass && !q.varName) {
1323                 // Add another script node.  This does not guarantee that the
1324                 // scripts will execute in order, but it does appear to fix the
1325                 // problem on fast connections more effectively than using an
1326                 // arbitrary timeout.  It is possible that the browser does
1327                 // block subsequent script execution in this case for a limited
1328                 // time.
1329                 var extra = _scriptNode(null, q.win, q.attributes);
1330                 extra.innerHTML='YAHOO.util.Get._finalize("' + id + '");';
1331                 q.nodes.push(extra); h.appendChild(extra);
1332
1333             } else {
1334                 _finish(id);
1335             }
1336
1337             return;
1338         } 
1339
1340
1341         var url = q.url[0];
1342
1343         // if the url is undefined, this is probably a trailing comma problem in IE
1344         if (!url) {
1345             q.url.shift(); 
1346             return _next(id);
1347         }
1348
1349
1350         if (q.timeout) {
1351             // Y.log('create timer');
1352             q.timer = lang.later(q.timeout, q, _timeout, id);
1353         }
1354
1355         if (q.type === "script") {
1356             n = _scriptNode(url, w, q.attributes);
1357         } else {
1358             n = _linkNode(url, w, q.attributes);
1359         }
1360
1361         // track this node's load progress
1362         _track(q.type, n, id, url, w, q.url.length);
1363
1364         // add the node to the queue so we can return it to the user supplied callback
1365         q.nodes.push(n);
1366
1367         // add it to the head or insert it before 'insertBefore'
1368         if (q.insertBefore) {
1369             var s = _get(q.insertBefore, id);
1370             if (s) {
1371                 s.parentNode.insertBefore(n, s);
1372             }
1373         } else {
1374             h.appendChild(n);
1375         }
1376         
1377
1378         // FireFox does not support the onload event for link nodes, so there is
1379         // no way to make the css requests synchronous. This means that the css 
1380         // rules in multiple files could be applied out of order in this browser
1381         // if a later request returns before an earlier one.  Safari too.
1382         if ((ua.webkit || ua.gecko) && q.type === "css") {
1383             _next(id, url);
1384         }
1385     };
1386
1387     /**
1388      * Removes processed queues and corresponding nodes
1389      * @method _autoPurge
1390      * @private
1391      */
1392     var _autoPurge = function() {
1393
1394         if (purging) {
1395             return;
1396         }
1397
1398         purging = true;
1399         for (var i in queues) {
1400             var q = queues[i];
1401             if (q.autopurge && q.finished) {
1402                 _purge(q.tId);
1403                 delete queues[i];
1404             }
1405         }
1406
1407         purging = false;
1408     };
1409
1410     /**
1411      * Removes the nodes for the specified queue
1412      * @method _purge
1413      * @private
1414      */
1415     var _purge = function(tId) {
1416         if (queues[tId]) {
1417
1418             var q     = queues[tId],
1419                 nodes = q.nodes, 
1420                 l     = nodes.length, 
1421                 d     = q.win.document, 
1422                 h     = d.getElementsByTagName("head")[0],
1423                 sib, i, node, attr;
1424
1425             if (q.insertBefore) {
1426                 sib = _get(q.insertBefore, tId);
1427                 if (sib) {
1428                     h = sib.parentNode;
1429                 }
1430             }
1431
1432             for (i=0; i<l; i=i+1) {
1433                 node = nodes[i];
1434                 if (node.clearAttributes) {
1435                     node.clearAttributes();
1436                 } else {
1437                     for (attr in node) {
1438                         delete node[attr];
1439                     }
1440                 }
1441
1442                 h.removeChild(node);
1443             }
1444
1445             q.nodes = [];
1446         }
1447     };
1448
1449     /**
1450      * Saves the state for the request and begins loading
1451      * the requested urls
1452      * @method queue
1453      * @param type {string} the type of node to insert
1454      * @param url {string} the url to load
1455      * @param opts the hash of options for this request
1456      * @private
1457      */
1458     var _queue = function(type, url, opts) {
1459
1460         var id = "q" + (qidx++);
1461         opts = opts || {};
1462
1463         if (qidx % YAHOO.util.Get.PURGE_THRESH === 0) {
1464             _autoPurge();
1465         }
1466
1467         queues[id] = lang.merge(opts, {
1468             tId: id,
1469             type: type,
1470             url: url,
1471             finished: false,
1472             aborted: false,
1473             nodes: []
1474         });
1475
1476         var q = queues[id];
1477         q.win = q.win || window;
1478         q.scope = q.scope || q.win;
1479         q.autopurge = ("autopurge" in q) ? q.autopurge : 
1480                       (type === "script") ? true : false;
1481
1482         if (opts.charset) {
1483             q.attributes = q.attributes || {};
1484             q.attributes.charset = opts.charset;
1485         }
1486
1487         lang.later(0, q, _next, id);
1488
1489         return {
1490             tId: id
1491         };
1492     };
1493
1494     /**
1495      * Detects when a node has been loaded.  In the case of
1496      * script nodes, this does not guarantee that contained
1497      * script is ready to use.
1498      * @method _track
1499      * @param type {string} the type of node to track
1500      * @param n {HTMLElement} the node to track
1501      * @param id {string} the id of the request
1502      * @param url {string} the url that is being loaded
1503      * @param win {Window} the targeted window
1504      * @param qlength the number of remaining items in the queue,
1505      * including this one
1506      * @param trackfn {Function} function to execute when finished
1507      * the default is _next
1508      * @private
1509      */
1510     var _track = function(type, n, id, url, win, qlength, trackfn) {
1511         var f = trackfn || _next;
1512
1513         // IE supports the readystatechange event for script and css nodes
1514         if (ua.ie) {
1515             n.onreadystatechange = function() {
1516                 var rs = this.readyState;
1517                 if ("loaded" === rs || "complete" === rs) {
1518                     n.onreadystatechange = null;
1519                     f(id, url);
1520                 }
1521             };
1522
1523         // webkit prior to 3.x is problemmatic
1524         } else if (ua.webkit) {
1525
1526             if (type === "script") {
1527
1528                 // Safari 3.x supports the load event for script nodes (DOM2)
1529                 if (ua.webkit >= 420) {
1530
1531                     n.addEventListener("load", function() {
1532                         f(id, url);
1533                     });
1534
1535                 // Nothing can be done with Safari < 3.x except to pause and hope
1536                 // for the best, particularly after last script is inserted. The
1537                 // scripts will always execute in the order they arrive, not
1538                 // necessarily the order in which they were inserted.  To support
1539                 // script nodes with complete reliability in these browsers, script
1540                 // nodes either need to invoke a function in the window once they
1541                 // are loaded or the implementer needs to provide a well-known
1542                 // property that the utility can poll for.
1543                 } else {
1544                     // Poll for the existence of the named variable, if it
1545                     // was supplied.
1546                     var q = queues[id];
1547                     if (q.varName) {
1548                         var freq=YAHOO.util.Get.POLL_FREQ;
1549                         q.maxattempts = YAHOO.util.Get.TIMEOUT/freq;
1550                         q.attempts = 0;
1551                         q._cache = q.varName[0].split(".");
1552                         q.timer = lang.later(freq, q, function(o) {
1553                             var a=this._cache, l=a.length, w=this.win, i;
1554                             for (i=0; i<l; i=i+1) {
1555                                 w = w[a[i]];
1556                                 if (!w) {
1557                                     // if we have exausted our attempts, give up
1558                                     this.attempts++;
1559                                     if (this.attempts++ > this.maxattempts) {
1560                                         var msg = "Over retry limit, giving up";
1561                                         q.timer.cancel();
1562                                         _fail(id, msg);
1563                                     } else {
1564                                     }
1565                                     return;
1566                                 }
1567                             }
1568                             
1569
1570                             q.timer.cancel();
1571                             f(id, url);
1572
1573                         }, null, true);
1574                     } else {
1575                         lang.later(YAHOO.util.Get.POLL_FREQ, null, f, [id, url]);
1576                     }
1577                 }
1578             } 
1579
1580         // FireFox and Opera support onload (but not DOM2 in FF) handlers for
1581         // script nodes.  Opera, but not FF, supports the onload event for link
1582         // nodes.
1583         } else { 
1584             n.onload = function() {
1585                 f(id, url);
1586             };
1587         }
1588     };
1589
1590     return {
1591
1592         /**
1593          * The default poll freqency in ms, when needed
1594          * @property POLL_FREQ
1595          * @static
1596          * @type int
1597          * @default 10
1598          */
1599         POLL_FREQ: 10,
1600
1601         /**
1602          * The number of request required before an automatic purge.
1603          * property PURGE_THRESH
1604          * @static
1605          * @type int
1606          * @default 20
1607          */
1608         PURGE_THRESH: 20,
1609
1610         /**
1611          * The length time to poll for varName when loading a script in
1612          * Safari 2.x before the transaction fails.
1613          * property TIMEOUT
1614          * @static
1615          * @type int
1616          * @default 2000
1617          */
1618         TIMEOUT: 2000,
1619         
1620         /**
1621          * Called by the helper for detecting script load in Safari
1622          * @method _finalize
1623          * @param id {string} the transaction id
1624          * @private
1625          */
1626         _finalize: function(id) {
1627             lang.later(0, null, _finish, id);
1628         },
1629
1630         /**
1631          * Abort a transaction
1632          * @method abort
1633          * @param {string|object} either the tId or the object returned from
1634          * script() or css()
1635          */
1636         abort: function(o) {
1637             var id = (lang.isString(o)) ? o : o.tId;
1638             var q = queues[id];
1639             if (q) {
1640                 q.aborted = true;
1641             }
1642         }, 
1643
1644         /**
1645          * Fetches and inserts one or more script nodes into the head
1646          * of the current document or the document in a specified window.
1647          *
1648          * @method script
1649          * @static
1650          * @param url {string|string[]} the url or urls to the script(s)
1651          * @param opts {object} Options: 
1652          * <dl>
1653          * <dt>onSuccess</dt>
1654          * <dd>
1655          * callback to execute when the script(s) are finished loading
1656          * The callback receives an object back with the following
1657          * data:
1658          * <dl>
1659          * <dt>win</dt>
1660          * <dd>the window the script(s) were inserted into</dd>
1661          * <dt>data</dt>
1662          * <dd>the data object passed in when the request was made</dd>
1663          * <dt>nodes</dt>
1664          * <dd>An array containing references to the nodes that were
1665          * inserted</dd>
1666          * <dt>purge</dt>
1667          * <dd>A function that, when executed, will remove the nodes
1668          * that were inserted</dd>
1669          * <dt>
1670          * </dl>
1671          * </dd>
1672          * <dt>onFailure</dt>
1673          * <dd>
1674          * callback to execute when the script load operation fails
1675          * The callback receives an object back with the following
1676          * data:
1677          * <dl>
1678          * <dt>win</dt>
1679          * <dd>the window the script(s) were inserted into</dd>
1680          * <dt>data</dt>
1681          * <dd>the data object passed in when the request was made</dd>
1682          * <dt>nodes</dt>
1683          * <dd>An array containing references to the nodes that were
1684          * inserted successfully</dd>
1685          * <dt>purge</dt>
1686          * <dd>A function that, when executed, will remove any nodes
1687          * that were inserted</dd>
1688          * <dt>
1689          * </dl>
1690          * </dd>
1691          * <dt>onTimeout</dt>
1692          * <dd>
1693          * callback to execute when a timeout occurs.
1694          * The callback receives an object back with the following
1695          * data:
1696          * <dl>
1697          * <dt>win</dt>
1698          * <dd>the window the script(s) were inserted into</dd>
1699          * <dt>data</dt>
1700          * <dd>the data object passed in when the request was made</dd>
1701          * <dt>nodes</dt>
1702          * <dd>An array containing references to the nodes that were
1703          * inserted</dd>
1704          * <dt>purge</dt>
1705          * <dd>A function that, when executed, will remove the nodes
1706          * that were inserted</dd>
1707          * <dt>
1708          * </dl>
1709          * </dd>
1710          * <dt>scope</dt>
1711          * <dd>the execution context for the callbacks</dd>
1712          * <dt>win</dt>
1713          * <dd>a window other than the one the utility occupies</dd>
1714          * <dt>autopurge</dt>
1715          * <dd>
1716          * setting to true will let the utilities cleanup routine purge 
1717          * the script once loaded
1718          * </dd>
1719          * <dt>data</dt>
1720          * <dd>
1721          * data that is supplied to the callback when the script(s) are
1722          * loaded.
1723          * </dd>
1724          * <dt>varName</dt>
1725          * <dd>
1726          * variable that should be available when a script is finished
1727          * loading.  Used to help Safari 2.x and below with script load 
1728          * detection.  The type of this property should match what was
1729          * passed into the url parameter: if loading a single url, a
1730          * string can be supplied.  If loading multiple scripts, you
1731          * must supply an array that contains the variable name for
1732          * each script.
1733          * </dd>
1734          * <dt>insertBefore</dt>
1735          * <dd>node or node id that will become the new node's nextSibling</dd>
1736          * </dl>
1737          * <dt>charset</dt>
1738          * <dd>Node charset, deprecated, use 'attributes'</dd>
1739          * <dt>attributes</dt>
1740          * <dd>A hash of attributes to apply to dynamic nodes.</dd>
1741          * <dt>timeout</dt>
1742          * <dd>Number of milliseconds to wait before aborting and firing the timeout event</dd>
1743          * <pre>
1744          * // assumes yahoo, dom, and event are already on the page
1745          * &nbsp;&nbsp;YAHOO.util.Get.script(
1746          * &nbsp;&nbsp;["http://yui.yahooapis.com/2.7.0/build/dragdrop/dragdrop-min.js",
1747          * &nbsp;&nbsp;&nbsp;"http://yui.yahooapis.com/2.7.0/build/animation/animation-min.js"], &#123;
1748          * &nbsp;&nbsp;&nbsp;&nbsp;onSuccess: function(o) &#123;
1749          * &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;new YAHOO.util.DDProxy("dd1"); // also new o.reference("dd1"); would work
1750          * &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;this.log("won't cause error because YAHOO is the scope");
1751          * &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;this.log(o.nodes.length === 2) // true
1752          * &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// o.purge(); // optionally remove the script nodes immediately
1753          * &nbsp;&nbsp;&nbsp;&nbsp;&#125;,
1754          * &nbsp;&nbsp;&nbsp;&nbsp;onFailure: function(o) &#123;
1755          * &nbsp;&nbsp;&nbsp;&nbsp;&#125;,
1756          * &nbsp;&nbsp;&nbsp;&nbsp;data: "foo",
1757          * &nbsp;&nbsp;&nbsp;&nbsp;timeout: 10000, // 10 second timeout
1758          * &nbsp;&nbsp;&nbsp;&nbsp;scope: YAHOO,
1759          * &nbsp;&nbsp;&nbsp;&nbsp;// win: otherframe // target another window/frame
1760          * &nbsp;&nbsp;&nbsp;&nbsp;autopurge: true // allow the utility to choose when to remove the nodes
1761          * &nbsp;&nbsp;&#125;);
1762          * </pre>
1763          * @return {tId: string} an object containing info about the transaction
1764          */
1765         script: function(url, opts) { return _queue("script", url, opts); },
1766
1767         /**
1768          * Fetches and inserts one or more css link nodes into the 
1769          * head of the current document or the document in a specified
1770          * window.
1771          * @method css
1772          * @static
1773          * @param url {string} the url or urls to the css file(s)
1774          * @param opts Options: 
1775          * <dl>
1776          * <dt>onSuccess</dt>
1777          * <dd>
1778          * callback to execute when the css file(s) are finished loading
1779          * The callback receives an object back with the following
1780          * data:
1781          * <dl>win</dl>
1782          * <dd>the window the link nodes(s) were inserted into</dd>
1783          * <dt>data</dt>
1784          * <dd>the data object passed in when the request was made</dd>
1785          * <dt>nodes</dt>
1786          * <dd>An array containing references to the nodes that were
1787          * inserted</dd>
1788          * <dt>purge</dt>
1789          * <dd>A function that, when executed, will remove the nodes
1790          * that were inserted</dd>
1791          * <dt>
1792          * </dl>
1793          * </dd>
1794          * <dt>scope</dt>
1795          * <dd>the execution context for the callbacks</dd>
1796          * <dt>win</dt>
1797          * <dd>a window other than the one the utility occupies</dd>
1798          * <dt>data</dt>
1799          * <dd>
1800          * data that is supplied to the callbacks when the nodes(s) are
1801          * loaded.
1802          * </dd>
1803          * <dt>insertBefore</dt>
1804          * <dd>node or node id that will become the new node's nextSibling</dd>
1805          * <dt>charset</dt>
1806          * <dd>Node charset, deprecated, use 'attributes'</dd>
1807          * <dt>attributes</dt>
1808          * <dd>A hash of attributes to apply to dynamic nodes.</dd>
1809          * </dl>
1810          * <pre>
1811          *      YAHOO.util.Get.css("http://yui.yahooapis.com/2.7.0/build/menu/assets/skins/sam/menu.css");
1812          * </pre>
1813          * <pre>
1814          *      YAHOO.util.Get.css(["http://yui.yahooapis.com/2.7.0/build/menu/assets/skins/sam/menu.css",
1815          * </pre>
1816          * @return {tId: string} an object containing info about the transaction
1817          */
1818         css: function(url, opts) {
1819             return _queue("css", url, opts); 
1820         }
1821     };
1822 }();
1823
1824 YAHOO.register("get", YAHOO.util.Get, {version: "2.8.0r4", build: "2449"});
1825 /**
1826  * Provides dynamic loading for the YUI library.  It includes the dependency
1827  * info for the library, and will automatically pull in dependencies for
1828  * the modules requested.  It supports rollup files (such as utilities.js
1829  * and yahoo-dom-event.js), and will automatically use these when
1830  * appropriate in order to minimize the number of http connections
1831  * required to load all of the dependencies.
1832  * 
1833  * @module yuiloader
1834  * @namespace YAHOO.util
1835  */
1836
1837 /**
1838  * YUILoader provides dynamic loading for YUI.
1839  * @class YAHOO.util.YUILoader
1840  * @todo
1841  *      version management, automatic sandboxing
1842  */
1843 (function() {
1844
1845     var Y=YAHOO, util=Y.util, lang=Y.lang, env=Y.env,
1846         PROV = "_provides", SUPER = "_supersedes",
1847         REQ = "expanded", AFTER = "_after";
1848  
1849     var YUI = {
1850
1851         dupsAllowed: {'yahoo': true, 'get': true},
1852
1853         /*
1854          * The library metadata for the current release  The is the default
1855          * value for YAHOO.util.YUILoader.moduleInfo
1856          * @property YUIInfo
1857          * @static
1858          */
1859         info: {
1860
1861     // 'root': '2.5.2/build/',
1862     // 'base': 'http://yui.yahooapis.com/2.5.2/build/',
1863
1864     'root': '2.8.0r4/build/',
1865     'base': 'http://yui.yahooapis.com/2.8.0r4/build/',
1866
1867     'comboBase': 'http://yui.yahooapis.com/combo?',
1868
1869     'skin': {
1870         'defaultSkin': 'sam',
1871         'base': 'assets/skins/',
1872         'path': 'skin.css',
1873         'after': ['reset', 'fonts', 'grids', 'base'],
1874         'rollup': 3
1875     },
1876
1877     dupsAllowed: ['yahoo', 'get'],
1878
1879     'moduleInfo': {
1880
1881         'animation': {
1882             'type': 'js',
1883             'path': 'animation/animation-min.js',
1884             'requires': ['dom', 'event']
1885         },
1886
1887         'autocomplete': {
1888             'type': 'js',
1889             'path': 'autocomplete/autocomplete-min.js',
1890             'requires': ['dom', 'event', 'datasource'],
1891             'optional': ['connection', 'animation'],
1892             'skinnable': true
1893         },
1894
1895         'base': {
1896             'type': 'css',
1897             'path': 'base/base-min.css',
1898             'after': ['reset', 'fonts', 'grids']
1899         },
1900
1901         'button': {
1902             'type': 'js',
1903             'path': 'button/button-min.js',
1904             'requires': ['element'],
1905             'optional': ['menu'],
1906             'skinnable': true
1907         },
1908
1909         'calendar': {
1910             'type': 'js',
1911             'path': 'calendar/calendar-min.js',
1912             'requires': ['event', 'dom'],
1913             supersedes: ['datemeth'],
1914             'skinnable': true
1915         },
1916
1917         'carousel': {
1918             'type': 'js',
1919             'path': 'carousel/carousel-min.js',
1920             'requires': ['element'],
1921             'optional': ['animation'],
1922             'skinnable': true
1923         },
1924
1925         'charts': {
1926             'type': 'js',
1927             'path': 'charts/charts-min.js',
1928             'requires': ['element', 'json', 'datasource', 'swf']
1929         },
1930
1931         'colorpicker': {
1932             'type': 'js',
1933             'path': 'colorpicker/colorpicker-min.js',
1934             'requires': ['slider', 'element'],
1935             'optional': ['animation'],
1936             'skinnable': true
1937         },
1938
1939         'connection': {
1940             'type': 'js',
1941             'path': 'connection/connection-min.js',
1942             'requires': ['event'],
1943             'supersedes': ['connectioncore']
1944         },
1945
1946         'connectioncore': {
1947             'type': 'js',
1948             'path': 'connection/connection_core-min.js',
1949             'requires': ['event'],
1950             'pkg': 'connection'
1951         },
1952
1953         'container': {
1954             'type': 'js',
1955             'path': 'container/container-min.js',
1956             'requires': ['dom', 'event'],
1957             // button is also optional, but this creates a circular 
1958             // dependency when loadOptional is specified.  button
1959             // optionally includes menu, menu requires container.
1960             'optional': ['dragdrop', 'animation', 'connection'],
1961             'supersedes': ['containercore'],
1962             'skinnable': true
1963         },
1964
1965         'containercore': {
1966             'type': 'js',
1967             'path': 'container/container_core-min.js',
1968             'requires': ['dom', 'event'],
1969             'pkg': 'container'
1970         },
1971
1972         'cookie': {
1973             'type': 'js',
1974             'path': 'cookie/cookie-min.js',
1975             'requires': ['yahoo']
1976         },
1977
1978         'datasource': {
1979             'type': 'js',
1980             'path': 'datasource/datasource-min.js',
1981             'requires': ['event'],
1982             'optional': ['connection']
1983         },
1984
1985         'datatable': {
1986             'type': 'js',
1987             'path': 'datatable/datatable-min.js',
1988             'requires': ['element', 'datasource'],
1989             'optional': ['calendar', 'dragdrop', 'paginator'],
1990             'skinnable': true
1991         },
1992
1993         datemath: {
1994             'type': 'js',
1995             'path': 'datemath/datemath-min.js',
1996             'requires': ['yahoo']
1997         },
1998
1999         'dom': {
2000             'type': 'js',
2001             'path': 'dom/dom-min.js',
2002             'requires': ['yahoo']
2003         },
2004
2005         'dragdrop': {
2006             'type': 'js',
2007             'path': 'dragdrop/dragdrop-min.js',
2008             'requires': ['dom', 'event']
2009         },
2010
2011         'editor': {
2012             'type': 'js',
2013             'path': 'editor/editor-min.js',
2014             'requires': ['menu', 'element', 'button'],
2015             'optional': ['animation', 'dragdrop'],
2016             'supersedes': ['simpleeditor'],
2017             'skinnable': true
2018         },
2019
2020         'element': {
2021             'type': 'js',
2022             'path': 'element/element-min.js',
2023             'requires': ['dom', 'event'],
2024             'optional': ['event-mouseenter', 'event-delegate']
2025         },
2026
2027         'element-delegate': {
2028             'type': 'js',
2029             'path': 'element-delegate/element-delegate-min.js',
2030             'requires': ['element']
2031         },
2032
2033         'event': {
2034             'type': 'js',
2035             'path': 'event/event-min.js',
2036             'requires': ['yahoo']
2037         },
2038
2039         'event-simulate': {
2040             'type': 'js',
2041             'path': 'event-simulate/event-simulate-min.js',
2042             'requires': ['event']
2043         },
2044
2045         'event-delegate': {
2046             'type': 'js',
2047             'path': 'event-delegate/event-delegate-min.js',
2048             'requires': ['event'],
2049             'optional': ['selector']
2050         },
2051
2052         'event-mouseenter': {
2053             'type': 'js',
2054             'path': 'event-mouseenter/event-mouseenter-min.js',
2055             'requires': ['dom', 'event']
2056         },
2057
2058         'fonts': {
2059             'type': 'css',
2060             'path': 'fonts/fonts-min.css'
2061         },
2062
2063         'get': {
2064             'type': 'js',
2065             'path': 'get/get-min.js',
2066             'requires': ['yahoo']
2067         },
2068
2069         'grids': {
2070             'type': 'css',
2071             'path': 'grids/grids-min.css',
2072             'requires': ['fonts'],
2073             'optional': ['reset']
2074         },
2075
2076         'history': {
2077             'type': 'js',
2078             'path': 'history/history-min.js',
2079             'requires': ['event']
2080         },
2081
2082          'imagecropper': {
2083              'type': 'js',
2084              'path': 'imagecropper/imagecropper-min.js',
2085              'requires': ['dragdrop', 'element', 'resize'],
2086              'skinnable': true
2087          },
2088
2089          'imageloader': {
2090             'type': 'js',
2091             'path': 'imageloader/imageloader-min.js',
2092             'requires': ['event', 'dom']
2093          },
2094
2095          'json': {
2096             'type': 'js',
2097             'path': 'json/json-min.js',
2098             'requires': ['yahoo']
2099          },
2100
2101          'layout': {
2102              'type': 'js',
2103              'path': 'layout/layout-min.js',
2104              'requires': ['element'],
2105              'optional': ['animation', 'dragdrop', 'resize', 'selector'],
2106              'skinnable': true
2107          }, 
2108
2109         'logger': {
2110             'type': 'js',
2111             'path': 'logger/logger-min.js',
2112             'requires': ['event', 'dom'],
2113             'optional': ['dragdrop'],
2114             'skinnable': true
2115         },
2116
2117         'menu': {
2118             'type': 'js',
2119             'path': 'menu/menu-min.js',
2120             'requires': ['containercore'],
2121             'skinnable': true
2122         },
2123
2124         'paginator': {
2125             'type': 'js',
2126             'path': 'paginator/paginator-min.js',
2127             'requires': ['element'],
2128             'skinnable': true
2129         },
2130
2131         'profiler': {
2132             'type': 'js',
2133             'path': 'profiler/profiler-min.js',
2134             'requires': ['yahoo']
2135         },
2136
2137
2138         'profilerviewer': {
2139             'type': 'js',
2140             'path': 'profilerviewer/profilerviewer-min.js',
2141             'requires': ['profiler', 'yuiloader', 'element'],
2142             'skinnable': true
2143         },
2144
2145         'progressbar': {
2146             'type': 'js',
2147             'path': 'progressbar/progressbar-min.js',
2148             'requires': ['element'],
2149             'optional': ['animation'],
2150             'skinnable': true
2151         },
2152
2153         'reset': {
2154             'type': 'css',
2155             'path': 'reset/reset-min.css'
2156         },
2157
2158         'reset-fonts-grids': {
2159             'type': 'css',
2160             'path': 'reset-fonts-grids/reset-fonts-grids.css',
2161             'supersedes': ['reset', 'fonts', 'grids', 'reset-fonts'],
2162             'rollup': 4
2163         },
2164
2165         'reset-fonts': {
2166             'type': 'css',
2167             'path': 'reset-fonts/reset-fonts.css',
2168             'supersedes': ['reset', 'fonts'],
2169             'rollup': 2
2170         },
2171
2172          'resize': {
2173              'type': 'js',
2174              'path': 'resize/resize-min.js',
2175              'requires': ['dragdrop', 'element'],
2176              'optional': ['animation'],
2177              'skinnable': true
2178          },
2179
2180         'selector': {
2181             'type': 'js',
2182             'path': 'selector/selector-min.js',
2183             'requires': ['yahoo', 'dom']
2184         },
2185
2186         'simpleeditor': {
2187             'type': 'js',
2188             'path': 'editor/simpleeditor-min.js',
2189             'requires': ['element'],
2190             'optional': ['containercore', 'menu', 'button', 'animation', 'dragdrop'],
2191             'skinnable': true,
2192             'pkg': 'editor'
2193         },
2194
2195         'slider': {
2196             'type': 'js',
2197             'path': 'slider/slider-min.js',
2198             'requires': ['dragdrop'],
2199             'optional': ['animation'],
2200             'skinnable': true
2201         },
2202
2203         'storage': {
2204             'type': 'js',
2205             'path': 'storage/storage-min.js',
2206             'requires': ['yahoo', 'event', 'cookie'],
2207             'optional': ['swfstore']
2208         },
2209
2210          'stylesheet': {
2211             'type': 'js',
2212             'path': 'stylesheet/stylesheet-min.js',
2213             'requires': ['yahoo']
2214          },
2215
2216         'swf': {
2217             'type': 'js',
2218             'path': 'swf/swf-min.js',
2219             'requires': ['element'],
2220             'supersedes': ['swfdetect']
2221         },
2222
2223         'swfdetect': {
2224             'type': 'js',
2225             'path': 'swfdetect/swfdetect-min.js',
2226             'requires': ['yahoo']
2227         },
2228
2229         'swfstore': {
2230             'type': 'js',
2231             'path': 'swfstore/swfstore-min.js',
2232             'requires': ['element', 'cookie', 'swf']
2233         },
2234
2235         'tabview': {
2236             'type': 'js',
2237             'path': 'tabview/tabview-min.js',
2238             'requires': ['element'],
2239             'optional': ['connection'],
2240             'skinnable': true
2241         },
2242
2243         'treeview': {
2244             'type': 'js',
2245             'path': 'treeview/treeview-min.js',
2246             'requires': ['event', 'dom'],
2247             'optional': ['json', 'animation', 'calendar'],
2248             'skinnable': true
2249         },
2250
2251         'uploader': {
2252             'type': 'js',
2253             'path': 'uploader/uploader-min.js',
2254             'requires': ['element']
2255         },
2256
2257         'utilities': {
2258             'type': 'js',
2259             'path': 'utilities/utilities.js',
2260             'supersedes': ['yahoo', 'event', 'dragdrop', 'animation', 'dom', 'connection', 'element', 'yahoo-dom-event', 'get', 'yuiloader', 'yuiloader-dom-event'],
2261             'rollup': 8
2262         },
2263
2264         'yahoo': {
2265             'type': 'js',
2266             'path': 'yahoo/yahoo-min.js'
2267         },
2268
2269         'yahoo-dom-event': {
2270             'type': 'js',
2271             'path': 'yahoo-dom-event/yahoo-dom-event.js',
2272             'supersedes': ['yahoo', 'event', 'dom'],
2273             'rollup': 3
2274         },
2275
2276         'yuiloader': {
2277             'type': 'js',
2278             'path': 'yuiloader/yuiloader-min.js',
2279             'supersedes': ['yahoo', 'get']
2280         },
2281
2282         'yuiloader-dom-event': {
2283             'type': 'js',
2284             'path': 'yuiloader-dom-event/yuiloader-dom-event.js',
2285             'supersedes': ['yahoo', 'dom', 'event', 'get', 'yuiloader', 'yahoo-dom-event'],
2286             'rollup': 5
2287         },
2288
2289         'yuitest': {
2290             'type': 'js',
2291             'path': 'yuitest/yuitest-min.js',
2292             'requires': ['logger'],
2293             'optional': ['event-simulate'],
2294             'skinnable': true
2295         }
2296     }
2297 }
2298  , 
2299
2300         ObjectUtil: {
2301             appendArray: function(o, a) {
2302                 if (a) {
2303                     for (var i=0; i<a.length; i=i+1) {
2304                         o[a[i]] = true;
2305                     }
2306                 }
2307             },
2308
2309             keys: function(o, ordered) {
2310                 var a=[], i;
2311                 for (i in o) {
2312                     if (lang.hasOwnProperty(o, i)) {
2313                         a.push(i);
2314                     }
2315                 }
2316
2317                 return a;
2318             }
2319         },
2320
2321         ArrayUtil: {
2322
2323             appendArray: function(a1, a2) {
2324                 Array.prototype.push.apply(a1, a2);
2325                 /*
2326                 for (var i=0; i<a2.length; i=i+1) {
2327                     a1.push(a2[i]);
2328                 }
2329                 */
2330             },
2331
2332             indexOf: function(a, val) {
2333                 for (var i=0; i<a.length; i=i+1) {
2334                     if (a[i] === val) {
2335                         return i;
2336                     }
2337                 }
2338
2339                 return -1;
2340             },
2341
2342             toObject: function(a) {
2343                 var o = {};
2344                 for (var i=0; i<a.length; i=i+1) {
2345                     o[a[i]] = true;
2346                 }
2347
2348                 return o;
2349             },
2350
2351             /*
2352              * Returns a unique array.  Does not maintain order, which is fine
2353              * for this application, and performs better than it would if it
2354              * did.
2355              */
2356             uniq: function(a) {
2357                 return YUI.ObjectUtil.keys(YUI.ArrayUtil.toObject(a));
2358             }
2359         }
2360     };
2361
2362     YAHOO.util.YUILoader = function(o) {
2363
2364         /**
2365          * Internal callback to handle multiple internal insert() calls
2366          * so that css is inserted prior to js
2367          * @property _internalCallback
2368          * @private
2369          */
2370         this._internalCallback = null;
2371
2372         /**
2373          * Use the YAHOO environment listener to detect script load.  This
2374          * is only switched on for Safari 2.x and below.
2375          * @property _useYahooListener
2376          * @private
2377          */
2378         this._useYahooListener = false;
2379
2380         /**
2381          * Callback that will be executed when the loader is finished
2382          * with an insert
2383          * @method onSuccess
2384          * @type function
2385          */
2386         this.onSuccess = null;
2387
2388         /**
2389          * Callback that will be executed if there is a failure
2390          * @method onFailure
2391          * @type function
2392          */
2393         this.onFailure = Y.log;
2394
2395         /**
2396          * Callback that will be executed each time a new module is loaded
2397          * @method onProgress
2398          * @type function
2399          */
2400         this.onProgress = null;
2401
2402         /**
2403          * Callback that will be executed if a timeout occurs
2404          * @method onTimeout
2405          * @type function
2406          */
2407         this.onTimeout = null;
2408
2409         /**
2410          * The execution scope for all callbacks
2411          * @property scope
2412          * @default this
2413          */
2414         this.scope = this;
2415
2416         /**
2417          * Data that is passed to all callbacks
2418          * @property data
2419          */
2420         this.data = null;
2421
2422         /**
2423          * Node reference or id where new nodes should be inserted before
2424          * @property insertBefore
2425          * @type string|HTMLElement
2426          */
2427         this.insertBefore = null;
2428
2429         /**
2430          * The charset attribute for inserted nodes
2431          * @property charset
2432          * @type string
2433          * @default utf-8
2434          */
2435         this.charset = null;
2436
2437         /**
2438          * The name of the variable in a sandbox or script node 
2439          * (for external script support in Safari 2.x and earlier)
2440          * to reference when the load is complete.  If this variable 
2441          * is not available in the specified scripts, the operation will 
2442          * fail.  
2443          * @property varName
2444          * @type string
2445          */
2446         this.varName = null;
2447
2448         /**
2449          * The base directory.
2450          * @property base
2451          * @type string
2452          * @default http://yui.yahooapis.com/[YUI VERSION]/build/
2453          */
2454         this.base = YUI.info.base;
2455
2456         /**
2457          * Base path for the combo service
2458          * @property comboBase
2459          * @type string
2460          * @default http://yui.yahooapis.com/combo?
2461          */
2462         this.comboBase = YUI.info.comboBase;
2463
2464         /**
2465          * If configured, YUI will use the combo handler on the
2466          * Yahoo! CDN to pontentially reduce the number of http requests
2467          * required.
2468          * @property combine
2469          * @type boolean
2470          * @default false
2471          */
2472         // this.combine = (o && !('base' in o));
2473         this.combine = false;
2474
2475
2476         /**
2477          * Root path to prepend to module path for the combo
2478          * service
2479          * @property root
2480          * @type string
2481          * @default [YUI VERSION]/build/
2482          */
2483         this.root = YUI.info.root;
2484
2485         /**
2486          * Timeout value in milliseconds.  If set, this value will be used by
2487          * the get utility.  the timeout event will fire if
2488          * a timeout occurs.
2489          * @property timeout
2490          * @type int
2491          */
2492         this.timeout = 0;
2493
2494         /**
2495          * A list of modules that should not be loaded, even if
2496          * they turn up in the dependency tree
2497          * @property ignore
2498          * @type string[]
2499          */
2500         this.ignore = null;
2501
2502         /**
2503          * A list of modules that should always be loaded, even
2504          * if they have already been inserted into the page.
2505          * @property force
2506          * @type string[]
2507          */
2508         this.force = null;
2509
2510         /**
2511          * Should we allow rollups
2512          * @property allowRollup
2513          * @type boolean
2514          * @default true
2515          */
2516         this.allowRollup = true;
2517
2518         /**
2519          * A filter to apply to result urls.  This filter will modify the default
2520          * path for all modules.  The default path for the YUI library is the
2521          * minified version of the files (e.g., event-min.js).  The filter property
2522          * can be a predefined filter or a custom filter.  The valid predefined 
2523          * filters are:
2524          * <dl>
2525          *  <dt>DEBUG</dt>
2526          *  <dd>Selects the debug versions of the library (e.g., event-debug.js).
2527          *      This option will automatically include the logger widget</dd>
2528          *  <dt>RAW</dt>
2529          *  <dd>Selects the non-minified version of the library (e.g., event.js).
2530          * </dl>
2531          * You can also define a custom filter, which must be an object literal 
2532          * containing a search expression and a replace string:
2533          * <pre>
2534          *  myFilter: &#123; 
2535          *      'searchExp': "-min\\.js", 
2536          *      'replaceStr': "-debug.js"
2537          *  &#125;
2538          * </pre>
2539          * @property filter
2540          * @type string|{searchExp: string, replaceStr: string}
2541          */
2542         this.filter = null;
2543
2544         /**
2545          * The list of requested modules
2546          * @property required
2547          * @type {string: boolean}
2548          */
2549         this.required = {};
2550
2551         /**
2552          * The library metadata
2553          * @property moduleInfo
2554          */
2555         this.moduleInfo = lang.merge(YUI.info.moduleInfo);
2556
2557         /**
2558          * List of rollup files found in the library metadata
2559          * @property rollups
2560          */
2561         this.rollups = null;
2562
2563         /**
2564          * Whether or not to load optional dependencies for 
2565          * the requested modules
2566          * @property loadOptional
2567          * @type boolean
2568          * @default false
2569          */
2570         this.loadOptional = false;
2571
2572         /**
2573          * All of the derived dependencies in sorted order, which
2574          * will be populated when either calculate() or insert()
2575          * is called
2576          * @property sorted
2577          * @type string[]
2578          */
2579         this.sorted = [];
2580
2581         /**
2582          * Set when beginning to compute the dependency tree. 
2583          * Composed of what YAHOO reports to be loaded combined
2584          * with what has been loaded by the tool
2585          * @propery loaded
2586          * @type {string: boolean}
2587          */
2588         this.loaded = {};
2589
2590         /**
2591          * Flag to indicate the dependency tree needs to be recomputed
2592          * if insert is called again.
2593          * @property dirty
2594          * @type boolean
2595          * @default true
2596          */
2597         this.dirty = true;
2598
2599         /**
2600          * List of modules inserted by the utility
2601          * @property inserted
2602          * @type {string: boolean}
2603          */
2604         this.inserted = {};
2605
2606         /**
2607          * Provides the information used to skin the skinnable components.
2608          * The following skin definition would result in 'skin1' and 'skin2'
2609          * being loaded for calendar (if calendar was requested), and
2610          * 'sam' for all other skinnable components:
2611          *
2612          *   <code>
2613          *   skin: {
2614          *
2615          *      // The default skin, which is automatically applied if not
2616          *      // overriden by a component-specific skin definition.
2617          *      // Change this in to apply a different skin globally
2618          *      defaultSkin: 'sam', 
2619          *
2620          *      // This is combined with the loader base property to get
2621          *      // the default root directory for a skin. ex:
2622          *      // http://yui.yahooapis.com/2.3.0/build/assets/skins/sam/
2623          *      base: 'assets/skins/',
2624          *
2625          *      // The name of the rollup css file for the skin
2626          *      path: 'skin.css',
2627          *
2628          *      // The number of skinnable components requested that are
2629          *      // required before using the rollup file rather than the
2630          *      // individual component css files
2631          *      rollup: 3,
2632          *
2633          *      // Any component-specific overrides can be specified here,
2634          *      // making it possible to load different skins for different
2635          *      // components.  It is possible to load more than one skin
2636          *      // for a given component as well.
2637          *      overrides: {
2638          *          calendar: ['skin1', 'skin2']
2639          *      }
2640          *   }
2641          *   </code>
2642          *   @property skin
2643          */
2644
2645         var self = this;
2646
2647         env.listeners.push(function(m) {
2648             if (self._useYahooListener) {
2649                 //Y.log("YAHOO listener: " + m.name);
2650                 self.loadNext(m.name);
2651             }
2652         });
2653
2654         this.skin = lang.merge(YUI.info.skin); 
2655
2656         this._config(o);
2657
2658     };
2659
2660     Y.util.YUILoader.prototype = {
2661
2662         FILTERS: {
2663             RAW: { 
2664                 'searchExp': "-min\\.js", 
2665                 'replaceStr': ".js"
2666             },
2667             DEBUG: { 
2668                 'searchExp': "-min\\.js", 
2669                 'replaceStr': "-debug.js"
2670             }
2671         },
2672
2673         SKIN_PREFIX: "skin-",
2674
2675         _config: function(o) {
2676
2677             // apply config values
2678             if (o) {
2679                 for (var i in o) {
2680                     if (lang.hasOwnProperty(o, i)) {
2681                         if (i == "require") {
2682                             this.require(o[i]);
2683                         } else {
2684                             this[i] = o[i];
2685                         }
2686                     }
2687                 }
2688             }
2689
2690             // fix filter
2691             var f = this.filter;
2692
2693             if (lang.isString(f)) {
2694                 f = f.toUpperCase();
2695
2696                 // the logger must be available in order to use the debug
2697                 // versions of the library
2698                 if (f === "DEBUG") {
2699                     this.require("logger");
2700                 }
2701
2702                 // hack to handle a a bug where LogWriter is being instantiated
2703                 // at load time, and the loader has no way to sort above it
2704                 // at the moment.
2705                 if (!Y.widget.LogWriter) {
2706                     Y.widget.LogWriter = function() {
2707                         return Y;
2708                     };
2709                 }
2710
2711                 this.filter = this.FILTERS[f];
2712             }
2713
2714         },
2715
2716         /** Add a new module to the component metadata.         
2717          * <dl>
2718          *     <dt>name:</dt>       <dd>required, the component name</dd>
2719          *     <dt>type:</dt>       <dd>required, the component type (js or css)</dd>
2720          *     <dt>path:</dt>       <dd>required, the path to the script from "base"</dd>
2721          *     <dt>requires:</dt>   <dd>array of modules required by this component</dd>
2722          *     <dt>optional:</dt>   <dd>array of optional modules for this component</dd>
2723          *     <dt>supersedes:</dt> <dd>array of the modules this component replaces</dd>
2724          *     <dt>after:</dt>      <dd>array of modules the components which, if present, should be sorted above this one</dd>
2725          *     <dt>rollup:</dt>     <dd>the number of superseded modules required for automatic rollup</dd>
2726          *     <dt>fullpath:</dt>   <dd>If fullpath is specified, this is used instead of the configured base + path</dd>
2727          *     <dt>skinnable:</dt>  <dd>flag to determine if skin assets should automatically be pulled in</dd>
2728          * </dl>
2729          * @method addModule
2730          * @param o An object containing the module data
2731          * @return {boolean} true if the module was added, false if 
2732          * the object passed in did not provide all required attributes
2733          */
2734         addModule: function(o) {
2735
2736             if (!o || !o.name || !o.type || (!o.path && !o.fullpath)) {
2737                 return false;
2738             }
2739
2740             o.ext = ('ext' in o) ? o.ext : true;
2741             o.requires = o.requires || [];
2742
2743             this.moduleInfo[o.name] = o;
2744             this.dirty = true;
2745
2746             return true;
2747         },
2748
2749         /**
2750          * Add a requirement for one or more module
2751          * @method require
2752          * @param what {string[] | string*} the modules to load
2753          */
2754         require: function(what) {
2755             var a = (typeof what === "string") ? arguments : what;
2756             this.dirty = true;
2757             YUI.ObjectUtil.appendArray(this.required, a);
2758         },
2759
2760         /**
2761          * Adds the skin def to the module info
2762          * @method _addSkin
2763          * @param skin {string} the name of the skin
2764          * @param mod {string} the name of the module
2765          * @return {string} the module name for the skin
2766          * @private
2767          */
2768         _addSkin: function(skin, mod) {
2769
2770             // Add a module definition for the skin rollup css
2771             var name = this.formatSkin(skin), info = this.moduleInfo,
2772                 sinf = this.skin, ext = info[mod] && info[mod].ext;
2773
2774             // Y.log('ext? ' + mod + ": " + ext);
2775             if (!info[name]) {
2776                 // Y.log('adding skin ' + name);
2777                 this.addModule({
2778                     'name': name,
2779                     'type': 'css',
2780                     'path': sinf.base + skin + '/' + sinf.path,
2781                     //'supersedes': '*',
2782                     'after': sinf.after,
2783                     'rollup': sinf.rollup,
2784                     'ext': ext
2785                 });
2786             }
2787
2788             // Add a module definition for the module-specific skin css
2789             if (mod) {
2790                 name = this.formatSkin(skin, mod);
2791                 if (!info[name]) {
2792                     var mdef = info[mod], pkg = mdef.pkg || mod;
2793                     // Y.log('adding skin ' + name);
2794                     this.addModule({
2795                         'name': name,
2796                         'type': 'css',
2797                         'after': sinf.after,
2798                         'path': pkg + '/' + sinf.base + skin + '/' + mod + '.css',
2799                         'ext': ext
2800                     });
2801                 }
2802             }
2803
2804             return name;
2805         },
2806
2807         /**
2808          * Returns an object containing properties for all modules required
2809          * in order to load the requested module
2810          * @method getRequires
2811          * @param mod The module definition from moduleInfo
2812          */
2813         getRequires: function(mod) {
2814             if (!mod) {
2815                 return [];
2816             }
2817
2818             if (!this.dirty && mod.expanded) {
2819                 return mod.expanded;
2820             }
2821
2822             mod.requires=mod.requires || [];
2823             var i, d=[], r=mod.requires, o=mod.optional, info=this.moduleInfo, m;
2824             for (i=0; i<r.length; i=i+1) {
2825                 d.push(r[i]);
2826                 m = info[r[i]];
2827                 YUI.ArrayUtil.appendArray(d, this.getRequires(m));
2828
2829                 // add existing skins for skinnable modules as well.  The only
2830                 // way to do this is go through the list of required items (this
2831                 // assumes that _skin is called before getRequires is called on
2832                 // the module.
2833                 // if (m.skinnable) {
2834                 //     var req=this.required, l=req.length;
2835                 //     for (var j=0; j<l; j=j+1) {
2836                 //         // YAHOO.log('checking ' + r[j]);
2837                 //         if (req[j].indexOf(r[j]) > -1) {
2838                 //             // YAHOO.log('adding ' + r[j]);
2839                 //             d.push(req[j]);
2840                 //         }
2841                 //     }
2842                 // }
2843             }
2844
2845             if (o && this.loadOptional) {
2846                 for (i=0; i<o.length; i=i+1) {
2847                     d.push(o[i]);
2848                     YUI.ArrayUtil.appendArray(d, this.getRequires(info[o[i]]));
2849                 }
2850             }
2851
2852             mod.expanded = YUI.ArrayUtil.uniq(d);
2853
2854             return mod.expanded;
2855         },
2856
2857
2858         /**
2859          * Returns an object literal of the modules the supplied module satisfies
2860          * @method getProvides
2861          * @param name{string} The name of the module
2862          * @param notMe {string} don't add this module name, only include superseded modules
2863          * @return what this module provides
2864          */
2865         getProvides: function(name, notMe) {
2866             var addMe = !(notMe), ckey = (addMe) ? PROV : SUPER,
2867                 m = this.moduleInfo[name], o = {};
2868
2869             if (!m) {
2870                 return o;
2871             }
2872
2873             if (m[ckey]) {
2874 // Y.log('cached: ' + name + ' ' + ckey + ' ' + lang.dump(this.moduleInfo[name][ckey], 0));
2875                 return m[ckey];
2876             }
2877
2878             var s = m.supersedes, done={}, me = this;
2879
2880             // use worker to break cycles
2881             var add = function(mm) {
2882                 if (!done[mm]) {
2883                     // Y.log(name + ' provides worker trying: ' + mm);
2884                     done[mm] = true;
2885                     // we always want the return value normal behavior 
2886                     // (provides) for superseded modules.
2887                     lang.augmentObject(o, me.getProvides(mm));
2888                 } 
2889                 
2890                 // else {
2891                 // Y.log(name + ' provides worker skipping done: ' + mm);
2892                 // }
2893             };
2894
2895             // calculate superseded modules
2896             if (s) {
2897                 for (var i=0; i<s.length; i=i+1) {
2898                     add(s[i]);
2899                 }
2900             }
2901
2902             // supersedes cache
2903             m[SUPER] = o;
2904             // provides cache
2905             m[PROV] = lang.merge(o);
2906             m[PROV][name] = true;
2907
2908 // Y.log(name + " supersedes " + lang.dump(m[SUPER], 0));
2909 // Y.log(name + " provides " + lang.dump(m[PROV], 0));
2910
2911             return m[ckey];
2912         },
2913
2914
2915         /**
2916          * Calculates the dependency tree, the result is stored in the sorted 
2917          * property
2918          * @method calculate
2919          * @param o optional options object
2920          */
2921         calculate: function(o) {
2922             if (o || this.dirty) {
2923                 this._config(o);
2924                 this._setup();
2925                 this._explode();
2926                 // this._skin(); // deprecated
2927                 if (this.allowRollup) {
2928                     this._rollup();
2929                 }
2930                 this._reduce();
2931                 this._sort();
2932
2933                 // Y.log("after calculate: " + lang.dump(this.required));
2934
2935                 this.dirty = false;
2936             }
2937         },
2938
2939         /**
2940          * Investigates the current YUI configuration on the page.  By default,
2941          * modules already detected will not be loaded again unless a force
2942          * option is encountered.  Called by calculate()
2943          * @method _setup
2944          * @private
2945          */
2946         _setup: function() {
2947
2948             var info = this.moduleInfo, name, i, j;
2949
2950             // Create skin modules
2951             for (name in info) {
2952
2953                 if (lang.hasOwnProperty(info, name)) {
2954                     var m = info[name];
2955                     if (m && m.skinnable) {
2956                         // Y.log("skinning: " + name);
2957                         var o=this.skin.overrides, smod;
2958                         if (o && o[name]) {
2959                             for (i=0; i<o[name].length; i=i+1) {
2960                                 smod = this._addSkin(o[name][i], name);
2961                             }
2962                         } else {
2963                             smod = this._addSkin(this.skin.defaultSkin, name);
2964                         }
2965
2966                         m.requires.push(smod);
2967                     }
2968                 }
2969
2970             }
2971
2972             var l = lang.merge(this.inserted); // shallow clone
2973             
2974             if (!this._sandbox) {
2975                 l = lang.merge(l, env.modules);
2976             }
2977
2978             // Y.log("Already loaded stuff: " + lang.dump(l, 0));
2979
2980             // add the ignore list to the list of loaded packages
2981             if (this.ignore) {
2982                 YUI.ObjectUtil.appendArray(l, this.ignore);
2983             }
2984
2985             // remove modules on the force list from the loaded list
2986             if (this.force) {
2987                 for (i=0; i<this.force.length; i=i+1) {
2988                     if (this.force[i] in l) {
2989                         delete l[this.force[i]];
2990                     }
2991                 }
2992             }
2993
2994             // expand the list to include superseded modules
2995             for (j in l) {
2996                 // Y.log("expanding: " + j);
2997                 if (lang.hasOwnProperty(l, j)) {
2998                     lang.augmentObject(l, this.getProvides(j));
2999                 }
3000             }
3001
3002             // Y.log("loaded expanded: " + lang.dump(l, 0));
3003
3004             this.loaded = l;
3005
3006         },
3007         
3008
3009         /**
3010          * Inspects the required modules list looking for additional 
3011          * dependencies.  Expands the required list to include all 
3012          * required modules.  Called by calculate()
3013          * @method _explode
3014          * @private
3015          */
3016         _explode: function() {
3017
3018             var r=this.required, i, mod;
3019
3020             for (i in r) {
3021                 if (lang.hasOwnProperty(r, i)) {
3022                     mod = this.moduleInfo[i];
3023                     if (mod) {
3024
3025                         var req = this.getRequires(mod);
3026
3027                         if (req) {
3028                             YUI.ObjectUtil.appendArray(r, req);
3029                         }
3030                     }
3031                 }
3032             }
3033         },
3034
3035         /**
3036          * Sets up the requirements for the skin assets if any of the
3037          * requested modules are skinnable
3038          * @method _skin
3039          * @private
3040          * @deprecated skin modules are generated for all skinnable
3041          *             components during _setup(), and the components
3042          *             are configured to require the skin.
3043          */
3044         _skin: function() {
3045
3046         },
3047
3048         /**
3049          * Returns the skin module name for the specified skin name.  If a
3050          * module name is supplied, the returned skin module name is 
3051          * specific to the module passed in.
3052          * @method formatSkin
3053          * @param skin {string} the name of the skin
3054          * @param mod {string} optional: the name of a module to skin
3055          * @return {string} the full skin module name
3056          */
3057         formatSkin: function(skin, mod) {
3058             var s = this.SKIN_PREFIX + skin;
3059             if (mod) {
3060                 s = s + "-" + mod;
3061             }
3062
3063             return s;
3064         },
3065         
3066         /**
3067          * Reverses <code>formatSkin</code>, providing the skin name and
3068          * module name if the string matches the pattern for skins.
3069          * @method parseSkin
3070          * @param mod {string} the module name to parse
3071          * @return {skin: string, module: string} the parsed skin name 
3072          * and module name, or null if the supplied string does not match
3073          * the skin pattern
3074          */
3075         parseSkin: function(mod) {
3076             
3077             if (mod.indexOf(this.SKIN_PREFIX) === 0) {
3078                 var a = mod.split("-");
3079                 return {skin: a[1], module: a[2]};
3080             } 
3081
3082             return null;
3083         },
3084
3085         /**
3086          * Look for rollup packages to determine if all of the modules a
3087          * rollup supersedes are required.  If so, include the rollup to
3088          * help reduce the total number of connections required.  Called
3089          * by calculate()
3090          * @method _rollup
3091          * @private
3092          */
3093         _rollup: function() {
3094             var i, j, m, s, rollups={}, r=this.required, roll,
3095                 info = this.moduleInfo;
3096
3097             // find and cache rollup modules
3098             if (this.dirty || !this.rollups) {
3099                 for (i in info) {
3100                     if (lang.hasOwnProperty(info, i)) {
3101                         m = info[i];
3102                         //if (m && m.rollup && m.supersedes) {
3103                         if (m && m.rollup) {
3104                             rollups[i] = m;
3105                         }
3106                     }
3107                 }
3108
3109                 this.rollups = rollups;
3110             }
3111
3112             // make as many passes as needed to pick up rollup rollups
3113             for (;;) {
3114                 var rolled = false;
3115
3116                 // go through the rollup candidates
3117                 for (i in rollups) { 
3118
3119                     // there can be only one
3120                     if (!r[i] && !this.loaded[i]) {
3121                         m =info[i]; s = m.supersedes; roll=false;
3122
3123                         if (!m.rollup) {
3124                             continue;
3125                         }
3126
3127                         var skin = (m.ext) ? false : this.parseSkin(i), c = 0;
3128
3129                         // Y.log('skin? ' + i + ": " + skin);
3130                         if (skin) {
3131                             for (j in r) {
3132                                 if (lang.hasOwnProperty(r, j)) {
3133                                     if (i !== j && this.parseSkin(j)) {
3134                                         c++;
3135                                         roll = (c >= m.rollup);
3136                                         if (roll) {
3137                                             // Y.log("skin rollup " + lang.dump(r));
3138                                             break;
3139                                         }
3140                                     }
3141                                 }
3142                             }
3143
3144                         } else {
3145
3146                             // check the threshold
3147                             for (j=0;j<s.length;j=j+1) {
3148
3149                                 // if the superseded module is loaded, we can't load the rollup
3150                                 if (this.loaded[s[j]] && (!YUI.dupsAllowed[s[j]])) {
3151                                     roll = false;
3152                                     break;
3153                                 // increment the counter if this module is required.  if we are
3154                                 // beyond the rollup threshold, we will use the rollup module
3155                                 } else if (r[s[j]]) {
3156                                     c++;
3157                                     roll = (c >= m.rollup);
3158                                     if (roll) {
3159                                         // Y.log("over thresh " + c + ", " + lang.dump(r));
3160                                         break;
3161                                     }
3162                                 }
3163                             }
3164                         }
3165
3166                         if (roll) {
3167                             // Y.log("rollup: " +  i + ", " + lang.dump(this, 1));
3168                             // add the rollup
3169                             r[i] = true;
3170                             rolled = true;
3171
3172                             // expand the rollup's dependencies
3173                             this.getRequires(m);
3174                         }
3175                     }
3176                 }
3177
3178                 // if we made it here w/o rolling up something, we are done
3179                 if (!rolled) {
3180                     break;
3181                 }
3182             }
3183         },
3184
3185         /**
3186          * Remove superceded modules and loaded modules.  Called by
3187          * calculate() after we have the mega list of all dependencies
3188          * @method _reduce
3189          * @private
3190          */
3191         _reduce: function() {
3192
3193             var i, j, s, m, r=this.required;
3194             for (i in r) {
3195
3196                 // remove if already loaded
3197                 if (i in this.loaded) { 
3198                     delete r[i];
3199
3200                 // remove anything this module supersedes
3201                 } else {
3202
3203                     var skinDef = this.parseSkin(i);
3204
3205                     if (skinDef) {
3206                         //YAHOO.log("skin found in reduce: " + skinDef.skin + ", " + skinDef.module);
3207                         // the skin rollup will not have a module name
3208                         if (!skinDef.module) {
3209                             var skin_pre = this.SKIN_PREFIX + skinDef.skin;
3210                             //YAHOO.log("skin_pre: " + skin_pre);
3211                             for (j in r) {
3212
3213                                 if (lang.hasOwnProperty(r, j)) {
3214                                     m = this.moduleInfo[j];
3215                                     var ext = m && m.ext;
3216                                     if (!ext && j !== i && j.indexOf(skin_pre) > -1) {
3217                                         // Y.log ("removing component skin: " + j);
3218                                         delete r[j];
3219                                     }
3220                                 }
3221                             }
3222                         }
3223                     } else {
3224
3225                          m = this.moduleInfo[i];
3226                          s = m && m.supersedes;
3227                          if (s) {
3228                              for (j=0; j<s.length; j=j+1) {
3229                                  if (s[j] in r) {
3230                                      delete r[s[j]];
3231                                  }
3232                              }
3233                          }
3234                     }
3235                 }
3236             }
3237         },
3238
3239         _onFailure: function(msg) {
3240             YAHOO.log('Failure', 'info', 'loader');
3241
3242             var f = this.onFailure;
3243             if (f) {
3244                 f.call(this.scope, {
3245                     msg: 'failure: ' + msg,
3246                     data: this.data,
3247                     success: false
3248                 });
3249             }
3250         },
3251
3252         _onTimeout: function() {
3253             YAHOO.log('Timeout', 'info', 'loader');
3254             var f = this.onTimeout;
3255             if (f) {
3256                 f.call(this.scope, {
3257                     msg: 'timeout',
3258                     data: this.data,
3259                     success: false
3260                 });
3261             }
3262         },
3263         
3264         /**
3265          * Sorts the dependency tree.  The last step of calculate()
3266          * @method _sort
3267          * @private
3268          */
3269         _sort: function() {
3270             // create an indexed list
3271             var s=[], info=this.moduleInfo, loaded=this.loaded,
3272                 checkOptional=!this.loadOptional, me = this;
3273
3274             // returns true if b is not loaded, and is required
3275             // directly or by means of modules it supersedes.
3276             var requires = function(aa, bb) {
3277
3278                 var mm=info[aa];
3279
3280                 if (loaded[bb] || !mm) {
3281                     return false;
3282                 }
3283
3284                 var ii, 
3285                     rr = mm.expanded, 
3286                     after = mm.after, 
3287                     other = info[bb],
3288                     optional = mm.optional;
3289
3290
3291                 // check if this module requires the other directly
3292                 if (rr && YUI.ArrayUtil.indexOf(rr, bb) > -1) {
3293                     return true;
3294                 }
3295
3296                 // check if this module should be sorted after the other
3297                 if (after && YUI.ArrayUtil.indexOf(after, bb) > -1) {
3298                     return true;
3299                 }
3300
3301                 // if loadOptional is not specified, optional dependencies still
3302                 // must be sorted correctly when present.
3303                 if (checkOptional && optional && YUI.ArrayUtil.indexOf(optional, bb) > -1) {
3304                     return true;
3305                 }
3306
3307                 // check if this module requires one the other supersedes
3308                 var ss=info[bb] && info[bb].supersedes;
3309                 if (ss) {
3310                     for (ii=0; ii<ss.length; ii=ii+1) {
3311                         if (requires(aa, ss[ii])) {
3312                             return true;
3313                         }
3314                     }
3315                 }
3316
3317                 // var ss=me.getProvides(bb, true);
3318                 // if (ss) {
3319                 //     for (ii in ss) {
3320                 //         if (requires(aa, ii)) {
3321                 //             return true;
3322                 //         }
3323                 //     }
3324                 // }
3325
3326                 // external css files should be sorted below yui css
3327                 if (mm.ext && mm.type == 'css' && !other.ext && other.type == 'css') {
3328                     return true;
3329                 }
3330
3331                 return false;
3332             };
3333
3334             // get the required items out of the obj into an array so we
3335             // can sort
3336             for (var i in this.required) {
3337                 if (lang.hasOwnProperty(this.required, i)) {
3338                     s.push(i);
3339                 }
3340             }
3341
3342             // pointer to the first unsorted item
3343             var p=0; 
3344
3345             // keep going until we make a pass without moving anything
3346             for (;;) {
3347                
3348                 var l=s.length, a, b, j, k, moved=false;
3349
3350                 // start the loop after items that are already sorted
3351                 for (j=p; j<l; j=j+1) {
3352
3353                     // check the next module on the list to see if its
3354                     // dependencies have been met
3355                     a = s[j];
3356
3357                     // check everything below current item and move if we
3358                     // find a requirement for the current item
3359                     for (k=j+1; k<l; k=k+1) {
3360                         if (requires(a, s[k])) {
3361
3362                             // extract the dependency so we can move it up
3363                             b = s.splice(k, 1);
3364
3365                             // insert the dependency above the item that 
3366                             // requires it
3367                             s.splice(j, 0, b[0]);
3368
3369                             moved = true;
3370                             break;
3371                         }
3372                     }
3373
3374                     // jump out of loop if we moved something
3375                     if (moved) {
3376                         break;
3377                     // this item is sorted, move our pointer and keep going
3378                     } else {
3379                         p = p + 1;
3380                     }
3381                 }
3382
3383                 // when we make it here and moved is false, we are 
3384                 // finished sorting
3385                 if (!moved) {
3386                     break;
3387                 }
3388
3389             }
3390
3391             this.sorted = s;
3392         },
3393
3394         toString: function() {
3395             var o = {
3396                 type: "YUILoader",
3397                 base: this.base,
3398                 filter: this.filter,
3399                 required: this.required,
3400                 loaded: this.loaded,
3401                 inserted: this.inserted
3402             };
3403
3404             lang.dump(o, 1);
3405         },
3406
3407         _combine: function() {
3408
3409                 this._combining = []; 
3410
3411                 var self = this,
3412                     s=this.sorted,
3413                     len = s.length,
3414                     js = this.comboBase,
3415                     css = this.comboBase,
3416                     target, 
3417                     startLen = js.length,
3418                     i, m, type = this.loadType;
3419
3420                 YAHOO.log('type ' + type);
3421
3422                 for (i=0; i<len; i=i+1) {
3423
3424                     m = this.moduleInfo[s[i]];
3425
3426                     if (m && !m.ext && (!type || type === m.type)) {
3427
3428                         target = this.root + m.path;
3429
3430                         // if (i < len-1) {
3431                         target += '&';
3432                         // }
3433
3434                         if (m.type == 'js') {
3435                             js += target;
3436                         } else {
3437                             css += target;
3438                         }
3439
3440                         // YAHOO.log(target);
3441                         this._combining.push(s[i]);
3442                     }
3443                 }
3444
3445                 if (this._combining.length) {
3446
3447 YAHOO.log('Attempting to combine: ' + this._combining, "info", "loader");
3448
3449                     var callback=function(o) {
3450                         // YAHOO.log('Combo complete: ' + o.data, "info", "loader");
3451                         // this._combineComplete = true;
3452
3453                         var c=this._combining, len=c.length, i, m;
3454                         for (i=0; i<len; i=i+1) {
3455                             this.inserted[c[i]] = true;
3456                         }
3457
3458                         this.loadNext(o.data);
3459                     }, 
3460                     
3461                     loadScript = function() {
3462                         // YAHOO.log('combining js: ' + js);
3463                         if (js.length > startLen) {
3464                             YAHOO.util.Get.script(self._filter(js), {
3465                                 data: self._loading,
3466                                 onSuccess: callback,
3467                                 onFailure: self._onFailure,
3468                                 onTimeout: self._onTimeout,
3469                                 insertBefore: self.insertBefore,
3470                                 charset: self.charset,
3471                                 timeout: self.timeout,
3472                                 scope: self 
3473                             });
3474                         }
3475                     };
3476
3477                     // load the css first
3478                     // YAHOO.log('combining css: ' + css);
3479                     if (css.length > startLen) {
3480                         YAHOO.util.Get.css(this._filter(css), {
3481                             data: this._loading,
3482                             onSuccess: loadScript,
3483                             onFailure: this._onFailure,
3484                             onTimeout: this._onTimeout,
3485                             insertBefore: this.insertBefore,
3486                             charset: this.charset,
3487                             timeout: this.timeout,
3488                             scope: self 
3489                         });
3490                     } else {
3491                         loadScript();
3492                     }
3493
3494                     return;
3495
3496                 } else {
3497                     // this._combineComplete = true;
3498                     this.loadNext(this._loading);
3499                 }
3500         }, 
3501
3502         /**
3503          * inserts the requested modules and their dependencies.  
3504          * <code>type</code> can be "js" or "css".  Both script and 
3505          * css are inserted if type is not provided.
3506          * @method insert
3507          * @param o optional options object
3508          * @param type {string} the type of dependency to insert
3509          */
3510         insert: function(o, type) {
3511             // if (o) {
3512             //     Y.log("insert: " + lang.dump(o, 1) + ", " + type);
3513             // } else {
3514             //     Y.log("insert: " + this.toString() + ", " + type);
3515             // }
3516
3517             // build the dependency list
3518             this.calculate(o);
3519
3520
3521             // set a flag to indicate the load has started
3522             this._loading = true;
3523
3524             // flag to indicate we are done with the combo service
3525             // and any additional files will need to be loaded
3526             // individually
3527             // this._combineComplete = false;
3528
3529             // keep the loadType (js, css or undefined) cached
3530             this.loadType = type;
3531
3532             if (this.combine) {
3533                 return this._combine();
3534             }
3535
3536             if (!type) {
3537                 // Y.log("trying to load css first");
3538                 var self = this;
3539                 this._internalCallback = function() {
3540                             self._internalCallback = null;
3541                             self.insert(null, "js");
3542                         };
3543                 this.insert(null, "css");
3544                 return;
3545             }
3546
3547
3548             // start the load
3549             this.loadNext();
3550
3551         },
3552
3553         /**
3554          * Interns the script for the requested modules.  The callback is
3555          * provided a reference to the sandboxed YAHOO object.  This only
3556          * applies to the script: css can not be sandboxed; css will be
3557          * loaded into the page normally if specified.
3558          * @method sandbox
3559          * @param callback {Function} the callback to exectued when the load is
3560          *        complete.
3561          */
3562         sandbox: function(o, type) {
3563             // if (o) {
3564                 // YAHOO.log("sandbox: " + lang.dump(o, 1) + ", " + type);
3565             // } else {
3566                 // YAHOO.log("sandbox: " + this.toString() + ", " + type);
3567             // }
3568
3569             this._config(o);
3570
3571             if (!this.onSuccess) {
3572 throw new Error("You must supply an onSuccess handler for your sandbox");
3573             }
3574
3575             this._sandbox = true;
3576
3577             var self = this;
3578
3579             // take care of any css first (this can't be sandboxed)
3580             if (!type || type !== "js") {
3581                 this._internalCallback = function() {
3582                             self._internalCallback = null;
3583                             self.sandbox(null, "js");
3584                         };
3585                 this.insert(null, "css");
3586                 return;
3587             }
3588
3589             // get the connection manager if not on the page
3590             if (!util.Connect) {
3591                 // get a new loader instance to load connection.
3592                 var ld = new YAHOO.util.YUILoader();
3593                 ld.insert({
3594                     base: this.base,
3595                     filter: this.filter,
3596                     require: "connection",
3597                     insertBefore: this.insertBefore,
3598                     charset: this.charset,
3599                     onSuccess: function() {
3600                         this.sandbox(null, "js");
3601                     },
3602                     scope: this
3603                 }, "js");
3604                 return;
3605             }
3606
3607             this._scriptText = [];
3608             this._loadCount = 0;
3609             this._stopCount = this.sorted.length;
3610             this._xhr = [];
3611
3612             this.calculate();
3613
3614             var s=this.sorted, l=s.length, i, m, url;
3615
3616             for (i=0; i<l; i=i+1) {
3617                 m = this.moduleInfo[s[i]];
3618
3619                 // undefined modules cause a failure
3620                 if (!m) {
3621                     this._onFailure("undefined module " + m);
3622                     for (var j=0;j<this._xhr.length;j=j+1) {
3623                         this._xhr[j].abort();
3624                     }
3625                     return;
3626                 }
3627
3628                 // css files should be done
3629                 if (m.type !== "js") {
3630                     this._loadCount++;
3631                     continue;
3632                 }
3633
3634                 url = m.fullpath;
3635                 url = (url) ? this._filter(url) : this._url(m.path);
3636
3637                 // YAHOO.log("xhr request: " + url + ", " + i);
3638
3639                 var xhrData = {
3640
3641                     success: function(o) {
3642                         
3643                         var idx=o.argument[0], name=o.argument[2];
3644
3645                         // store the response in the position it was requested
3646                         this._scriptText[idx] = o.responseText; 
3647                         
3648                         // YAHOO.log("received: " + o.responseText.substr(0, 100) + ", " + idx);
3649                     
3650                         if (this.onProgress) {
3651                             this.onProgress.call(this.scope, {
3652                                         name: name,
3653                                         scriptText: o.responseText,
3654                                         xhrResponse: o,
3655                                         data: this.data
3656                                     });
3657                         }
3658
3659                         // only generate the sandbox once everything is loaded
3660                         this._loadCount++;
3661
3662                         if (this._loadCount >= this._stopCount) {
3663
3664                             // the variable to find
3665                             var v = this.varName || "YAHOO";
3666
3667                             // wrap the contents of the requested modules in an anonymous function
3668                             var t = "(function() {\n";
3669                         
3670                             // return the locally scoped reference.
3671                             var b = "\nreturn " + v + ";\n})();";
3672
3673                             var ref = eval(t + this._scriptText.join("\n") + b);
3674
3675                             this._pushEvents(ref);
3676
3677                             if (ref) {
3678                                 this.onSuccess.call(this.scope, {
3679                                         reference: ref,
3680                                         data: this.data
3681                                     });
3682                             } else {
3683                                 this._onFailure.call(this.varName + " reference failure");
3684                             }
3685                         }
3686                     },
3687
3688                     failure: function(o) {
3689                         this.onFailure.call(this.scope, {
3690                                 msg: "XHR failure",
3691                                 xhrResponse: o,
3692                                 data: this.data
3693                             });
3694                     },
3695
3696                     scope: this,
3697
3698                     // module index, module name, sandbox name
3699                     argument: [i, url, s[i]]
3700
3701                 };
3702
3703                 this._xhr.push(util.Connect.asyncRequest('GET', url, xhrData));
3704             }
3705         },
3706
3707         /**
3708          * Executed every time a module is loaded, and if we are in a load
3709          * cycle, we attempt to load the next script.  Public so that it
3710          * is possible to call this if using a method other than
3711          * YAHOO.register to determine when scripts are fully loaded
3712          * @method loadNext
3713          * @param mname {string} optional the name of the module that has
3714          * been loaded (which is usually why it is time to load the next
3715          * one)
3716          */
3717         loadNext: function(mname) {
3718
3719             // It is possible that this function is executed due to something
3720             // else one the page loading a YUI module.  Only react when we
3721             // are actively loading something
3722             if (!this._loading) {
3723                 return;
3724             }
3725
3726
3727             if (mname) {
3728
3729                 // if the module that was just loaded isn't what we were expecting,
3730                 // continue to wait
3731                 if (mname !== this._loading) {
3732                     return;
3733                 }
3734
3735                 // YAHOO.log("loadNext executing, just loaded " + mname);
3736
3737                 // The global handler that is called when each module is loaded
3738                 // will pass that module name to this function.  Storing this
3739                 // data to avoid loading the same module multiple times
3740                 this.inserted[mname] = true;
3741
3742                 if (this.onProgress) {
3743                     this.onProgress.call(this.scope, {
3744                             name: mname,
3745                             data: this.data
3746                         });
3747                 }
3748                 //var o = this.getProvides(mname);
3749                 //this.inserted = lang.merge(this.inserted, o);
3750             }
3751
3752             var s=this.sorted, len=s.length, i, m;
3753
3754             for (i=0; i<len; i=i+1) {
3755
3756                 // This.inserted keeps track of what the loader has loaded
3757                 if (s[i] in this.inserted) {
3758                     // YAHOO.log(s[i] + " alread loaded ");
3759                     continue;
3760                 }
3761
3762                 // Because rollups will cause multiple load notifications
3763                 // from YAHOO, loadNext may be called multiple times for
3764                 // the same module when loading a rollup.  We can safely
3765                 // skip the subsequent requests
3766                 if (s[i] === this._loading) {
3767                     // YAHOO.log("still loading " + s[i] + ", waiting");
3768                     return;
3769                 }
3770
3771                 // log("inserting " + s[i]);
3772                 m = this.moduleInfo[s[i]];
3773
3774                 if (!m) {
3775                     this.onFailure.call(this.scope, {
3776                             msg: "undefined module " + m,
3777                             data: this.data
3778                         });
3779                     return;
3780                 }
3781
3782                 // The load type is stored to offer the possibility to load
3783                 // the css separately from the script.
3784                 if (!this.loadType || this.loadType === m.type) {
3785                     this._loading = s[i];
3786                     //YAHOO.log("attempting to load " + s[i] + ", " + this.base);
3787
3788                     var fn=(m.type === "css") ? util.Get.css : util.Get.script,
3789                         url = m.fullpath,
3790                         self=this, 
3791                         c=function(o) {
3792                             self.loadNext(o.data);
3793                         };
3794
3795                         url = (url) ? this._filter(url) : this._url(m.path);
3796
3797                     // safari 2.x or lower, script, and part of YUI
3798                     if (env.ua.webkit && env.ua.webkit < 420 && m.type === "js" && 
3799                           !m.varName) {
3800                           //YUI.info.moduleInfo[s[i]]) {
3801                           //YAHOO.log("using YAHOO env " + s[i] + ", " + m.varName);
3802                         c = null;
3803                         this._useYahooListener = true;
3804                     }
3805
3806                     fn(url, {
3807                         data: s[i],
3808                         onSuccess: c,
3809                         onFailure: this._onFailure,
3810                         onTimeout: this._onTimeout,
3811                         insertBefore: this.insertBefore,
3812                         charset: this.charset,
3813                         timeout: this.timeout,
3814                         varName: m.varName,
3815                         scope: self 
3816                     });
3817
3818                     return;
3819                 }
3820             }
3821
3822             // we are finished
3823             this._loading = null;
3824
3825             // internal callback for loading css first
3826             if (this._internalCallback) {
3827                 var f = this._internalCallback;
3828                 this._internalCallback = null;
3829                 f.call(this);
3830             } else if (this.onSuccess) {
3831                 this._pushEvents();
3832                 this.onSuccess.call(this.scope, {
3833                         data: this.data
3834                     });
3835             }
3836
3837         },
3838
3839         /**
3840          * In IE, the onAvailable/onDOMReady events need help when Event is
3841          * loaded dynamically
3842          * @method _pushEvents
3843          * @param {Function} optional function reference
3844          * @private
3845          */
3846         _pushEvents: function(ref) {
3847             var r = ref || YAHOO;
3848             if (r.util && r.util.Event) {
3849                 r.util.Event._load();
3850             }
3851         },
3852
3853         /**
3854          * Applies filter
3855          * method _filter
3856          * @return {string} the filtered string
3857          * @private
3858          */
3859         _filter: function(str) {
3860             var f = this.filter;
3861             return (f) ?  str.replace(new RegExp(f.searchExp, 'g'), f.replaceStr) : str;
3862         },
3863
3864         /**
3865          * Generates the full url for a module
3866          * method _url
3867          * @param path {string} the path fragment
3868          * @return {string} the full url
3869          * @private
3870          */
3871         _url: function(path) {
3872             return this._filter((this.base || "") + path);
3873         }
3874
3875     };
3876
3877 })();
3878
3879 YAHOO.register("yuiloader", YAHOO.util.YUILoader, {version: "2.8.0r4", build: "2449"});