]> git.pond.sub.org Git - eow/blob - static/dojo-release-1.1.1/dojo/dojo.js.uncompressed.js
Comment class stub
[eow] / static / dojo-release-1.1.1 / dojo / dojo.js.uncompressed.js
1 /*
2         Copyright (c) 2004-2008, The Dojo Foundation
3         All Rights Reserved.
4
5         Licensed under the Academic Free License version 2.1 or above OR the
6         modified BSD license. For more information on Dojo licensing, see:
7
8                 http://dojotoolkit.org/book/dojo-book-0-9/introduction/licensing
9 */
10
11 /*
12         This is a compiled version of Dojo, built for deployment and not for
13         development. To get an editable version, please visit:
14
15                 http://dojotoolkit.org
16
17         for documentation and information on getting the source.
18 */
19
20 ;(function(){
21
22         /*
23         dojo, dijit, and dojox must always be the first three, and in that order.
24         djConfig.scopeMap = [
25                 ["dojo", "fojo"],
26                 ["dijit", "fijit"],
27                 ["dojox", "fojox"]
28         
29         ]
30         */
31
32         /**Build will replace this comment with a scoped djConfig **/
33
34         //The null below can be relaced by a build-time value used instead of djConfig.scopeMap.
35         var sMap = null;
36
37         //See if new scopes need to be defined.
38         if((sMap || (typeof djConfig != "undefined" && djConfig.scopeMap)) && (typeof window != "undefined")){
39                 var scopeDef = "", scopePrefix = "", scopeSuffix = "", scopeMap = {}, scopeMapRev = {};
40                 sMap = sMap || djConfig.scopeMap;
41                 for(var i = 0; i < sMap.length; i++){
42                         //Make local variables, then global variables that use the locals.
43                         var newScope = sMap[i];
44                         scopeDef += "var " + newScope[0] + " = {}; " + newScope[1] + " = " + newScope[0] + ";" + newScope[1] + "._scopeName = '" + newScope[1] + "';";
45                         scopePrefix += (i == 0 ? "" : ",") + newScope[0];
46                         scopeSuffix += (i == 0 ? "" : ",") + newScope[1];
47                         scopeMap[newScope[0]] = newScope[1];
48                         scopeMapRev[newScope[1]] = newScope[0];
49                 }
50
51                 eval(scopeDef + "dojo._scopeArgs = [" + scopeSuffix + "];");
52
53                 dojo._scopePrefixArgs = scopePrefix;
54                 dojo._scopePrefix = "(function(" + scopePrefix + "){";
55                 dojo._scopeSuffix = "})(" + scopeSuffix + ")";
56                 dojo._scopeMap = scopeMap;
57                 dojo._scopeMapRev = scopeMapRev;
58         }
59
60 /*=====
61 // note:
62 //              'djConfig' does not exist under 'dojo.*' so that it can be set before the
63 //              'dojo' variable exists.
64 // note:
65 //              Setting any of these variables *after* the library has loaded does
66 //              nothing at all.
67
68 djConfig = {
69         // summary:
70         //              Application code can set the global 'djConfig' prior to loading
71         //              the library to override certain global settings for how dojo works.
72         //
73         // isDebug: Boolean
74         //              Defaults to `false`. If set to `true`, ensures that Dojo provides
75         //              extende debugging feedback via Firebug. If Firebug is not available
76         //              on your platform, setting `isDebug` to `true` will force Dojo to
77         //              pull in (and display) the version of Firebug Lite which is
78         //              integrated into the Dojo distribution, thereby always providing a
79         //              debugging/logging console when `isDebug` is enabled. Note that
80         //              Firebug's `console.*` methods are ALWAYS defined by Dojo. If
81         //              `isDebug` is false and you are on a platform without Firebug, these
82         //              methods will be defined as no-ops.
83         isDebug: false,
84         // debugAtAllCosts: Boolean
85         //              Defaults to `false`. If set to `true`, this triggers an alternate
86         //              mode of the package system in which dependencies are detected and
87         //              only then are resources evaluated in dependency order via
88         //              `<script>` tag inclusion. This may double-request resources and
89         //              cause problems with scripts which expect `dojo.require()` to
90         //              preform synchronously. `debugAtAllCosts` can be an invaluable
91         //              debugging aid, but when using it, ensure that all code which
92         //              depends on Dojo modules is wrapped in `dojo.addOnLoad()` handlers.
93         //              Due to the somewhat unpredictable side-effects of using
94         //              `debugAtAllCosts`, it is strongly recommended that you enable this
95         //              flag as a last resort. `debugAtAllCosts` has no effect when loading
96         //              resources across domains. For usage information, see the
97         //              [Dojo Book](http://dojotoolkit.org/book/book-dojo/part-4-meta-dojo-making-your-dojo-code-run-faster-and-better/debugging-facilities/deb)
98         debugAtAllCosts: false,
99         // locale: String
100         //              The locale to assume for loading localized resources in this page,
101         //              specified according to [RFC 3066](http://www.ietf.org/rfc/rfc3066.txt).
102         //              Must be specified entirely in lowercase, e.g. `en-us` and `zh-cn`.
103         //              See the documentation for `dojo.i18n` and `dojo.requireLocalization`
104         //              for details on loading localized resources. If no locale is specified,
105         //              Dojo assumes the locale of the user agent, according to `navigator.userLanguage`
106         //              or `navigator.language` properties.
107         locale: undefined,
108         // extraLocale: Array
109         //              No default value. Specifies additional locales whose
110         //              resources should also be loaded alongside the default locale when
111         //              calls to `dojo.requireLocalization()` are processed.
112         extraLocale: undefined,
113         // baseUrl: String
114         //              The directory in which `dojo.js` is located. Under normal
115         //              conditions, Dojo auto-detects the correct location from which it
116         //              was loaded. You may need to manually configure `baseUrl` in cases
117         //              where you have renamed `dojo.js` or in which `<base>` tags confuse
118         //              some browsers (e.g., IE 6). The variable `dojo.baseUrl` is assigned
119         //              either the value of `djConfig.baseUrl` if one is provided or the
120         //              auto-detected root if not. Other modules are located relative to
121         //              this path.
122         baseUrl: undefined,
123         // modulePaths: Object
124         //              A map of module names to paths relative to `dojo.baseUrl`. The
125         //              key/value pairs correspond directly to the arguments which
126         //              `dojo.registerModulePath` accepts. Specifiying
127         //              `djConfig.modulePaths = { "foo": "../../bar" }` is the equivalent
128         //              of calling `dojo.registerModulePath("foo", "../../bar");`. Multiple
129         //              modules may be configured via `djConfig.modulePaths`.
130         modulePaths: {},
131 }
132 =====*/
133
134 (function(){
135         // firebug stubs
136
137         // if((!this["console"])||(!console["firebug"])){
138
139         if(!this["console"]){
140                 this.console = {
141                         log: function(){} // no-op
142                 };
143         }
144
145         var cn = [
146                 "assert", "count", "debug", "dir", "dirxml", "error", "group",
147                 "groupEnd", "info", "profile", "profileEnd", "time", "timeEnd",
148                 "trace", "warn", "log" 
149         ];
150         var i=0, tn;
151         while((tn=cn[i++])){
152                 if(!console[tn]){
153                         (function(){
154                                 var tcn = tn+"";
155                                 console[tcn] = function(){ 
156                                         var a = Array.apply({}, arguments);
157                                         a.unshift(tcn+":");
158                                         console.log(a.join(" "));
159                                 }
160                         })();
161                 }
162         }
163
164         //TODOC:  HOW TO DOC THIS?
165         // dojo is the root variable of (almost all) our public symbols -- make sure it is defined.
166         if(typeof dojo == "undefined"){
167                 this.dojo = {
168                         _scopeName: "dojo",
169                         _scopePrefix: "",
170                         _scopePrefixArgs: "",
171                         _scopeSuffix: "",
172                         _scopeMap: {},
173                         _scopeMapRev: {}
174                 };
175         }
176
177         var d = dojo;
178
179         //Need placeholders for dijit and dojox for scoping code.
180         if(typeof dijit == "undefined"){
181                 this.dijit = {_scopeName: "dijit"};
182         }
183         if(typeof dojox == "undefined"){
184                 this.dojox = {_scopeName: "dojox"};
185         }
186         
187         if(!d._scopeArgs){
188                 d._scopeArgs = [dojo, dijit, dojox];
189         }
190
191 /*=====
192 dojo.global = {
193         //      summary:
194         //              Alias for the global scope
195         //              (e.g. the window object in a browser).
196         //      description:
197         //              Refer to 'dojo.global' rather than referring to window to ensure your
198         //              code runs correctly in contexts other than web browsers (e.g. Rhino on a server).
199 }
200 =====*/
201         d.global = this;
202
203         d.config =/*===== djConfig = =====*/{
204                 isDebug: false,
205                 debugAtAllCosts: false
206         };
207
208         if(typeof djConfig != "undefined"){
209                 for(var opt in djConfig){
210                         d.config[opt] = djConfig[opt];
211                 }
212         }
213
214         var _platforms = ["Browser", "Rhino", "Spidermonkey", "Mobile"];
215         var t;
216         while((t=_platforms.shift())){
217                 d["is"+t] = false;
218         }
219
220 /*=====
221         // Override locale setting, if specified
222         dojo.locale = {
223                 // summary: the locale as defined by Dojo (read-only)
224         };
225 =====*/
226         dojo.locale = d.config.locale;
227         
228         var rev = "$Rev: 13707 $".match(/\d+/);
229
230         dojo.version = {
231                 // summary: 
232                 //              version number of dojo
233                 //      major: Integer
234                 //              Major version. If total version is "1.2.0beta1", will be 1
235                 //      minor: Integer
236                 //              Minor version. If total version is "1.2.0beta1", will be 2
237                 //      patch: Integer
238                 //              Patch version. If total version is "1.2.0beta1", will be 0
239                 //      flag: String
240                 //              Descriptor flag. If total version is "1.2.0beta1", will be "beta1"
241                 //      revision: Number
242                 //              The SVN rev from which dojo was pulled
243                 major: 1, minor: 1, patch: 1, flag: "",
244                 revision: rev ? +rev[0] : 999999, //FIXME: use NaN?
245                 toString: function(){
246                         with(d.version){
247                                 return major + "." + minor + "." + patch + flag + " (" + revision + ")";        // String
248                         }
249                 }
250         }
251
252         // Register with the OpenAjax hub
253         if(typeof OpenAjax != "undefined"){
254                 OpenAjax.hub.registerLibrary(dojo._scopeName, "http://dojotoolkit.org", d.version.toString());
255         }
256
257         dojo._mixin = function(/*Object*/ obj, /*Object*/ props){
258                 // summary:
259                 //              Adds all properties and methods of props to obj. This addition
260                 //              is "prototype extension safe", so that instances of objects
261                 //              will not pass along prototype defaults.
262                 var tobj = {};
263                 for(var x in props){
264                         // the "tobj" condition avoid copying properties in "props"
265                         // inherited from Object.prototype.  For example, if obj has a custom
266                         // toString() method, don't overwrite it with the toString() method
267                         // that props inherited from Object.prototype
268                         if(tobj[x] === undefined || tobj[x] != props[x]){
269                                 obj[x] = props[x];
270                         }
271                 }
272                 // IE doesn't recognize custom toStrings in for..in
273                 if(d["isIE"] && props){
274                         var p = props.toString;
275                         if(typeof p == "function" && p != obj.toString && p != tobj.toString &&
276                                 p != "\nfunction toString() {\n    [native code]\n}\n"){
277                                         obj.toString = props.toString;
278                         }
279                 }
280                 return obj; // Object
281         }
282
283         dojo.mixin = function(/*Object*/obj, /*Object...*/props){
284                 // summary:     
285                 //              Adds all properties and methods of props to obj and returns the
286                 //              (now modified) obj.
287                 //      description:
288                 //              `dojo.mixin` can mix multiple source objects into a
289                 //              destionation object which is then returned. Unlike regular
290                 //              `for...in` iteration, `dojo.mixin` is also smart about avoiding
291                 //              extensions which other toolkits may unwisely add to the root
292                 //              object prototype
293                 //      obj:
294                 //              The object to mix properties into. Also the return value.
295                 //      props:
296                 //              One or more objects whose values are successively copied into
297                 //              obj. If more than one of these objects contain the same value,
298                 //              the one specified last in the function call will "win".
299                 //      example:
300                 //              make a shallow copy of an object
301                 //      |       var copy = dojo.mixin({}, source);
302                 //      example:
303                 //              many class constructors often take an object which specifies
304                 //              values to be configured on the object. In this case, it is
305                 //              often simplest to call `dojo.mixin` on the `this` object:
306                 //      |       dojo.declare("acme.Base", null, {
307                 //      |               constructor: function(properties){
308                 //      |                       // property configuration:
309                 //      |                       dojo.mixin(this, properties);
310                 //      |       
311                 //      |                       console.debug(this.quip);
312                 //      |                       //  ...
313                 //      |               },
314                 //      |               quip: "I wasn't born yesterday, you know - I've seen movies.",
315                 //      |               // ...
316                 //      |       });
317                 //      |
318                 //      |       // create an instance of the class and configure it
319                 //      |       var b = new acme.Base({quip: "That's what it does!" });
320                 //      example:
321                 //              copy in properties from multiple objects
322                 //      |       var flattened = dojo.mixin(
323                 //      |               {
324                 //      |                       name: "Frylock",
325                 //      |                       braces: true,
326                 //      |               }
327                 //      |               {
328                 //      |                       name: "Carl Brutanananadilewski"
329                 //      |               }
330                 //      |       );
331                 //      |       
332                 //      |       // will print "Carl Brutanananadilewski"
333                 //      |       console.debug(flattened.name);
334                 //      |       // will print "true"
335                 //      |       console.debug(flattened.braces);
336                 for(var i=1, l=arguments.length; i<l; i++){
337                         d._mixin(obj, arguments[i]);
338                 }
339                 return obj; // Object
340         }
341
342         dojo._getProp = function(/*Array*/parts, /*Boolean*/create, /*Object*/context){
343                 var obj=context || d.global;
344                 for(var i=0, p; obj && (p=parts[i]); i++){
345                         if(i == 0 && this._scopeMap[p]){
346                                 p = this._scopeMap[p];
347                         }
348                         obj = (p in obj ? obj[p] : (create ? obj[p]={} : undefined));
349                 }
350                 return obj; // mixed
351         }
352
353         dojo.setObject = function(/*String*/name, /*Object*/value, /*Object?*/context){
354                 // summary: 
355                 //              Set a property from a dot-separated string, such as "A.B.C"
356                 //      description: 
357                 //              Useful for longer api chains where you have to test each object in
358                 //              the chain, or when you have an object reference in string format.
359                 //              Objects are created as needed along `path`. Returns the passed
360                 //              value if setting is successful or `undefined` if not.
361                 //      name:   
362                 //              Path to a property, in the form "A.B.C".
363                 //      context:
364                 //              Optional. Object to use as root of path. Defaults to
365                 //              `dojo.global`.
366                 //      example:
367                 //              set the value of `foo.bar.baz`, regardless of whether
368                 //              intermediate objects already exist:
369                 //      |       dojo.setObject("foo.bar.baz", value);
370                 //      example:
371                 //              without `dojo.setObject`, we often see code like this:
372                 //      |       // ensure that intermediate objects are available
373                 //      |       if(!obj["parent"]){ obj.parent = {}; }
374                 //      |       if(!obj.parent["child"]){ obj.parent.child= {}; }
375                 //      |       // now we can safely set the property
376                 //      |       obj.parent.child.prop = "some value";
377                 //              wheras with `dojo.setObject`, we can shorten that to:
378                 //      |       dojo.setObject("parent.child.prop", "some value", obj);
379                 var parts=name.split("."), p=parts.pop(), obj=d._getProp(parts, true, context);
380                 return obj && p ? (obj[p]=value) : undefined; // Object
381         }
382
383         dojo.getObject = function(/*String*/name, /*Boolean*/create, /*Object*/context){
384                 // summary: 
385                 //              Get a property from a dot-separated string, such as "A.B.C"
386                 //      description: 
387                 //              Useful for longer api chains where you have to test each object in
388                 //              the chain, or when you have an object reference in string format.
389                 //      name:   
390                 //              Path to an property, in the form "A.B.C".
391                 //      context:
392                 //              Optional. Object to use as root of path. Defaults to
393                 //              'dojo.global'. Null may be passed.
394                 //      create: 
395                 //              Optional. Defaults to `false`. If `true`, Objects will be
396                 //              created at any point along the 'path' that is undefined.
397                 return d._getProp(name.split("."), create, context); // Object
398         }
399
400         dojo.exists = function(/*String*/name, /*Object?*/obj){
401                 //      summary: 
402                 //              determine if an object supports a given method
403                 //      description: 
404                 //              useful for longer api chains where you have to test each object in
405                 //              the chain
406                 //      name:   
407                 //              Path to an object, in the form "A.B.C".
408                 //      obj:
409                 //              Object to use as root of path. Defaults to
410                 //              'dojo.global'. Null may be passed.
411                 //      example:
412                 //      |       // define an object
413                 //      |       var foo = {
414                 //      |               bar: { }
415                 //      |       };
416                 //      |
417                 //      |       // search the global scope
418                 //      |       dojo.exists("foo.bar"); // true
419                 //      |       dojo.exists("foo.bar.baz"); // false
420                 //      |
421                 //      |       // search from a particular scope
422                 //      |       dojo.exists("bar", foo); // true
423                 //      |       dojo.exists("bar.baz", foo); // false
424                 return !!d.getObject(name, false, obj); // Boolean
425         }
426
427
428         dojo["eval"] = function(/*String*/ scriptFragment){
429                 //      summary: 
430                 //              Perform an evaluation in the global scope. Use this rather than
431                 //              calling 'eval()' directly.
432                 //      description: 
433                 //              Placed in a separate function to minimize size of trapped
434                 //              exceptions. Calling eval() directly from some other scope may
435                 //              complicate tracebacks on some platforms.
436                 //      return:
437                 //              The result of the evaluation. Often `undefined`
438
439
440                 // note:
441                 //       - JSC eval() takes an optional second argument which can be 'unsafe'.
442                 //       - Mozilla/SpiderMonkey eval() takes an optional second argument which is the
443                 //       scope object for new symbols.
444
445                 // FIXME: investigate Joseph Smarr's technique for IE:
446                 //              http://josephsmarr.com/2007/01/31/fixing-eval-to-use-global-scope-in-ie/
447                 //      see also:
448                 //              http://trac.dojotoolkit.org/ticket/744
449                 return d.global.eval ? d.global.eval(scriptFragment) : eval(scriptFragment);    // Object
450         }
451
452         /*=====
453                 dojo.deprecated = function(behaviour, extra, removal){
454                         //      summary: 
455                         //              Log a debug message to indicate that a behavior has been
456                         //              deprecated.
457                         //      behaviour: String
458                         //              The API or behavior being deprecated. Usually in the form
459                         //              of "myApp.someFunction()".
460                         //      extra: String?
461                         //              Text to append to the message. Often provides advice on a
462                         //              new function or facility to achieve the same goal during
463                         //              the deprecation period.
464                         //      removal: String?
465                         //              Text to indicate when in the future the behavior will be
466                         //              removed. Usually a version number.
467                         //      example:
468                         //      |       dojo.deprecated("myApp.getTemp()", "use myApp.getLocaleTemp() instead", "1.0");
469                 }
470
471                 dojo.experimental = function(moduleName, extra){
472                         //      summary: Marks code as experimental.
473                         //      description: 
474                         //              This can be used to mark a function, file, or module as
475                         //              experimental.  Experimental code is not ready to be used, and the
476                         //              APIs are subject to change without notice.  Experimental code may be
477                         //              completed deleted without going through the normal deprecation
478                         //              process.
479                         //      moduleName: String
480                         //              The name of a module, or the name of a module file or a specific
481                         //              function
482                         //      extra: String?
483                         //              some additional message for the user
484                         //      example:
485                         //      |       dojo.experimental("dojo.data.Result");
486                         //      example:
487                         //      |       dojo.experimental("dojo.weather.toKelvin()", "PENDING approval from NOAA");
488                 }
489         =====*/
490
491         //Real functions declared in dojo._firebug.firebug.
492         d.deprecated = d.experimental = function(){};
493
494 })();
495 // vim:ai:ts=4:noet
496
497 /*
498  * loader.js - A bootstrap module.  Runs before the hostenv_*.js file. Contains
499  * all of the package loading methods.
500  */
501
502 (function(){
503         var d = dojo;
504
505         d.mixin(d, {
506                 _loadedModules: {},
507                 _inFlightCount: 0,
508                 _hasResource: {},
509
510                 _modulePrefixes: {
511                         dojo:   {       name: "dojo", value: "." },
512                         // dojox:       {       name: "dojox", value: "../dojox" },
513                         // dijit:       {       name: "dijit", value: "../dijit" },
514                         doh:    {       name: "doh", value: "../util/doh" },
515                         tests:  {       name: "tests", value: "tests" }
516                 },
517
518                 _moduleHasPrefix: function(/*String*/module){
519                         // summary: checks to see if module has been established
520                         var mp = this._modulePrefixes;
521                         return !!(mp[module] && mp[module].value); // Boolean
522                 },
523
524                 _getModulePrefix: function(/*String*/module){
525                         // summary: gets the prefix associated with module
526                         var mp = this._modulePrefixes;
527                         if(this._moduleHasPrefix(module)){
528                                 return mp[module].value; // String
529                         }
530                         return module; // String
531                 },
532
533                 _loadedUrls: [],
534
535                 //WARNING: 
536                 //              This variable is referenced by packages outside of bootstrap:
537                 //              FloatingPane.js and undo/browser.js
538                 _postLoad: false,
539                 
540                 //Egad! Lots of test files push on this directly instead of using dojo.addOnLoad.
541                 _loaders: [],
542                 _unloaders: [],
543                 _loadNotifying: false
544         });
545
546
547                 dojo._loadPath = function(/*String*/relpath, /*String?*/module, /*Function?*/cb){
548                 //      summary:
549                 //              Load a Javascript module given a relative path
550                 //
551                 //      description:
552                 //              Loads and interprets the script located at relpath, which is
553                 //              relative to the script root directory.  If the script is found but
554                 //              its interpretation causes a runtime exception, that exception is
555                 //              not caught by us, so the caller will see it.  We return a true
556                 //              value if and only if the script is found.
557                 //
558                 // relpath: 
559                 //              A relative path to a script (no leading '/', and typically ending
560                 //              in '.js').
561                 // module: 
562                 //              A module whose existance to check for after loading a path.  Can be
563                 //              used to determine success or failure of the load.
564                 // cb: 
565                 //              a callback function to pass the result of evaluating the script
566
567                 var uri = ((relpath.charAt(0) == '/' || relpath.match(/^\w+:/)) ? "" : this.baseUrl) + relpath;
568                 try{
569                         return !module ? this._loadUri(uri, cb) : this._loadUriAndCheck(uri, module, cb); // Boolean
570                 }catch(e){
571                         console.error(e);
572                         return false; // Boolean
573                 }
574         }
575
576         dojo._loadUri = function(/*String*/uri, /*Function?*/cb){
577                 //      summary:
578                 //              Loads JavaScript from a URI
579                 //      description:
580                 //              Reads the contents of the URI, and evaluates the contents.  This is
581                 //              used to load modules as well as resource bundles. Returns true if
582                 //              it succeeded. Returns false if the URI reading failed.  Throws if
583                 //              the evaluation throws.
584                 //      uri: a uri which points at the script to be loaded
585                 //      cb: 
586                 //              a callback function to process the result of evaluating the script
587                 //              as an expression, typically used by the resource bundle loader to
588                 //              load JSON-style resources
589
590                 if(this._loadedUrls[uri]){
591                         return true; // Boolean
592                 }
593                 var contents = this._getText(uri, true);
594                 if(!contents){ return false; } // Boolean
595                 this._loadedUrls[uri] = true;
596                 this._loadedUrls.push(uri);
597                 if(cb){
598                         contents = '('+contents+')';
599                 }else{
600                         //Only do the scoping if no callback. If a callback is specified,
601                         //it is most likely the i18n bundle stuff.
602                         contents = this._scopePrefix + contents + this._scopeSuffix;
603                 }
604                 if(d.isMoz){ contents += "\r\n//@ sourceURL=" + uri; } // debugging assist for Firebug
605                 var value = d["eval"](contents);
606                 if(cb){ cb(value); }
607                 return true; // Boolean
608         }
609         
610         // FIXME: probably need to add logging to this method
611         dojo._loadUriAndCheck = function(/*String*/uri, /*String*/moduleName, /*Function?*/cb){
612                 // summary: calls loadUri then findModule and returns true if both succeed
613                 var ok = false;
614                 try{
615                         ok = this._loadUri(uri, cb);
616                 }catch(e){
617                         console.error("failed loading " + uri + " with error: " + e);
618                 }
619                 return !!(ok && this._loadedModules[moduleName]); // Boolean
620         }
621
622         dojo.loaded = function(){
623                 // summary:
624                 //              signal fired when initial environment and package loading is
625                 //              complete. You may use dojo.addOnLoad() or dojo.connect() to
626                 //              this method in order to handle initialization tasks that
627                 //              require the environment to be initialized. In a browser host,
628                 //              declarative widgets will be constructed when this function
629                 //              finishes runing.
630                 this._loadNotifying = true;
631                 this._postLoad = true;
632                 var mll = d._loaders;
633                 
634                 //Clear listeners so new ones can be added
635                 //For other xdomain package loads after the initial load.
636                 this._loaders = [];
637
638                 for(var x = 0; x < mll.length; x++){
639                         try{
640                                 mll[x]();
641                         }catch(e){
642                                 throw e;
643                                 console.error("dojo.addOnLoad callback failed: " + e, e); /* let other load events fire, like the parser, but report the error */
644                         }
645                 }
646
647                 this._loadNotifying = false;
648                 
649                 //Make sure nothing else got added to the onload queue
650                 //after this first run. If something did, and we are not waiting for any
651                 //more inflight resources, run again.
652                 if(d._postLoad && d._inFlightCount == 0 && mll.length){
653                         d._callLoaded();
654                 }
655         }
656
657         dojo.unloaded = function(){
658                 // summary:
659                 //              signal fired by impending environment destruction. You may use
660                 //              dojo.addOnUnload() or dojo.connect() to this method to perform
661                 //              page/application cleanup methods.
662                 var mll = this._unloaders;
663                 while(mll.length){
664                         (mll.pop())();
665                 }
666         }
667
668         var onto = function(arr, obj, fn){
669                 if(!fn){
670                         arr.push(obj);
671                 }else if(fn){
672                         var func = (typeof fn == "string") ? obj[fn] : fn;
673                         arr.push(function(){ func.call(obj); });
674                 }
675         }
676
677         dojo.addOnLoad = function(/*Object?*/obj, /*String|Function*/functionName){
678                 // summary:
679                 //              Registers a function to be triggered after the DOM has finished
680                 //              loading and widgets declared in markup have been instantiated.
681                 //              Images and CSS files may or may not have finished downloading when
682                 //              the specified function is called.  (Note that widgets' CSS and HTML
683                 //              code is guaranteed to be downloaded before said widgets are
684                 //              instantiated.)
685                 // example:
686                 //      |       dojo.addOnLoad(functionPointer);
687                 //      |       dojo.addOnLoad(object, "functionName");
688                 //      |       dojo.addOnLoad(object, function(){ /* ... */});
689
690                 onto(d._loaders, obj, functionName);
691
692                 //Added for xdomain loading. dojo.addOnLoad is used to
693                 //indicate callbacks after doing some dojo.require() statements.
694                 //In the xdomain case, if all the requires are loaded (after initial
695                 //page load), then immediately call any listeners.
696                 if(d._postLoad && d._inFlightCount == 0 && !d._loadNotifying){
697                         d._callLoaded();
698                 }
699         }
700
701         dojo.addOnUnload = function(/*Object?*/obj, /*String|Function?*/functionName){
702                 // summary:
703                 //              registers a function to be triggered when the page unloads
704                 // example:
705                 //      |       dojo.addOnUnload(functionPointer)
706                 //      |       dojo.addOnUnload(object, "functionName")
707                 //      |       dojo.addOnUnload(object, function(){ /* ... */});
708
709                 onto(d._unloaders, obj, functionName);
710         }
711
712         dojo._modulesLoaded = function(){
713                 if(d._postLoad){ return; }
714                 if(d._inFlightCount > 0){ 
715                         console.warn("files still in flight!");
716                         return;
717                 }
718                 d._callLoaded();
719         }
720
721         dojo._callLoaded = function(){
722
723                 // The "object" check is for IE, and the other opera check fixes an
724                 // issue in Opera where it could not find the body element in some
725                 // widget test cases.  For 0.9, maybe route all browsers through the
726                 // setTimeout (need protection still for non-browser environments
727                 // though). This might also help the issue with FF 2.0 and freezing
728                 // issues where we try to do sync xhr while background css images are
729                 // being loaded (trac #2572)? Consider for 0.9.
730                 if(typeof setTimeout == "object" || (dojo.config.useXDomain && d.isOpera)){
731                         if(dojo.isAIR){
732                                 setTimeout(function(){dojo.loaded();}, 0);
733                         }else{
734                                 setTimeout(dojo._scopeName + ".loaded();", 0);
735                         }
736                 }else{
737                         d.loaded();
738                 }
739         }
740
741         dojo._getModuleSymbols = function(/*String*/modulename){
742                 // summary:
743                 //              Converts a module name in dotted JS notation to an array
744                 //              representing the path in the source tree
745                 var syms = modulename.split(".");
746                 for(var i = syms.length; i>0; i--){
747                         var parentModule = syms.slice(0, i).join(".");
748                         if((i==1) && !this._moduleHasPrefix(parentModule)){             
749                                 // Support default module directory (sibling of dojo) for top-level modules 
750                                 syms[0] = "../" + syms[0];
751                         }else{
752                                 var parentModulePath = this._getModulePrefix(parentModule);
753                                 if(parentModulePath != parentModule){
754                                         syms.splice(0, i, parentModulePath);
755                                         break;
756                                 }
757                         }
758                 }
759                 // console.debug(syms);
760                 return syms; // Array
761         }
762
763         dojo._global_omit_module_check = false;
764
765         dojo._loadModule = dojo.require = function(/*String*/moduleName, /*Boolean?*/omitModuleCheck){
766                 //      summary:
767                 //              loads a Javascript module from the appropriate URI
768                 //      moduleName:
769                 //              module name to load. Module paths are de-referenced by dojo's
770                 //              internal mapping of locations to names and are disambiguated by
771                 //              longest prefix. See `dojo.registerModulePath()` for details on
772                 //              registering new modules.
773                 //      omitModuleCheck:
774                 //              if `true`, omitModuleCheck skips the step of ensuring that the
775                 //              loaded file actually defines the symbol it is referenced by.
776                 //              For example if it called as `dojo._loadModule("a.b.c")` and the
777                 //              file located at `a/b/c.js` does not define an object `a.b.c`,
778                 //              and exception will be throws whereas no exception is raised
779                 //              when called as `dojo._loadModule("a.b.c", true)`
780                 //      description:
781                 //              `dojo._loadModule("A.B")` first checks to see if symbol A.B is
782                 //              defined. If it is, it is simply returned (nothing to do).
783                 //      
784                 //              If it is not defined, it will look for `A/B.js` in the script root
785                 //              directory.
786                 //      
787                 //              `dojo._loadModule` throws an excpetion if it cannot find a file
788                 //              to load, or if the symbol `A.B` is not defined after loading.
789                 //      
790                 //              It returns the object `A.B`.
791                 //      
792                 //              `dojo._loadModule()` does nothing about importing symbols into
793                 //              the current namespace.  It is presumed that the caller will
794                 //              take care of that. For example, to import all symbols into a
795                 //              local block, you might write:
796                 //      
797                 //              |       with (dojo._loadModule("A.B")) {
798                 //              |               ...
799                 //              |       }
800                 //      
801                 //              And to import just the leaf symbol to a local variable:
802                 //      
803                 //              |       var B = dojo._loadModule("A.B");
804                 //              |       ...
805                 //      returns: the required namespace object
806                 omitModuleCheck = this._global_omit_module_check || omitModuleCheck;
807
808                 //Check if it is already loaded.
809                 var module = this._loadedModules[moduleName];
810                 if(module){
811                         return module;
812                 }
813
814                 // convert periods to slashes
815                 var relpath = this._getModuleSymbols(moduleName).join("/") + '.js';
816
817                 var modArg = (!omitModuleCheck) ? moduleName : null;
818                 var ok = this._loadPath(relpath, modArg);
819
820                 if(!ok && !omitModuleCheck){
821                         throw new Error("Could not load '" + moduleName + "'; last tried '" + relpath + "'");
822                 }
823
824                 // check that the symbol was defined
825                 // Don't bother if we're doing xdomain (asynchronous) loading.
826                 if(!omitModuleCheck && !this._isXDomain){
827                         // pass in false so we can give better error
828                         module = this._loadedModules[moduleName];
829                         if(!module){
830                                 throw new Error("symbol '" + moduleName + "' is not defined after loading '" + relpath + "'"); 
831                         }
832                 }
833
834                 return module;
835         }
836
837         dojo.provide = function(/*String*/ resourceName){
838                 //      summary:
839                 //              Each javascript source file must have at least one
840                 //              `dojo.provide()` call at the top of the file, corresponding to
841                 //              the file name.  For example, `js/dojo/foo.js` must have
842                 //              `dojo.provide("dojo.foo");` before any calls to
843                 //              `dojo.require()` are made.
844                 //      description:
845                 //              Each javascript source file is called a resource.  When a
846                 //              resource is loaded by the browser, `dojo.provide()` registers
847                 //              that it has been loaded.
848                 //      
849                 //              For backwards compatibility reasons, in addition to registering
850                 //              the resource, `dojo.provide()` also ensures that the javascript
851                 //              object for the module exists.  For example,
852                 //              `dojo.provide("dojox.data.FlickrStore")`, in addition to
853                 //              registering that `FlickrStore.js` is a resource for the
854                 //              `dojox.data` module, will ensure that the `dojox.data`
855                 //              javascript object exists, so that calls like 
856                 //              `dojo.data.foo = function(){ ... }` don't fail.
857                 //
858                 //              In the case of a build where multiple javascript source files
859                 //              are combined into one bigger file (similar to a .lib or .jar
860                 //              file), that file may contain multiple dojo.provide() calls, to
861                 //              note that it includes multiple resources.
862
863                 //Make sure we have a string.
864                 resourceName = resourceName + "";
865                 return (d._loadedModules[resourceName] = d.getObject(resourceName, true)); // Object
866         }
867
868         //Start of old bootstrap2:
869
870         dojo.platformRequire = function(/*Object*/modMap){
871                 //      summary:
872                 //              require one or more modules based on which host environment
873                 //              Dojo is currently operating in
874                 //      description:
875                 //              This method takes a "map" of arrays which one can use to
876                 //              optionally load dojo modules. The map is indexed by the
877                 //              possible dojo.name_ values, with two additional values:
878                 //              "default" and "common". The items in the "default" array will
879                 //              be loaded if none of the other items have been choosen based on
880                 //              dojo.name_, set by your host environment. The items in the
881                 //              "common" array will *always* be loaded, regardless of which
882                 //              list is chosen.
883                 //      example:
884                 //              |       dojo.platformRequire({
885                 //              |               browser: [
886                 //              |                       "foo.sample", // simple module
887                 //              |                       "foo.test",
888                 //              |                       ["foo.bar.baz", true] // skip object check in _loadModule
889                 //              |               ],
890                 //              |               default: [ "foo.sample._base" ],
891                 //              |               common: [ "important.module.common" ]
892                 //              |       });
893
894                 var common = modMap.common || [];
895                 var result = common.concat(modMap[d._name] || modMap["default"] || []);
896
897                 for(var x=0; x<result.length; x++){
898                         var curr = result[x];
899                         if(curr.constructor == Array){
900                                 d._loadModule.apply(d, curr);
901                         }else{
902                                 d._loadModule(curr);
903                         }
904                 }
905         }
906
907         dojo.requireIf = function(/*Boolean*/ condition, /*String*/ resourceName){
908                 // summary:
909                 //              If the condition is true then call dojo.require() for the specified
910                 //              resource
911                 if(condition === true){
912                         // FIXME: why do we support chained require()'s here? does the build system?
913                         var args = [];
914                         for(var i = 1; i < arguments.length; i++){ 
915                                 args.push(arguments[i]);
916                         }
917                         d.require.apply(d, args);
918                 }
919         }
920
921         dojo.requireAfterIf = d.requireIf;
922
923         dojo.registerModulePath = function(/*String*/module, /*String*/prefix){
924                 //      summary: 
925                 //              maps a module name to a path
926                 //      description: 
927                 //              An unregistered module is given the default path of ../[module],
928                 //              relative to Dojo root. For example, module acme is mapped to
929                 //              ../acme.  If you want to use a different module name, use
930                 //              dojo.registerModulePath. 
931                 //      example:
932                 //              If your dojo.js is located at this location in the web root:
933                 //      |       /myapp/js/dojo/dojo/dojo.js
934                 //              and your modules are located at:
935                 //      |       /myapp/js/foo/bar.js
936                 //      |       /myapp/js/foo/baz.js
937                 //      |       /myapp/js/foo/thud/xyzzy.js
938                 //              Your application can tell Dojo to locate the "foo" namespace by calling:
939                 //      |       dojo.registerModulePath("foo", "../../foo");
940                 //              At which point you can then use dojo.require() to load the
941                 //              modules (assuming they provide() the same things which are
942                 //              required). The full code might be:
943                 //      |       <script type="text/javascript" 
944                 //      |               src="/myapp/js/dojo/dojo/dojo.js"></script>
945                 //      |       <script type="text/javascript">
946                 //      |               dojo.registerModulePath("foo", "../../foo");
947                 //      |               dojo.require("foo.bar");
948                 //      |               dojo.require("foo.baz");
949                 //      |               dojo.require("foo.thud.xyzzy");
950                 //      |       </script>
951                 d._modulePrefixes[module] = { name: module, value: prefix };
952         }
953
954         dojo.requireLocalization = function(/*String*/moduleName, /*String*/bundleName, /*String?*/locale, /*String?*/availableFlatLocales){
955                 // summary:
956                 //              Declares translated resources and loads them if necessary, in the
957                 //              same style as dojo.require.  Contents of the resource bundle are
958                 //              typically strings, but may be any name/value pair, represented in
959                 //              JSON format.  See also dojo.i18n.getLocalization.
960                 // moduleName: 
961                 //              name of the package containing the "nls" directory in which the
962                 //              bundle is found
963                 // bundleName: 
964                 //              bundle name, i.e. the filename without the '.js' suffix
965                 // locale: 
966                 //              the locale to load (optional)  By default, the browser's user
967                 //              locale as defined by dojo.locale
968                 // availableFlatLocales: 
969                 //              A comma-separated list of the available, flattened locales for this
970                 //              bundle. This argument should only be set by the build process.
971                 // description:
972                 //              Load translated resource bundles provided underneath the "nls"
973                 //              directory within a package.  Translated resources may be located in
974                 //              different packages throughout the source tree.  For example, a
975                 //              particular widget may define one or more resource bundles,
976                 //              structured in a program as follows, where moduleName is
977                 //              mycode.mywidget and bundleNames available include bundleone and
978                 //              bundletwo:
979                 //
980                 //      |               ...
981                 //      |               mycode/
982                 //      |                mywidget/
983                 //      |                 nls/
984                 //      |                  bundleone.js (the fallback translation, English in this example)
985                 //      |                  bundletwo.js (also a fallback translation)
986                 //      |                  de/
987                 //      |                   bundleone.js
988                 //      |                   bundletwo.js
989                 //      |                  de-at/
990                 //      |                   bundleone.js
991                 //      |                  en/
992                 //      |                   (empty; use the fallback translation)
993                 //      |                  en-us/
994                 //      |                   bundleone.js
995                 //      |                  en-gb/
996                 //      |                   bundleone.js
997                 //      |                  es/
998                 //      |                   bundleone.js
999                 //      |                   bundletwo.js
1000                 //      |                 ...etc
1001                 //      |               ...
1002                 //
1003                 //              Each directory is named for a locale as specified by RFC 3066,
1004                 //              (http://www.ietf.org/rfc/rfc3066.txt), normalized in lowercase.
1005                 //              Note that the two bundles in the example do not define all the
1006                 //              same variants.  For a given locale, bundles will be loaded for
1007                 //              that locale and all more general locales above it, including a
1008                 //              fallback at the root directory.  For example, a declaration for
1009                 //              the "de-at" locale will first load `nls/de-at/bundleone.js`,
1010                 //              then `nls/de/bundleone.js` and finally `nls/bundleone.js`.  The
1011                 //              data will be flattened into a single Object so that lookups
1012                 //              will follow this cascading pattern.  An optional build step can
1013                 //              preload the bundles to avoid data redundancy and the multiple
1014                 //              network hits normally required to load these resources.
1015
1016                 d.require("dojo.i18n");
1017                 d.i18n._requireLocalization.apply(d.hostenv, arguments);
1018         };
1019
1020
1021         var ore = new RegExp("^(([^:/?#]+):)?(//([^/?#]*))?([^?#]*)(\\?([^#]*))?(#(.*))?$");
1022         var ire = new RegExp("^((([^:]+:)?([^@]+))@)?([^:]*)(:([0-9]+))?$");
1023
1024         dojo._Url = function(/*dojo._Url||String...*/){
1025                 // summary: 
1026                 //              Constructor to create an object representing a URL.
1027                 //              It is marked as private, since we might consider removing
1028                 //              or simplifying it.
1029                 // description: 
1030                 //              Each argument is evaluated in order relative to the next until
1031                 //              a canonical uri is produced. To get an absolute Uri relative to
1032                 //              the current document use:
1033                 //              new dojo._Url(document.baseURI, url)
1034
1035                 var n = null;
1036
1037                 // TODO: support for IPv6, see RFC 2732
1038                 var _a = arguments;
1039                 var uri = [_a[0]];
1040                 // resolve uri components relative to each other
1041                 for(var i = 1; i<_a.length; i++){
1042                         if(!_a[i]){ continue; }
1043
1044                         // Safari doesn't support this.constructor so we have to be explicit
1045                         // FIXME: Tracked (and fixed) in Webkit bug 3537.
1046                         //              http://bugs.webkit.org/show_bug.cgi?id=3537
1047                         var relobj = new d._Url(_a[i]+"");
1048                         var uriobj = new d._Url(uri[0]+"");
1049
1050                         if(
1051                                 relobj.path == "" &&
1052                                 !relobj.scheme &&
1053                                 !relobj.authority &&
1054                                 !relobj.query
1055                         ){
1056                                 if(relobj.fragment != n){
1057                                         uriobj.fragment = relobj.fragment;
1058                                 }
1059                                 relobj = uriobj;
1060                         }else if(!relobj.scheme){
1061                                 relobj.scheme = uriobj.scheme;
1062
1063                                 if(!relobj.authority){
1064                                         relobj.authority = uriobj.authority;
1065
1066                                         if(relobj.path.charAt(0) != "/"){
1067                                                 var path = uriobj.path.substring(0,
1068                                                         uriobj.path.lastIndexOf("/") + 1) + relobj.path;
1069
1070                                                 var segs = path.split("/");
1071                                                 for(var j = 0; j < segs.length; j++){
1072                                                         if(segs[j] == "."){
1073                                                                 // flatten "./" references
1074                                                                 if(j == segs.length - 1){
1075                                                                         segs[j] = "";
1076                                                                 }else{
1077                                                                         segs.splice(j, 1);
1078                                                                         j--;
1079                                                                 }
1080                                                         }else if(j > 0 && !(j == 1 && segs[0] == "") &&
1081                                                                 segs[j] == ".." && segs[j-1] != ".."){
1082                                                                 // flatten "../" references
1083                                                                 if(j == (segs.length - 1)){
1084                                                                         segs.splice(j, 1);
1085                                                                         segs[j - 1] = "";
1086                                                                 }else{
1087                                                                         segs.splice(j - 1, 2);
1088                                                                         j -= 2;
1089                                                                 }
1090                                                         }
1091                                                 }
1092                                                 relobj.path = segs.join("/");
1093                                         }
1094                                 }
1095                         }
1096
1097                         uri = [];
1098                         if(relobj.scheme){ 
1099                                 uri.push(relobj.scheme, ":");
1100                         }
1101                         if(relobj.authority){
1102                                 uri.push("//", relobj.authority);
1103                         }
1104                         uri.push(relobj.path);
1105                         if(relobj.query){
1106                                 uri.push("?", relobj.query);
1107                         }
1108                         if(relobj.fragment){
1109                                 uri.push("#", relobj.fragment);
1110                         }
1111                 }
1112
1113                 this.uri = uri.join("");
1114
1115                 // break the uri into its main components
1116                 var r = this.uri.match(ore);
1117
1118                 this.scheme = r[2] || (r[1] ? "" : n);
1119                 this.authority = r[4] || (r[3] ? "" : n);
1120                 this.path = r[5]; // can never be undefined
1121                 this.query = r[7] || (r[6] ? "" : n);
1122                 this.fragment  = r[9] || (r[8] ? "" : n);
1123
1124                 if(this.authority != n){
1125                         // server based naming authority
1126                         r = this.authority.match(ire);
1127
1128                         this.user = r[3] || n;
1129                         this.password = r[4] || n;
1130                         this.host = r[5];
1131                         this.port = r[7] || n;
1132                 }
1133         }
1134
1135         dojo._Url.prototype.toString = function(){ return this.uri; };
1136
1137         dojo.moduleUrl = function(/*String*/module, /*dojo._Url||String*/url){
1138                 //      summary: 
1139                 //              Returns a `dojo._Url` object relative to a module.
1140                 //      example:
1141                 //      |       var pngPath = dojo.moduleUrl("acme","images/small.png");
1142                 //      |       console.dir(pngPath); // list the object properties
1143                 //      |       // create an image and set it's source to pngPath's value:
1144                 //      |       var img = document.createElement("img");
1145                 //      |       // NOTE: we assign the string representation of the url object
1146                 //      |       img.src = pngPath.toString(); 
1147                 //      |       // add our image to the document
1148                 //      |       dojo.body().appendChild(img);
1149                 //      example: 
1150                 //              you may de-reference as far as you like down the package
1151                 //              hierarchy.  This is sometimes handy to avoid lenghty relative
1152                 //              urls or for building portable sub-packages. In this example,
1153                 //              the `acme.widget` and `acme.util` directories may be located
1154                 //              under different roots (see `dojo.registerModulePath`) but the
1155                 //              the modules which reference them can be unaware of their
1156                 //              relative locations on the filesystem:
1157                 //      |       // somewhere in a configuration block
1158                 //      |       dojo.registerModulePath("acme.widget", "../../acme/widget");
1159                 //      |       dojo.registerModulePath("acme.util", "../../util");
1160                 //      |       
1161                 //      |       // ...
1162                 //      |       
1163                 //      |       // code in a module using acme resources
1164                 //      |       var tmpltPath = dojo.moduleUrl("acme.widget","templates/template.html");
1165                 //      |       var dataPath = dojo.moduleUrl("acme.util","resources/data.json");
1166
1167                 var loc = d._getModuleSymbols(module).join('/');
1168                 if(!loc){ return null; }
1169                 if(loc.lastIndexOf("/") != loc.length-1){
1170                         loc += "/";
1171                 }
1172                 
1173                 //If the path is an absolute path (starts with a / or is on another
1174                 //domain/xdomain) then don't add the baseUrl.
1175                 var colonIndex = loc.indexOf(":");
1176                 if(loc.charAt(0) != "/" && (colonIndex == -1 || colonIndex > loc.indexOf("/"))){
1177                         loc = d.baseUrl + loc;
1178                 }
1179
1180                 return new d._Url(loc, url); // String
1181         }
1182 })();
1183
1184 /*=====
1185 dojo.isBrowser = {
1186         //      example:
1187         //      |       if(dojo.isBrowser){ ... }
1188 };
1189
1190 dojo.isFF = {
1191         //      example:
1192         //      |       if(dojo.isFF > 1){ ... }
1193 };
1194
1195 dojo.isIE = {
1196         // example:
1197         //      |       if(dojo.isIE > 6){
1198         //      |               // we are IE7
1199         //      |       }
1200 };
1201
1202 dojo.isSafari = {
1203         //      example:
1204         //      |       if(dojo.isSafari){ ... }
1205         //      example: 
1206         //              Detect iPhone:
1207         //      |       if(dojo.isSafari && (navigator.userAgent.indexOf("iPhone") < 0)){ 
1208         //      |               // we are iPhone. iPod touch reports "iPod" above
1209         //      |       }
1210 };
1211
1212 dojo = {
1213         // isBrowser: Boolean
1214         //              True if the client is a web-browser
1215         isBrowser: true,
1216         //      isFF: Number
1217         //              Greater than zero if client is FireFox. 0 otherwise. Corresponds to
1218         //              major detected FireFox version (1.5, 2, 3, etc.)
1219         isFF: 2,
1220         //      isIE: Number
1221         //              Greater than zero if client is MSIE(PC). 0 otherwise. Corresponds to
1222         //              major detected IE version (6, 7, 8, etc.)
1223         isIE: 6,
1224         //      isKhtml: Number
1225         //              Greater than zero if client is a KTHML-derived browser (Konqueror,
1226         //              Safari, etc.). 0 otherwise. Corresponds to major detected version.
1227         isKhtml: 0,
1228         //      isMozilla: Number
1229         //              Greater than zero if client is a Mozilla-based browser (Firefox,
1230         //              SeaMonkey). 0 otherwise. Corresponds to major detected version.
1231         isMozilla: 0,
1232         //      isOpera: Number
1233         //              Greater than zero if client is Opera. 0 otherwise. Corresponds to
1234         //              major detected version.
1235         isOpera: 0,
1236         //      isSafari: Number
1237         //              Greater than zero if client is Safari or iPhone. 0 otherwise.
1238         isSafari: 0
1239 }
1240 =====*/
1241
1242 if(typeof window != 'undefined'){
1243         dojo.isBrowser = true;
1244         dojo._name = "browser";
1245
1246
1247         // attempt to figure out the path to dojo if it isn't set in the config
1248         (function(){
1249                 var d = dojo;
1250                 // this is a scope protection closure. We set browser versions and grab
1251                 // the URL we were loaded from here.
1252
1253                 // grab the node we were loaded from
1254                 if(document && document.getElementsByTagName){
1255                         var scripts = document.getElementsByTagName("script");
1256                         var rePkg = /dojo(\.xd)?\.js(\W|$)/i;
1257                         for(var i = 0; i < scripts.length; i++){
1258                                 var src = scripts[i].getAttribute("src");
1259                                 if(!src){ continue; }
1260                                 var m = src.match(rePkg);
1261                                 if(m){
1262                                         // find out where we came from
1263                                         if(!d.config.baseUrl){
1264                                                 d.config.baseUrl = src.substring(0, m.index);
1265                                         }
1266                                         // and find out if we need to modify our behavior
1267                                         var cfg = scripts[i].getAttribute("djConfig");
1268                                         if(cfg){
1269                                                 var cfgo = eval("({ "+cfg+" })");
1270                                                 for(var x in cfgo){
1271                                                         dojo.config[x] = cfgo[x];
1272                                                 }
1273                                         }
1274                                         break; // "first Dojo wins"
1275                                 }
1276                         }
1277                 }
1278                 d.baseUrl = d.config.baseUrl;
1279
1280                 // fill in the rendering support information in dojo.render.*
1281                 var n = navigator;
1282                 var dua = n.userAgent;
1283                 var dav = n.appVersion;
1284                 var tv = parseFloat(dav);
1285
1286                 d.isOpera = (dua.indexOf("Opera") >= 0) ? tv : 0;
1287                 // safari detection derived from:
1288                 //              http://developer.apple.com/internet/safari/faq.html#anchor2
1289                 //              http://developer.apple.com/internet/safari/uamatrix.html
1290                 var idx = Math.max(dav.indexOf("WebKit"), dav.indexOf("Safari"), 0);
1291                 if(idx){
1292                         // try to grab the explicit Safari version first. If we don't get
1293                         // one, look for 419.3+ as the indication that we're on something
1294                         // "Safari 3-ish". Lastly, default to "Safari 2" handling.
1295                         d.isSafari = parseFloat(dav.split("Version/")[1]) || ( ( parseFloat(dav.substr(idx+7)) >= 419.3 ) ? 3 : 2 ) || 2;
1296                 }
1297                 d.isAIR = (dua.indexOf("AdobeAIR") >= 0) ? 1 : 0;
1298                 d.isKhtml = (dav.indexOf("Konqueror") >= 0 || d.isSafari) ? tv : 0;
1299                 d.isMozilla = d.isMoz = (dua.indexOf("Gecko") >= 0 && !d.isKhtml) ? tv : 0;
1300                 d.isFF = d.isIE = 0;
1301                 if(d.isMoz){
1302                         d.isFF = parseFloat(dua.split("Firefox/")[1]) || 0;
1303                 }
1304                 if(document.all && !d.isOpera){
1305                         d.isIE = parseFloat(dav.split("MSIE ")[1]) || 0;
1306                 }
1307
1308                 //Workaround to get local file loads of dojo to work on IE 7
1309                 //by forcing to not use native xhr.
1310                 if(dojo.isIE && window.location.protocol === "file:"){
1311                         dojo.config.ieForceActiveXXhr=true;
1312                 }
1313
1314                 var cm = document.compatMode;
1315                 d.isQuirks = cm == "BackCompat" || cm == "QuirksMode" || d.isIE < 6;
1316
1317                 // TODO: is the HTML LANG attribute relevant?
1318                 d.locale = dojo.config.locale || (d.isIE ? n.userLanguage : n.language).toLowerCase();
1319
1320                 // These are in order of decreasing likelihood; this will change in time.
1321                 d._XMLHTTP_PROGIDS = ['Msxml2.XMLHTTP', 'Microsoft.XMLHTTP', 'Msxml2.XMLHTTP.4.0'];
1322
1323                 d._xhrObj = function(){
1324                         // summary: 
1325                         //              does the work of portably generating a new XMLHTTPRequest
1326                         //              object.
1327                         var http = null;
1328                         var last_e = null;
1329                         if(!dojo.isIE || !dojo.config.ieForceActiveXXhr){
1330                                 try{ http = new XMLHttpRequest(); }catch(e){}
1331                         }
1332                         if(!http){
1333                                 for(var i=0; i<3; ++i){
1334                                         var progid = d._XMLHTTP_PROGIDS[i];
1335                                         try{
1336                                                 http = new ActiveXObject(progid);
1337                                         }catch(e){
1338                                                 last_e = e;
1339                                         }
1340
1341                                         if(http){
1342                                                 d._XMLHTTP_PROGIDS = [progid];  // so faster next time
1343                                                 break;
1344                                         }
1345                                 }
1346                         }
1347
1348                         if(!http){
1349                                 throw new Error("XMLHTTP not available: "+last_e);
1350                         }
1351
1352                         return http; // XMLHTTPRequest instance
1353                 }
1354
1355                 d._isDocumentOk = function(http){
1356                         var stat = http.status || 0;
1357                         return (stat >= 200 && stat < 300) ||   // Boolean
1358                                 stat == 304 ||                                          // allow any 2XX response code
1359                                 stat == 1223 ||                                                 // get it out of the cache
1360                                 (!stat && (location.protocol=="file:" || location.protocol=="chrome:") ); // Internet Explorer mangled the status code
1361                 }
1362
1363                 //See if base tag is in use.
1364                 //This is to fix http://trac.dojotoolkit.org/ticket/3973,
1365                 //but really, we need to find out how to get rid of the dojo._Url reference
1366                 //below and still have DOH work with the dojo.i18n test following some other
1367                 //test that uses the test frame to load a document (trac #2757).
1368                 //Opera still has problems, but perhaps a larger issue of base tag support
1369                 //with XHR requests (hasBase is true, but the request is still made to document
1370                 //path, not base path).
1371                 var owloc = window.location+"";
1372                 var base = document.getElementsByTagName("base");
1373                 var hasBase = (base && base.length > 0);
1374
1375                 d._getText = function(/*URI*/ uri, /*Boolean*/ fail_ok){
1376                         // summary: Read the contents of the specified uri and return those contents.
1377                         // uri:
1378                         //              A relative or absolute uri. If absolute, it still must be in
1379                         //              the same "domain" as we are.
1380                         // fail_ok:
1381                         //              Default false. If fail_ok and loading fails, return null
1382                         //              instead of throwing.
1383                         // returns: The response text. null is returned when there is a
1384                         //              failure and failure is okay (an exception otherwise)
1385
1386                         // alert("_getText: " + uri);
1387
1388                         // NOTE: must be declared before scope switches ie. this._xhrObj()
1389                         var http = this._xhrObj();
1390
1391                         if(!hasBase && dojo._Url){
1392                                 uri = (new dojo._Url(owloc, uri)).toString();
1393                         }
1394                         /*
1395                         console.debug("_getText:", uri);
1396                         console.debug(window.location+"");
1397                         alert(uri);
1398                         */
1399
1400                         if(d.config.cacheBust){
1401                                 uri += (uri.indexOf("?") == -1 ? "?" : "&") + String(d.config.cacheBust).replace(/\W+/g,"");
1402                         }
1403
1404                         http.open('GET', uri, false);
1405                         try{
1406                                 http.send(null);
1407                                 // alert(http);
1408                                 if(!d._isDocumentOk(http)){
1409                                         var err = Error("Unable to load "+uri+" status:"+ http.status);
1410                                         err.status = http.status;
1411                                         err.responseText = http.responseText;
1412                                         throw err;
1413                                 }
1414                         }catch(e){
1415                                 if(fail_ok){ return null; } // null
1416                                 // rethrow the exception
1417                                 throw e;
1418                         }
1419                         return http.responseText; // String
1420                 }
1421         })();
1422
1423         dojo._initFired = false;
1424         //      BEGIN DOMContentLoaded, from Dean Edwards (http://dean.edwards.name/weblog/2006/06/again/)
1425         dojo._loadInit = function(e){
1426                 dojo._initFired = true;
1427                 // allow multiple calls, only first one will take effect
1428                 // A bug in khtml calls events callbacks for document for event which isnt supported
1429                 // for example a created contextmenu event calls DOMContentLoaded, workaround
1430                 var type = (e && e.type) ? e.type.toLowerCase() : "load";
1431                 if(arguments.callee.initialized || (type != "domcontentloaded" && type != "load")){ return; }
1432                 arguments.callee.initialized = true;
1433                 if("_khtmlTimer" in dojo){
1434                         clearInterval(dojo._khtmlTimer);
1435                         delete dojo._khtmlTimer;
1436                 }
1437
1438                 if(dojo._inFlightCount == 0){
1439                         dojo._modulesLoaded();
1440                 }
1441         }
1442
1443         dojo._fakeLoadInit = function(){
1444                 dojo._loadInit({type: "load"});
1445         }
1446
1447         if(!dojo.config.afterOnLoad){
1448                 //      START DOMContentLoaded
1449                 // Mozilla and Opera 9 expose the event we could use
1450                 if(document.addEventListener){
1451                         // NOTE: 
1452                         //              due to a threading issue in Firefox 2.0, we can't enable
1453                         //              DOMContentLoaded on that platform. For more information, see:
1454                         //              http://trac.dojotoolkit.org/ticket/1704
1455                         if(dojo.isOpera || dojo.isFF >= 3 || (dojo.isMoz && dojo.config.enableMozDomContentLoaded === true)){
1456                                 document.addEventListener("DOMContentLoaded", dojo._loadInit, null);
1457                         }
1458         
1459                         //      mainly for Opera 8.5, won't be fired if DOMContentLoaded fired already.
1460                         //  also used for Mozilla because of trac #1640
1461                         window.addEventListener("load", dojo._loadInit, null);
1462                 }
1463         
1464                 if(dojo.isAIR){
1465                         window.addEventListener("load", dojo._loadInit, null);
1466                 }else if(/(WebKit|khtml)/i.test(navigator.userAgent)){ // sniff
1467                         dojo._khtmlTimer = setInterval(function(){
1468                                 if(/loaded|complete/.test(document.readyState)){
1469                                         dojo._loadInit(); // call the onload handler
1470                                 }
1471                         }, 10);
1472                 }
1473                 //      END DOMContentLoaded
1474         }
1475
1476         (function(){
1477                 var _w = window;
1478                 var _handleNodeEvent = function(/*String*/evtName, /*Function*/fp){
1479                         // summary:
1480                         //              non-destructively adds the specified function to the node's
1481                         //              evtName handler.
1482                         // evtName: should be in the form "onclick" for "onclick" handlers.
1483                         // Make sure you pass in the "on" part.
1484                         var oldHandler = _w[evtName] || function(){};
1485                         _w[evtName] = function(){
1486                                 fp.apply(_w, arguments);
1487                                 oldHandler.apply(_w, arguments);
1488                         };
1489                 };
1490
1491                 if(dojo.isIE){
1492                         //      for Internet Explorer. readyState will not be achieved on init
1493                         //      call, but dojo doesn't need it however, we'll include it
1494                         //      because we don't know if there are other functions added that
1495                         //      might.  Note that this has changed because the build process
1496                         //      strips all comments -- including conditional ones.
1497                         if(!dojo.config.afterOnLoad){
1498                                 document.write('<scr'+'ipt defer src="//:" '
1499                                         + 'onreadystatechange="if(this.readyState==\'complete\'){' + dojo._scopeName + '._loadInit();}">'
1500                                         + '</scr'+'ipt>'
1501                                 );
1502                         }
1503
1504                         // IE WebControl hosted in an application can fire "beforeunload" and "unload"
1505                         // events when control visibility changes, causing Dojo to unload too soon. The
1506                         // following code fixes the problem
1507                         // Reference: http://support.microsoft.com/default.aspx?scid=kb;en-us;199155
1508                         var _unloading = true;
1509                         _handleNodeEvent("onbeforeunload", function(){
1510                                 _w.setTimeout(function(){ _unloading = false; }, 0);
1511                         });
1512                         _handleNodeEvent("onunload", function(){
1513                                 if(_unloading){ dojo.unloaded(); }
1514                         });
1515
1516                         try{
1517                                 document.namespaces.add("v","urn:schemas-microsoft-com:vml");
1518                                 document.createStyleSheet().addRule("v\\:*", "behavior:url(#default#VML)");
1519                         }catch(e){}
1520                 }else{
1521                         // FIXME: dojo.unloaded requires dojo scope, so using anon function wrapper.
1522                         _handleNodeEvent("onbeforeunload", function() { dojo.unloaded(); });
1523                 }
1524
1525         })();
1526
1527         /*
1528         OpenAjax.subscribe("OpenAjax", "onload", function(){
1529                 if(dojo._inFlightCount == 0){
1530                         dojo._modulesLoaded();
1531                 }
1532         });
1533
1534         OpenAjax.subscribe("OpenAjax", "onunload", function(){
1535                 dojo.unloaded();
1536         });
1537         */
1538 } //if (typeof window != 'undefined')
1539
1540 //Register any module paths set up in djConfig. Need to do this
1541 //in the hostenvs since hostenv_browser can read djConfig from a
1542 //script tag's attribute.
1543 (function(){
1544         var mp = dojo.config["modulePaths"];
1545         if(mp){
1546                 for(var param in mp){
1547                         dojo.registerModulePath(param, mp[param]);
1548                 }
1549         }
1550 })();
1551
1552 //Load debug code if necessary.
1553 if(dojo.config.isDebug){
1554         dojo.require("dojo._firebug.firebug");
1555 }
1556
1557 if(dojo.config.debugAtAllCosts){
1558         dojo.config.useXDomain = true;
1559         dojo.require("dojo._base._loader.loader_xd");
1560         dojo.require("dojo._base._loader.loader_debug");
1561         dojo.require("dojo.i18n");
1562 }
1563
1564 if(!dojo._hasResource["dojo._base.lang"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
1565 dojo._hasResource["dojo._base.lang"] = true;
1566 dojo.provide("dojo._base.lang");
1567
1568 // Crockford (ish) functions
1569
1570 dojo.isString = function(/*anything*/ it){
1571         //      summary:
1572         //              Return true if it is a String
1573         return !!arguments.length && it != null && (typeof it == "string" || it instanceof String); // Boolean
1574 }
1575
1576 dojo.isArray = function(/*anything*/ it){
1577         //      summary:
1578         //              Return true if it is an Array
1579         return it && (it instanceof Array || typeof it == "array"); // Boolean
1580 }
1581
1582 /*=====
1583 dojo.isFunction = function(it){
1584         // summary: Return true if it is a Function
1585         // it: anything
1586         //      return: Boolean
1587 }
1588 =====*/
1589
1590 dojo.isFunction = (function(){
1591         var _isFunction = function(/*anything*/ it){
1592                 return it && (typeof it == "function" || it instanceof Function); // Boolean
1593         };
1594
1595         return dojo.isSafari ?
1596                 // only slow this down w/ gratuitious casting in Safari since it's what's b0rken
1597                 function(/*anything*/ it){
1598                         if(typeof it == "function" && it == "[object NodeList]"){ return false; }
1599                         return _isFunction(it); // Boolean
1600                 } : _isFunction;
1601 })();
1602
1603 dojo.isObject = function(/*anything*/ it){
1604         // summary: 
1605         //              Returns true if it is a JavaScript object (or an Array, a Function
1606         //              or null)
1607         return it !== undefined &&
1608                 (it === null || typeof it == "object" || dojo.isArray(it) || dojo.isFunction(it)); // Boolean
1609 }
1610
1611 dojo.isArrayLike = function(/*anything*/ it){
1612         //      summary:
1613         //              similar to dojo.isArray() but more permissive
1614         //      description:
1615         //              Doesn't strongly test for "arrayness".  Instead, settles for "isn't
1616         //              a string or number and has a length property". Arguments objects
1617         //              and DOM collections will return true when passed to
1618         //              dojo.isArrayLike(), but will return false when passed to
1619         //              dojo.isArray().
1620         //      return:
1621         //              If it walks like a duck and quicks like a duck, return `true`
1622         var d = dojo;
1623         return it && it !== undefined &&
1624                 // keep out built-in constructors (Number, String, ...) which have length
1625                 // properties
1626                 !d.isString(it) && !d.isFunction(it) &&
1627                 !(it.tagName && it.tagName.toLowerCase() == 'form') &&
1628                 (d.isArray(it) || isFinite(it.length)); // Boolean
1629 }
1630
1631 dojo.isAlien = function(/*anything*/ it){
1632         // summary: 
1633         //              Returns true if it is a built-in function or some other kind of
1634         //              oddball that *should* report as a function but doesn't
1635         return it && !dojo.isFunction(it) && /\{\s*\[native code\]\s*\}/.test(String(it)); // Boolean
1636 }
1637
1638 dojo.extend = function(/*Object*/ constructor, /*Object...*/ props){
1639         // summary:
1640         //              Adds all properties and methods of props to constructor's
1641         //              prototype, making them available to all instances created with
1642         //              constructor.
1643         for(var i=1, l=arguments.length; i<l; i++){
1644                 dojo._mixin(constructor.prototype, arguments[i]);
1645         }
1646         return constructor; // Object
1647 }
1648
1649 dojo._hitchArgs = function(scope, method /*,...*/){
1650         var pre = dojo._toArray(arguments, 2);
1651         var named = dojo.isString(method);
1652         return function(){
1653                 // arrayify arguments
1654                 var args = dojo._toArray(arguments);
1655                 // locate our method
1656                 var f = named ? (scope||dojo.global)[method] : method;
1657                 // invoke with collected args
1658                 return f && f.apply(scope || this, pre.concat(args)); // mixed
1659         } // Function
1660 }
1661
1662 dojo.hitch = function(/*Object*/scope, /*Function|String*/method /*,...*/){
1663         //      summary: 
1664         //              Returns a function that will only ever execute in the a given scope. 
1665         //              This allows for easy use of object member functions
1666         //              in callbacks and other places in which the "this" keyword may
1667         //              otherwise not reference the expected scope. 
1668         //              Any number of default positional arguments may be passed as parameters 
1669         //              beyond "method".
1670         //              Each of these values will be used to "placehold" (similar to curry)
1671         //              for the hitched function. 
1672         //      scope: 
1673         //              The scope to use when method executes. If method is a string, 
1674         //              scope is also the object containing method.
1675         //      method:
1676         //              A function to be hitched to scope, or the name of the method in
1677         //              scope to be hitched.
1678         //      example:
1679         //      |       dojo.hitch(foo, "bar")(); 
1680         //              runs foo.bar() in the scope of foo
1681         //      example:
1682         //      |       dojo.hitch(foo, myFunction);
1683         //              returns a function that runs myFunction in the scope of foo
1684         if(arguments.length > 2){
1685                 return dojo._hitchArgs.apply(dojo, arguments); // Function
1686         }
1687         if(!method){
1688                 method = scope;
1689                 scope = null;
1690         }
1691         if(dojo.isString(method)){
1692                 scope = scope || dojo.global;
1693                 if(!scope[method]){ throw(['dojo.hitch: scope["', method, '"] is null (scope="', scope, '")'].join('')); }
1694                 return function(){ return scope[method].apply(scope, arguments || []); }; // Function
1695         }
1696         return !scope ? method : function(){ return method.apply(scope, arguments || []); }; // Function
1697 }
1698
1699 /*=====
1700 dojo.delegate = function(obj, props){
1701         //      summary:
1702         //              returns a new object which "looks" to obj for properties which it
1703         //              does not have a value for. Optionally takes a bag of properties to
1704         //              seed the returned object with initially. 
1705         //      description:
1706         //              This is a small implementaton of the Boodman/Crockford delegation
1707         //              pattern in JavaScript. An intermediate object constructor mediates
1708         //              the prototype chain for the returned object, using it to delegate
1709         //              down to obj for property lookup when object-local lookup fails.
1710         //              This can be thought of similarly to ES4's "wrap", save that it does
1711         //              not act on types but rather on pure objects.
1712         //      obj:
1713         //              The object to delegate to for properties not found directly on the
1714         //              return object or in props.
1715         //      props:
1716         //              an object containing properties to assign to the returned object
1717         //      returns:
1718         //              an Object of anonymous type
1719         //      example:
1720         //      |       var foo = { bar: "baz" };
1721         //      |       var thinger = dojo.delegate(foo, { thud: "xyzzy"});
1722         //      |       thinger.bar == "baz"; // delegated to foo
1723         //      |       foo.thud == undefined; // by definition
1724         //      |       thinger.thud == "xyzzy"; // mixed in from props
1725         //      |       foo.bar = "thonk";
1726         //      |       thinger.bar == "thonk"; // still delegated to foo's bar
1727 }
1728 =====*/
1729
1730
1731 dojo.delegate = dojo._delegate = function(obj, props){
1732
1733         // boodman/crockford delegation
1734         function TMP(){};
1735         TMP.prototype = obj;
1736         var tmp = new TMP();
1737         if(props){
1738                 dojo.mixin(tmp, props);
1739         }
1740         return tmp; // Object
1741 }
1742
1743 dojo.partial = function(/*Function|String*/method /*, ...*/){
1744         //      summary:
1745         //              similar to hitch() except that the scope object is left to be
1746         //              whatever the execution context eventually becomes.
1747         //      description:
1748         //              Calling dojo.partial is the functional equivalent of calling:
1749         //              |       dojo.hitch(null, funcName, ...);
1750         var arr = [ null ];
1751         return dojo.hitch.apply(dojo, arr.concat(dojo._toArray(arguments))); // Function
1752 }
1753
1754 dojo._toArray = function(/*Object*/obj, /*Number?*/offset, /*Array?*/ startWith){
1755         //      summary:
1756         //              Converts an array-like object (i.e. arguments, DOMCollection) to an
1757         //              array. Returns a new Array with the elements of obj.
1758         //      obj:
1759         //              the object to "arrayify". We expect the object to have, at a
1760         //              minimum, a length property which corresponds to integer-indexed
1761         //              properties.
1762         //      offset:
1763         //              the location in obj to start iterating from. Defaults to 0.
1764         //              Optional.
1765         //      startWith:
1766         //              An array to pack with the properties of obj. If provided,
1767         //              properties in obj are appended at the end of startWith and
1768         //              startWith is the returned array.
1769         var arr = startWith||[];
1770         for(var x = offset || 0; x < obj.length; x++){
1771                 arr.push(obj[x]);
1772         }
1773         return arr; // Array
1774 }
1775
1776 dojo.clone = function(/*anything*/ o){
1777         // summary:
1778         //              Clones objects (including DOM nodes) and all children.
1779         //              Warning: do not clone cyclic structures.
1780         if(!o){ return o; }
1781         if(dojo.isArray(o)){
1782                 var r = [];
1783                 for(var i = 0; i < o.length; ++i){
1784                         r.push(dojo.clone(o[i]));
1785                 }
1786                 return r; // Array
1787         }
1788         if(!dojo.isObject(o)){
1789                 return o;       /*anything*/
1790         }
1791         if(o.nodeType && o.cloneNode){ // isNode
1792                 return o.cloneNode(true); // Node
1793         }
1794         if(o instanceof Date){
1795                 return new Date(o.getTime());   // Date
1796         }
1797         // Generic objects
1798         var r = new o.constructor(); // specific to dojo.declare()'d classes!
1799         for(var i in o){
1800                 if(!(i in r) || r[i] != o[i]){
1801                         r[i] = dojo.clone(o[i]);
1802                 }
1803         }
1804         return r; // Object
1805 }
1806
1807 dojo.trim = function(/*String*/ str){
1808         // summary: 
1809         //              trims whitespaces from both sides of the string
1810         // description:
1811         //              This version of trim() was selected for inclusion into the base due
1812         //              to its compact size and relatively good performance (see Steven
1813         //              Levithan's blog:
1814         //              http://blog.stevenlevithan.com/archives/faster-trim-javascript).
1815         //              The fastest but longest version of this function is located at
1816         //              dojo.string.trim()
1817         return str.replace(/^\s\s*/, '').replace(/\s\s*$/, ''); // String
1818 }
1819
1820 }
1821
1822 if(!dojo._hasResource["dojo._base.declare"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
1823 dojo._hasResource["dojo._base.declare"] = true;
1824 dojo.provide("dojo._base.declare");
1825
1826
1827 // this file courtesy of the TurboAjax group, licensed under a Dojo CLA
1828
1829 dojo.declare = function(/*String*/ className, /*Function|Function[]*/ superclass, /*Object*/ props){
1830         //      summary: 
1831         //              Create a feature-rich constructor from compact notation
1832         //      className:
1833         //              The name of the constructor (loosely, a "class")
1834         //              stored in the "declaredClass" property in the created prototype
1835         //      superclass:
1836         //              May be null, a Function, or an Array of Functions. If an array, 
1837         //              the first element is used as the prototypical ancestor and
1838         //              any following Functions become mixin ancestors.
1839         //      props:
1840         //              An object whose properties are copied to the
1841         //              created prototype.
1842         //              Add an instance-initialization function by making it a property 
1843         //              named "constructor".
1844         //      description:
1845         //              Create a constructor using a compact notation for inheritance and
1846         //              prototype extension. 
1847         //
1848         //              All superclasses (including mixins) must be Functions (not simple Objects).
1849         //
1850         //              Mixin ancestors provide a type of multiple inheritance. Prototypes of mixin 
1851         //              ancestors are copied to the new class: changes to mixin prototypes will
1852         //              not affect classes to which they have been mixed in.
1853         //
1854         //              "className" is cached in "declaredClass" property of the new class.
1855         //
1856         //      example:
1857         //      |       dojo.declare("my.classes.bar", my.classes.foo, {
1858         //      |               // properties to be added to the class prototype
1859         //      |               someValue: 2,
1860         //      |               // initialization function
1861         //      |               constructor: function(){
1862         //      |                       this.myComplicatedObject = new ReallyComplicatedObject(); 
1863         //      |               },
1864         //      |               // other functions
1865         //      |               someMethod: function(){ 
1866         //      |                       doStuff(); 
1867         //      |               }
1868         //      |       );
1869
1870         // process superclass argument
1871         // var dd=dojo.declare, mixins=null;
1872         var dd = arguments.callee, mixins;
1873         if(dojo.isArray(superclass)){
1874                 mixins = superclass;
1875                 superclass = mixins.shift();
1876         }
1877         // construct intermediate classes for mixins
1878         if(mixins){
1879                 dojo.forEach(mixins, function(m){
1880                         if(!m){ throw(className + ": mixin #" + i + " is null"); } // It's likely a required module is not loaded
1881                         superclass = dd._delegate(superclass, m);
1882                 });
1883         }
1884         // prepare values
1885         var init = (props||0).constructor, ctor = dd._delegate(superclass), fn;
1886         // name methods (experimental)
1887         for(var i in props){ if(dojo.isFunction(fn = props[i]) && !0[i]){fn.nom = i;} } // 0[i] checks Object.prototype
1888         // decorate prototype
1889         dojo.extend(ctor, {declaredClass: className, _constructor: init, preamble: null}, props || 0); 
1890         // special help for IE
1891         ctor.prototype.constructor = ctor;
1892         // create named reference
1893         return dojo.setObject(className, ctor); // Function
1894 };
1895
1896 dojo.mixin(dojo.declare, {
1897         _delegate: function(base, mixin){
1898                 var bp = (base||0).prototype, mp = (mixin||0).prototype;
1899                 // fresh constructor, fresh prototype
1900                 var ctor = dojo.declare._makeCtor();
1901                 // cache ancestry
1902                 dojo.mixin(ctor, {superclass: bp, mixin: mp, extend: dojo.declare._extend});
1903                 // chain prototypes
1904                 if(base){ctor.prototype = dojo._delegate(bp);}
1905                 // add mixin and core
1906                 dojo.extend(ctor, dojo.declare._core, mp||0, {_constructor: null, preamble: null});
1907                 // special help for IE
1908                 ctor.prototype.constructor = ctor;
1909                 // name this class for debugging
1910                 ctor.prototype.declaredClass = (bp||0).declaredClass + '_' + (mp||0).declaredClass;
1911                 return ctor;
1912         },
1913         _extend: function(props){
1914                 for(var i in props){ if(dojo.isFunction(fn=props[i]) && !0[i]){fn.nom=i;} }
1915                 dojo.extend(this, props);
1916         },
1917         _makeCtor: function(){
1918                 // we have to make a function, but don't want to close over anything
1919                 return function(){ this._construct(arguments); };
1920         },
1921         _core: { 
1922                 _construct: function(args){
1923                         var c=args.callee, s=c.superclass, ct=s&&s.constructor, m=c.mixin, mct=m&&m.constructor, a=args, ii, fn;
1924                         // side-effect of = used on purpose here, lint may complain, don't try this at home
1925                         if(a[0]){ 
1926                                 // FIXME: preambles for each mixin should be allowed
1927                                 // FIXME: 
1928                                 //              should we allow the preamble here NOT to modify the
1929                                 //              default args, but instead to act on each mixin
1930                                 //              independently of the class instance being constructed
1931                                 //              (for impedence matching)?
1932
1933                                 // allow any first argument w/ a "preamble" property to act as a
1934                                 // class preamble (not exclusive of the prototype preamble)
1935                                 if(/*dojo.isFunction*/((fn = a[0].preamble))){ 
1936                                         a = fn.apply(this, a) || a; 
1937                                 }
1938                         } 
1939                         // prototype preamble
1940                         if((fn = c.prototype.preamble)){a = fn.apply(this, a) || a;}
1941                         // FIXME: 
1942                         //              need to provide an optional prototype-settable
1943                         //              "_explicitSuper" property which disables this
1944                         // initialize superclass
1945                         if(ct&&ct.apply){ct.apply(this, a);}
1946                         // initialize mixin
1947                         if(mct&&mct.apply){mct.apply(this, a);}
1948                         // initialize self
1949                         if((ii=c.prototype._constructor)){ii.apply(this, args);}
1950                         // post construction
1951                         if(this.constructor.prototype==c.prototype && (ct=this.postscript)){ ct.apply(this, args); }
1952                 },
1953                 _findMixin: function(mixin){
1954                         var c = this.constructor, p, m;
1955                         while(c){
1956                                 p = c.superclass;
1957                                 m = c.mixin;
1958                                 if(m==mixin || (m instanceof mixin.constructor)){return p;}
1959                                 if(m && (m=m._findMixin(mixin))){return m;}
1960                                 c = p && p.constructor;
1961                         }
1962                 },
1963                 _findMethod: function(name, method, ptype, has){
1964                         // consciously trading readability for bytes and speed in this low-level method
1965                         var p=ptype, c, m, f;
1966                         do{
1967                                 c = p.constructor;
1968                                 m = c.mixin;
1969                                 // find method by name in our mixin ancestor
1970                                 if(m && (m=this._findMethod(name, method, m, has))){return m;}
1971                                 // if we found a named method that either exactly-is or exactly-is-not 'method'
1972                                 if((f=p[name])&&(has==(f==method))){return p;}
1973                                 // ascend chain
1974                                 p = c.superclass;
1975                         }while(p);
1976                         // if we couldn't find an ancestor in our primary chain, try a mixin chain
1977                         return !has && (p=this._findMixin(ptype)) && this._findMethod(name, method, p, has);
1978                 },
1979                 inherited: function(name, args, newArgs){
1980                         // optionalize name argument (experimental)
1981                         var a = arguments;
1982                         if(!dojo.isString(a[0])){newArgs=args; args=name; name=args.callee.nom;}
1983                         a = newArgs||args;
1984                         var c = args.callee, p = this.constructor.prototype, fn, mp;
1985                         // if not an instance override 
1986                         if(this[name] != c || p[name] == c){
1987                                 mp = this._findMethod(name, c, p, true);
1988                                 if(!mp){throw(this.declaredClass + ': inherited method "' + name + '" mismatch');}
1989                                 p = this._findMethod(name, c, mp, false);
1990                         }
1991                         fn = p && p[name];
1992                         if(!fn){throw(mp.declaredClass + ': inherited method "' + name + '" not found');}
1993                         // if the function exists, invoke it in our scope
1994                         return fn.apply(this, a);
1995                 }
1996         }
1997 });
1998
1999 }
2000
2001 if(!dojo._hasResource["dojo._base.connect"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
2002 dojo._hasResource["dojo._base.connect"] = true;
2003 dojo.provide("dojo._base.connect");
2004
2005
2006 // this file courtesy of the TurboAjax Group, licensed under a Dojo CLA
2007
2008 // low-level delegation machinery
2009 dojo._listener = {
2010         // create a dispatcher function
2011         getDispatcher: function(){
2012                 // following comments pulled out-of-line to prevent cloning them 
2013                 // in the returned function.
2014                 // - indices (i) that are really in the array of listeners (ls) will 
2015                 //   not be in Array.prototype. This is the 'sparse array' trick
2016                 //   that keeps us safe from libs that take liberties with built-in 
2017                 //   objects
2018                 // - listener is invoked with current scope (this)
2019                 return function(){
2020                         var ap=Array.prototype, c=arguments.callee, ls=c._listeners, t=c.target;
2021                         // return value comes from original target function
2022                         var r=t && t.apply(this, arguments);
2023                         // invoke listeners after target function
2024                         for(var i in ls){
2025                                 if(!(i in ap)){
2026                                         ls[i].apply(this, arguments);
2027                                 }
2028                         }
2029                         // return value comes from original target function
2030                         return r;
2031                 }
2032         },
2033         // add a listener to an object
2034         add: function(/*Object*/ source, /*String*/ method, /*Function*/ listener){
2035                 // Whenever 'method' is invoked, 'listener' will have the same scope.
2036                 // Trying to supporting a context object for the listener led to 
2037                 // complexity. 
2038                 // Non trivial to provide 'once' functionality here
2039                 // because listener could be the result of a dojo.hitch call,
2040                 // in which case two references to the same hitch target would not
2041                 // be equivalent. 
2042                 source = source || dojo.global;
2043                 // The source method is either null, a dispatcher, or some other function
2044                 var f = source[method];
2045                 // Ensure a dispatcher
2046                 if(!f||!f._listeners){
2047                         var d = dojo._listener.getDispatcher();
2048                         // original target function is special
2049                         d.target = f;
2050                         // dispatcher holds a list of listeners
2051                         d._listeners = []; 
2052                         // redirect source to dispatcher
2053                         f = source[method] = d;
2054                 }
2055                 // The contract is that a handle is returned that can 
2056                 // identify this listener for disconnect. 
2057                 //
2058                 // The type of the handle is private. Here is it implemented as Integer. 
2059                 // DOM event code has this same contract but handle is Function 
2060                 // in non-IE browsers.
2061                 //
2062                 // We could have separate lists of before and after listeners.
2063                 return f._listeners.push(listener) ; /*Handle*/
2064         },
2065         // remove a listener from an object
2066         remove: function(/*Object*/ source, /*String*/ method, /*Handle*/ handle){
2067                 var f = (source||dojo.global)[method];
2068                 // remember that handle is the index+1 (0 is not a valid handle)
2069                 if(f && f._listeners && handle--){
2070                         delete f._listeners[handle]; 
2071                 }
2072         }
2073 };
2074
2075 // Multiple delegation for arbitrary methods.
2076
2077 // This unit knows nothing about DOM, 
2078 // but we include DOM aware 
2079 // documentation and dontFix
2080 // argument here to help the autodocs.
2081 // Actual DOM aware code is in event.js.
2082
2083 dojo.connect = function(/*Object|null*/ obj, 
2084                                                 /*String*/ event, 
2085                                                 /*Object|null*/ context, 
2086                                                 /*String|Function*/ method,
2087                                                 /*Boolean*/ dontFix){
2088         // summary:
2089         //              Create a link that calls one function when another executes. 
2090         //
2091         // description:
2092         //              Connects method to event, so that after event fires, method
2093         //              does too. All connected functions are passed the same arguments as
2094         //              the event function was initially called with. You may connect as
2095         //              many methods to event as needed.
2096         //
2097         //              event must be a string. If obj is null, dojo.global is used.
2098         //
2099         //              null arguments may simply be omitted.
2100         //
2101         //              obj[event] can resolve to a function or undefined (null). 
2102         //              If obj[event] is null, it is assigned a function.
2103         //
2104         //              The return value is a handle that is needed to 
2105         //              remove this connection with dojo.disconnect.
2106         //
2107         // obj: 
2108         //              The source object for the event function. 
2109         //              Defaults to dojo.global if null.
2110         //              If obj is a DOM node, the connection is delegated 
2111         //              to the DOM event manager (unless dontFix is true).
2112         //
2113         // event:
2114         //              String name of the event function in obj. 
2115         //              I.e. identifies a property obj[event].
2116         //
2117         // context: 
2118         //              The object that method will receive as "this".
2119         //
2120         //              If context is null and method is a function, then method
2121         //              inherits the context of event.
2122         //      
2123         //              If method is a string then context must be the source 
2124         //              object object for method (context[method]). If context is null,
2125         //              dojo.global is used.
2126         //
2127         // method:
2128         //              A function reference, or name of a function in context. 
2129         //              The function identified by method fires after event does. 
2130         //              method receives the same arguments as the event.
2131         //              See context argument comments for information on method's scope.
2132         //
2133         // dontFix:
2134         //              If obj is a DOM node, set dontFix to true to prevent delegation 
2135         //              of this connection to the DOM event manager. 
2136         //
2137         // example:
2138         //              When obj.onchange(), do ui.update():
2139         //      |       dojo.connect(obj, "onchange", ui, "update");
2140         //      |       dojo.connect(obj, "onchange", ui, ui.update); // same
2141         //
2142         // example:
2143         //              Using return value for disconnect:
2144         //      |       var link = dojo.connect(obj, "onchange", ui, "update");
2145         //      |       ...
2146         //      |       dojo.disconnect(link);
2147         //
2148         // example:
2149         //              When onglobalevent executes, watcher.handler is invoked:
2150         //      |       dojo.connect(null, "onglobalevent", watcher, "handler");
2151         //
2152         // example:
2153         //              When ob.onCustomEvent executes, customEventHandler is invoked:
2154         //      |       dojo.connect(ob, "onCustomEvent", null, "customEventHandler");
2155         //      |       dojo.connect(ob, "onCustomEvent", "customEventHandler"); // same
2156         //
2157         // example:
2158         //              When ob.onCustomEvent executes, customEventHandler is invoked
2159         //              with the same scope (this):
2160         //      |       dojo.connect(ob, "onCustomEvent", null, customEventHandler);
2161         //      |       dojo.connect(ob, "onCustomEvent", customEventHandler); // same
2162         //
2163         // example:
2164         //              When globalEvent executes, globalHandler is invoked
2165         //              with the same scope (this):
2166         //      |       dojo.connect(null, "globalEvent", null, globalHandler);
2167         //      |       dojo.connect("globalEvent", globalHandler); // same
2168
2169         // normalize arguments
2170         var a=arguments, args=[], i=0;
2171         // if a[0] is a String, obj was ommited
2172         args.push(dojo.isString(a[0]) ? null : a[i++], a[i++]);
2173         // if the arg-after-next is a String or Function, context was NOT omitted
2174         var a1 = a[i+1];
2175         args.push(dojo.isString(a1)||dojo.isFunction(a1) ? a[i++] : null, a[i++]);
2176         // absorb any additional arguments
2177         for(var l=a.length; i<l; i++){  args.push(a[i]); }
2178         // do the actual work
2179         return dojo._connect.apply(this, args); /*Handle*/
2180 }
2181
2182 // used by non-browser hostenvs. always overriden by event.js
2183 dojo._connect = function(obj, event, context, method){
2184         var l=dojo._listener, h=l.add(obj, event, dojo.hitch(context, method)); 
2185         return [obj, event, h, l]; // Handle
2186 }
2187
2188 dojo.disconnect = function(/*Handle*/ handle){
2189         // summary:
2190         //              Remove a link created by dojo.connect.
2191         // description:
2192         //              Removes the connection between event and the method referenced by handle.
2193         // handle:
2194         //              the return value of the dojo.connect call that created the connection.
2195         if(handle && handle[0] !== undefined){
2196                 dojo._disconnect.apply(this, handle);
2197                 // let's not keep this reference
2198                 delete handle[0];
2199         }
2200 }
2201
2202 dojo._disconnect = function(obj, event, handle, listener){
2203         listener.remove(obj, event, handle);
2204 }
2205
2206 // topic publish/subscribe
2207
2208 dojo._topics = {};
2209
2210 dojo.subscribe = function(/*String*/ topic, /*Object|null*/ context, /*String|Function*/ method){
2211         //      summary:
2212         //              Attach a listener to a named topic. The listener function is invoked whenever the
2213         //              named topic is published (see: dojo.publish).
2214         //              Returns a handle which is needed to unsubscribe this listener.
2215         //      context:
2216         //              Scope in which method will be invoked, or null for default scope.
2217         //      method:
2218         //              The name of a function in context, or a function reference. This is the function that
2219         //              is invoked when topic is published.
2220         //      example:
2221         //      |       dojo.subscribe("alerts", null, function(caption, message){ alert(caption + "\n" + message); };
2222         //      |       dojo.publish("alerts", [ "read this", "hello world" ]);                                                                                                                                 
2223
2224         // support for 2 argument invocation (omitting context) depends on hitch
2225         return [topic, dojo._listener.add(dojo._topics, topic, dojo.hitch(context, method))]; /*Handle*/
2226 }
2227
2228 dojo.unsubscribe = function(/*Handle*/ handle){
2229         //      summary:
2230         //              Remove a topic listener. 
2231         //      handle:
2232         //              The handle returned from a call to subscribe.
2233         //      example:
2234         //      |       var alerter = dojo.subscribe("alerts", null, function(caption, message){ alert(caption + "\n" + message); };
2235         //      |       ...
2236         //      |       dojo.unsubscribe(alerter);
2237         if(handle){
2238                 dojo._listener.remove(dojo._topics, handle[0], handle[1]);
2239         }
2240 }
2241
2242 dojo.publish = function(/*String*/ topic, /*Array*/ args){
2243         //      summary:
2244         //              Invoke all listener method subscribed to topic.
2245         //      topic:
2246         //              The name of the topic to publish.
2247         //      args:
2248         //              An array of arguments. The arguments will be applied 
2249         //              to each topic subscriber (as first class parameters, via apply).
2250         //      example:
2251         //      |       dojo.subscribe("alerts", null, function(caption, message){ alert(caption + "\n" + message); };
2252         //      |       dojo.publish("alerts", [ "read this", "hello world" ]); 
2253
2254         // Note that args is an array, which is more efficient vs variable length
2255         // argument list.  Ideally, var args would be implemented via Array
2256         // throughout the APIs.
2257         var f = dojo._topics[topic];
2258         if(f){
2259                 f.apply(this, args||[]);
2260         }
2261 }
2262
2263 dojo.connectPublisher = function(       /*String*/ topic, 
2264                                                                         /*Object|null*/ obj, 
2265                                                                         /*String*/ event){
2266         //      summary:
2267         //              Ensure that everytime obj.event() is called, a message is published
2268         //              on the topic. Returns a handle which can be passed to
2269         //              dojo.disconnect() to disable subsequent automatic publication on
2270         //              the topic.
2271         //      topic:
2272         //              The name of the topic to publish.
2273         //      obj: 
2274         //              The source object for the event function. Defaults to dojo.global
2275         //              if null.
2276         //      event:
2277         //              The name of the event function in obj. 
2278         //              I.e. identifies a property obj[event].
2279         //      example:
2280         //      |       dojo.connectPublisher("/ajax/start", dojo, "xhrGet"};
2281         var pf = function(){ dojo.publish(topic, arguments); }
2282         return (event) ? dojo.connect(obj, event, pf) : dojo.connect(obj, pf); //Handle
2283 };
2284
2285 }
2286
2287 if(!dojo._hasResource["dojo._base.Deferred"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
2288 dojo._hasResource["dojo._base.Deferred"] = true;
2289 dojo.provide("dojo._base.Deferred");
2290
2291
2292 dojo.Deferred = function(/*Function?*/ canceller){
2293         // summary:
2294         //              Encapsulates a sequence of callbacks in response to a value that
2295         //              may not yet be available.  This is modeled after the Deferred class
2296         //              from Twisted <http://twistedmatrix.com>.
2297         // description:
2298         //              JavaScript has no threads, and even if it did, threads are hard.
2299         //              Deferreds are a way of abstracting non-blocking events, such as the
2300         //              final response to an XMLHttpRequest. Deferreds create a promise to
2301         //              return a response a some point in the future and an easy way to
2302         //              register your interest in receiving that response.
2303         //
2304         //              The most important methods for Deffered users are:
2305         //
2306         //                      * addCallback(handler)
2307         //                      * addErrback(handler)
2308         //                      * callback(result)
2309         //                      * errback(result)
2310         //
2311         //              In general, when a function returns a Deferred, users then "fill
2312         //              in" the second half of the contract by registering callbacks and
2313         //              error handlers. You may register as many callback and errback
2314         //              handlers as you like and they will be executed in the order
2315         //              registered when a result is provided. Usually this result is
2316         //              provided as the result of an asynchronous operation. The code
2317         //              "managing" the Deferred (the code that made the promise to provide
2318         //              an answer later) will use the callback() and errback() methods to
2319         //              communicate with registered listeners about the result of the
2320         //              operation. At this time, all registered result handlers are called
2321         //              *with the most recent result value*.
2322         //
2323         //              Deferred callback handlers are treated as a chain, and each item in
2324         //              the chain is required to return a value that will be fed into
2325         //              successive handlers. The most minimal callback may be registered
2326         //              like this:
2327         //
2328         //              |       var d = new dojo.Deferred();
2329         //              |       d.addCallback(function(result){ return result; });
2330         //
2331         //              Perhaps the most common mistake when first using Deferreds is to
2332         //              forget to return a value (in most cases, the value you were
2333         //              passed).
2334         //
2335         //              The sequence of callbacks is internally represented as a list of
2336         //              2-tuples containing the callback/errback pair.  For example, the
2337         //              following call sequence:
2338         //              
2339         //              |       var d = new dojo.Deferred();
2340         //              |       d.addCallback(myCallback);
2341         //              |       d.addErrback(myErrback);
2342         //              |       d.addBoth(myBoth);
2343         //              |       d.addCallbacks(myCallback, myErrback);
2344         //
2345         //              is translated into a Deferred with the following internal
2346         //              representation:
2347         //
2348         //              |       [
2349         //              |               [myCallback, null],
2350         //              |               [null, myErrback],
2351         //              |               [myBoth, myBoth],
2352         //              |               [myCallback, myErrback]
2353         //              |       ]
2354         //
2355         //              The Deferred also keeps track of its current status (fired).  Its
2356         //              status may be one of three things:
2357         //
2358         //                      * -1: no value yet (initial condition)
2359         //                      * 0: success
2360         //                      * 1: error
2361         //      
2362         //              A Deferred will be in the error state if one of the following three
2363         //              conditions are met:
2364         //
2365         //                      1. The result given to callback or errback is "instanceof" Error
2366         //                      2. The previous callback or errback raised an exception while
2367         //                         executing
2368         //                      3. The previous callback or errback returned a value
2369         //                         "instanceof" Error
2370         //
2371         //              Otherwise, the Deferred will be in the success state. The state of
2372         //              the Deferred determines the next element in the callback sequence
2373         //              to run.
2374         //
2375         //              When a callback or errback occurs with the example deferred chain,
2376         //              something equivalent to the following will happen (imagine
2377         //              that exceptions are caught and returned):
2378         //
2379         //              |       // d.callback(result) or d.errback(result)
2380         //              |       if(!(result instanceof Error)){
2381         //              |               result = myCallback(result);
2382         //              |       }
2383         //              |       if(result instanceof Error){
2384         //              |               result = myErrback(result);
2385         //              |       }
2386         //              |       result = myBoth(result);
2387         //              |       if(result instanceof Error){
2388         //              |               result = myErrback(result);
2389         //              |       }else{
2390         //              |               result = myCallback(result);
2391         //              |       }
2392         //
2393         //              The result is then stored away in case another step is added to the
2394         //              callback sequence.      Since the Deferred already has a value
2395         //              available, any new callbacks added will be called immediately.
2396         //
2397         //              There are two other "advanced" details about this implementation
2398         //              that are useful:
2399         //
2400         //              Callbacks are allowed to return Deferred instances themselves, so
2401         //              you can build complicated sequences of events with ease.
2402         //
2403         //              The creator of the Deferred may specify a canceller.  The canceller
2404         //              is a function that will be called if Deferred.cancel is called
2405         //              before the Deferred fires. You can use this to implement clean
2406         //              aborting of an XMLHttpRequest, etc. Note that cancel will fire the
2407         //              deferred with a CancelledError (unless your canceller returns
2408         //              another kind of error), so the errbacks should be prepared to
2409         //              handle that error for cancellable Deferreds.
2410         // example:
2411         //      |       var deferred = new dojo.Deferred();
2412         //      |       setTimeout(function(){ deferred.callback({success: true}); }, 1000);
2413         //      |       return deferred;
2414         // example:
2415         //              Deferred objects are often used when making code asynchronous. It
2416         //              may be easiest to write functions in a synchronous manner and then
2417         //              split code using a deferred to trigger a response to a long-lived
2418         //              operation. For example, instead of register a callback function to
2419         //              denote when a rendering operation completes, the function can
2420         //              simply return a deferred:
2421         //
2422         //              |       // callback style:
2423         //              |       function renderLotsOfData(data, callback){
2424         //              |               var success = false
2425         //              |               try{
2426         //              |                       for(var x in data){
2427         //              |                               renderDataitem(data[x]);
2428         //              |                       }
2429         //              |                       success = true;
2430         //              |               }catch(e){ }
2431         //              |               if(callback){
2432         //              |                       callback(success);
2433         //              |               }
2434         //              |       }
2435         //
2436         //              |       // using callback style
2437         //              |       renderLotsOfData(someDataObj, function(success){
2438         //              |               // handles success or failure
2439         //              |               if(!success){
2440         //              |                       promptUserToRecover();
2441         //              |               }
2442         //              |       });
2443         //              |       // NOTE: no way to add another callback here!!
2444         // example:
2445         //              Using a Deferred doesn't simplify the sending code any, but it
2446         //              provides a standard interface for callers and senders alike,
2447         //              providing both with a simple way to service multiple callbacks for
2448         //              an operation and freeing both sides from worrying about details
2449         //              such as "did this get called already?". With Deferreds, new
2450         //              callbacks can be added at any time.
2451         //
2452         //              |       // Deferred style:
2453         //              |       function renderLotsOfData(data){
2454         //              |               var d = new dojo.Deferred();
2455         //              |               try{
2456         //              |                       for(var x in data){
2457         //              |                               renderDataitem(data[x]);
2458         //              |                       }
2459         //              |                       d.callback(true);
2460         //              |               }catch(e){ 
2461         //              |                       d.errback(new Error("rendering failed"));
2462         //              |               }
2463         //              |               return d;
2464         //              |       }
2465         //
2466         //              |       // using Deferred style
2467         //              |       renderLotsOfData(someDataObj).addErrback(function(){
2468         //              |               promptUserToRecover();
2469         //              |       });
2470         //              |       // NOTE: addErrback and addCallback both return the Deferred
2471         //              |       // again, so we could chain adding callbacks or save the
2472         //              |       // deferred for later should we need to be notified again.
2473         // example:
2474         //              In this example, renderLotsOfData is syncrhonous and so both
2475         //              versions are pretty artificial. Putting the data display on a
2476         //              timeout helps show why Deferreds rock:
2477         //
2478         //              |       // Deferred style and async func
2479         //              |       function renderLotsOfData(data){
2480         //              |               var d = new dojo.Deferred();
2481         //              |               setTimeout(function(){
2482         //              |                       try{
2483         //              |                               for(var x in data){
2484         //              |                                       renderDataitem(data[x]);
2485         //              |                               }
2486         //              |                               d.callback(true);
2487         //              |                       }catch(e){ 
2488         //              |                               d.errback(new Error("rendering failed"));
2489         //              |                       }
2490         //              |               }, 100);
2491         //              |               return d;
2492         //              |       }
2493         //
2494         //              |       // using Deferred style
2495         //              |       renderLotsOfData(someDataObj).addErrback(function(){
2496         //              |               promptUserToRecover();
2497         //              |       });
2498         //
2499         //              Note that the caller doesn't have to change his code at all to
2500         //              handle the asynchronous case.
2501
2502         this.chain = [];
2503         this.id = this._nextId();
2504         this.fired = -1;
2505         this.paused = 0;
2506         this.results = [null, null];
2507         this.canceller = canceller;
2508         this.silentlyCancelled = false;
2509 };
2510
2511 dojo.extend(dojo.Deferred, {
2512         /*
2513         makeCalled: function(){
2514                 // summary:
2515                 //              returns a new, empty deferred, which is already in the called
2516                 //              state. Calling callback() or errback() on this deferred will
2517                 //              yeild an error and adding new handlers to it will result in
2518                 //              them being called immediately.
2519                 var deferred = new dojo.Deferred();
2520                 deferred.callback();
2521                 return deferred;
2522         },
2523
2524         toString: function(){
2525                 var state;
2526                 if(this.fired == -1){
2527                         state = 'unfired';
2528                 }else{
2529                         state = this.fired ? 'success' : 'error';
2530                 }
2531                 return 'Deferred(' + this.id + ', ' + state + ')';
2532         },
2533         */
2534
2535         _nextId: (function(){
2536                 var n = 1;
2537                 return function(){ return n++; };
2538         })(),
2539
2540         cancel: function(){
2541                 // summary:     
2542                 //              Cancels a Deferred that has not yet received a value, or is
2543                 //              waiting on another Deferred as its value.
2544                 // description:
2545                 //              If a canceller is defined, the canceller is called. If the
2546                 //              canceller did not return an error, or there was no canceller,
2547                 //              then the errback chain is started.
2548                 var err;
2549                 if(this.fired == -1){
2550                         if(this.canceller){
2551                                 err = this.canceller(this);
2552                         }else{
2553                                 this.silentlyCancelled = true;
2554                         }
2555                         if(this.fired == -1){
2556                                 if(!(err instanceof Error)){
2557                                         var res = err;
2558                                         err = new Error("Deferred Cancelled");
2559                                         err.dojoType = "cancel";
2560                                         err.cancelResult = res;
2561                                 }
2562                                 this.errback(err);
2563                         }
2564                 }else if(       (this.fired == 0) &&
2565                                         (this.results[0] instanceof dojo.Deferred)
2566                 ){
2567                         this.results[0].cancel();
2568                 }
2569         },
2570                         
2571
2572         _resback: function(res){
2573                 // summary:
2574                 //              The private primitive that means either callback or errback
2575                 this.fired = ((res instanceof Error) ? 1 : 0);
2576                 this.results[this.fired] = res;
2577                 this._fire();
2578         },
2579
2580         _check: function(){
2581                 if(this.fired != -1){
2582                         if(!this.silentlyCancelled){
2583                                 throw new Error("already called!");
2584                         }
2585                         this.silentlyCancelled = false;
2586                         return;
2587                 }
2588         },
2589
2590         callback: function(res){
2591                 //      summary:        
2592                 //              Begin the callback sequence with a non-error value.
2593                 
2594                 /*
2595                 callback or errback should only be called once on a given
2596                 Deferred.
2597                 */
2598                 this._check();
2599                 this._resback(res);
2600         },
2601
2602         errback: function(/*Error*/res){
2603                 //      summary: 
2604                 //              Begin the callback sequence with an error result.
2605                 this._check();
2606                 if(!(res instanceof Error)){
2607                         res = new Error(res);
2608                 }
2609                 this._resback(res);
2610         },
2611
2612         addBoth: function(/*Function|Object*/cb, /*String?*/cbfn){
2613                 //      summary:
2614                 //              Add the same function as both a callback and an errback as the
2615                 //              next element on the callback sequence.This is useful for code
2616                 //              that you want to guarantee to run, e.g. a finalizer.
2617                 var enclosed = dojo.hitch.apply(dojo, arguments);
2618                 return this.addCallbacks(enclosed, enclosed);
2619         },
2620
2621         addCallback: function(/*Function|Object*/cb, /*String?*/cbfn /*...*/){
2622                 //      summary: 
2623                 //              Add a single callback to the end of the callback sequence.
2624                 return this.addCallbacks(dojo.hitch.apply(dojo, arguments));
2625         },
2626
2627         addErrback: function(cb, cbfn){
2628                 //      summary: 
2629                 //              Add a single callback to the end of the callback sequence.
2630                 return this.addCallbacks(null, dojo.hitch.apply(dojo, arguments));
2631         },
2632
2633         addCallbacks: function(cb, eb){
2634                 // summary: 
2635                 //              Add separate callback and errback to the end of the callback
2636                 //              sequence.
2637                 this.chain.push([cb, eb])
2638                 if(this.fired >= 0){
2639                         this._fire();
2640                 }
2641                 return this;
2642         },
2643
2644         _fire: function(){
2645                 // summary: 
2646                 //              Used internally to exhaust the callback sequence when a result
2647                 //              is available.
2648                 var chain = this.chain;
2649                 var fired = this.fired;
2650                 var res = this.results[fired];
2651                 var self = this;
2652                 var cb = null;
2653                 while(
2654                         (chain.length > 0) &&
2655                         (this.paused == 0)
2656                 ){
2657                         // Array
2658                         var f = chain.shift()[fired];
2659                         if(!f){ continue; }
2660                         try{
2661                                 res = f(res);
2662                                 fired = ((res instanceof Error) ? 1 : 0);
2663                                 if(res instanceof dojo.Deferred){
2664                                         cb = function(res){
2665                                                 self._resback(res);
2666                                                 // inlined from _pause()
2667                                                 self.paused--;
2668                                                 if(
2669                                                         (self.paused == 0) && 
2670                                                         (self.fired >= 0)
2671                                                 ){
2672                                                         self._fire();
2673                                                 }
2674                                         }
2675                                         // inlined from _unpause
2676                                         this.paused++;
2677                                 }
2678                         }catch(err){
2679                                 console.debug(err);
2680                                 fired = 1;
2681                                 res = err;
2682                         }
2683                 }
2684                 this.fired = fired;
2685                 this.results[fired] = res;
2686                 if((cb)&&(this.paused)){
2687                         // this is for "tail recursion" in case the dependent
2688                         // deferred is already fired
2689                         res.addBoth(cb);
2690                 }
2691         }
2692 });
2693
2694 }
2695
2696 if(!dojo._hasResource["dojo._base.json"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
2697 dojo._hasResource["dojo._base.json"] = true;
2698 dojo.provide("dojo._base.json");
2699
2700 dojo.fromJson = function(/*String*/ json){
2701         // summary:
2702         //              Parses a [JSON](http://json.org) string to return a JavaScript object.
2703         // json: 
2704         //              a string literal of a JSON item, for instance:
2705         //                      `'{ "foo": [ "bar", 1, { "baz": "thud" } ] }'`
2706
2707         return eval("(" + json + ")"); // Object
2708 }
2709
2710 dojo._escapeString = function(/*String*/str){
2711         //summary:
2712         //              Adds escape sequences for non-visual characters, double quote and
2713         //              backslash and surrounds with double quotes to form a valid string
2714         //              literal.
2715         return ('"' + str.replace(/(["\\])/g, '\\$1') + '"').
2716                 replace(/[\f]/g, "\\f").replace(/[\b]/g, "\\b").replace(/[\n]/g, "\\n").
2717                 replace(/[\t]/g, "\\t").replace(/[\r]/g, "\\r"); // string
2718 }
2719
2720 dojo.toJsonIndentStr = "\t";
2721 dojo.toJson = function(/*Object*/ it, /*Boolean?*/ prettyPrint, /*String?*/ _indentStr){
2722         // summary:
2723         //              Returns a [JSON](http://json.org) serialization of an object.
2724         //
2725         // description:
2726         //              Returns a [JSON](http://json.org) serialization of an object.
2727         //              Note that this doesn't check for infinite recursion, so don't do that!
2728         //
2729         // it:
2730         //              an object to be serialized. Objects may define their own
2731         //              serialization via a special "__json__" or "json" function
2732         //              property. If a specialized serializer has been defined, it will
2733         //              be used as a fallback.
2734         //
2735         // prettyPrint:
2736         //              if true, we indent objects and arrays to make the output prettier.
2737         //              The variable dojo.toJsonIndentStr is used as the indent string 
2738         //              -- to use something other than the default (tab), 
2739         //              change that variable before calling dojo.toJson().
2740         //
2741         // _indentStr:
2742         //              private variable for recursive calls when pretty printing, do not use.
2743
2744         if(it === undefined){
2745                 return "undefined";
2746         }
2747         var objtype = typeof it;
2748         if(objtype == "number" || objtype == "boolean"){
2749                 return it + "";
2750         }
2751         if(it === null){
2752                 return "null";
2753         }
2754         if(dojo.isString(it)){ 
2755                 return dojo._escapeString(it); 
2756         }
2757         if(it.nodeType && it.cloneNode){ // isNode
2758                 return ""; // FIXME: would something like outerHTML be better here?
2759         }
2760         // recurse
2761         var recurse = arguments.callee;
2762         // short-circuit for objects that support "json" serialization
2763         // if they return "self" then just pass-through...
2764         var newObj;
2765         _indentStr = _indentStr || "";
2766         var nextIndent = prettyPrint ? _indentStr + dojo.toJsonIndentStr : "";
2767         if(typeof it.__json__ == "function"){
2768                 newObj = it.__json__();
2769                 if(it !== newObj){
2770                         return recurse(newObj, prettyPrint, nextIndent);
2771                 }
2772         }
2773         if(typeof it.json == "function"){
2774                 newObj = it.json();
2775                 if(it !== newObj){
2776                         return recurse(newObj, prettyPrint, nextIndent);
2777                 }
2778         }
2779
2780         var sep = prettyPrint ? " " : "";
2781         var newLine = prettyPrint ? "\n" : "";
2782
2783         // array
2784         if(dojo.isArray(it)){
2785                 var res = dojo.map(it, function(obj){
2786                         var val = recurse(obj, prettyPrint, nextIndent);
2787                         if(typeof val != "string"){
2788                                 val = "undefined";
2789                         }
2790                         return newLine + nextIndent + val;
2791                 });
2792                 return "[" + res.join("," + sep) + newLine + _indentStr + "]";
2793         }
2794         /*
2795         // look in the registry
2796         try {
2797                 window.o = it;
2798                 newObj = dojo.json.jsonRegistry.match(it);
2799                 return recurse(newObj, prettyPrint, nextIndent);
2800         }catch(e){
2801                 // console.debug(e);
2802         }
2803         // it's a function with no adapter, skip it
2804         */
2805         if(objtype == "function"){
2806                 return null; // null
2807         }
2808         // generic object code path
2809         var output = [];
2810         for(var key in it){
2811                 var keyStr;
2812                 if(typeof key == "number"){
2813                         keyStr = '"' + key + '"';
2814                 }else if(typeof key == "string"){
2815                         keyStr = dojo._escapeString(key);
2816                 }else{
2817                         // skip non-string or number keys
2818                         continue;
2819                 }
2820                 val = recurse(it[key], prettyPrint, nextIndent);
2821                 if(typeof val != "string"){
2822                         // skip non-serializable values
2823                         continue;
2824                 }
2825                 // FIXME: use += on Moz!!
2826                 //       MOW NOTE: using += is a pain because you have to account for the dangling comma...
2827                 output.push(newLine + nextIndent + keyStr + ":" + sep + val);
2828         }
2829         return "{" + output.join("," + sep) + newLine + _indentStr + "}"; // String
2830 }
2831
2832 }
2833
2834 if(!dojo._hasResource["dojo._base.array"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
2835 dojo._hasResource["dojo._base.array"] = true;
2836
2837 dojo.provide("dojo._base.array");
2838
2839 (function(){
2840         var _getParts = function(arr, obj, cb){
2841                 return [ 
2842                         dojo.isString(arr) ? arr.split("") : arr, 
2843                         obj || dojo.global,
2844                         // FIXME: cache the anonymous functions we create here?
2845                         dojo.isString(cb) ? new Function("item", "index", "array", cb) : cb
2846                 ];
2847         };
2848
2849         dojo.mixin(dojo, {
2850                 indexOf: function(      /*Array*/               array, 
2851                                                         /*Object*/              value,
2852                                                         /*Integer?*/    fromIndex,
2853                                                         /*Boolean?*/    findLast){
2854                         // summary:
2855                         //              locates the first index of the provided value in the
2856                         //              passed array. If the value is not found, -1 is returned.
2857                         // description:
2858                         //              For details on this method, see:
2859                         //                      <http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Reference:Global_Objects:Array:indexOf>
2860
2861                         var step = 1, end = array.length || 0, i = 0;
2862                         if(findLast){
2863                                 i = end - 1;
2864                                 step = end = -1;
2865                         }
2866                         if(fromIndex != undefined){ i = fromIndex; }
2867                         if((findLast && i > end) || i < end){
2868                                 for(; i != end; i += step){
2869                                         if(array[i] == value){ return i; }
2870                                 }
2871                         }
2872                         return -1;      // Number
2873                 },
2874
2875                 lastIndexOf: function(/*Array*/array, /*Object*/value, /*Integer?*/fromIndex){
2876                         // summary:
2877                         //              locates the last index of the provided value in the passed array. 
2878                         //              If the value is not found, -1 is returned.
2879                         // description:
2880                         //              For details on this method, see:
2881                         //                      <http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Reference:Global_Objects:Array:lastIndexOf>
2882                         return dojo.indexOf(array, value, fromIndex, true); // Number
2883                 },
2884
2885                 forEach: function(/*Array|String*/arr, /*Function|String*/callback, /*Object?*/thisObject){
2886                         // summary:
2887                         //              for every item in arr, callback is invoked.  Return values are ignored.
2888                         // arr: the array to iterate on.  If a string, operates on individual characters.
2889                         // callback: a function is invoked with three arguments: item, index, and array
2890                         // thisObject: may be used to scope the call to callback
2891                         // description:
2892                         //              This function corresponds to the JavaScript 1.6 Array.forEach() method.
2893                         //              In environments that support JavaScript 1.6, this function is a passthrough to the built-in method.
2894                         //              For more details, see:
2895                         //                      <http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Reference:Global_Objects:Array:forEach>
2896
2897                         // match the behavior of the built-in forEach WRT empty arrs
2898                         if(!arr || !arr.length){ return; }
2899
2900                         // FIXME: there are several ways of handilng thisObject. Is
2901                         // dojo.global always the default context?
2902                         var _p = _getParts(arr, thisObject, callback); arr = _p[0];
2903                         for(var i=0,l=_p[0].length; i<l; i++){ 
2904                                 _p[2].call(_p[1], arr[i], i, arr);
2905                         }
2906                 },
2907
2908                 _everyOrSome: function(/*Boolean*/every, /*Array|String*/arr, /*Function|String*/callback, /*Object?*/thisObject){
2909                         var _p = _getParts(arr, thisObject, callback); arr = _p[0];
2910                         for(var i = 0, l = arr.length; i < l; i++){
2911                                 var result = !!_p[2].call(_p[1], arr[i], i, arr);
2912                                 if(every ^ result){
2913                                         return result; // Boolean
2914                                 }
2915                         }
2916                         return every; // Boolean
2917                 },
2918
2919                 every: function(/*Array|String*/arr, /*Function|String*/callback, /*Object?*/thisObject){
2920                         // summary:
2921                         //              Determines whether or not every item in arr satisfies the
2922                         //              condition implemented by callback.
2923                         // arr: the array to iterate on.  If a string, operates on individual characters.
2924                         // callback: a function is invoked with three arguments: item, index, and array and returns true
2925                         //              if the condition is met.
2926                         // thisObject: may be used to scope the call to callback
2927                         // description:
2928                         //              This function corresponds to the JavaScript 1.6 Array.every() method.
2929                         //              In environments that support JavaScript 1.6, this function is a passthrough to the built-in method.
2930                         //              For more details, see:
2931                         //                      <http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Reference:Global_Objects:Array:every>
2932                         // example:
2933                         //      |       dojo.every([1, 2, 3, 4], function(item){ return item>1; });
2934                         //              returns false
2935                         // example:
2936                         //      |       dojo.every([1, 2, 3, 4], function(item){ return item>0; });
2937                         //              returns true 
2938                         return this._everyOrSome(true, arr, callback, thisObject); // Boolean
2939                 },
2940
2941                 some: function(/*Array|String*/arr, /*Function|String*/callback, /*Object?*/thisObject){
2942                         // summary:
2943                         //              Determines whether or not any item in arr satisfies the
2944                         //              condition implemented by callback.
2945                         // arr: the array to iterate on.  If a string, operates on individual characters.
2946                         // callback: a function is invoked with three arguments: item, index, and array and returns true
2947                         //              if the condition is met.
2948                         // thisObject: may be used to scope the call to callback
2949                         // description:
2950                         //              This function corresponds to the JavaScript 1.6 Array.some() method.
2951                         //              In environments that support JavaScript 1.6, this function is a passthrough to the built-in method.
2952                         //              For more details, see:
2953                         //                      <http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Reference:Global_Objects:Array:some>
2954                         // example:
2955                         //      |       dojo.some([1, 2, 3, 4], function(item){ return item>1; });
2956                         //              returns true
2957                         // example:
2958                         //      |       dojo.some([1, 2, 3, 4], function(item){ return item<1; });
2959                         //              returns false
2960                         return this._everyOrSome(false, arr, callback, thisObject); // Boolean
2961                 },
2962
2963                 map: function(/*Array|String*/arr, /*Function|String*/callback, /*Function?*/thisObject){
2964                         // summary:
2965                         //              applies callback to each element of arr and returns
2966                         //              an Array with the results
2967                         // arr: the array to iterate on.  If a string, operates on individual characters.
2968                         // callback: a function is invoked with three arguments: item, index, and array and returns a value
2969                         // thisObject: may be used to scope the call to callback
2970                         // description:
2971                         //              This function corresponds to the JavaScript 1.6 Array.map() method.
2972                         //              In environments that support JavaScript 1.6, this function is a passthrough to the built-in method.
2973                         //              For more details, see:
2974                         //                      <http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Reference:Global_Objects:Array:map>
2975                         // example:
2976                         //      |       dojo.map([1, 2, 3, 4], function(item){ return item+1 });
2977                         //              returns [2, 3, 4, 5]
2978                         var _p = _getParts(arr, thisObject, callback); arr = _p[0];
2979                         var outArr = (arguments[3] ? (new arguments[3]()) : []);
2980                         for(var i=0;i<arr.length;++i){
2981                                 outArr.push(_p[2].call(_p[1], arr[i], i, arr));
2982                         }
2983                         return outArr; // Array
2984                 },
2985
2986                 filter: function(/*Array*/arr, /*Function|String*/callback, /*Object?*/thisObject){
2987                         // summary:
2988                         //              Returns a new Array with those items from arr that match the
2989                         //              condition implemented by callback.
2990                         // arr: the array to iterate on.  If a string, operates on individual characters.
2991                         // callback: a function is invoked with three arguments: item, index, and array and returns true
2992                         //              if the condition is met.
2993                         // thisObject: may be used to scope the call to callback
2994                         // description:
2995                         //              This function corresponds to the JavaScript 1.6 Array.filter() method.
2996                         //              In environments that support JavaScript 1.6, this function is a passthrough to the built-in method.
2997                         //              For more details, see:
2998                         //                      <http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Reference:Global_Objects:Array:filter>
2999                         // example:
3000                         //      |       dojo.filter([1, 2, 3, 4], function(item){ return item>1; });
3001                         //              returns [2, 3, 4]
3002
3003                         var _p = _getParts(arr, thisObject, callback); arr = _p[0];
3004                         var outArr = [];
3005                         for(var i = 0; i < arr.length; i++){
3006                                 if(_p[2].call(_p[1], arr[i], i, arr)){
3007                                         outArr.push(arr[i]);
3008                                 }
3009                         }
3010                         return outArr; // Array
3011                 }
3012         });
3013 })();
3014
3015 }
3016
3017 if(!dojo._hasResource["dojo._base.Color"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
3018 dojo._hasResource["dojo._base.Color"] = true;
3019 dojo.provide("dojo._base.Color");
3020
3021
3022
3023 dojo.Color = function(/*Array|String|Object*/ color){
3024         // summary:
3025         //              takes a named string, hex string, array of rgb or rgba values,
3026         //              an object with r, g, b, and a properties, or another dojo.Color object
3027         if(color){ this.setColor(color); }
3028 };
3029
3030 // FIXME: there's got to be a more space-efficient way to encode or discover these!!  Use hex?
3031 dojo.Color.named = {
3032         black:      [0,0,0],
3033         silver:     [192,192,192],
3034         gray:       [128,128,128],
3035         white:      [255,255,255],
3036         maroon:         [128,0,0],
3037         red:        [255,0,0],
3038         purple:         [128,0,128],
3039         fuchsia:        [255,0,255],
3040         green:      [0,128,0],
3041         lime:       [0,255,0],
3042         olive:          [128,128,0],
3043         yellow:         [255,255,0],
3044         navy:       [0,0,128],
3045         blue:       [0,0,255],
3046         teal:           [0,128,128],
3047         aqua:           [0,255,255]
3048 };
3049
3050
3051 dojo.extend(dojo.Color, {
3052         r: 255, g: 255, b: 255, a: 1,
3053         _set: function(r, g, b, a){
3054                 var t = this; t.r = r; t.g = g; t.b = b; t.a = a;
3055         },
3056         setColor: function(/*Array|String|Object*/ color){
3057                 // summary:
3058                 //              takes a named string, hex string, array of rgb or rgba values,
3059                 //              an object with r, g, b, and a properties, or another dojo.Color object
3060                 var d = dojo;
3061                 if(d.isString(color)){
3062                         d.colorFromString(color, this);
3063                 }else if(d.isArray(color)){
3064                         d.colorFromArray(color, this);
3065                 }else{
3066                         this._set(color.r, color.g, color.b, color.a);
3067                         if(!(color instanceof d.Color)){ this.sanitize(); }
3068                 }
3069                 return this;    // dojo.Color
3070         },
3071         sanitize: function(){
3072                 // summary:
3073                 //              makes sure that the object has correct attributes
3074                 // description: 
3075                 //              the default implementation does nothing, include dojo.colors to
3076                 //              augment it to real checks
3077                 return this;    // dojo.Color
3078         },
3079         toRgb: function(){
3080                 // summary: returns 3 component array of rgb values
3081                 var t = this;
3082                 return [t.r, t.g, t.b]; // Array
3083         },
3084         toRgba: function(){
3085                 // summary: returns a 4 component array of rgba values
3086                 var t = this;
3087                 return [t.r, t.g, t.b, t.a];    // Array
3088         },
3089         toHex: function(){
3090                 // summary: returns a css color string in hexadecimal representation
3091                 var arr = dojo.map(["r", "g", "b"], function(x){
3092                         var s = this[x].toString(16);
3093                         return s.length < 2 ? "0" + s : s;
3094                 }, this);
3095                 return "#" + arr.join("");      // String
3096         },
3097         toCss: function(/*Boolean?*/ includeAlpha){
3098                 // summary: returns a css color string in rgb(a) representation
3099                 var t = this, rgb = t.r + ", " + t.g + ", " + t.b;
3100                 return (includeAlpha ? "rgba(" + rgb + ", " + t.a : "rgb(" + rgb) + ")";        // String
3101         },
3102         toString: function(){
3103                 // summary: returns a visual representation of the color
3104                 return this.toCss(true); // String
3105         }
3106 });
3107
3108 dojo.blendColors = function(
3109         /*dojo.Color*/ start, 
3110         /*dojo.Color*/ end, 
3111         /*Number*/ weight,
3112         /*dojo.Color?*/ obj
3113 ){
3114         // summary: 
3115         //              blend colors end and start with weight from 0 to 1, 0.5 being a 50/50 blend,
3116         //              can reuse a previously allocated dojo.Color object for the result
3117         var d = dojo, t = obj || new dojo.Color();
3118         d.forEach(["r", "g", "b", "a"], function(x){
3119                 t[x] = start[x] + (end[x] - start[x]) * weight;
3120                 if(x != "a"){ t[x] = Math.round(t[x]); }
3121         });
3122         return t.sanitize();    // dojo.Color
3123 };
3124
3125 dojo.colorFromRgb = function(/*String*/ color, /*dojo.Color?*/ obj){
3126         // summary: get rgb(a) array from css-style color declarations
3127         var m = color.toLowerCase().match(/^rgba?\(([\s\.,0-9]+)\)/);
3128         return m && dojo.colorFromArray(m[1].split(/\s*,\s*/), obj);    // dojo.Color
3129 };
3130
3131 dojo.colorFromHex = function(/*String*/ color, /*dojo.Color?*/ obj){
3132         // summary: converts a hex string with a '#' prefix to a color object.
3133         //      Supports 12-bit #rgb shorthand.
3134         var d = dojo, t = obj || new d.Color(),
3135                 bits = (color.length == 4) ? 4 : 8,
3136                 mask = (1 << bits) - 1;
3137         color = Number("0x" + color.substr(1));
3138         if(isNaN(color)){
3139                 return null; // dojo.Color
3140         }
3141         d.forEach(["b", "g", "r"], function(x){
3142                 var c = color & mask;
3143                 color >>= bits;
3144                 t[x] = bits == 4 ? 17 * c : c;
3145         });
3146         t.a = 1;
3147         return t;       // dojo.Color
3148 };
3149
3150 dojo.colorFromArray = function(/*Array*/ a, /*dojo.Color?*/ obj){
3151         // summary: builds a color from 1, 2, 3, or 4 element array
3152         var t = obj || new dojo.Color();
3153         t._set(Number(a[0]), Number(a[1]), Number(a[2]), Number(a[3]));
3154         if(isNaN(t.a)){ t.a = 1; }
3155         return t.sanitize();    // dojo.Color
3156 };
3157
3158 dojo.colorFromString = function(/*String*/ str, /*dojo.Color?*/ obj){
3159         //      summary:
3160         //              parses str for a color value.
3161         //      description:
3162         //              Acceptable input values for str may include arrays of any form
3163         //              accepted by dojo.colorFromArray, hex strings such as "#aaaaaa", or
3164         //              rgb or rgba strings such as "rgb(133, 200, 16)" or "rgba(10, 10,
3165         //              10, 50)"
3166         //      returns:
3167         //              a dojo.Color object. If obj is passed, it will be the return value.
3168         var a = dojo.Color.named[str];
3169         return a && dojo.colorFromArray(a, obj) || dojo.colorFromRgb(str, obj) || dojo.colorFromHex(str, obj);
3170 };
3171
3172 }
3173
3174 if(!dojo._hasResource["dojo._base"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
3175 dojo._hasResource["dojo._base"] = true;
3176 dojo.provide("dojo._base");
3177
3178
3179
3180
3181
3182
3183
3184
3185
3186 }
3187
3188 if(!dojo._hasResource["dojo._base.window"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
3189 dojo._hasResource["dojo._base.window"] = true;
3190 dojo.provide("dojo._base.window");
3191
3192 dojo._gearsObject = function(){
3193         // summary: 
3194         //              factory method to get a Google Gears plugin instance to
3195         //              expose in the browser runtime environment, if present
3196         var factory;
3197         var results;
3198         
3199         var gearsObj = dojo.getObject("google.gears");
3200         if(gearsObj){ return gearsObj; } // already defined elsewhere
3201         
3202         if(typeof GearsFactory != "undefined"){ // Firefox
3203                 factory = new GearsFactory();
3204         }else{
3205                 if(dojo.isIE){
3206                         // IE
3207                         try{
3208                                 factory = new ActiveXObject("Gears.Factory");
3209                         }catch(e){
3210                                 // ok to squelch; there's no gears factory.  move on.
3211                         }
3212                 }else if(navigator.mimeTypes["application/x-googlegears"]){
3213                         // Safari?
3214                         factory = document.createElement("object");
3215                         factory.setAttribute("type", "application/x-googlegears");
3216                         factory.setAttribute("width", 0);
3217                         factory.setAttribute("height", 0);
3218                         factory.style.display = "none";
3219                         document.documentElement.appendChild(factory);
3220                 }
3221         }
3222
3223         // still nothing?
3224         if(!factory){ return null; }
3225         
3226         // define the global objects now; don't overwrite them though if they
3227         // were somehow set internally by the Gears plugin, which is on their
3228         // dev roadmap for the future
3229         dojo.setObject("google.gears.factory", factory);
3230         return dojo.getObject("google.gears");
3231 };
3232
3233 /*=====
3234 dojo.isGears = {
3235         // summary: True if client is using Google Gears
3236 };
3237 =====*/
3238 // see if we have Google Gears installed, and if
3239 // so, make it available in the runtime environment
3240 // and in the Google standard 'google.gears' global object
3241 dojo.isGears = (!!dojo._gearsObject())||0;
3242
3243 /*=====
3244 dojo.doc = {
3245         // summary:
3246         //              Alias for the current document. 'dojo.doc' can be modified
3247         //              for temporary context shifting. Also see dojo.withDoc().
3248         // description:
3249         //    Refer to dojo.doc rather
3250         //    than referring to 'window.document' to ensure your code runs
3251         //    correctly in managed contexts.
3252         // example:
3253         //      |       n.appendChild(dojo.doc.createElement('div'));
3254 }
3255 =====*/
3256 dojo.doc = window["document"] || null;
3257
3258 dojo.body = function(){
3259         // summary:
3260         //              Return the body element of the document
3261         //              return the body object associated with dojo.doc
3262         // example:
3263         //      |       dojo.body().appendChild(dojo.doc.createElement('div'));
3264
3265         // Note: document.body is not defined for a strict xhtml document
3266         // Would like to memoize this, but dojo.doc can change vi dojo.withDoc().
3267         return dojo.doc.body || dojo.doc.getElementsByTagName("body")[0]; // Node
3268 }
3269
3270 dojo.setContext = function(/*Object*/globalObject, /*DocumentElement*/globalDocument){
3271         // summary:
3272         //              changes the behavior of many core Dojo functions that deal with
3273         //              namespace and DOM lookup, changing them to work in a new global
3274         //              context (e.g., an iframe). The varibles dojo.global and dojo.doc
3275         //              are modified as a result of calling this function and the result of
3276         //              `dojo.body()` likewise differs.
3277         dojo.global = globalObject;
3278         dojo.doc = globalDocument;
3279 };
3280
3281 dojo._fireCallback = function(callback, context, cbArguments){
3282         if(context && dojo.isString(callback)){
3283                 callback = context[callback];
3284         }
3285         return callback.apply(context, cbArguments || [ ]);
3286 }
3287
3288 dojo.withGlobal = function(     /*Object*/globalObject, 
3289                                                         /*Function*/callback, 
3290                                                         /*Object?*/thisObject, 
3291                                                         /*Array?*/cbArguments){
3292         // summary:
3293         //              Call callback with globalObject as dojo.global and
3294         //              globalObject.document as dojo.doc. If provided, globalObject
3295         //              will be executed in the context of object thisObject
3296         // description:
3297         //              When callback() returns or throws an error, the dojo.global
3298         //              and dojo.doc will be restored to its previous state.
3299         var rval;
3300         var oldGlob = dojo.global;
3301         var oldDoc = dojo.doc;
3302         try{
3303                 dojo.setContext(globalObject, globalObject.document);
3304                 rval = dojo._fireCallback(callback, thisObject, cbArguments);
3305         }finally{
3306                 dojo.setContext(oldGlob, oldDoc);
3307         }
3308         return rval;
3309 }
3310
3311 dojo.withDoc = function(        /*Object*/documentObject, 
3312                                                         /*Function*/callback, 
3313                                                         /*Object?*/thisObject, 
3314                                                         /*Array?*/cbArguments){
3315         // summary:
3316         //              Call callback with documentObject as dojo.doc. If provided,
3317         //              callback will be executed in the context of object thisObject
3318         // description:
3319         //              When callback() returns or throws an error, the dojo.doc will
3320         //              be restored to its previous state.
3321         var rval;
3322         var oldDoc = dojo.doc;
3323         try{
3324                 dojo.doc = documentObject;
3325                 rval = dojo._fireCallback(callback, thisObject, cbArguments);
3326         }finally{
3327                 dojo.doc = oldDoc;
3328         }
3329         return rval;
3330 };
3331
3332 }
3333
3334 if(!dojo._hasResource["dojo._base.event"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
3335 dojo._hasResource["dojo._base.event"] = true;
3336 dojo.provide("dojo._base.event");
3337
3338
3339 // this file courtesy of the TurboAjax Group, licensed under a Dojo CLA
3340
3341 (function(){
3342         // DOM event listener machinery
3343         var del = (dojo._event_listener = {
3344                 add: function(/*DOMNode*/node, /*String*/name, /*Function*/fp){
3345                         if(!node){return;} 
3346                         name = del._normalizeEventName(name);
3347                         fp = del._fixCallback(name, fp);
3348                         var oname = name;
3349                         if(!dojo.isIE && (name == "mouseenter" || name == "mouseleave")){
3350                                 var ofp = fp;
3351                                 //oname = name;
3352                                 name = (name == "mouseenter") ? "mouseover" : "mouseout";
3353                                 fp = function(e){
3354                                         // thanks ben!
3355                                         if(!dojo.isDescendant(e.relatedTarget, node)){
3356                                                 // e.type = oname; // FIXME: doesn't take? SJM: event.type is generally immutable.
3357                                                 return ofp.call(this, e); 
3358                                         }
3359                                 }
3360                         }
3361                         node.addEventListener(name, fp, false);
3362                         return fp; /*Handle*/
3363                 },
3364                 remove: function(/*DOMNode*/node, /*String*/event, /*Handle*/handle){
3365                         // summary:
3366                         //              clobbers the listener from the node
3367                         // node:
3368                         //              DOM node to attach the event to
3369                         // event:
3370                         //              the name of the handler to remove the function from
3371                         // handle:
3372                         //              the handle returned from add
3373                         if (node){
3374                                 node.removeEventListener(del._normalizeEventName(event), handle, false);
3375                         }
3376                 },
3377                 _normalizeEventName: function(/*String*/name){
3378                         // Generally, name should be lower case, unless it is special
3379                         // somehow (e.g. a Mozilla DOM event).
3380                         // Remove 'on'.
3381                         return name.slice(0,2) =="on" ? name.slice(2) : name;
3382                 },
3383                 _fixCallback: function(/*String*/name, fp){
3384                         // By default, we only invoke _fixEvent for 'keypress'
3385                         // If code is added to _fixEvent for other events, we have
3386                         // to revisit this optimization.
3387                         // This also applies to _fixEvent overrides for Safari and Opera
3388                         // below.
3389                         return name != "keypress" ? fp : function(e){ return fp.call(this, del._fixEvent(e, this)); };
3390                 },
3391                 _fixEvent: function(evt, sender){
3392                         // _fixCallback only attaches us to keypress.
3393                         // Switch on evt.type anyway because we might 
3394                         // be called directly from dojo.fixEvent.
3395                         switch(evt.type){
3396                                 case "keypress":
3397                                         del._setKeyChar(evt);
3398                                         break;
3399                         }
3400                         return evt;
3401                 },
3402                 _setKeyChar: function(evt){
3403                         evt.keyChar = evt.charCode ? String.fromCharCode(evt.charCode) : '';
3404                 }
3405         });
3406
3407         // DOM events
3408         
3409         dojo.fixEvent = function(/*Event*/evt, /*DOMNode*/sender){
3410                 // summary:
3411                 //              normalizes properties on the event object including event
3412                 //              bubbling methods, keystroke normalization, and x/y positions
3413                 // evt: Event
3414                 //              native event object
3415                 // sender: DOMNode
3416                 //              node to treat as "currentTarget"
3417                 return del._fixEvent(evt, sender);
3418         }
3419
3420         dojo.stopEvent = function(/*Event*/evt){
3421                 // summary:
3422                 //              prevents propagation and clobbers the default action of the
3423                 //              passed event
3424                 // evt: Event
3425                 //              The event object. If omitted, window.event is used on IE.
3426                 evt.preventDefault();
3427                 evt.stopPropagation();
3428                 // NOTE: below, this method is overridden for IE
3429         }
3430
3431         // the default listener to use on dontFix nodes, overriden for IE
3432         var node_listener = dojo._listener;
3433         
3434         // Unify connect and event listeners
3435         dojo._connect = function(obj, event, context, method, dontFix){
3436                 // FIXME: need a more strict test
3437                 var isNode = obj && (obj.nodeType||obj.attachEvent||obj.addEventListener);
3438                 // choose one of three listener options: raw (connect.js), DOM event on a Node, custom event on a Node
3439                 // we need the third option to provide leak prevention on broken browsers (IE)
3440                 var lid = !isNode ? 0 : (!dontFix ? 1 : 2), l = [dojo._listener, del, node_listener][lid];
3441                 // create a listener
3442                 var h = l.add(obj, event, dojo.hitch(context, method));
3443                 // formerly, the disconnect package contained "l" directly, but if client code
3444                 // leaks the disconnect package (by connecting it to a node), referencing "l" 
3445                 // compounds the problem.
3446                 // instead we return a listener id, which requires custom _disconnect below.
3447                 // return disconnect package
3448                 return [ obj, event, h, lid ];
3449         }
3450
3451         dojo._disconnect = function(obj, event, handle, listener){
3452                 ([dojo._listener, del, node_listener][listener]).remove(obj, event, handle);
3453         }
3454
3455         // Constants
3456
3457         // Public: client code should test
3458         // keyCode against these named constants, as the
3459         // actual codes can vary by browser.
3460         dojo.keys = {
3461                 // summary: definitions for common key values
3462                 BACKSPACE: 8,
3463                 TAB: 9,
3464                 CLEAR: 12,
3465                 ENTER: 13,
3466                 SHIFT: 16,
3467                 CTRL: 17,
3468                 ALT: 18,
3469                 PAUSE: 19,
3470                 CAPS_LOCK: 20,
3471                 ESCAPE: 27,
3472                 SPACE: 32,
3473                 PAGE_UP: 33,
3474                 PAGE_DOWN: 34,
3475                 END: 35,
3476                 HOME: 36,
3477                 LEFT_ARROW: 37,
3478                 UP_ARROW: 38,
3479                 RIGHT_ARROW: 39,
3480                 DOWN_ARROW: 40,
3481                 INSERT: 45,
3482                 DELETE: 46,
3483                 HELP: 47,
3484                 LEFT_WINDOW: 91,
3485                 RIGHT_WINDOW: 92,
3486                 SELECT: 93,
3487                 NUMPAD_0: 96,
3488                 NUMPAD_1: 97,
3489                 NUMPAD_2: 98,
3490                 NUMPAD_3: 99,
3491                 NUMPAD_4: 100,
3492                 NUMPAD_5: 101,
3493                 NUMPAD_6: 102,
3494                 NUMPAD_7: 103,
3495                 NUMPAD_8: 104,
3496                 NUMPAD_9: 105,
3497                 NUMPAD_MULTIPLY: 106,
3498                 NUMPAD_PLUS: 107,
3499                 NUMPAD_ENTER: 108,
3500                 NUMPAD_MINUS: 109,
3501                 NUMPAD_PERIOD: 110,
3502                 NUMPAD_DIVIDE: 111,
3503                 F1: 112,
3504                 F2: 113,
3505                 F3: 114,
3506                 F4: 115,
3507                 F5: 116,
3508                 F6: 117,
3509                 F7: 118,
3510                 F8: 119,
3511                 F9: 120,
3512                 F10: 121,
3513                 F11: 122,
3514                 F12: 123,
3515                 F13: 124,
3516                 F14: 125,
3517                 F15: 126,
3518                 NUM_LOCK: 144,
3519                 SCROLL_LOCK: 145
3520         };
3521         
3522         // IE event normalization
3523         if(dojo.isIE){ 
3524                 var _trySetKeyCode = function(e, code){
3525                         try{
3526                                 // squelch errors when keyCode is read-only
3527                                 // (e.g. if keyCode is ctrl or shift)
3528                                 return (e.keyCode = code);
3529                         }catch(e){
3530                                 return 0;
3531                         }
3532                 }
3533
3534                 // by default, use the standard listener
3535                 var iel = dojo._listener;
3536                 // dispatcher tracking property
3537                 if(!dojo.config._allow_leaks){
3538                         // custom listener that handles leak protection for DOM events
3539                         node_listener = iel = dojo._ie_listener = {
3540                                 // support handler indirection: event handler functions are 
3541                                 // referenced here. Event dispatchers hold only indices.
3542                                 handlers: [],
3543                                 // add a listener to an object
3544                                 add: function(/*Object*/ source, /*String*/ method, /*Function*/ listener){
3545                                         source = source || dojo.global;
3546                                         var f = source[method];
3547                                         if(!f||!f._listeners){
3548                                                 var d = dojo._getIeDispatcher();
3549                                                 // original target function is special
3550                                                 d.target = f && (ieh.push(f) - 1);
3551                                                 // dispatcher holds a list of indices into handlers table
3552                                                 d._listeners = [];
3553                                                 // redirect source to dispatcher
3554                                                 f = source[method] = d;
3555                                         }
3556                                         return f._listeners.push(ieh.push(listener) - 1) ; /*Handle*/
3557                                 },
3558                                 // remove a listener from an object
3559                                 remove: function(/*Object*/ source, /*String*/ method, /*Handle*/ handle){
3560                                         var f = (source||dojo.global)[method], l = f && f._listeners;
3561                                         if(f && l && handle--){
3562                                                 delete ieh[l[handle]];
3563                                                 delete l[handle];
3564                                         }
3565                                 }
3566                         };
3567                         // alias used above
3568                         var ieh = iel.handlers;
3569                 }
3570
3571                 dojo.mixin(del, {
3572                         add: function(/*DOMNode*/node, /*String*/event, /*Function*/fp){
3573                                 if(!node){return;} // undefined
3574                                 event = del._normalizeEventName(event);
3575                                 if(event=="onkeypress"){
3576                                         // we need to listen to onkeydown to synthesize
3577                                         // keypress events that otherwise won't fire
3578                                         // on IE
3579                                         var kd = node.onkeydown;
3580                                         if(!kd || !kd._listeners || !kd._stealthKeydownHandle){
3581                                                 var h = del.add(node, "onkeydown", del._stealthKeyDown);
3582                                                 kd = node.onkeydown;
3583                                                 kd._stealthKeydownHandle = h;
3584                                                 kd._stealthKeydownRefs = 1;
3585                                         }else{
3586                                                 kd._stealthKeydownRefs++;
3587                                         }
3588                                 }
3589                                 return iel.add(node, event, del._fixCallback(fp));
3590                         },
3591                         remove: function(/*DOMNode*/node, /*String*/event, /*Handle*/handle){
3592                                 event = del._normalizeEventName(event);
3593                                 iel.remove(node, event, handle); 
3594                                 if(event=="onkeypress"){
3595                                         var kd = node.onkeydown;
3596                                         if(--kd._stealthKeydownRefs <= 0){
3597                                                 iel.remove(node, "onkeydown", kd._stealthKeydownHandle);
3598                                                 delete kd._stealthKeydownHandle;
3599                                         }
3600                                 }
3601                         },
3602                         _normalizeEventName: function(/*String*/eventName){
3603                                 // Generally, eventName should be lower case, unless it is
3604                                 // special somehow (e.g. a Mozilla event)
3605                                 // ensure 'on'
3606                                 return eventName.slice(0,2) != "on" ? "on" + eventName : eventName;
3607                         },
3608                         _nop: function(){},
3609                         _fixEvent: function(/*Event*/evt, /*DOMNode*/sender){
3610                                 // summary:
3611                                 //              normalizes properties on the event object including event
3612                                 //              bubbling methods, keystroke normalization, and x/y positions
3613                                 // evt: native event object
3614                                 // sender: node to treat as "currentTarget"
3615                                 if(!evt){
3616                                         var w = sender && (sender.ownerDocument || sender.document || sender).parentWindow || window;
3617                                         evt = w.event; 
3618                                 }
3619                                 if(!evt){return(evt);}
3620                                 evt.target = evt.srcElement; 
3621                                 evt.currentTarget = (sender || evt.srcElement); 
3622                                 evt.layerX = evt.offsetX;
3623                                 evt.layerY = evt.offsetY;
3624                                 // FIXME: scroll position query is duped from dojo.html to
3625                                 // avoid dependency on that entire module. Now that HTML is in
3626                                 // Base, we should convert back to something similar there.
3627                                 var se = evt.srcElement, doc = (se && se.ownerDocument) || document;
3628                                 // DO NOT replace the following to use dojo.body(), in IE, document.documentElement should be used
3629                                 // here rather than document.body
3630                                 var docBody = ((dojo.isIE < 6) || (doc["compatMode"] == "BackCompat")) ? doc.body : doc.documentElement;
3631                                 var offset = dojo._getIeDocumentElementOffset();
3632                                 evt.pageX = evt.clientX + dojo._fixIeBiDiScrollLeft(docBody.scrollLeft || 0) - offset.x;
3633                                 evt.pageY = evt.clientY + (docBody.scrollTop || 0) - offset.y;
3634                                 if(evt.type == "mouseover"){ 
3635                                         evt.relatedTarget = evt.fromElement;
3636                                 }
3637                                 if(evt.type == "mouseout"){ 
3638                                         evt.relatedTarget = evt.toElement;
3639                                 }
3640                                 evt.stopPropagation = del._stopPropagation;
3641                                 evt.preventDefault = del._preventDefault;
3642                                 return del._fixKeys(evt);
3643                         },
3644                         _fixKeys: function(evt){
3645                                 switch(evt.type){
3646                                         case "keypress":
3647                                                 var c = ("charCode" in evt ? evt.charCode : evt.keyCode);
3648                                                 if (c==10){
3649                                                         // CTRL-ENTER is CTRL-ASCII(10) on IE, but CTRL-ENTER on Mozilla
3650                                                         c=0;
3651                                                         evt.keyCode = 13;
3652                                                 }else if(c==13||c==27){
3653                                                         c=0; // Mozilla considers ENTER and ESC non-printable
3654                                                 }else if(c==3){
3655                                                         c=99; // Mozilla maps CTRL-BREAK to CTRL-c
3656                                                 }
3657                                                 // Mozilla sets keyCode to 0 when there is a charCode
3658                                                 // but that stops the event on IE.
3659                                                 evt.charCode = c;
3660                                                 del._setKeyChar(evt);
3661                                                 break;
3662                                 }
3663                                 return evt;
3664                         },
3665                         // some ctrl-key combinations (mostly w/punctuation) do not emit a char code in IE
3666                         // we map those virtual key codes to ascii here
3667                         // not valid for all (non-US) keyboards, so maybe we shouldn't bother
3668                         _punctMap: { 
3669                                 106:42, 
3670                                 111:47, 
3671                                 186:59, 
3672                                 187:43, 
3673                                 188:44, 
3674                                 189:45, 
3675                                 190:46, 
3676                                 191:47, 
3677                                 192:96, 
3678                                 219:91, 
3679                                 220:92, 
3680                                 221:93, 
3681                                 222:39 
3682                         },
3683                         _stealthKeyDown: function(evt){
3684                                 // IE doesn't fire keypress for most non-printable characters.
3685                                 // other browsers do, we simulate it here.
3686                                 var kp = evt.currentTarget.onkeypress;
3687                                 // only works if kp exists and is a dispatcher
3688                                 if(!kp || !kp._listeners){ return; }
3689                                 // munge key/charCode
3690                                 var k=evt.keyCode;
3691                                 // These are Windows Virtual Key Codes
3692                                 // http://msdn.microsoft.com/library/default.asp?url=/library/en-us/winui/WinUI/WindowsUserInterface/UserInput/VirtualKeyCodes.asp
3693                                 var unprintable = (k!=13)&&(k!=32)&&(k!=27)&&(k<48||k>90)&&(k<96||k>111)&&(k<186||k>192)&&(k<219||k>222);
3694                                 // synthesize keypress for most unprintables and CTRL-keys
3695                                 if(unprintable||evt.ctrlKey){
3696                                         var c = unprintable ? 0 : k;
3697                                         if(evt.ctrlKey){
3698                                                 if(k==3 || k==13){
3699                                                         return; // IE will post CTRL-BREAK, CTRL-ENTER as keypress natively 
3700                                                 }else if(c>95 && c<106){ 
3701                                                         c -= 48; // map CTRL-[numpad 0-9] to ASCII
3702                                                 }else if((!evt.shiftKey)&&(c>=65&&c<=90)){ 
3703                                                         c += 32; // map CTRL-[A-Z] to lowercase
3704                                                 }else{ 
3705                                                         c = del._punctMap[c] || c; // map other problematic CTRL combinations to ASCII
3706                                                 }
3707                                         }
3708                                         // simulate a keypress event
3709                                         var faux = del._synthesizeEvent(evt, {type: 'keypress', faux: true, charCode: c});
3710                                         kp.call(evt.currentTarget, faux);
3711                                         evt.cancelBubble = faux.cancelBubble;
3712                                         evt.returnValue = faux.returnValue;
3713                                         _trySetKeyCode(evt, faux.keyCode);
3714                                 }
3715                         },
3716                         // Called in Event scope
3717                         _stopPropagation: function(){
3718                                 this.cancelBubble = true; 
3719                         },
3720                         _preventDefault: function(){
3721                                 // Setting keyCode to 0 is the only way to prevent certain keypresses (namely
3722                                 // ctrl-combinations that correspond to menu accelerator keys).
3723                                 // Otoh, it prevents upstream listeners from getting this information
3724                                 // Try to split the difference here by clobbering keyCode only for ctrl 
3725                                 // combinations. If you still need to access the key upstream, bubbledKeyCode is
3726                                 // provided as a workaround.
3727                                 this.bubbledKeyCode = this.keyCode;
3728                                 if(this.ctrlKey){_trySetKeyCode(this, 0);}
3729                                 this.returnValue = false;
3730                         }
3731                 });
3732                                 
3733                 // override stopEvent for IE
3734                 dojo.stopEvent = function(evt){
3735                         evt = evt || window.event;
3736                         del._stopPropagation.call(evt);
3737                         del._preventDefault.call(evt);
3738                 }
3739         }
3740
3741         del._synthesizeEvent = function(evt, props){
3742                         var faux = dojo.mixin({}, evt, props);
3743                         del._setKeyChar(faux);
3744                         // FIXME: would prefer to use dojo.hitch: dojo.hitch(evt, evt.preventDefault); 
3745                         // but it throws an error when preventDefault is invoked on Safari
3746                         // does Event.preventDefault not support "apply" on Safari?
3747                         faux.preventDefault = function(){ evt.preventDefault(); }; 
3748                         faux.stopPropagation = function(){ evt.stopPropagation(); }; 
3749                         return faux;
3750         }
3751         
3752         // Opera event normalization
3753         if(dojo.isOpera){
3754                 dojo.mixin(del, {
3755                         _fixEvent: function(evt, sender){
3756                                 switch(evt.type){
3757                                         case "keypress":
3758                                                 var c = evt.which;
3759                                                 if(c==3){
3760                                                         c=99; // Mozilla maps CTRL-BREAK to CTRL-c
3761                                                 }
3762                                                 // can't trap some keys at all, like INSERT and DELETE
3763                                                 // there is no differentiating info between DELETE and ".", or INSERT and "-"
3764                                                 c = ((c<41)&&(!evt.shiftKey) ? 0 : c);
3765                                                 if((evt.ctrlKey)&&(!evt.shiftKey)&&(c>=65)&&(c<=90)){
3766                                                         // lowercase CTRL-[A-Z] keys
3767                                                         c += 32;
3768                                                 }
3769                                                 return del._synthesizeEvent(evt, { charCode: c });
3770                                 }
3771                                 return evt;
3772                         }
3773                 });
3774         }
3775
3776         // Safari event normalization
3777         if(dojo.isSafari){
3778                 dojo.mixin(del, {
3779                         _fixEvent: function(evt, sender){
3780                                 switch(evt.type){
3781                                         case "keypress":
3782                                                 var c = evt.charCode, s = evt.shiftKey, k = evt.keyCode;
3783                                                 // FIXME: This is a hack, suggest we rethink keyboard strategy.
3784                                                 // Arrow and page keys have 0 "keyCode" in keypress events.on Safari for Windows
3785                                                 k = k || identifierMap[evt.keyIdentifier] || 0;
3786                                                 if(evt.keyIdentifier=="Enter"){
3787                                                         c = 0; // differentiate Enter from CTRL-m (both code 13)
3788                                                 }else if((evt.ctrlKey)&&(c>0)&&(c<27)){
3789                                                         c += 96; // map CTRL-[A-Z] codes to ASCII
3790                                                 } else if (c==dojo.keys.SHIFT_TAB) {
3791                                                         c = dojo.keys.TAB; // morph SHIFT_TAB into TAB + shiftKey: true
3792                                                         s = true;
3793                                                 } else {
3794                                                         c = (c>=32 && c<63232 ? c : 0); // avoid generating keyChar for non-printables
3795                                                 }
3796                                                 return del._synthesizeEvent(evt, {charCode: c, shiftKey: s, keyCode: k});
3797                                 }
3798                                 return evt;
3799                         }
3800                 });
3801                 
3802                 dojo.mixin(dojo.keys, {
3803                         SHIFT_TAB: 25,
3804                         UP_ARROW: 63232,
3805                         DOWN_ARROW: 63233,
3806                         LEFT_ARROW: 63234,
3807                         RIGHT_ARROW: 63235,
3808                         F1: 63236,
3809                         F2: 63237,
3810                         F3: 63238,
3811                         F4: 63239,
3812                         F5: 63240,
3813                         F6: 63241,
3814                         F7: 63242,
3815                         F8: 63243,
3816                         F9: 63244,
3817                         F10: 63245,
3818                         F11: 63246,
3819                         F12: 63247,
3820                         PAUSE: 63250,
3821                         DELETE: 63272,
3822                         HOME: 63273,
3823                         END: 63275,
3824                         PAGE_UP: 63276,
3825                         PAGE_DOWN: 63277,
3826                         INSERT: 63302,
3827                         PRINT_SCREEN: 63248,
3828                         SCROLL_LOCK: 63249,
3829                         NUM_LOCK: 63289
3830                 });
3831                 var dk = dojo.keys, identifierMap = { "Up": dk.UP_ARROW, "Down": dk.DOWN_ARROW, "Left": dk.LEFT_ARROW, "Right": dk.RIGHT_ARROW, "PageUp": dk.PAGE_UP, "PageDown": dk.PAGE_DOWN }; 
3832         }
3833 })();
3834
3835 if(dojo.isIE){
3836         // keep this out of the closure
3837         // closing over 'iel' or 'ieh' b0rks leak prevention
3838         // ls[i] is an index into the master handler array
3839         dojo._ieDispatcher = function(args, sender){
3840                 var ap=Array.prototype, h=dojo._ie_listener.handlers, c=args.callee, ls=c._listeners, t=h[c.target];
3841                 // return value comes from original target function
3842                 var r = t && t.apply(sender, args);
3843                 // invoke listeners after target function
3844                 for(var i in ls){
3845                         if(!(i in ap)){
3846                                 h[ls[i]].apply(sender, args);
3847                         }
3848                 }
3849                 return r;
3850         }
3851         dojo._getIeDispatcher = function(){
3852                 // ensure the returned function closes over nothing
3853                 return new Function(dojo._scopeName + "._ieDispatcher(arguments, this)"); // function
3854         }
3855         // keep this out of the closure to reduce RAM allocation
3856         dojo._event_listener._fixCallback = function(fp){
3857                 var f = dojo._event_listener._fixEvent;
3858                 return function(e){ return fp.call(this, f(e, this)); };
3859         }
3860 }
3861
3862 }
3863
3864 if(!dojo._hasResource["dojo._base.html"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
3865 dojo._hasResource["dojo._base.html"] = true;
3866
3867 dojo.provide("dojo._base.html");
3868
3869 // FIXME: need to add unit tests for all the semi-public methods
3870
3871 try{
3872         document.execCommand("BackgroundImageCache", false, true);
3873 }catch(e){
3874         // sane browsers don't have cache "issues"
3875 }
3876
3877 // =============================
3878 // DOM Functions
3879 // =============================
3880
3881 /*=====
3882 dojo.byId = function(id, doc){
3883         //      summary:
3884         //              Returns DOM node with matching `id` attribute or `null` 
3885         //              if not found, similar to "$" function in another library.
3886         //              If `id` is a DomNode, this function is a no-op.
3887         //
3888         //      id: String|DOMNode
3889         //              A string to match an HTML id attribute or a reference to a DOM Node
3890         //
3891         //      doc: Document?
3892         //              Document to work in. Defaults to the current value of
3893         //              dojo.doc.  Can be used to retrieve
3894         //              node references from other documents.
3895 =====*/
3896 if(dojo.isIE || dojo.isOpera){
3897         dojo.byId = function(id, doc){
3898                 if(dojo.isString(id)){
3899                         var _d = doc || dojo.doc;
3900                         var te = _d.getElementById(id);
3901                         // attributes.id.value is better than just id in case the 
3902                         // user has a name=id inside a form
3903                         if(te && te.attributes.id.value == id){
3904                                 return te;
3905                         }else{
3906                                 var eles = _d.all[id];
3907                                 if(!eles || !eles.length){ return eles; }
3908                                 // if more than 1, choose first with the correct id
3909                                 var i=0;
3910                                 while((te=eles[i++])){
3911                                         if(te.attributes.id.value == id){ return te; }
3912                                 }
3913                         }
3914                 }else{
3915                         return id; // DomNode
3916                 }
3917         }
3918 }else{
3919         dojo.byId = function(id, doc){
3920                 return dojo.isString(id) ? (doc || dojo.doc).getElementById(id) : id; // DomNode
3921         }
3922 }
3923 /*=====
3924 }
3925 =====*/
3926
3927 (function(){
3928         /*
3929         dojo.createElement = function(obj, parent, position){
3930                 // TODO: need to finish this!
3931         }
3932         */
3933
3934         var d = dojo;
3935
3936         var _destroyContainer = null;
3937         dojo.addOnUnload(function(){
3938                 _destroyContainer=null; //prevent IE leak
3939         });
3940         dojo._destroyElement = function(/*String||DomNode*/node){
3941                 // summary:
3942                 //              removes node from its parent, clobbers it and all of its
3943                 //              children.
3944                 //      node:
3945                 //              the element to be destroyed, either as an ID or a reference
3946
3947                 node = d.byId(node);
3948                 try{
3949                         if(!_destroyContainer){
3950                                 _destroyContainer = document.createElement("div");
3951                         }
3952                         _destroyContainer.appendChild(node.parentNode ? node.parentNode.removeChild(node) : node);
3953                         // NOTE: see http://trac.dojotoolkit.org/ticket/2931. This may be a bug and not a feature
3954                         _destroyContainer.innerHTML = ""; 
3955                 }catch(e){
3956                         /* squelch */
3957                 }
3958         };
3959
3960         dojo.isDescendant = function(/*DomNode|String*/node, /*DomNode|String*/ancestor){
3961                 //      summary:
3962                 //              Returns true if node is a descendant of ancestor
3963                 //      node: id or node reference to test
3964                 //      ancestor: id or node reference of potential parent to test against
3965                 try{
3966                         node = d.byId(node);
3967                         ancestor = d.byId(ancestor);
3968                         while(node){
3969                                 if(node === ancestor){
3970                                         return true; // Boolean
3971                                 }
3972                                 node = node.parentNode;
3973                         }
3974                 }catch(e){ /* squelch, return false */ }
3975                 return false; // Boolean
3976         };
3977
3978         dojo.setSelectable = function(/*DomNode|String*/node, /*Boolean*/selectable){
3979                 //      summary: enable or disable selection on a node
3980                 //      node:
3981                 //              id or reference to node
3982                 //      selectable:
3983                 node = d.byId(node);
3984                 if(d.isMozilla){
3985                         node.style.MozUserSelect = selectable ? "" : "none";
3986                 }else if(d.isKhtml){
3987                         node.style.KhtmlUserSelect = selectable ? "auto" : "none";
3988                 }else if(d.isIE){
3989                         node.unselectable = selectable ? "" : "on";
3990                         d.query("*", node).forEach(function(descendant){
3991                                 descendant.unselectable = selectable ? "" : "on";
3992                         });
3993                 }
3994                 //FIXME: else?  Opera?
3995         };
3996
3997         var _insertBefore = function(/*Node*/node, /*Node*/ref){
3998                 ref.parentNode.insertBefore(node, ref);
3999                 return true;    //      boolean
4000         }
4001
4002         var _insertAfter = function(/*Node*/node, /*Node*/ref){
4003                 //      summary:
4004                 //              Try to insert node after ref
4005                 var pn = ref.parentNode;
4006                 if(ref == pn.lastChild){
4007                         pn.appendChild(node);
4008                 }else{
4009                         return _insertBefore(node, ref.nextSibling);    //      boolean
4010                 }
4011                 return true;    //      boolean
4012         }
4013
4014         dojo.place = function(/*String|DomNode*/node, /*String|DomNode*/refNode, /*String|Number*/position){
4015                 //      summary:
4016                 //              Attempt to insert node into the DOM, choosing from various positioning options.
4017                 //              Returns true if successful, false otherwise.
4018                 //      node: 
4019                 //              id or node reference to place relative to refNode
4020                 //      refNode: 
4021                 //              id or node reference to use as basis for placement
4022                 //      position:
4023                 //              string noting the position of node relative to refNode or a
4024                 //              number indicating the location in the childNodes collection of
4025                 //              refNode. Accepted string values are:
4026                 //
4027                 //              * before
4028                 //              * after
4029                 //              * first
4030                 //              * last
4031                 //
4032                 //              "first" and "last" indicate positions as children of refNode.
4033
4034                 // FIXME: need to write tests for this!!!!
4035                 if(!node || !refNode || position === undefined){ 
4036                         return false;   //      boolean 
4037                 }
4038                 node = d.byId(node);
4039                 refNode = d.byId(refNode);
4040                 if(typeof position == "number"){
4041                         var cn = refNode.childNodes;
4042                         if((position == 0 && cn.length == 0) ||
4043                                 cn.length == position){
4044                                 refNode.appendChild(node); return true;
4045                         }
4046                         if(position == 0){
4047                                 return _insertBefore(node, refNode.firstChild);
4048                         }
4049                         return _insertAfter(node, cn[position-1]);
4050                 }
4051                 switch(position.toLowerCase()){
4052                         case "before":
4053                                 return _insertBefore(node, refNode);    //      boolean
4054                         case "after":
4055                                 return _insertAfter(node, refNode);             //      boolean
4056                         case "first":
4057                                 if(refNode.firstChild){
4058                                         return _insertBefore(node, refNode.firstChild); //      boolean
4059                                 }
4060                                 // else fallthrough...
4061                         default: // aka: last
4062                                 refNode.appendChild(node);
4063                                 return true;    //      boolean
4064                 }
4065         }
4066
4067         // Box functions will assume this model.
4068         // On IE/Opera, BORDER_BOX will be set if the primary document is in quirks mode.
4069         // Can be set to change behavior of box setters.
4070         
4071         // can be either:
4072         //      "border-box"
4073         //      "content-box" (default)
4074         dojo.boxModel = "content-box";
4075         
4076         // We punt per-node box mode testing completely.
4077         // If anybody cares, we can provide an additional (optional) unit 
4078         // that overrides existing code to include per-node box sensitivity.
4079
4080         // Opera documentation claims that Opera 9 uses border-box in BackCompat mode.
4081         // but experiments (Opera 9.10.8679 on Windows Vista) indicate that it actually continues to use content-box.
4082         // IIRC, earlier versions of Opera did in fact use border-box.
4083         // Opera guys, this is really confusing. Opera being broken in quirks mode is not our fault.
4084
4085         if(d.isIE /*|| dojo.isOpera*/){
4086                 var _dcm = document.compatMode;
4087                 // client code may have to adjust if compatMode varies across iframes
4088                 d.boxModel = _dcm == "BackCompat" || _dcm == "QuirksMode" || d.isIE<6 ? "border-box" : "content-box"; // FIXME: remove IE < 6 support?
4089         }
4090
4091         // =============================
4092         // Style Functions
4093         // =============================
4094         
4095         // getComputedStyle drives most of the style code.
4096         // Wherever possible, reuse the returned object.
4097         //
4098         // API functions below that need to access computed styles accept an 
4099         // optional computedStyle parameter.
4100         // If this parameter is omitted, the functions will call getComputedStyle themselves.
4101         // This way, calling code can access computedStyle once, and then pass the reference to 
4102         // multiple API functions. 
4103
4104 /*=====
4105         dojo.getComputedStyle = function(node){
4106                 //      summary:
4107                 //              Returns a "computed style" object.
4108                 //
4109                 //      description:
4110                 //              Gets a "computed style" object which can be used to gather
4111                 //              information about the current state of the rendered node. 
4112                 //
4113                 //              Note that this may behave differently on different browsers.
4114                 //              Values may have different formats and value encodings across
4115                 //              browsers.
4116                 //
4117                 //              Note also that this method is expensive.  Wherever possible,
4118                 //              reuse the returned object.
4119                 //
4120                 //              Use the dojo.style() method for more consistent (pixelized)
4121                 //              return values.
4122                 //
4123                 //      node: DOMNode
4124                 //              A reference to a DOM node. Does NOT support taking an
4125                 //              ID string for speed reasons.
4126                 //      example:
4127                 //      |       dojo.getComputedStyle(dojo.byId('foo')).borderWidth;
4128                 return; // CSS2Properties
4129         }
4130 =====*/
4131
4132         var gcs, dv = document.defaultView;
4133         if(d.isSafari){
4134                 gcs = function(/*DomNode*/node){
4135                         var s = dv.getComputedStyle(node, null);
4136                         if(!s && node.style){ 
4137                                 node.style.display = ""; 
4138                                 s = dv.getComputedStyle(node, null);
4139                         }
4140                         return s || {};
4141                 }; 
4142         }else if(d.isIE){
4143                 gcs = function(node){
4144                         return node.currentStyle;
4145                 };
4146         }else{
4147                 gcs = function(node){
4148                         return dv.getComputedStyle(node, null);
4149                 };
4150         }
4151         dojo.getComputedStyle = gcs;
4152
4153         if(!d.isIE){
4154                 dojo._toPixelValue = function(element, value){
4155                         // style values can be floats, client code may want
4156                         // to round for integer pixels.
4157                         return parseFloat(value) || 0; 
4158                 }
4159         }else{
4160                 dojo._toPixelValue = function(element, avalue){
4161                         if(!avalue){ return 0; }
4162                         // on IE7, medium is usually 4 pixels
4163                         if(avalue=="medium"){ return 4; }
4164                         // style values can be floats, client code may
4165                         // want to round this value for integer pixels.
4166                         if(avalue.slice && (avalue.slice(-2)=='px')){ return parseFloat(avalue); }
4167                         with(element){
4168                                 var sLeft = style.left;
4169                                 var rsLeft = runtimeStyle.left;
4170                                 runtimeStyle.left = currentStyle.left;
4171                                 try{
4172                                         // 'avalue' may be incompatible with style.left, which can cause IE to throw
4173                                         // this has been observed for border widths using "thin", "medium", "thick" constants
4174                                         // those particular constants could be trapped by a lookup
4175                                         // but perhaps there are more
4176                                         style.left = avalue;
4177                                         avalue = style.pixelLeft;
4178                                 }catch(e){
4179                                         avalue = 0;
4180                                 }
4181                                 style.left = sLeft;
4182                                 runtimeStyle.left = rsLeft;
4183                         }
4184                         return avalue;
4185                 }
4186         }
4187         var px = d._toPixelValue;
4188
4189         // FIXME: there opacity quirks on FF that we haven't ported over. Hrm.
4190         /*=====
4191         dojo._getOpacity = function(node){
4192                         //      summary:
4193                         //              Returns the current opacity of the passed node as a
4194                         //              floating-point value between 0 and 1.
4195                         //      node: DomNode
4196                         //              a reference to a DOM node. Does NOT support taking an
4197                         //              ID string for speed reasons.
4198                         //      return: Number between 0 and 1
4199         }
4200         =====*/
4201
4202         dojo._getOpacity = d.isIE ? function(node){
4203                 try{
4204                         return node.filters.alpha.opacity / 100; // Number
4205                 }catch(e){
4206                         return 1; // Number
4207                 }
4208         } : function(node){
4209                 return gcs(node).opacity;
4210         };
4211
4212         /*=====
4213         dojo._setOpacity = function(node, opacity){
4214                         //      summary:
4215                         //              set the opacity of the passed node portably. Returns the
4216                         //              new opacity of the node.
4217                         //      node: DOMNode
4218                         //              a reference to a DOM node. Does NOT support taking an
4219                         //              ID string for performance reasons.
4220                         //      opacity: Number
4221                         //              A Number between 0 and 1. 0 specifies transparent.
4222                         //      return: Number between 0 and 1
4223         }
4224         =====*/
4225
4226         dojo._setOpacity = d.isIE ? function(/*DomNode*/node, /*Number*/opacity){
4227                 if(opacity == 1){
4228                         // on IE7 Alpha(Filter opacity=100) makes text look fuzzy so remove it altogether (bug #2661)
4229                         var filterRE = /FILTER:[^;]*;?/i;
4230                         node.style.cssText = node.style.cssText.replace(filterRE, "");
4231                         if(node.nodeName.toLowerCase() == "tr"){
4232                                 d.query("> td", node).forEach(function(i){
4233                                         i.style.cssText = i.style.cssText.replace(filterRE, "");
4234                                 });
4235                         }
4236                 }else{
4237                         var o = "Alpha(Opacity="+ opacity * 100 +")";
4238                         node.style.filter = o;
4239                 }
4240                 if(node.nodeName.toLowerCase() == "tr"){
4241                         d.query("> td", node).forEach(function(i){
4242                                 i.style.filter = o;
4243                         });
4244                 }
4245                 return opacity;
4246         } : function(node, opacity){
4247                 return node.style.opacity = opacity;
4248         };
4249
4250         var _pixelNamesCache = {
4251                 left: true, top: true
4252         };
4253         var _pixelRegExp = /margin|padding|width|height|max|min|offset/;  // |border
4254         var _toStyleValue = function(node, type, value){
4255                 type = type.toLowerCase();
4256                 if(d.isIE && value == "auto"){
4257                         if(type == "height"){ return node.offsetHeight; }
4258                         if(type == "width"){ return node.offsetWidth; }
4259                 }
4260                 if(!(type in _pixelNamesCache)){
4261                         //      if(dojo.isOpera && type == "cssText"){
4262                         //              FIXME: add workaround for #2855 here
4263                         //      }
4264                         _pixelNamesCache[type] = _pixelRegExp.test(type);
4265                 }
4266                 return _pixelNamesCache[type] ? px(node, value) : value;
4267         }
4268
4269         var _floatStyle = d.isIE ? "styleFloat" : "cssFloat";
4270         var _floatAliases = { "cssFloat": _floatStyle, "styleFloat": _floatStyle, "float": _floatStyle };
4271         
4272         // public API
4273         
4274         dojo.style = function(  /*DomNode|String*/ node, 
4275                                                         /*String?|Object?*/ style, 
4276                                                         /*String?*/ value){
4277                 //      summary:
4278                 //              Accesses styles on a node. If 2 arguments are
4279                 //              passed, acts as a getter. If 3 arguments are passed, acts
4280                 //              as a setter.
4281                 //      node:
4282                 //              id or reference to node to get/set style for
4283                 //      style:
4284                 //              the style property to set in DOM-accessor format
4285                 //              ("borderWidth", not "border-width") or an object with key/value
4286                 //              pairs suitable for setting each property.
4287                 //      value:
4288                 //              If passed, sets value on the node for style, handling
4289                 //              cross-browser concerns.
4290                 //      example:
4291                 //              Passing only an ID or node returns the computed style object of
4292                 //              the node:
4293                 //      |       dojo.style("thinger");
4294                 //      example:
4295                 //              Passing a node and a style property returns the current
4296                 //              normalized, computed value for that property:
4297                 //      |       dojo.style("thinger", "opacity"); // 1 by default
4298                 //
4299                 //      example:
4300                 //              Passing a node, a style property, and a value changes the
4301                 //              current display of the node and returns the new computed value
4302                 //      |       dojo.style("thinger", "opacity", 0.5); // == 0.5
4303                 //
4304                 //      example:
4305                 //              Passing a node, an object-style style property sets each of the values in turn and returns the computed style object of the node:
4306                 //      |       dojo.style("thinger", {
4307                 //      |               "opacity": 0.5,
4308                 //      |               "border": "3px solid black",
4309                 //      |               "height": 300
4310                 //      |       });
4311                 //
4312                 //      example:
4313                 //              When the CSS style property is hyphenated, the JavaScript property is camelCased.
4314                 //              font-size becomes fontSize, and so on.
4315                 //      |       dojo.style("thinger",{
4316                 //      |               fontSize:"14pt",
4317                 //      |               letterSpacing:"1.2em"
4318                 //      |       });
4319                 //
4320                 //      example:
4321                 //              dojo.NodeList implements .style() using the same syntax, omitting the "node" parameter, calling
4322                 //              dojo.style() on every element of the list. See: dojo.query and dojo.NodeList
4323                 //      |       dojo.query(".someClassName").style("visibility","hidden");
4324                 //      |       // or
4325                 //      |       dojo.query("#baz > div").style({
4326                 //      |               opacity:0.75,
4327                 //      |               fontSize:"13pt"
4328                 //      |       });
4329
4330                 var n = d.byId(node), args = arguments.length, op = (style=="opacity");
4331                 style = _floatAliases[style] || style;
4332                 if(args == 3){
4333                         return op ? d._setOpacity(n, value) : n.style[style] = value; /*Number*/
4334                 }
4335                 if(args == 2 && op){
4336                         return d._getOpacity(n);
4337                 }
4338                 var s = gcs(n);
4339                 if(args == 2 && !d.isString(style)){
4340                         for(var x in style){
4341                                 d.style(node, x, style[x]);
4342                         }
4343                         return s;
4344                 }
4345                 return (args == 1) ? s : _toStyleValue(n, style, s[style]); /* CSS2Properties||String||Number */
4346         }
4347
4348         // =============================
4349         // Box Functions
4350         // =============================
4351
4352         dojo._getPadExtents = function(/*DomNode*/n, /*Object*/computedStyle){
4353                 //      summary:
4354                 //              Returns object with special values specifically useful for node
4355                 //              fitting.
4356                 //
4357                 //              * l/t = left/top padding (respectively)
4358                 //              * w = the total of the left and right padding 
4359                 //              * h = the total of the top and bottom padding
4360                 //
4361                 //              If 'node' has position, l/t forms the origin for child nodes. 
4362                 //              The w/h are used for calculating boxes.
4363                 //              Normally application code will not need to invoke this
4364                 //              directly, and will use the ...box... functions instead.
4365                 var 
4366                         s = computedStyle||gcs(n), 
4367                         l = px(n, s.paddingLeft), 
4368                         t = px(n, s.paddingTop);
4369                 return { 
4370                         l: l,
4371                         t: t,
4372                         w: l+px(n, s.paddingRight),
4373                         h: t+px(n, s.paddingBottom)
4374                 };
4375         }
4376
4377         dojo._getBorderExtents = function(/*DomNode*/n, /*Object*/computedStyle){
4378                 //      summary:
4379                 //              returns an object with properties useful for noting the border
4380                 //              dimensions.
4381                 //
4382                 //              * l/t = the sum of left/top border (respectively)
4383                 //              * w = the sum of the left and right border
4384                 //              * h = the sum of the top and bottom border
4385                 //
4386                 //              The w/h are used for calculating boxes.
4387                 //              Normally application code will not need to invoke this
4388                 //              directly, and will use the ...box... functions instead.
4389                 var 
4390                         ne = "none",
4391                         s = computedStyle||gcs(n), 
4392                         bl = (s.borderLeftStyle != ne ? px(n, s.borderLeftWidth) : 0),
4393                         bt = (s.borderTopStyle != ne ? px(n, s.borderTopWidth) : 0);
4394                 return { 
4395                         l: bl,
4396                         t: bt,
4397                         w: bl + (s.borderRightStyle!=ne ? px(n, s.borderRightWidth) : 0),
4398                         h: bt + (s.borderBottomStyle!=ne ? px(n, s.borderBottomWidth) : 0)
4399                 };
4400         }
4401
4402         dojo._getPadBorderExtents = function(/*DomNode*/n, /*Object*/computedStyle){
4403                 //      summary:
4404                 //              returns object with properties useful for box fitting with
4405                 //              regards to padding.
4406                 //
4407                 //              * l/t = the sum of left/top padding and left/top border (respectively)
4408                 //              * w = the sum of the left and right padding and border
4409                 //              * h = the sum of the top and bottom padding and border
4410                 //
4411                 //              The w/h are used for calculating boxes.
4412                 //              Normally application code will not need to invoke this
4413                 //              directly, and will use the ...box... functions instead.
4414                 var 
4415                         s = computedStyle||gcs(n), 
4416                         p = d._getPadExtents(n, s),
4417                         b = d._getBorderExtents(n, s);
4418                 return { 
4419                         l: p.l + b.l,
4420                         t: p.t + b.t,
4421                         w: p.w + b.w,
4422                         h: p.h + b.h
4423                 };
4424         }
4425
4426         dojo._getMarginExtents = function(n, computedStyle){
4427                 //      summary:
4428                 //              returns object with properties useful for box fitting with
4429                 //              regards to box margins (i.e., the outer-box).
4430                 //
4431                 //              * l/t = marginLeft, marginTop, respectively
4432                 //              * w = total width, margin inclusive
4433                 //              * h = total height, margin inclusive
4434                 //
4435                 //              The w/h are used for calculating boxes.
4436                 //              Normally application code will not need to invoke this
4437                 //              directly, and will use the ...box... functions instead.
4438                 var 
4439                         s = computedStyle||gcs(n), 
4440                         l = px(n, s.marginLeft),
4441                         t = px(n, s.marginTop),
4442                         r = px(n, s.marginRight),
4443                         b = px(n, s.marginBottom);
4444                 if(d.isSafari && (s.position != "absolute")){
4445                         // FIXME: Safari's version of the computed right margin
4446                         // is the space between our right edge and the right edge 
4447                         // of our offsetParent. 
4448                         // What we are looking for is the actual margin value as 
4449                         // determined by CSS.
4450                         // Hack solution is to assume left/right margins are the same.
4451                         r = l;
4452                 }
4453                 return { 
4454                         l: l,
4455                         t: t,
4456                         w: l+r,
4457                         h: t+b
4458                 };
4459         }
4460
4461         // Box getters work in any box context because offsetWidth/clientWidth
4462         // are invariant wrt box context
4463         //
4464         // They do *not* work for display: inline objects that have padding styles
4465         // because the user agent ignores padding (it's bogus styling in any case)
4466         //
4467         // Be careful with IMGs because they are inline or block depending on 
4468         // browser and browser mode.
4469
4470         // Although it would be easier to read, there are not separate versions of 
4471         // _getMarginBox for each browser because:
4472         // 1. the branching is not expensive
4473         // 2. factoring the shared code wastes cycles (function call overhead)
4474         // 3. duplicating the shared code wastes bytes
4475         
4476         dojo._getMarginBox = function(/*DomNode*/node, /*Object*/computedStyle){
4477                 // summary:
4478                 //              returns an object that encodes the width, height, left and top
4479                 //              positions of the node's margin box.
4480                 var s = computedStyle||gcs(node), me = d._getMarginExtents(node, s);
4481                 var     l = node.offsetLeft - me.l,     t = node.offsetTop - me.t;
4482                 if(d.isMoz){
4483                         // Mozilla:
4484                         // If offsetParent has a computed overflow != visible, the offsetLeft is decreased
4485                         // by the parent's border.
4486                         // We don't want to compute the parent's style, so instead we examine node's
4487                         // computed left/top which is more stable.
4488                         var sl = parseFloat(s.left), st = parseFloat(s.top);
4489                         if(!isNaN(sl) && !isNaN(st)){
4490                                 l = sl, t = st;
4491                         }else{
4492                                 // If child's computed left/top are not parseable as a number (e.g. "auto"), we
4493                                 // have no choice but to examine the parent's computed style.
4494                                 var p = node.parentNode;
4495                                 if(p && p.style){
4496                                         var pcs = gcs(p);
4497                                         if(pcs.overflow != "visible"){
4498                                                 var be = d._getBorderExtents(p, pcs);
4499                                                 l += be.l, t += be.t;
4500                                         }
4501                                 }
4502                         }
4503                 }else if(d.isOpera){
4504                         // On Opera, offsetLeft includes the parent's border
4505                         var p = node.parentNode;
4506                         if(p){
4507                                 var be = d._getBorderExtents(p);
4508                                 l -= be.l, t -= be.t;
4509                         }
4510                 }
4511                 return { 
4512                         l: l, 
4513                         t: t, 
4514                         w: node.offsetWidth + me.w, 
4515                         h: node.offsetHeight + me.h 
4516                 };
4517         }
4518         
4519         dojo._getContentBox = function(node, computedStyle){
4520                 // summary:
4521                 //              Returns an object that encodes the width, height, left and top
4522                 //              positions of the node's content box, irrespective of the
4523                 //              current box model.
4524
4525                 // clientWidth/Height are important since the automatically account for scrollbars
4526                 // fallback to offsetWidth/Height for special cases (see #3378)
4527                 var s=computedStyle||gcs(node), pe=d._getPadExtents(node, s), be=d._getBorderExtents(node, s), w=node.clientWidth, h;
4528                 if(!w){
4529                         w=node.offsetWidth, h=node.offsetHeight;
4530                 }else{
4531                         h=node.clientHeight, be.w = be.h = 0; 
4532                 }
4533                 // On Opera, offsetLeft includes the parent's border
4534                 if(d.isOpera){ pe.l += be.l; pe.t += be.t; };
4535                 return { 
4536                         l: pe.l, 
4537                         t: pe.t, 
4538                         w: w - pe.w - be.w, 
4539                         h: h - pe.h - be.h
4540                 };
4541         }
4542
4543         dojo._getBorderBox = function(node, computedStyle){
4544                 var s=computedStyle||gcs(node), pe=d._getPadExtents(node, s), cb=d._getContentBox(node, s);
4545                 return { 
4546                         l: cb.l - pe.l, 
4547                         t: cb.t - pe.t, 
4548                         w: cb.w + pe.w, 
4549                         h: cb.h + pe.h
4550                 };
4551         }
4552
4553         // Box setters depend on box context because interpretation of width/height styles
4554         // vary wrt box context.
4555         //
4556         // The value of dojo.boxModel is used to determine box context.
4557         // dojo.boxModel can be set directly to change behavior.
4558         //
4559         // Beware of display: inline objects that have padding styles
4560         // because the user agent ignores padding (it's a bogus setup anyway)
4561         //
4562         // Be careful with IMGs because they are inline or block depending on 
4563         // browser and browser mode.
4564         // 
4565         // Elements other than DIV may have special quirks, like built-in
4566         // margins or padding, or values not detectable via computedStyle.
4567         // In particular, margins on TABLE do not seems to appear 
4568         // at all in computedStyle on Mozilla.
4569         
4570         dojo._setBox = function(/*DomNode*/node, /*Number?*/l, /*Number?*/t, /*Number?*/w, /*Number?*/h, /*String?*/u){
4571                 //      summary:
4572                 //              sets width/height/left/top in the current (native) box-model
4573                 //              dimentions. Uses the unit passed in u.
4574                 //      node: DOM Node reference. Id string not supported for performance reasons.
4575                 //      l: optional. left offset from parent.
4576                 //      t: optional. top offset from parent.
4577                 //      w: optional. width in current box model.
4578                 //      h: optional. width in current box model.
4579                 //      u: optional. unit measure to use for other measures. Defaults to "px".
4580                 u = u || "px";
4581                 var s = node.style;
4582                 if(!isNaN(l)){ s.left = l+u; }
4583                 if(!isNaN(t)){ s.top = t+u; }
4584                 if(w>=0){ s.width = w+u; }
4585                 if(h>=0){ s.height = h+u; }
4586         }
4587
4588         dojo._usesBorderBox = function(/*DomNode*/node){
4589                 //      summary: 
4590                 //              True if the node uses border-box layout.
4591
4592                 // We could test the computed style of node to see if a particular box
4593                 // has been specified, but there are details and we choose not to bother.
4594                 var n = node.tagName;
4595                 // For whatever reason, TABLE and BUTTON are always border-box by default.
4596                 // If you have assigned a different box to either one via CSS then
4597                 // box functions will break.
4598                 return d.boxModel=="border-box" || n=="TABLE" || n=="BUTTON"; // boolean
4599         }
4600
4601         dojo._setContentSize = function(/*DomNode*/node, /*Number*/widthPx, /*Number*/heightPx, /*Object*/computedStyle){
4602                 //      summary:
4603                 //              Sets the size of the node's contents, irrespective of margins,
4604                 //              padding, or borders.
4605                 if(d._usesBorderBox(node)){
4606                         var pb = d._getPadBorderExtents(node, computedStyle);
4607                         if(widthPx >= 0){ widthPx += pb.w; }
4608                         if(heightPx >= 0){ heightPx += pb.h; }
4609                 }
4610                 d._setBox(node, NaN, NaN, widthPx, heightPx);
4611         }
4612
4613         dojo._setMarginBox = function(/*DomNode*/node,  /*Number?*/leftPx, /*Number?*/topPx, 
4614                                                                                                         /*Number?*/widthPx, /*Number?*/heightPx, 
4615                                                                                                         /*Object*/computedStyle){
4616                 //      summary:
4617                 //              sets the size of the node's margin box and placement
4618                 //              (left/top), irrespective of box model. Think of it as a
4619                 //              passthrough to dojo._setBox that handles box-model vagaries for
4620                 //              you.
4621
4622                 var s = computedStyle||gcs(node);
4623                 // Some elements have special padding, margin, and box-model settings. 
4624                 // To use box functions you may need to set padding, margin explicitly.
4625                 // Controlling box-model is harder, in a pinch you might set dojo.boxModel.
4626                 var bb=d._usesBorderBox(node),
4627                                 pb=bb ? _nilExtents : d._getPadBorderExtents(node, s),
4628                                 mb=d._getMarginExtents(node, s);
4629                 if(widthPx>=0){ widthPx = Math.max(widthPx - pb.w - mb.w, 0); }
4630                 if(heightPx>=0){ heightPx = Math.max(heightPx - pb.h - mb.h, 0); }
4631                 d._setBox(node, leftPx, topPx, widthPx, heightPx);
4632         }
4633         
4634         var _nilExtents = { l:0, t:0, w:0, h:0 };
4635
4636         // public API
4637         
4638         dojo.marginBox = function(/*DomNode|String*/node, /*Object?*/box){
4639                 //      summary:
4640                 //              Getter/setter for the margin-box of node.
4641                 //      description: 
4642                 //              Returns an object in the expected format of box (regardless
4643                 //              if box is passed). The object might look like:
4644                 //                      `{ l: 50, t: 200, w: 300: h: 150 }`
4645                 //              for a node offset from its parent 50px to the left, 200px from
4646                 //              the top with a margin width of 300px and a margin-height of
4647                 //              150px.
4648                 //      node:
4649                 //              id or reference to DOM Node to get/set box for
4650                 //      box:
4651                 //              If passed, denotes that dojo.marginBox() should
4652                 //              update/set the margin box for node. Box is an object in the
4653                 //              above format. All properties are optional if passed.
4654                 var n=d.byId(node), s=gcs(n), b=box;
4655                 return !b ? d._getMarginBox(n, s) : d._setMarginBox(n, b.l, b.t, b.w, b.h, s); // Object
4656         }
4657
4658         dojo.contentBox = function(/*DomNode|String*/node, /*Object?*/box){
4659                 //      summary:
4660                 //              Getter/setter for the content-box of node.
4661                 //      description:
4662                 //              Returns an object in the expected format of box (regardless if box is passed).
4663                 //              The object might look like:
4664                 //                      `{ l: 50, t: 200, w: 300: h: 150 }`
4665                 //              for a node offset from its parent 50px to the left, 200px from
4666                 //              the top with a content width of 300px and a content-height of
4667                 //              150px. Note that the content box may have a much larger border
4668                 //              or margin box, depending on the box model currently in use and
4669                 //              CSS values set/inherited for node.
4670                 //      node:
4671                 //              id or reference to DOM Node to get/set box for
4672                 //      box:
4673                 //              If passed, denotes that dojo.contentBox() should
4674                 //              update/set the content box for node. Box is an object in the
4675                 //              above format. All properties are optional if passed.
4676                 var n=dojo.byId(node), s=gcs(n), b=box;
4677                 return !b ? d._getContentBox(n, s) : d._setContentSize(n, b.w, b.h, s); // Object
4678         }
4679         
4680         // =============================
4681         // Positioning 
4682         // =============================
4683         
4684         var _sumAncestorProperties = function(node, prop){
4685                 if(!(node = (node||0).parentNode)){return 0};
4686                 var val, retVal = 0, _b = d.body();
4687                 while(node && node.style){
4688                         if(gcs(node).position == "fixed"){
4689                                 return 0;
4690                         }
4691                         val = node[prop];
4692                         if(val){
4693                                 retVal += val - 0;
4694                                 // opera and khtml #body & #html has the same values, we only
4695                                 // need one value
4696                                 if(node == _b){ break; }
4697                         }
4698                         node = node.parentNode;
4699                 }
4700                 return retVal;  //      integer
4701         }
4702
4703         dojo._docScroll = function(){
4704                 var 
4705                         _b = d.body(),
4706                         _w = d.global,
4707                         de = d.doc.documentElement;
4708                 return {
4709                         y: (_w.pageYOffset || de.scrollTop || _b.scrollTop || 0),
4710                         x: (_w.pageXOffset || d._fixIeBiDiScrollLeft(de.scrollLeft) || _b.scrollLeft || 0)
4711                 };
4712         };
4713         
4714         dojo._isBodyLtr = function(){
4715                 //FIXME: could check html and body tags directly instead of computed style?  need to ignore case, accept empty values
4716                 return !("_bodyLtr" in d) ? 
4717                         d._bodyLtr = gcs(d.body()).direction == "ltr" :
4718                         d._bodyLtr; // Boolean 
4719         }
4720         
4721         dojo._getIeDocumentElementOffset = function(){
4722                 // summary
4723                 // The following values in IE contain an offset:
4724                 //     event.clientX 
4725                 //     event.clientY 
4726                 //     node.getBoundingClientRect().left
4727                 //     node.getBoundingClientRect().top
4728                 // But other position related values do not contain this offset, such as
4729                 // node.offsetLeft, node.offsetTop, node.style.left and node.style.top.
4730                 // The offset is always (2, 2) in LTR direction. When the body is in RTL
4731                 // direction, the offset counts the width of left scroll bar's width.
4732                 // This function computes the actual offset.
4733
4734                 //NOTE: assumes we're being called in an IE browser
4735
4736                 var de = d.doc.documentElement;
4737                 //FIXME: use this instead?                      var de = d.compatMode == "BackCompat" ? d.body : d.documentElement;
4738
4739                 return (d.isIE >= 7) ?
4740                         {x: de.getBoundingClientRect().left, y: de.getBoundingClientRect().top}
4741                 :
4742                         // IE 6.0
4743                         {x: d._isBodyLtr() || window.parent == window ?
4744                                 de.clientLeft : de.offsetWidth - de.clientWidth - de.clientLeft, 
4745                                 y: de.clientTop}; // Object
4746         };
4747         
4748         dojo._fixIeBiDiScrollLeft = function(/*Integer*/ scrollLeft){
4749                 // In RTL direction, scrollLeft should be a negative value, but IE 
4750                 // returns a positive one. All codes using documentElement.scrollLeft
4751                 // must call this function to fix this error, otherwise the position
4752                 // will offset to right when there is a horizontal scrollbar.
4753                 var dd = d.doc;
4754                 if(d.isIE && !dojo._isBodyLtr()){
4755                         var de = dd.compatMode == "BackCompat" ? dd.body : dd.documentElement;
4756                         return scrollLeft + de.clientWidth - de.scrollWidth; // Integer
4757                 }
4758                 return scrollLeft; // Integer
4759         }
4760
4761         dojo._abs = function(/*DomNode*/node, /*Boolean?*/includeScroll){
4762                 //      summary:
4763                 //              Gets the position of the passed element relative to
4764                 //              the viewport (if includeScroll==false), or relative to the
4765                 //              document root (if includeScroll==true).
4766                 //
4767                 //              Returns an object of the form:
4768                 //                      { x: 100, y: 300 }
4769                 //              if includeScroll is passed, the x and y values will include any
4770                 //              document offsets that may affect the position relative to the
4771                 //              viewport.
4772
4773                 // FIXME: need to decide in the brave-new-world if we're going to be
4774                 // margin-box or border-box.
4775                 var ownerDocument = node.ownerDocument;
4776                 var ret = {
4777                         x: 0,
4778                         y: 0
4779                 };
4780
4781                 // targetBoxType == "border-box"
4782                 var db = d.body();
4783                 if(d.isIE || (d.isFF >= 3)){
4784                         var client = node.getBoundingClientRect();
4785                         var offset = (d.isIE) ? d._getIeDocumentElementOffset() : { x: 0, y: 0};
4786                         ret.x = client.left - offset.x;
4787                         ret.y = client.top - offset.y;
4788                 }else if(ownerDocument["getBoxObjectFor"]){
4789                         // mozilla
4790                         var bo = ownerDocument.getBoxObjectFor(node),
4791                                 b = d._getBorderExtents(node);
4792                         ret.x = bo.x - b.l - _sumAncestorProperties(node, "scrollLeft");
4793                         ret.y = bo.y - b.t - _sumAncestorProperties(node, "scrollTop");
4794                 }else{
4795                         if(node["offsetParent"]){
4796                                 var endNode;
4797                                 // in Safari, if the node is an absolutely positioned child of
4798                                 // the body and the body has a margin the offset of the child
4799                                 // and the body contain the body's margins, so we need to end
4800                                 // at the body
4801                                 // FIXME: getting contrary results to the above in latest WebKit.
4802                                 if(d.isSafari &&
4803                                         //(node.style.getPropertyValue("position") == "absolute") &&
4804                                         (gcs(node).position == "absolute") &&
4805                                         (node.parentNode == db)){
4806                                         endNode = db;
4807                                 }else{
4808                                         endNode = db.parentNode;
4809                                 }
4810                                 if(node.parentNode != db){
4811                                         var nd = node;
4812                                         if(d.isOpera){ nd = db; }
4813                                         ret.x -= _sumAncestorProperties(nd, "scrollLeft");
4814                                         ret.y -= _sumAncestorProperties(nd, "scrollTop");
4815                                 }
4816                                 var curnode = node;
4817                                 do{
4818                                         var n = curnode.offsetLeft;
4819                                         //FIXME: ugly hack to workaround the submenu in 
4820                                         //popupmenu2 does not shown up correctly in opera. 
4821                                         //Someone have a better workaround?
4822                                         if(!d.isOpera || n > 0){
4823                                                 ret.x += isNaN(n) ? 0 : n;
4824                                         }
4825                                         var t = curnode.offsetTop;
4826                                         ret.y += isNaN(t) ? 0 : t;
4827                                         if(d.isSafari && curnode != node){
4828                                                 var cs = gcs(curnode);
4829                                                 ret.x += px(curnode, cs.borderLeftWidth);
4830                                                 ret.y += px(curnode, cs.borderTopWidth);
4831                                         }
4832                                         curnode = curnode.offsetParent;
4833                                 }while((curnode != endNode) && curnode);
4834                         }else if(node.x && node.y){
4835                                 ret.x += isNaN(node.x) ? 0 : node.x;
4836                                 ret.y += isNaN(node.y) ? 0 : node.y;
4837                         }
4838                 }
4839                 // account for document scrolling
4840                 // if offsetParent is used, ret value already includes scroll position
4841                 // so we may have to actually remove that value if !includeScroll
4842                 if(includeScroll){
4843                         var scroll = d._docScroll();
4844                         ret.y += scroll.y;
4845                         ret.x += scroll.x;
4846                 }
4847
4848                 return ret; // object
4849         }
4850
4851         // FIXME: need a setter for coords or a moveTo!!
4852         dojo.coords = function(/*DomNode|String*/node, /*Boolean?*/includeScroll){
4853                 //      summary:
4854                 //              Returns an object that measures margin box width/height and
4855                 //              absolute positioning data from dojo._abs().
4856                 //
4857                 //      description:
4858                 //              Returns an object that measures margin box width/height and
4859                 //              absolute positioning data from dojo._abs().
4860                 //              Return value will be in the form:
4861                 //                      `{ l: 50, t: 200, w: 300: h: 150, x: 100, y: 300 }`
4862                 //              Does not act as a setter. If includeScroll is passed, the x and
4863                 //              y params are affected as one would expect in dojo._abs().
4864                 var n=d.byId(node), s=gcs(n), mb=d._getMarginBox(n, s);
4865                 var abs = d._abs(n, includeScroll);
4866                 mb.x = abs.x;
4867                 mb.y = abs.y;
4868                 return mb;
4869         }
4870
4871         // =============================
4872         // Element attribute Functions
4873         // =============================
4874
4875         var _fixAttrName = function(/*String*/name){
4876                 switch(name.toLowerCase()){
4877                         case "tabindex":
4878                                 // Internet Explorer will only set or remove tabindex
4879                                 // if it is spelled "tabIndex"
4880                                 // console.debug((dojo.isIE && dojo.isIE < 8)? "tabIndex" : "tabindex");
4881                                 return (d.isIE && d.isIE < 8) ? "tabIndex" : "tabindex";
4882                         default:
4883                                 return name;
4884                 }
4885         }
4886
4887         // non-deprecated HTML4 attributes with default values
4888         // http://www.w3.org/TR/html401/index/attributes.html
4889         // FF and Safari will return the default values if you
4890         // access the attributes via a property but not
4891         // via getAttribute()
4892         var _attrProps = {
4893                 colspan: "colSpan",
4894                 enctype: "enctype",
4895                 frameborder: "frameborder",
4896                 method: "method",
4897                 rowspan: "rowSpan",
4898                 scrolling: "scrolling",
4899                 shape: "shape",
4900                 span: "span",
4901                 type: "type",
4902                 valuetype: "valueType"
4903         }
4904
4905         dojo.hasAttr = function(/*DomNode|String*/node, /*String*/name){
4906                 //      summary:
4907                 //              Returns true if the requested attribute is specified on the
4908                 //              given element, and false otherwise.
4909                 //      node:
4910                 //              id or reference to the element to check
4911                 //      name:
4912                 //              the name of the attribute
4913                 //      returns:
4914                 //              true if the requested attribute is specified on the
4915                 //              given element, and false otherwise
4916                 var attr = d.byId(node).getAttributeNode(_fixAttrName(name));
4917                 return attr ? attr.specified : false; // Boolean
4918         }
4919
4920         var _evtHdlrMap = {
4921                 
4922         }
4923
4924         var _ctr = 0;
4925         var _attrId = dojo._scopeName + "attrid";
4926
4927         dojo.attr = function(/*DomNode|String*/node, /*String|Object*/name, /*String?*/value){
4928                 //      summary:
4929                 //              Gets or sets an attribute on an HTML element.
4930                 //      description:
4931                 //              Handles normalized getting and setting of attributes on DOM
4932                 //              Nodes. If 2 arguments are passed, and a the second argumnt is a
4933                 //              string, acts as a getter.
4934                 //      
4935                 //              If a third argument is passed, or if the second argumnt is a
4936                 //              map of attributes, acts as a setter.
4937                 //
4938                 //              When passing functions as values, note that they will not be
4939                 //              directly assigned to slots on the node, but rather the default
4940                 //              behavior will be removed and the new behavior will be added
4941                 //              using `dojo.connect()`, meaning that event handler properties
4942                 //              will be normalized and that some caveats with regards to
4943                 //              non-standard behaviors for onsubmit apply. Namely that you
4944                 //              should cancel form submission using `dojo.stopEvent()` on the
4945                 //              passed event object instead of returning a boolean value from
4946                 //              the handler itself.
4947                 //      node:
4948                 //              id or reference to the element to get or set the attribute on
4949                 //      name:
4950                 //              the name of the attribute to get or set.
4951                 //      value:
4952                 //              The value to set for the attribute
4953                 //      returns:
4954                 //              when used as a getter, the value of the requested attribute
4955                 //              or null if that attribute does not have a specified or
4956                 //              default value;
4957                 //
4958                 //              when user as a setter, undefined
4959                 //      example:
4960                 //      |       // get the current value of the "foo" attribute on a node
4961                 //      |       dojo.attr(dojo.byId("nodeId"), "foo");
4962                 //      |       
4963                 //      |       // we can just pass the id:
4964                 //      |       dojo.attr("nodeId", "foo");
4965                 //      |
4966                 //      |       // use attr() to set the tab index
4967                 //      |       dojo.attr("nodeId", "tabindex", 3);
4968                 //      |
4969                 //      |       // set multiple values at once, including event handlers:
4970                 //      |       dojo.attr("formId", {
4971                 //      |               "foo": "bar",
4972                 //      |               "tabindex": -1,
4973                 //      |               "method": "POST",
4974                 //      |               "onsubmit": function(e){
4975                 //      |                       // stop submitting the form. Note that the IE behavior
4976                 //      |                       // of returning true or false will have no effect here
4977                 //      |                       // since our handler is connect()ed to the built-in
4978                 //      |                       // onsubmit behavior and so we need to use
4979                 //      |                       // dojo.stopEvent() to ensure that the submission
4980                 //      |                       // doesn't proceed.
4981                 //      |                       dojo.stopEvent(e);
4982                 //      |
4983                 //      |                       // submit the form with Ajax
4984                 //      |                       dojo.xhrPost({ form: "formId" });
4985                 //      |               }
4986                 //      |       });
4987
4988                 var args = arguments.length;
4989                 if(args == 2 && !d.isString(name)){
4990                         for(var x in name){ d.attr(node, x, name[x]); }
4991                         return;
4992                 }
4993                 node = d.byId(node);
4994                 name = _fixAttrName(name);
4995                 if(args == 3){
4996                         if(d.isFunction(value)){
4997                                 // clobber if we can
4998                                 var attrId = d.attr(node, _attrId);
4999                                 if(!attrId){
5000                                         attrId = _ctr++;
5001                                         d.attr(node, _attrId, attrId);
5002                                 }
5003                                 if(!_evtHdlrMap[attrId]){
5004                                         _evtHdlrMap[attrId] = {};
5005                                 }
5006                                 var h = _evtHdlrMap[attrId][name];
5007                                 if(h){
5008                                         d.disconnect(h);
5009                                 }else{
5010                                         try{
5011                                                 delete node[name];
5012                                         }catch(e){}
5013                                 }
5014
5015                                 // ensure that event objects are normalized, etc.
5016                                 _evtHdlrMap[attrId][name] = d.connect(node, name, value);
5017
5018                         }else if(typeof value == "boolean"){ // e.g. onsubmit, disabled
5019                                 // if a function, we should normalize the event object here!!!
5020                                 node[name] = value;
5021                         }else{
5022                                 node.setAttribute(name, value);
5023                         }
5024                         return;
5025                 }else{
5026                         // should we access this attribute via a property or
5027                         // via getAttribute()?
5028                         var prop = _attrProps[name.toLowerCase()];
5029                         if(prop){
5030                                 return node[prop];
5031                         }else{
5032                                 var value = node[name];
5033                                 return (typeof value == 'boolean' || typeof value == 'function') ? value : (d.hasAttr(node, name) ? node.getAttribute(name) : null);
5034                         }
5035                 }
5036         }
5037
5038         dojo.removeAttr = function(/*DomNode|String*/node, /*String*/name){
5039                 //      summary:
5040                 //              Removes an attribute from an HTML element.
5041                 //      node:
5042                 //              id or reference to the element to remove the attribute from
5043                 //      name:
5044                 //              the name of the attribute to remove
5045                 d.byId(node).removeAttribute(_fixAttrName(name));
5046         }
5047 })();
5048
5049 // =============================
5050 // (CSS) Class Functions
5051 // =============================
5052
5053 dojo.hasClass = function(/*DomNode|String*/node, /*String*/classStr){
5054         //      summary:
5055         //              Returns whether or not the specified classes are a portion of the
5056         //              class list currently applied to the node. 
5057         return ((" "+dojo.byId(node).className+" ").indexOf(" "+classStr+" ") >= 0);  // Boolean
5058 };
5059
5060 dojo.addClass = function(/*DomNode|String*/node, /*String*/classStr){
5061         //      summary:
5062         //              Adds the specified classes to the end of the class list on the
5063         //              passed node.
5064         node = dojo.byId(node);
5065         var cls = node.className;
5066         if((" "+cls+" ").indexOf(" "+classStr+" ") < 0){
5067                 node.className = cls + (cls ? ' ' : '') + classStr;
5068         }
5069 };
5070
5071 dojo.removeClass = function(/*DomNode|String*/node, /*String*/classStr){
5072         // summary: Removes the specified classes from node.
5073         node = dojo.byId(node);
5074         var t = dojo.trim((" " + node.className + " ").replace(" " + classStr + " ", " "));
5075         if(node.className != t){ node.className = t; }
5076 };
5077
5078 dojo.toggleClass = function(/*DomNode|String*/node, /*String*/classStr, /*Boolean?*/condition){
5079         //      summary:        
5080         //              Adds a class to node if not present, or removes if present.
5081         //              Pass a boolean condition if you want to explicitly add or remove.
5082         //      condition:
5083         //              If passed, true means to add the class, false means to remove.
5084         if(condition === undefined){
5085                 condition = !dojo.hasClass(node, classStr);
5086         }
5087         dojo[condition ? "addClass" : "removeClass"](node, classStr);
5088 };
5089
5090 }
5091
5092 if(!dojo._hasResource["dojo._base.NodeList"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
5093 dojo._hasResource["dojo._base.NodeList"] = true;
5094 dojo.provide("dojo._base.NodeList");
5095
5096
5097
5098 (function(){
5099
5100         var d = dojo;
5101
5102         var tnl = function(arr){
5103                 // decorate an array to make it look like a NodeList
5104                 arr.constructor = dojo.NodeList;
5105                 dojo._mixin(arr, dojo.NodeList.prototype);
5106                 return arr;
5107         }
5108
5109         var _mapIntoDojo = function(func, alwaysThis){
5110                 // returns a function which, when executed in the scope of its caller,
5111                 // applies the passed arguments to a particular dojo.* function (named
5112                 // in func) and aggregates the returns. if alwaysThis is true, it
5113                 // always returns the scope object and not the collected returns from
5114                 // the Dojo method
5115                 return function(){
5116                         var _a = arguments;
5117                         var aa = d._toArray(_a, 0, [null]);
5118                         var s = this.map(function(i){
5119                                 aa[0] = i;
5120                                 return d[func].apply(d, aa);
5121                         });
5122                         return (alwaysThis || ( (_a.length > 1) || !d.isString(_a[0]) )) ? this : s; // String||dojo.NodeList
5123                 }
5124         };
5125
5126         dojo.NodeList = function(){
5127                 //      summary:
5128                 //              dojo.NodeList is as subclass of Array which adds syntactic 
5129                 //              sugar for chaining, common iteration operations, animation, 
5130                 //              and node manipulation. NodeLists are most often returned as
5131                 //              the result of dojo.query() calls.
5132                 //      example:
5133                 //              create a node list from a node
5134                 //              |       new dojo.NodeList(dojo.byId("foo"));
5135
5136                 return tnl(Array.apply(null, arguments));
5137         }
5138
5139         dojo.NodeList._wrap = tnl;
5140
5141         dojo.extend(dojo.NodeList, {
5142                 // http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Reference:Global_Objects:Array#Methods
5143
5144                 // FIXME: handle return values for #3244
5145                 //              http://trac.dojotoolkit.org/ticket/3244
5146                 
5147                 // FIXME:
5148                 //              need to wrap or implement:
5149                 //                      join (perhaps w/ innerHTML/outerHTML overload for toString() of items?)
5150                 //                      reduce
5151                 //                      reduceRight
5152
5153                 slice: function(/*===== begin, end =====*/){
5154                         // summary:
5155                         //              Returns a new NodeList, maintaining this one in place
5156                         // description:
5157                         //              This method behaves exactly like the Array.slice method
5158                         //              with the caveat that it returns a dojo.NodeList and not a
5159                         //              raw Array. For more details, see:
5160                         //                      http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Reference:Global_Objects:Array:slice
5161                         // begin: Integer
5162                         //              Can be a positive or negative integer, with positive
5163                         //              integers noting the offset to begin at, and negative
5164                         //              integers denoting an offset from the end (i.e., to the left
5165                         //              of the end)
5166                         // end: Integer?
5167                         //              Optional parameter to describe what position relative to
5168                         //              the NodeList's zero index to end the slice at. Like begin,
5169                         //              can be positive or negative.
5170                         var a = dojo._toArray(arguments);
5171                         return tnl(a.slice.apply(this, a));
5172                 },
5173
5174                 splice: function(/*===== index, howmany, item =====*/){
5175                         // summary:
5176                         //              Returns a new NodeList, manipulating this NodeList based on
5177                         //              the arguments passed, potentially splicing in new elements
5178                         //              at an offset, optionally deleting elements
5179                         // description:
5180                         //              This method behaves exactly like the Array.splice method
5181                         //              with the caveat that it returns a dojo.NodeList and not a
5182                         //              raw Array. For more details, see:
5183                         //                      <http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Reference:Global_Objects:Array:splice>
5184                         // index: Integer
5185                         //              begin can be a positive or negative integer, with positive
5186                         //              integers noting the offset to begin at, and negative
5187                         //              integers denoting an offset from the end (i.e., to the left
5188                         //              of the end)
5189                         // howmany: Integer?
5190                         //              Optional parameter to describe what position relative to
5191                         //              the NodeList's zero index to end the slice at. Like begin,
5192                         //              can be positive or negative.
5193                         // item: Object...?
5194                         //              Any number of optional parameters may be passed in to be
5195                         //              spliced into the NodeList
5196                         // returns:
5197                         //              dojo.NodeList
5198                         var a = dojo._toArray(arguments);
5199                         return tnl(a.splice.apply(this, a));
5200                 },
5201
5202                 concat: function(/*===== item =====*/){
5203                         // summary:
5204                         //              Returns a new NodeList comprised of items in this NodeList
5205                         //              as well as items passed in as parameters
5206                         // description:
5207                         //              This method behaves exactly like the Array.concat method
5208                         //              with the caveat that it returns a dojo.NodeList and not a
5209                         //              raw Array. For more details, see:
5210                         //                      <http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Reference:Global_Objects:Array:concat>
5211                         // item: Object...?
5212                         //              Any number of optional parameters may be passed in to be
5213                         //              spliced into the NodeList
5214                         // returns:
5215                         //              dojo.NodeList
5216                         var a = dojo._toArray(arguments, 0, [this]);
5217                         return tnl(a.concat.apply([], a));
5218                 },
5219                 
5220                 indexOf: function(/*Object*/ value, /*Integer?*/ fromIndex){
5221                         //      summary:
5222                         //              see dojo.indexOf(). The primary difference is that the acted-on 
5223                         //              array is implicitly this NodeList
5224                         // value:
5225                         //              The value to search for.
5226                         // fromIndex:
5227                         //              The loction to start searching from. Optional. Defaults to 0.
5228                         //      description:
5229                         //              For more details on the behavior of indexOf, see:
5230                         //                      <http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Reference:Global_Objects:Array:indexOf>
5231                         //      returns:
5232                         //              Positive Integer or 0 for a match, -1 of not found.
5233                         return d.indexOf(this, value, fromIndex); // Integer
5234                 },
5235
5236                 lastIndexOf: function(/*===== value, fromIndex =====*/){
5237                         // summary:
5238                         //              see dojo.lastIndexOf(). The primary difference is that the
5239                         //              acted-on array is implicitly this NodeList
5240                         //      description:
5241                         //              For more details on the behavior of lastIndexOf, see:
5242                         //                      <http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Reference:Global_Objects:Array:lastIndexOf>
5243                         // value: Object
5244                         //              The value to search for.
5245                         // fromIndex: Integer?
5246                         //              The loction to start searching from. Optional. Defaults to 0.
5247                         // returns:
5248                         //              Positive Integer or 0 for a match, -1 of not found.
5249                         return d.lastIndexOf.apply(d, d._toArray(arguments, 0, [this])); // Integer
5250                 },
5251
5252                 every: function(/*Function*/callback, /*Object?*/thisObject){
5253                         //      summary:
5254                         //              see `dojo.every()` and:
5255                         //                      <http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Reference:Global_Objects:Array:every>
5256                         //              Takes the same structure of arguments and returns as
5257                         //              dojo.every() with the caveat that the passed array is
5258                         //              implicitly this NodeList
5259                         return d.every(this, callback, thisObject); // Boolean
5260                 },
5261
5262                 some: function(/*Function*/callback, /*Object?*/thisObject){
5263                         //      summary:
5264                         //              see dojo.some() and:
5265                         //                      http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Reference:Global_Objects:Array:some
5266                         //              Takes the same structure of arguments and returns as
5267                         //              dojo.some() with the caveat that the passed array is
5268                         //              implicitly this NodeList
5269                         return d.some(this, callback, thisObject); // Boolean
5270                 },
5271
5272                 map: function(/*Function*/ func, /*Function?*/ obj){
5273                         //      summary:
5274                         //              see dojo.map(). The primary difference is that the acted-on
5275                         //              array is implicitly this NodeList and the return is a
5276                         //              dojo.NodeList (a subclass of Array)
5277
5278                         return d.map(this, func, obj, d.NodeList); // dojo.NodeList
5279                 },
5280
5281                 forEach: function(callback, thisObj){
5282                         //      summary:
5283                         //              see dojo.forEach(). The primary difference is that the acted-on 
5284                         //              array is implicitly this NodeList
5285
5286                         d.forEach(this, callback, thisObj);
5287                         // non-standard return to allow easier chaining
5288                         return this; // dojo.NodeList 
5289                 },
5290
5291                 // custom methods
5292                 
5293                 coords: function(){
5294                         //      summary:
5295                         //              Returns the box objects all elements in a node list as
5296                         //              an Array (*not* a NodeList)
5297                         
5298                         return d.map(this, d.coords); // Array
5299                 },
5300
5301                 /*=====
5302                 attr: function(property, value){
5303                         //      summary:
5304                         //              gets or sets the DOM attribute for every element in the
5305                         //              NodeList
5306                         //      property: String
5307                         //              the attribute to get/set
5308                         //      value: String?
5309                         //              optional. The value to set the property to
5310                         //      return:
5311                         //              if no value is passed, the result is an array of attribute values
5312                         //              If a value is passed, the return is this NodeList
5313                 },
5314
5315                 style: function(property, value){
5316                         //      summary:
5317                         //              gets or sets the CSS property for every element in the NodeList
5318                         //      property: String
5319                         //              the CSS property to get/set, in JavaScript notation
5320                         //              ("lineHieght" instead of "line-height") 
5321                         //      value: String?
5322                         //              optional. The value to set the property to
5323                         //      return:
5324                         //              if no value is passed, the result is an array of strings.
5325                         //              If a value is passed, the return is this NodeList
5326                 },
5327
5328                 addClass: function(className){
5329                         //      summary:
5330                         //              adds the specified class to every node in the list
5331                         //      className: String
5332                         //              the CSS class to add
5333                         //      return:
5334                         //              dojo.NodeList, this list
5335                 },
5336
5337                 removeClass: function(className){
5338                         //      summary:
5339                         //              removes the specified class from every node in the list
5340                         //      className: String
5341                         //              the CSS class to add
5342                         //      return:
5343                         //              dojo.NodeList, this list
5344                 },
5345
5346                 toggleClass: function(className, condition){
5347                         //      summary:
5348                         //              Adds a class to node if not present, or removes if present.
5349                         //              Pass a boolean condition if you want to explicitly add or remove.
5350                         //      condition: Boolean?
5351                         //              If passed, true means to add the class, false means to remove.
5352                         //      className: String
5353                         //              the CSS class to add
5354                         //      return: dojo.NodeList
5355                         //              this list
5356                 },
5357
5358                 connect: function(methodName, objOrFunc, funcName){
5359                         //      summary:
5360                         //              attach event handlers to every item of the NodeList. Uses dojo.connect()
5361                         //              so event properties are normalized
5362                         //      methodName: String
5363                         //              the name of the method to attach to. For DOM events, this should be
5364                         //              the lower-case name of the event
5365                         //      objOrFunc: Object|Function|String
5366                         //              if 2 arguments are passed (methodName, objOrFunc), objOrFunc should
5367                         //              reference a function or be the name of the function in the global
5368                         //              namespace to attach. If 3 arguments are provided
5369                         //              (methodName, objOrFunc, funcName), objOrFunc must be the scope to 
5370                         //              locate the bound function in
5371                         //      funcName: String?
5372                         //              optional. A string naming the function in objOrFunc to bind to the
5373                         //              event. May also be a function reference.
5374                         //      example:
5375                         //              add an onclick handler to every button on the page
5376                         //              |       dojo.query("div:nth-child(odd)").connect("onclick", function(e){
5377                         //              |               console.debug("clicked!");
5378                         //              |       });
5379                         // example:
5380                         //              attach foo.bar() to every odd div's onmouseover
5381                         //              |       dojo.query("div:nth-child(odd)").connect("onmouseover", foo, "bar");
5382                 },
5383                 =====*/
5384                 attr: _mapIntoDojo("attr"),
5385                 style: _mapIntoDojo("style"),
5386                 addClass: _mapIntoDojo("addClass", true),
5387                 removeClass: _mapIntoDojo("removeClass", true),
5388                 toggleClass: _mapIntoDojo("toggleClass", true),
5389                 connect: _mapIntoDojo("connect", true),
5390
5391                 // FIXME: connectPublisher()? connectRunOnce()?
5392
5393                 place: function(/*String||Node*/ queryOrNode, /*String*/ position){
5394                         //      summary:
5395                         //              places elements of this node list relative to the first element matched
5396                         //              by queryOrNode. Returns the original NodeList.
5397                         //      queryOrNode:
5398                         //              may be a string representing any valid CSS3 selector or a DOM node.
5399                         //              In the selector case, only the first matching element will be used 
5400                         //              for relative positioning.
5401                         //      position:
5402                         //              can be one of:
5403                         //                      * "last"||"end" (default)
5404                         //                      * "first||"start"
5405                         //                      * "before"
5406                         //                      * "after"
5407                         //              or an offset in the childNodes property
5408                         var item = d.query(queryOrNode)[0];
5409                         return this.forEach(function(i){ d.place(i, item, (position||"last")); }); // dojo.NodeList
5410                 },
5411
5412                 orphan: function(/*String?*/ simpleFilter){
5413                         //      summary:
5414                         //              removes elements in this list that match the simple
5415                         //              filter from their parents and returns them as a new
5416                         //              NodeList.
5417                         //      simpleFilter:
5418                         //              single-expression CSS filter
5419                         //      return:
5420                         //              `dojo.NodeList` the orpahned elements 
5421                         var orphans = simpleFilter ? d._filterQueryResult(this, simpleFilter) : this;
5422                         orphans.forEach(function(item){
5423                                 if(item.parentNode){
5424                                         item.parentNode.removeChild(item);
5425                                 }
5426                         });
5427                         return orphans; // dojo.NodeList
5428                 },
5429
5430                 adopt: function(/*String||Array||DomNode*/ queryOrListOrNode, /*String?*/ position){
5431                         //      summary:
5432                         //              places any/all elements in queryOrListOrNode at a
5433                         //              position relative to the first element in this list.
5434                         //              Returns a dojo.NodeList of the adopted elements.
5435                         //      queryOrListOrNode:
5436                         //              a DOM node or a query string or a query result.
5437                         //              Represents the nodes to be adopted relative to the
5438                         //              first element of this NodeList.
5439                         //      position:
5440                         //              can be one of:
5441                         //                      * "last"||"end" (default)
5442                         //                      * "first||"start"
5443                         //                      * "before"
5444                         //                      * "after"
5445                         //              or an offset in the childNodes property
5446                         var item = this[0];
5447                         return d.query(queryOrListOrNode).forEach(function(ai){ d.place(ai, item, position || "last"); }); // dojo.NodeList
5448                 },
5449
5450                 // FIXME: do we need this?
5451                 query: function(/*String*/ queryStr){
5452                         //      summary:
5453                         //              Returns a new, flattened NodeList. Elements of the new list
5454                         //              satisfy the passed query but use elements of the
5455                         //              current NodeList as query roots.
5456
5457                         if(!queryStr){ return this; }
5458
5459                         // FIXME: probably slow
5460                         // FIXME: use map?
5461                         var ret = d.NodeList();
5462                         this.forEach(function(item){
5463                                 d.query(queryStr, item).forEach(function(subItem){
5464                                         if(subItem !== undefined){
5465                                                 ret.push(subItem);
5466                                         }
5467                                 });
5468                         });
5469                         return ret; // dojo.NodeList
5470                 },
5471
5472                 filter: function(/*String*/ simpleQuery){
5473                         //      summary:
5474                         //              "masks" the built-in javascript filter() method to support
5475                         //              passing a simple string filter in addition to supporting
5476                         //              filtering function objects.
5477                         //      example:
5478                         //              "regular" JS filter syntax as exposed in dojo.filter:
5479                         //              |       dojo.query("*").filter(function(item){
5480                         //              |               // highlight every paragraph
5481                         //              |               return (item.nodeName == "p");
5482                         //              |       }).styles("backgroundColor", "yellow");
5483                         // example:
5484                         //              the same filtering using a CSS selector
5485                         //              |       dojo.query("*").filter("p").styles("backgroundColor", "yellow");
5486
5487                         var items = this;
5488                         var _a = arguments;
5489                         var r = d.NodeList();
5490                         var rp = function(t){ 
5491                                 if(t !== undefined){
5492                                         r.push(t); 
5493                                 }
5494                         }
5495                         if(d.isString(simpleQuery)){
5496                                 items = d._filterQueryResult(this, _a[0]);
5497                                 if(_a.length == 1){
5498                                         // if we only got a string query, pass back the filtered results
5499                                         return items; // dojo.NodeList
5500                                 }
5501                                 // if we got a callback, run it over the filtered items
5502                                 _a.shift();
5503                         }
5504                         // handle the (callback, [thisObject]) case
5505                         d.forEach(d.filter(items, _a[0], _a[1]), rp);
5506                         return r; // dojo.NodeList
5507                 },
5508                 
5509                 /*
5510                 // FIXME: should this be "copyTo" and include parenting info?
5511                 clone: function(){
5512                         // summary:
5513                         //              creates node clones of each element of this list
5514                         //              and returns a new list containing the clones
5515                 },
5516                 */
5517
5518                 addContent: function(/*String*/ content, /*String||Integer?*/ position){
5519                         //      summary:
5520                         //              add a node or some HTML as a string to every item in the list. 
5521                         //              Returns the original list.
5522                         //      description:
5523                         //              a copy of the HTML content is added to each item in the
5524                         //              list, with an optional position argument. If no position
5525                         //              argument is provided, the content is appended to the end of
5526                         //              each item.
5527                         //      content:
5528                         //              the HTML in string format to add at position to every item
5529                         //      position:
5530                         //              can be one of:
5531                         //                      * "last"||"end" (default)
5532                         //                      * "first||"start"
5533                         //                      * "before"
5534                         //                      * "after"
5535                         //              or an offset in the childNodes property
5536                         //      example:
5537                         //              appends content to the end if the position is ommitted
5538                         //      |       dojo.query("h3 > p").addContent("hey there!");
5539                         //      example:
5540                         //              add something to the front of each element that has a "thinger" property:
5541                         //      |       dojo.query("[thinger]").addContent("...", "first");
5542                         //      example:
5543                         //              adds a header before each element of the list
5544                         //      |       dojo.query(".note").addContent("<h4>NOTE:</h4>", "before");
5545                         var ta = d.doc.createElement("span");
5546                         if(d.isString(content)){
5547                                 ta.innerHTML = content;
5548                         }else{
5549                                 ta.appendChild(content);
5550                         }
5551                         if(position === undefined){
5552                                 position = "last";
5553                         }
5554                         var ct = (position == "first" || position == "after") ? "lastChild" : "firstChild";
5555                         this.forEach(function(item){
5556                                 var tn = ta.cloneNode(true);
5557                                 while(tn[ct]){
5558                                         d.place(tn[ct], item, position);
5559                                 }
5560                         });
5561                         return this; // dojo.NodeList
5562                 },
5563
5564                 empty: function(){
5565                         //      summary:
5566                         //              clears all content from each node in the list
5567                         return this.forEach("item.innerHTML='';"); // dojo.NodeList
5568
5569                         // FIXME: should we be checking for and/or disposing of widgets below these nodes?
5570                 },
5571                 
5572                 instantiate: function(/*String|Object*/ declaredClass, /*Object?*/ properties){
5573                         //      summary:
5574                         //              Create a new instance of a specified class, using the
5575                         //              specified properties and each node in the nodeList as a
5576                         //              srcNodeRef
5577                         //
5578                         var c = d.isFunction(declaredClass) ? declaredClass : d.getObject(declaredClass);
5579                         return this.forEach(function(i){
5580                                 new c(properties||{},i);
5581                         }) // dojo.NodeList
5582                 }
5583
5584         });
5585
5586         // syntactic sugar for DOM events
5587         d.forEach([
5588                 "blur", "focus", "click", "keydown", "keypress", "keyup", "mousedown",
5589                 "mouseenter", "mouseleave", "mousemove", "mouseout", "mouseover",
5590                 "mouseup"
5591                 ], function(evt){
5592                         var _oe = "on"+evt;
5593                         dojo.NodeList.prototype[_oe] = function(a, b){
5594                                 return this.connect(_oe, a, b);
5595                         }
5596                                 // FIXME: should these events trigger publishes?
5597                                 /*
5598                                 return (a ? this.connect(_oe, a, b) : 
5599                                                         this.forEach(function(n){  
5600                                                                 // FIXME:
5601                                                                 //              listeners get buried by
5602                                                                 //              addEventListener and can't be dug back
5603                                                                 //              out to be triggered externally.
5604                                                                 // see:
5605                                                                 //              http://developer.mozilla.org/en/docs/DOM:element
5606
5607                                                                 console.debug(n, evt, _oe);
5608
5609                                                                 // FIXME: need synthetic event support!
5610                                                                 var _e = { target: n, faux: true, type: evt };
5611                                                                 // dojo._event_listener._synthesizeEvent({}, { target: n, faux: true, type: evt });
5612                                                                 try{ n[evt](_e); }catch(e){ console.debug(e); }
5613                                                                 try{ n[_oe](_e); }catch(e){ console.debug(e); }
5614                                                         })
5615                                 );
5616                         }
5617                         */
5618                 }
5619         );
5620
5621 })();
5622
5623 }
5624
5625 if(!dojo._hasResource["dojo._base.query"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
5626 dojo._hasResource["dojo._base.query"] = true;
5627 dojo.provide("dojo._base.query");
5628
5629
5630 /*
5631         dojo.query() architectural overview:
5632
5633                 dojo.query is a relatively full-featured CSS3 query library. It is
5634                 designed to take any valid CSS3 selector and return the nodes matching
5635                 the selector. To do this quickly, it processes queries in several
5636                 steps, applying caching where profitable.
5637                 
5638                 The steps (roughly in reverse order of the way they appear in the code):
5639                         1.) check to see if we already have a "query dispatcher"
5640                                 - if so, use that with the given parameterization. Skip to step 4.
5641                         2.) attempt to determine which branch to dispatch the query to:
5642                                 - JS (optimized DOM iteration)
5643                                 - xpath (for browsers that support it and where it's fast)
5644                                 - native (not available in any browser yet)
5645                         3.) tokenize and convert to executable "query dispatcher"
5646                                 - this is where the lion's share of the complexity in the
5647                                   system lies. In the DOM version, the query dispatcher is
5648                                   assembled as a chain of "yes/no" test functions pertaining to
5649                                   a section of a simple query statement (".blah:nth-child(odd)"
5650                                   but not "div div", which is 2 simple statements). Individual
5651                                   statement dispatchers are cached (to prevent re-definition)
5652                                   as are entire dispatch chains (to make re-execution of the
5653                                   same query fast)
5654                                 - in the xpath path, tokenization yeilds a concatenation of
5655                                   parameterized xpath selectors. As with the DOM version, both
5656                                   simple selector blocks and overall evaluators are cached to
5657                                   prevent re-defintion
5658                         4.) the resulting query dispatcher is called in the passed scope (by default the top-level document)
5659                                 - for DOM queries, this results in a recursive, top-down
5660                                   evaluation of nodes based on each simple query section
5661                                 - xpath queries can, thankfully, be executed in one shot
5662                         5.) matched nodes are pruned to ensure they are unique
5663 */
5664
5665 ;(function(){
5666         // define everything in a closure for compressability reasons. "d" is an
5667         // alias to "dojo" since it's so frequently used. This seems a
5668         // transformation that the build system could perform on a per-file basis.
5669
5670         ////////////////////////////////////////////////////////////////////////
5671         // Utility code
5672         ////////////////////////////////////////////////////////////////////////
5673
5674         var d = dojo;
5675         var childNodesName = dojo.isIE ? "children" : "childNodes";
5676         var caseSensitive = false;
5677
5678         var getQueryParts = function(query){
5679                 // summary: state machine for query tokenization
5680                 if(">~+".indexOf(query.charAt(query.length-1)) >= 0){
5681                         query += " *"
5682                 }
5683                 query += " "; // ensure that we terminate the state machine
5684
5685                 var ts = function(s, e){
5686                         return d.trim(query.slice(s, e));
5687                 }
5688
5689                 // the overall data graph of the full query, as represented by queryPart objects
5690                 var qparts = []; 
5691                 // state keeping vars
5692                 var inBrackets = -1;
5693                 var inParens = -1;
5694                 var inMatchFor = -1;
5695                 var inPseudo = -1;
5696                 var inClass = -1;
5697                 var inId = -1;
5698                 var inTag = -1;
5699                 var lc = ""; // the last character
5700                 var cc = ""; // the current character
5701                 var pStart;
5702                 // iteration vars
5703                 var x = 0; // index in the query
5704                 var ql = query.length;
5705                 var currentPart = null; // data structure representing the entire clause
5706                 var _cp = null; // the current pseudo or attr matcher
5707
5708                 var endTag = function(){
5709                         if(inTag >= 0){
5710                                 var tv = (inTag == x) ? null : ts(inTag, x).toLowerCase();
5711                                 currentPart[ (">~+".indexOf(tv) < 0) ? "tag" : "oper" ] = tv;
5712                                 inTag = -1;
5713                         }
5714                 }
5715
5716                 var endId = function(){
5717                         if(inId >= 0){
5718                                 currentPart.id = ts(inId, x).replace(/\\/g, "");
5719                                 inId = -1;
5720                         }
5721                 }
5722
5723                 var endClass = function(){
5724                         if(inClass >= 0){
5725                                 currentPart.classes.push(ts(inClass+1, x).replace(/\\/g, ""));
5726                                 inClass = -1;
5727                         }
5728                 }
5729
5730                 var endAll = function(){
5731                         endId(); endTag(); endClass();
5732                 }
5733
5734                 for(; lc=cc, cc=query.charAt(x),x<ql; x++){
5735                         if(lc == "\\"){ continue; }
5736                         if(!currentPart){
5737                                 // NOTE: I hate all this alloc, but it's shorter than writing tons of if's
5738                                 pStart = x;
5739                                 currentPart = {
5740                                         query: null,
5741                                         pseudos: [],
5742                                         attrs: [],
5743                                         classes: [],
5744                                         tag: null,
5745                                         oper: null,
5746                                         id: null
5747                                 };
5748                                 inTag = x;
5749                         }
5750
5751                         if(inBrackets >= 0){
5752                                 // look for a the close first
5753                                 if(cc == "]"){
5754                                         if(!_cp.attr){
5755                                                 _cp.attr = ts(inBrackets+1, x);
5756                                         }else{
5757                                                 _cp.matchFor = ts((inMatchFor||inBrackets+1), x);
5758                                         }
5759                                         var cmf = _cp.matchFor;
5760                                         if(cmf){
5761                                                 if(     (cmf.charAt(0) == '"') || (cmf.charAt(0)  == "'") ){
5762                                                         _cp.matchFor = cmf.substring(1, cmf.length-1);
5763                                                 }
5764                                         }
5765                                         currentPart.attrs.push(_cp);
5766                                         _cp = null; // necessaray?
5767                                         inBrackets = inMatchFor = -1;
5768                                 }else if(cc == "="){
5769                                         var addToCc = ("|~^$*".indexOf(lc) >=0 ) ? lc : "";
5770                                         _cp.type = addToCc+cc;
5771                                         _cp.attr = ts(inBrackets+1, x-addToCc.length);
5772                                         inMatchFor = x+1;
5773                                 }
5774                                 // now look for other clause parts
5775                         }else if(inParens >= 0){
5776                                 if(cc == ")"){
5777                                         if(inPseudo >= 0){
5778                                                 _cp.value = ts(inParens+1, x);
5779                                         }
5780                                         inPseudo = inParens = -1;
5781                                 }
5782                         }else if(cc == "#"){
5783                                 endAll();
5784                                 inId = x+1;
5785                         }else if(cc == "."){
5786                                 endAll();
5787                                 inClass = x;
5788                         }else if(cc == ":"){
5789                                 endAll();
5790                                 inPseudo = x;
5791                         }else if(cc == "["){
5792                                 endAll();
5793                                 inBrackets = x;
5794                                 _cp = {
5795                                         /*=====
5796                                         attr: null, type: null, matchFor: null
5797                                         =====*/
5798                                 };
5799                         }else if(cc == "("){
5800                                 if(inPseudo >= 0){
5801                                         _cp = { 
5802                                                 name: ts(inPseudo+1, x), 
5803                                                 value: null
5804                                         }
5805                                         currentPart.pseudos.push(_cp);
5806                                 }
5807                                 inParens = x;
5808                         }else if(cc == " " && lc != cc){
5809                                 // note that we expect the string to be " " terminated
5810                                 endAll();
5811                                 if(inPseudo >= 0){
5812                                         currentPart.pseudos.push({ name: ts(inPseudo+1, x) });
5813                                 }
5814                                 currentPart.hasLoops = (        
5815                                                 currentPart.pseudos.length || 
5816                                                 currentPart.attrs.length || 
5817                                                 currentPart.classes.length      );
5818                                 currentPart.query = ts(pStart, x);
5819                                 currentPart.tag = (currentPart["oper"]) ? null : (currentPart.tag || "*");
5820                                 qparts.push(currentPart);
5821                                 currentPart = null;
5822                         }
5823                 }
5824                 return qparts;
5825         };
5826         
5827
5828         ////////////////////////////////////////////////////////////////////////
5829         // XPath query code
5830         ////////////////////////////////////////////////////////////////////////
5831
5832         // this array is a lookup used to generate an attribute matching function.
5833         // There is a similar lookup/generator list for the DOM branch with similar
5834         // calling semantics.
5835         var xPathAttrs = {
5836                 "*=": function(attr, value){
5837                         return "[contains(@"+attr+", '"+ value +"')]";
5838                 },
5839                 "^=": function(attr, value){
5840                         return "[starts-with(@"+attr+", '"+ value +"')]";
5841                 },
5842                 "$=": function(attr, value){
5843                         return "[substring(@"+attr+", string-length(@"+attr+")-"+(value.length-1)+")='"+value+"']";
5844                 },
5845                 "~=": function(attr, value){
5846                         return "[contains(concat(' ',@"+attr+",' '), ' "+ value +" ')]";
5847                 },
5848                 "|=": function(attr, value){
5849                         return "[contains(concat(' ',@"+attr+",' '), ' "+ value +"-')]";
5850                 },
5851                 "=": function(attr, value){
5852                         return "[@"+attr+"='"+ value +"']";
5853                 }
5854         };
5855
5856         // takes a list of attribute searches, the overall query, a function to
5857         // generate a default matcher, and a closure-bound method for providing a
5858         // matching function that generates whatever type of yes/no distinguisher
5859         // the query method needs. The method is a bit tortured and hard to read
5860         // because it needs to be used in both the XPath and DOM branches.
5861         var handleAttrs = function(     attrList, 
5862                                                                 query, 
5863                                                                 getDefault, 
5864                                                                 handleMatch){
5865                 d.forEach(query.attrs, function(attr){
5866                         var matcher;
5867                         // type, attr, matchFor
5868                         if(attr.type && attrList[attr.type]){
5869                                 matcher = attrList[attr.type](attr.attr, attr.matchFor);
5870                         }else if(attr.attr.length){
5871                                 matcher = getDefault(attr.attr);
5872                         }
5873                         if(matcher){ handleMatch(matcher); }
5874                 });
5875         }
5876
5877         var buildPath = function(query){
5878                 var xpath = ".";
5879                 var qparts = getQueryParts(d.trim(query));
5880                 while(qparts.length){
5881                         var tqp = qparts.shift();
5882                         var prefix;
5883                         var postfix = "";
5884                         if(tqp.oper == ">"){
5885                                 prefix = "/";
5886                                 // prefix = "/child::*";
5887                                 tqp = qparts.shift();
5888                         }else if(tqp.oper == "~"){
5889                                 prefix = "/following-sibling::"; // get element following siblings
5890                                 tqp = qparts.shift();
5891                         }else if(tqp.oper == "+"){
5892                                 // FIXME: 
5893                                 //              fails when selecting subsequent siblings by node type
5894                                 //              because the position() checks the position in the list
5895                                 //              of matching elements and not the localized siblings
5896                                 prefix = "/following-sibling::";
5897                                 postfix = "[position()=1]";
5898                                 tqp = qparts.shift();
5899                         }else{
5900                                 prefix = "//";
5901                                 // prefix = "/descendant::*"
5902                         }
5903
5904                         // get the tag name (if any)
5905
5906                         xpath += prefix + tqp.tag + postfix;
5907                         
5908                         // check to see if it's got an id. Needs to come first in xpath.
5909                         if(tqp.id){
5910                                 xpath += "[@id='"+tqp.id+"'][1]";
5911                         }
5912
5913                         d.forEach(tqp.classes, function(cn){
5914                                 var cnl = cn.length;
5915                                 var padding = " ";
5916                                 if(cn.charAt(cnl-1) == "*"){
5917                                         padding = ""; cn = cn.substr(0, cnl-1);
5918                                 }
5919                                 xpath += 
5920                                         "[contains(concat(' ',@class,' '), ' "+
5921                                         cn + padding + "')]";
5922                         });
5923
5924                         handleAttrs(xPathAttrs, tqp, 
5925                                 function(condition){
5926                                                 return "[@"+condition+"]";
5927                                 },
5928                                 function(matcher){
5929                                         xpath += matcher;
5930                                 }
5931                         );
5932
5933                         // FIXME: need to implement pseudo-class checks!!
5934                 };
5935                 return xpath;
5936         };
5937
5938         var _xpathFuncCache = {};
5939         var getXPathFunc = function(path){
5940                 if(_xpathFuncCache[path]){
5941                         return _xpathFuncCache[path];
5942                 }
5943
5944                 var doc = d.doc;
5945                 // don't need to memoize. The closure scope handles it for us.
5946                 var xpath = buildPath(path);
5947
5948                 var tf = function(parent){
5949                         // XPath query strings are memoized.
5950                         var ret = [];
5951                         var xpathResult;
5952                         try{
5953                                 xpathResult = doc.evaluate(xpath, parent, null, 
5954                                                                                                 // XPathResult.UNORDERED_NODE_ITERATOR_TYPE, null);
5955                                                                                                 XPathResult.ANY_TYPE, null);
5956                         }catch(e){
5957                                 console.debug("failure in exprssion:", xpath, "under:", parent);
5958                                 console.debug(e);
5959                         }
5960                         var result = xpathResult.iterateNext();
5961                         while(result){
5962                                 ret.push(result);
5963                                 result = xpathResult.iterateNext();
5964                         }
5965                         return ret;
5966                 }
5967                 return _xpathFuncCache[path] = tf;
5968         };
5969
5970         /*
5971         d.xPathMatch = function(query){
5972                 // XPath based DOM query system. Handles a small subset of CSS
5973                 // selectors, subset is identical to the non-XPath version of this
5974                 // function. 
5975
5976                 return getXPathFunc(query)();
5977         }
5978         */
5979
5980         ////////////////////////////////////////////////////////////////////////
5981         // DOM query code
5982         ////////////////////////////////////////////////////////////////////////
5983
5984         var _filtersCache = {};
5985         var _simpleFiltersCache = {};
5986
5987         // the basic building block of the yes/no chaining system. agree(f1, f2)
5988         // generates a new function which returns the boolean results of both of
5989         // the passed functions to a single logical-anded result.
5990         var agree = function(first, second){
5991                 if(!first){ return second; }
5992                 if(!second){ return first; }
5993
5994                 return function(){
5995                         return first.apply(window, arguments) && second.apply(window, arguments);
5996                 }
5997         }
5998
5999         var _childElements = function(root){
6000                 var ret = [];
6001                 var te, x=0, tret = root[childNodesName];
6002                 while(te=tret[x++]){
6003                         if(te.nodeType == 1){ ret.push(te); }
6004                 }
6005                 return ret;
6006         }
6007
6008         var _nextSiblings = function(root, single){
6009                 var ret = [];
6010                 var te = root;
6011                 while(te = te.nextSibling){
6012                         if(te.nodeType == 1){
6013                                 ret.push(te);
6014                                 if(single){ break; }
6015                         }
6016                 }
6017                 return ret;
6018         }
6019
6020         var _filterDown = function(element, queryParts, matchArr, idx){
6021                 // NOTE:
6022                 //              in the fast path! this function is called recursively and for
6023                 //              every run of a query.
6024                 var nidx = idx+1;
6025                 var isFinal = (queryParts.length == nidx);
6026                 var tqp = queryParts[idx];
6027
6028                 // see if we can constrain our next level to direct children
6029                 if(tqp.oper){
6030                         var ecn = (tqp.oper == ">") ? 
6031                                 _childElements(element) :
6032                                 _nextSiblings(element, (tqp.oper == "+"));
6033
6034                         if(!ecn || !ecn.length){
6035                                 return;
6036                         }
6037                         nidx++;
6038                         isFinal = (queryParts.length == nidx);
6039                         // kinda janky, too much array alloc
6040                         var tf = getFilterFunc(queryParts[idx+1]);
6041                         // for(var x=ecn.length-1, te; x>=0, te=ecn[x]; x--){
6042                         for(var x=0, ecnl=ecn.length, te; x<ecnl, te=ecn[x]; x++){
6043                                 if(tf(te)){
6044                                         if(isFinal){
6045                                                 matchArr.push(te);
6046                                         }else{
6047                                                 _filterDown(te, queryParts, matchArr, nidx);
6048                                         }
6049                                 }
6050                                 /*
6051                                 if(x==0){
6052                                         break;
6053                                 }
6054                                 */
6055                         }
6056                 }
6057
6058                 // otherwise, keep going down, unless we'er at the end
6059                 var candidates = getElementsFunc(tqp)(element);
6060                 if(isFinal){
6061                         while(candidates.length){
6062                                 matchArr.push(candidates.shift());
6063                         }
6064                         /*
6065                         candidates.unshift(0, matchArr.length-1);
6066                         matchArr.splice.apply(matchArr, candidates);
6067                         */
6068                 }else{
6069                         // if we're not yet at the bottom, keep going!
6070                         while(candidates.length){
6071                                 _filterDown(candidates.shift(), queryParts, matchArr, nidx);
6072                         }
6073                 }
6074         }
6075
6076         var filterDown = function(elements, queryParts){
6077                 var ret = [];
6078
6079                 // for every root, get the elements that match the descendant selector
6080                 // for(var x=elements.length-1, te; x>=0, te=elements[x]; x--){
6081                 var x = elements.length - 1, te;
6082                 while(te = elements[x--]){
6083                         _filterDown(te, queryParts, ret, 0);
6084                 }
6085                 return ret;
6086         }
6087
6088         var getFilterFunc = function(q){
6089                 // note: query can't have spaces!
6090                 if(_filtersCache[q.query]){
6091                         return _filtersCache[q.query];
6092                 }
6093                 var ff = null;
6094
6095                 // does it have a tagName component?
6096                 if(q.tag){
6097                         if(q.tag == "*"){
6098                                 ff = agree(ff, 
6099                                         function(elem){
6100                                                 return (elem.nodeType == 1);
6101                                         }
6102                                 );
6103                         }else{
6104                                 // tag name match
6105                                 ff = agree(ff, 
6106                                         function(elem){
6107                                                 return (
6108                                                         (elem.nodeType == 1) &&
6109                                                         (q.tag == elem.tagName.toLowerCase())
6110                                                 );
6111                                                 // return isTn;
6112                                         }
6113                                 );
6114                         }
6115                 }
6116
6117                 // does the node have an ID?
6118                 if(q.id){
6119                         ff = agree(ff, 
6120                                 function(elem){
6121                                         return (
6122                                                 (elem.nodeType == 1) &&
6123                                                 (elem.id == q.id)
6124                                         );
6125                                 }
6126                         );
6127                 }
6128
6129                 if(q.hasLoops){
6130                         // if we have other query param parts, make sure we add them to the
6131                         // filter chain
6132                         ff = agree(ff, getSimpleFilterFunc(q));
6133                 }
6134
6135                 return _filtersCache[q.query] = ff;
6136         }
6137
6138         var getNodeIndex = function(node){
6139                 // NOTE: 
6140                 //              we could have a more accurate caching mechanism by invalidating
6141                 //              caches after the query has finished, but I think that'd lead to
6142                 //              significantly more cache churn than the cache would provide
6143                 //              value for in the common case. Generally, we're more
6144                 //              conservative (and therefore, more accurate) than jQuery and
6145                 //              DomQuery WRT node node indexes, but there may be corner cases
6146                 //              in which we fall down.  How much we care about them is TBD.
6147
6148                 var pn = node.parentNode;
6149                 var pnc = pn.childNodes;
6150
6151                 // check to see if we can trust the cache. If not, re-key the whole
6152                 // thing and return our node match from that.
6153
6154                 var nidx = -1;
6155                 var child = pn.firstChild;
6156                 if(!child){
6157                         return nidx;
6158                 }
6159
6160                 var ci = node["__cachedIndex"];
6161                 var cl = pn["__cachedLength"];
6162
6163                 // only handle cache building if we've gone out of sync
6164                 if(((typeof cl == "number")&&(cl != pnc.length))||(typeof ci != "number")){
6165                         // rip though the whole set, building cache indexes as we go
6166                         pn["__cachedLength"] = pnc.length;
6167                         var idx = 1;
6168                         do{
6169                                 // we only assign indexes for nodes with nodeType == 1, as per:
6170                                 //              http://www.w3.org/TR/css3-selectors/#nth-child-pseudo
6171                                 // only elements are counted in the search order, and they
6172                                 // begin at 1 for the first child's index
6173
6174                                 if(child === node){
6175                                         nidx = idx;
6176                                 }
6177                                 if(child.nodeType == 1){
6178                                         child["__cachedIndex"] = idx;
6179                                         idx++;
6180                                 }
6181                                 child = child.nextSibling;
6182                         }while(child);
6183                 }else{
6184                         // NOTE: 
6185                         //              could be incorrect in some cases (node swaps involving the
6186                         //              passed node, etc.), but we ignore those due to the relative
6187                         //              unlikelihood of that occuring
6188                         nidx = ci;
6189                 }
6190                 return nidx;
6191         }
6192
6193         var firedCount = 0;
6194
6195         var blank = "";
6196         var _getAttr = function(elem, attr){
6197                 if(attr == "class"){
6198                         return elem.className || blank;
6199                 }
6200                 if(attr == "for"){
6201                         return elem.htmlFor || blank;
6202                 }
6203                 return elem.getAttribute(attr, 2) || blank;
6204         }
6205
6206         var attrs = {
6207                 "*=": function(attr, value){
6208                         return function(elem){
6209                                 // E[foo*="bar"]
6210                                 //              an E element whose "foo" attribute value contains
6211                                 //              the substring "bar"
6212                                 return (_getAttr(elem, attr).indexOf(value)>=0);
6213                         }
6214                 },
6215                 "^=": function(attr, value){
6216                         // E[foo^="bar"]
6217                         //              an E element whose "foo" attribute value begins exactly
6218                         //              with the string "bar"
6219                         return function(elem){
6220                                 return (_getAttr(elem, attr).indexOf(value)==0);
6221                         }
6222                 },
6223                 "$=": function(attr, value){
6224                         // E[foo$="bar"]        
6225                         //              an E element whose "foo" attribute value ends exactly
6226                         //              with the string "bar"
6227                         var tval = " "+value;
6228                         return function(elem){
6229                                 var ea = " "+_getAttr(elem, attr);
6230                                 return (ea.lastIndexOf(value)==(ea.length-value.length));
6231                         }
6232                 },
6233                 "~=": function(attr, value){
6234                         // E[foo~="bar"]        
6235                         //              an E element whose "foo" attribute value is a list of
6236                         //              space-separated values, one of which is exactly equal
6237                         //              to "bar"
6238
6239                         // return "[contains(concat(' ',@"+attr+",' '), ' "+ value +" ')]";
6240                         var tval = " "+value+" ";
6241                         return function(elem){
6242                                 var ea = " "+_getAttr(elem, attr)+" ";
6243                                 return (ea.indexOf(tval)>=0);
6244                         }
6245                 },
6246                 "|=": function(attr, value){
6247                         // E[hreflang|="en"]
6248                         //              an E element whose "hreflang" attribute has a
6249                         //              hyphen-separated list of values beginning (from the
6250                         //              left) with "en"
6251                         var valueDash = " "+value+"-";
6252                         return function(elem){
6253                                 var ea = " "+(elem.getAttribute(attr, 2) || "");
6254                                 return (
6255                                         (ea == value) ||
6256                                         (ea.indexOf(valueDash)==0)
6257                                 );
6258                         }
6259                 },
6260                 "=": function(attr, value){
6261                         return function(elem){
6262                                 return (_getAttr(elem, attr) == value);
6263                         }
6264                 }
6265         };
6266
6267         var pseudos = {
6268                 "first-child": function(name, condition){
6269                         return function(elem){
6270                                 if(elem.nodeType != 1){ return false; }
6271                                 // check to see if any of the previous siblings are elements
6272                                 var fc = elem.previousSibling;
6273                                 while(fc && (fc.nodeType != 1)){
6274                                         fc = fc.previousSibling;
6275                                 }
6276                                 return (!fc);
6277                         }
6278                 },
6279                 "last-child": function(name, condition){
6280                         return function(elem){
6281                                 if(elem.nodeType != 1){ return false; }
6282                                 // check to see if any of the next siblings are elements
6283                                 var nc = elem.nextSibling;
6284                                 while(nc && (nc.nodeType != 1)){
6285                                         nc = nc.nextSibling;
6286                                 }
6287                                 return (!nc);
6288                         }
6289                 },
6290                 "empty": function(name, condition){
6291                         return function(elem){
6292                                 // DomQuery and jQuery get this wrong, oddly enough.
6293                                 // The CSS 3 selectors spec is pretty explicit about
6294                                 // it, too.
6295                                 var cn = elem.childNodes;
6296                                 var cnl = elem.childNodes.length;
6297                                 // if(!cnl){ return true; }
6298                                 for(var x=cnl-1; x >= 0; x--){
6299                                         var nt = cn[x].nodeType;
6300                                         if((nt == 1)||(nt == 3)){ return false; }
6301                                 }
6302                                 return true;
6303                         }
6304                 },
6305                 "contains": function(name, condition){
6306                         return function(elem){
6307                                 // FIXME: I dislike this version of "contains", as
6308                                 // whimsical attribute could set it off. An inner-text
6309                                 // based version might be more accurate, but since
6310                                 // jQuery and DomQuery also potentially get this wrong,
6311                                 // I'm leaving it for now.
6312                                 return (elem.innerHTML.indexOf(condition) >= 0);
6313                         }
6314                 },
6315                 "not": function(name, condition){
6316                         var ntf = getFilterFunc(getQueryParts(condition)[0]);
6317                         return function(elem){
6318                                 return (!ntf(elem));
6319                         }
6320                 },
6321                 "nth-child": function(name, condition){
6322                         var pi = parseInt;
6323                         if(condition == "odd"){
6324                                 return function(elem){
6325                                         return (
6326                                                 ((getNodeIndex(elem)) % 2) == 1
6327                                         );
6328                                 }
6329                         }else if((condition == "2n")||
6330                                 (condition == "even")){
6331                                 return function(elem){
6332                                         return ((getNodeIndex(elem) % 2) == 0);
6333                                 }
6334                         }else if(condition.indexOf("0n+") == 0){
6335                                 var ncount = pi(condition.substr(3));
6336                                 return function(elem){
6337                                         return (elem.parentNode[childNodesName][ncount-1] === elem);
6338                                 }
6339                         }else if(       (condition.indexOf("n+") > 0) &&
6340                                                 (condition.length > 3) ){
6341                                 var tparts = condition.split("n+", 2);
6342                                 var pred = pi(tparts[0]);
6343                                 var idx = pi(tparts[1]);
6344                                 return function(elem){
6345                                         return ((getNodeIndex(elem) % pred) == idx);
6346                                 }
6347                         }else if(condition.indexOf("n") == -1){
6348                                 var ncount = pi(condition);
6349                                 return function(elem){
6350                                         return (getNodeIndex(elem) == ncount);
6351                                 }
6352                         }
6353                 }
6354         };
6355
6356         var defaultGetter = (d.isIE) ? function(cond){
6357                 var clc = cond.toLowerCase();
6358                 return function(elem){
6359                         return elem[cond]||elem[clc];
6360                 }
6361         } : function(cond){
6362                 return function(elem){
6363                         return (elem && elem.getAttribute && elem.hasAttribute(cond));
6364                 }
6365         };
6366
6367         var getSimpleFilterFunc = function(query){
6368
6369                 var fcHit = (_simpleFiltersCache[query.query]||_filtersCache[query.query]);
6370                 if(fcHit){ return fcHit; }
6371
6372                 var ff = null;
6373
6374                 // the only case where we'll need the tag name is if we came from an ID query
6375                 if(query.id){ // do we have an ID component?
6376                         if(query.tag != "*"){
6377                                 ff = agree(ff, function(elem){
6378                                         return (elem.tagName.toLowerCase() == query.tag);
6379                                 });
6380                         }
6381                 }
6382
6383                 // if there's a class in our query, generate a match function for it
6384                 d.forEach(query.classes, function(cname, idx, arr){
6385                         // get the class name
6386                         var isWildcard = cname.charAt(cname.length-1) == "*";
6387                         if(isWildcard){
6388                                 cname = cname.substr(0, cname.length-1);
6389                         }
6390                         // I dislike the regex thing, even if memozied in a cache, but it's VERY short
6391                         var re = new RegExp("(?:^|\\s)" + cname + (isWildcard ? ".*" : "") + "(?:\\s|$)");
6392                         ff = agree(ff, function(elem){
6393                                 return re.test(elem.className);
6394                         });
6395                         ff.count = idx;
6396                 });
6397
6398                 d.forEach(query.pseudos, function(pseudo){
6399                         if(pseudos[pseudo.name]){
6400                                 ff = agree(ff, pseudos[pseudo.name](pseudo.name, pseudo.value));
6401                         }
6402                 });
6403
6404                 handleAttrs(attrs, query, defaultGetter,
6405                         function(tmatcher){ ff = agree(ff, tmatcher); }
6406                 );
6407                 if(!ff){
6408                         ff = function(){ return true; };
6409                 }
6410                 return _simpleFiltersCache[query.query] = ff;
6411         }
6412
6413         var _getElementsFuncCache = { };
6414
6415         var getElementsFunc = function(query, root){
6416                 var fHit = _getElementsFuncCache[query.query];
6417                 if(fHit){ return fHit; }
6418
6419                 // NOTE: this function is in the fast path! not memoized!!!
6420
6421                 // the query doesn't contain any spaces, so there's only so many
6422                 // things it could be
6423
6424                 if(query.id && !query.hasLoops && !query.tag){
6425                         // ID-only query. Easy.
6426                         return _getElementsFuncCache[query.query] = function(root){
6427                                 // FIXME: if root != document, check for parenting!
6428                                 return [ d.byId(query.id) ];
6429                         }
6430                 }
6431
6432                 var filterFunc = getSimpleFilterFunc(query);
6433
6434                 var retFunc;
6435                 if(query.tag && query.id && !query.hasLoops){
6436                         // we got a filtered ID search (e.g., "h4#thinger")
6437                         retFunc = function(root){
6438                                 var te = d.byId(query.id);
6439                                 if(filterFunc(te)){
6440                                         return [ te ];
6441                                 }
6442                         }
6443                 }else{
6444                         var tret;
6445
6446                         if(!query.hasLoops){
6447                                 // it's just a plain-ol elements-by-tag-name query from the root
6448                                 retFunc = function(root){
6449                                         var ret = [];
6450                                         var te, x=0, tret = root.getElementsByTagName(query.tag);
6451                                         while(te=tret[x++]){
6452                                                 ret.push(te);
6453                                         }
6454                                         return ret;
6455                                 }
6456                         }else{
6457                                 retFunc = function(root){
6458                                         var ret = [];
6459                                         var te, x=0, tret = root.getElementsByTagName(query.tag);
6460                                         while(te=tret[x++]){
6461                                                 if(filterFunc(te)){
6462                                                         ret.push(te);
6463                                                 }
6464                                         }
6465                                         return ret;
6466                                 }
6467                         }
6468                 }
6469                 return _getElementsFuncCache[query.query] = retFunc;
6470         }
6471
6472         var _partsCache = {};
6473
6474         ////////////////////////////////////////////////////////////////////////
6475         // the query runner
6476         ////////////////////////////////////////////////////////////////////////
6477
6478         // this is the second level of spliting, from full-length queries (e.g.,
6479         // "div.foo .bar") into simple query expressions (e.g., ["div.foo",
6480         // ".bar"])
6481         var _queryFuncCache = {
6482                 "*": d.isIE ? 
6483                         function(root){ 
6484                                         return root.all;
6485                         } : 
6486                         function(root){
6487                                  return root.getElementsByTagName("*");
6488                         },
6489                 "~": _nextSiblings,
6490                 "+": function(root){ return _nextSiblings(root, true); },
6491                 ">": _childElements
6492         };
6493
6494         var getStepQueryFunc = function(query){
6495                 // if it's trivial, get a fast-path dispatcher
6496                 var qparts = getQueryParts(d.trim(query));
6497                 // if(query[query.length-1] == ">"){ query += " *"; }
6498                 if(qparts.length == 1){
6499                         var tt = getElementsFunc(qparts[0]);
6500                         tt.nozip = true;
6501                         return tt;
6502                 }
6503
6504                 // otherwise, break it up and return a runner that iterates over the parts recursively
6505                 var sqf = function(root){
6506                         var localQueryParts = qparts.slice(0); // clone the src arr
6507                         var candidates;
6508                         if(localQueryParts[0].oper == ">"){ // FIXME: what if it's + or ~?
6509                                 candidates = [ root ];
6510                                 // root = document;
6511                         }else{
6512                                 candidates = getElementsFunc(localQueryParts.shift())(root);
6513                         }
6514                         return filterDown(candidates, localQueryParts);
6515                 }
6516                 return sqf;
6517         }
6518
6519         // a specialized method that implements our primoridal "query optimizer".
6520         // This allows us to dispatch queries to the fastest subsystem we can get.
6521         var _getQueryFunc = (
6522                 // NOTE: 
6523                 //              XPath on the Webkit nighlies is slower than it's DOM iteration
6524                 //              for most test cases
6525                 // FIXME: 
6526                 //              we should try to capture some runtime speed data for each query
6527                 //              function to determine on the fly if we should stick w/ the
6528                 //              potentially optimized variant or if we should try something
6529                 //              new.
6530                 (document["evaluate"] && !d.isSafari) ? 
6531                 function(query){
6532                         // has xpath support that's faster than DOM
6533                         var qparts = query.split(" ");
6534                         // can we handle it?
6535                         if(     (document["evaluate"])&&
6536                                 (query.indexOf(":") == -1)&&
6537                                 (query.indexOf("+") == -1) // skip direct sibling matches. See line ~344
6538                         ){
6539                                 // dojo.debug(query);
6540                                 // should we handle it?
6541
6542                                 // kind of a lame heuristic, but it works
6543                                 if(     
6544                                         // a "div div div" style query
6545                                         ((qparts.length > 2)&&(query.indexOf(">") == -1))||
6546                                         // or something else with moderate complexity. kinda janky
6547                                         (qparts.length > 3)||
6548                                         (query.indexOf("[")>=0)||
6549                                         // or if it's a ".thinger" query
6550                                         ((1 == qparts.length)&&(0 <= query.indexOf(".")))
6551
6552                                 ){
6553                                         // use get and cache a xpath runner for this selector
6554                                         return getXPathFunc(query);
6555                                 }
6556                         }
6557
6558                         // fallthrough
6559                         return getStepQueryFunc(query);
6560                 } : getStepQueryFunc
6561         );
6562         // uncomment to disable XPath for testing and tuning the DOM path
6563         // _getQueryFunc = getStepQueryFunc;
6564
6565         // FIXME: we've got problems w/ the NodeList query()/filter() functions if we go XPath for everything
6566
6567         // uncomment to disable DOM queries for testing and tuning XPath
6568         // _getQueryFunc = getXPathFunc;
6569
6570         // this is the primary caching for full-query results. The query dispatcher
6571         // functions are generated here and then pickled for hash lookup in the
6572         // future
6573         var getQueryFunc = function(query){
6574                 // return a cached version if one is available
6575                 var qcz = query.charAt(0);
6576                 if(d.doc["querySelectorAll"] && 
6577                         ( (!d.isSafari) || (d.isSafari > 3.1) ) && // see #5832
6578                         // as per CSS 3, we can't currently start w/ combinator:
6579                         //              http://www.w3.org/TR/css3-selectors/#w3cselgrammar
6580                         (">+~".indexOf(qcz) == -1)
6581                 ){
6582                         return function(root){
6583                                 var r = root.querySelectorAll(query);
6584                                 r.nozip = true; // skip expensive duplication checks and just wrap in a NodeList
6585                                 return r;
6586                         };
6587                 }
6588                 if(_queryFuncCache[query]){ return _queryFuncCache[query]; }
6589                 if(0 > query.indexOf(",")){
6590                         // if it's not a compound query (e.g., ".foo, .bar"), cache and return a dispatcher
6591                         return _queryFuncCache[query] = _getQueryFunc(query);
6592                 }else{
6593                         // if it's a complex query, break it up into it's constituent parts
6594                         // and return a dispatcher that will merge the parts when run
6595
6596                         // var parts = query.split(", ");
6597                         var parts = query.split(/\s*,\s*/);
6598                         var tf = function(root){
6599                                 var pindex = 0; // avoid array alloc for every invocation
6600                                 var ret = [];
6601                                 var tp;
6602                                 while(tp = parts[pindex++]){
6603                                         ret = ret.concat(_getQueryFunc(tp, tp.indexOf(" "))(root));
6604                                 }
6605                                 return ret;
6606                         }
6607                         // ...cache and return
6608                         return _queryFuncCache[query] = tf;
6609                 }
6610         }
6611
6612         // FIXME: 
6613         //              Dean's Base2 uses a system whereby queries themselves note if
6614         //              they'll need duplicate filtering. We need to get on that plan!!
6615
6616         // attempt to efficiently determine if an item in a list is a dupe,
6617         // returning a list of "uniques", hopefully in doucment order
6618         var _zipIdx = 0;
6619         var _zip = function(arr){
6620                 if(arr && arr.nozip){ return d.NodeList._wrap(arr); }
6621                 var ret = new d.NodeList();
6622                 if(!arr){ return ret; }
6623                 if(arr[0]){
6624                         ret.push(arr[0]);
6625                 }
6626                 if(arr.length < 2){ return ret; }
6627                 _zipIdx++;
6628                 arr[0]["_zipIdx"] = _zipIdx;
6629                 for(var x=1, te; te = arr[x]; x++){
6630                         if(arr[x]["_zipIdx"] != _zipIdx){ 
6631                                 ret.push(te);
6632                         }
6633                         te["_zipIdx"] = _zipIdx;
6634                 }
6635                 // FIXME: should we consider stripping these properties?
6636                 return ret;
6637         }
6638
6639         // the main executor
6640         d.query = function(/*String*/ query, /*String|DOMNode?*/ root){
6641                 //      summary:
6642                 //              Returns nodes which match the given CSS3 selector, searching the
6643                 //              entire document by default but optionally taking a node to scope
6644                 //              the search by. Returns an instance of dojo.NodeList.
6645                 //      description:
6646                 //              dojo.query() is the swiss army knife of DOM node manipulation in
6647                 //              Dojo. Much like Prototype's "$$" (bling-bling) function or JQuery's
6648                 //              "$" function, dojo.query provides robust, high-performance
6649                 //              CSS-based node selector support with the option of scoping searches
6650                 //              to a particular sub-tree of a document.
6651                 //
6652                 //              Supported Selectors:
6653                 //              --------------------
6654                 //
6655                 //              dojo.query() supports a rich set of CSS3 selectors, including:
6656                 //
6657                 //                      * class selectors (e.g., `.foo`)
6658                 //                      * node type selectors like `span`
6659                 //                      * ` ` descendant selectors
6660                 //                      * `>` child element selectors 
6661                 //                      * `#foo` style ID selectors
6662                 //                      * `*` universal selector
6663                 //                      * `~`, the immediately preceeded-by sibling selector
6664                 //                      * `+`, the preceeded-by sibling selector
6665                 //                      * attribute queries:
6666                 //                      |       * `[foo]` attribute presence selector
6667                 //                      |       * `[foo='bar']` attribute value exact match
6668                 //                      |       * `[foo~='bar']` attribute value list item match
6669                 //                      |       * `[foo^='bar']` attribute start match
6670                 //                      |       * `[foo$='bar']` attribute end match
6671                 //                      |       * `[foo*='bar']` attribute substring match
6672                 //                      * `:first-child`, `:last-child` positional selectors
6673                 //                      * `:empty` content emtpy selector
6674                 //                      * `:empty` content emtpy selector
6675                 //                      * `:nth-child(n)`, `:nth-child(2n+1)` style positional calculations
6676                 //                      * `:nth-child(even)`, `:nth-child(odd)` positional selectors
6677                 //                      * `:not(...)` negation pseudo selectors
6678                 //
6679                 //              Any legal combination of these selectors will work with
6680                 //              `dojo.query()`, including compound selectors ("," delimited).
6681                 //              Very complex and useful searches can be constructed with this
6682                 //              palette of selectors and when combined with functions for
6683                 //              maniplation presented by dojo.NodeList, many types of DOM
6684                 //              manipulation operations become very straightforward.
6685                 //              
6686                 //              Unsupported Selectors:
6687                 //              ----------------------
6688                 //
6689                 //              While dojo.query handles many CSS3 selectors, some fall outside of
6690                 //              what's resaonable for a programmatic node querying engine to
6691                 //              handle. Currently unsupported selectors include:
6692                 //              
6693                 //                      * namespace-differentiated selectors of any form
6694                 //                      * all `::` pseduo-element selectors
6695                 //                      * certain pseduo-selectors which don't get a lot of day-to-day use:
6696                 //                      |       * `:root`, `:lang()`, `:target`, `:focus`
6697                 //                      * all visual and state selectors:
6698                 //                      |       * `:root`, `:active`, `:hover`, `:visisted`, `:link`,
6699                 //                                `:enabled`, `:disabled`, `:checked`
6700                 //                      * `:*-of-type` pseudo selectors
6701                 //              
6702                 //              dojo.query and XML Documents:
6703                 //              -----------------------------
6704                 //              
6705                 //              `dojo.query` currently only supports searching XML documents
6706                 //              whose tags and attributes are 100% lower-case. This is a known
6707                 //              limitation and will [be addressed soon](http://trac.dojotoolkit.org/ticket/3866)
6708                 //              Non-selector Queries:
6709                 //              ---------------------
6710                 //
6711                 //              If something other than a String is passed for the query,
6712                 //              `dojo.query` will return a new `dojo.NodeList` constructed from
6713                 //              that parameter alone and all further processing will stop. This
6714                 //              means that if you have a reference to a node or NodeList, you
6715                 //              can quickly construct a new NodeList from the original by
6716                 //              calling `dojo.query(node)` or `dojo.query(list)`.
6717                 //
6718                 //      query:
6719                 //              The CSS3 expression to match against. For details on the syntax of
6720                 //              CSS3 selectors, see <http://www.w3.org/TR/css3-selectors/#selectors>
6721                 //      root:
6722                 //              A DOMNode (or node id) to scope the search from. Optional.
6723                 //      returns: dojo.NodeList
6724                 //              An instance of `dojo.NodeList`. Many methods are available on
6725                 //              NodeLists for searching, iterating, manipulating, and handling
6726                 //              events on the matched nodes in the returned list.
6727                 //      example:
6728                 //              search the entire document for elements with the class "foo":
6729                 //      |       dojo.query(".foo");
6730                 //              these elements will match:
6731                 //      |       <span class="foo"></span>
6732                 //      |       <span class="foo bar"></span>
6733                 //      |       <p class="thud foo"></p>
6734                 //      example:
6735                 //              search the entire document for elements with the classes "foo" *and* "bar":
6736                 //      |       dojo.query(".foo.bar");
6737                 //              these elements will match:
6738                 //      |       <span class="foo bar"></span>
6739                 //              while these will not:
6740                 //      |       <span class="foo"></span>
6741                 //      |       <p class="thud foo"></p>
6742                 //      example:
6743                 //              find `<span>` elements which are descendants of paragraphs and
6744                 //              which have a "highlighted" class:
6745                 //      |       dojo.query("p span.highlighted");
6746                 //              the innermost span in this fragment matches:
6747                 //      |       <p class="foo">
6748                 //      |               <span>...
6749                 //      |                       <span class="highlighted foo bar">...</span>
6750                 //      |               </span>
6751                 //      |       </p>
6752                 //      example:
6753                 //              set an "odd" class on all odd table rows inside of the table
6754                 //              `#tabular_data`, using the `>` (direct child) selector to avoid
6755                 //              affecting any nested tables:
6756                 //      |       dojo.query("#tabular_data > tbody > tr:nth-child(odd)").addClass("odd");
6757                 //      example:
6758                 //              remove all elements with the class "error" from the document
6759                 //              and store them in a list:
6760                 //      |       var errors = dojo.query(".error").orphan();
6761                 //      example:
6762                 //              add an onclick handler to every submit button in the document
6763                 //              which causes the form to be sent via Ajax instead:
6764                 //      |       dojo.query("input[type='submit']").onclick(function(e){
6765                 //      |               dojo.stopEvent(e); // prevent sending the form
6766                 //      |               var btn = e.target;
6767                 //      |               dojo.xhrPost({
6768                 //      |                       form: btn.form,
6769                 //      |                       load: function(data){
6770                 //      |                               // replace the form with the response
6771                 //      |                               var div = dojo.doc.createElement("div");
6772                 //      |                               dojo.place(div, btn.form, "after");
6773                 //      |                               div.innerHTML = data;
6774                 //      |                               dojo.style(btn.form, "display", "none");
6775                 //      |                       }
6776                 //      |               });
6777                 //      |       });
6778
6779
6780                 // NOTE: elementsById is not currently supported
6781                 // NOTE: ignores xpath-ish queries for now
6782
6783                 if(query.constructor == d.NodeList){
6784                         return query;
6785                 }
6786                 if(!d.isString(query)){
6787                         return new d.NodeList(query); // dojo.NodeList
6788                 }
6789                 if(d.isString(root)){
6790                         root = d.byId(root);
6791                 }
6792
6793                 return _zip(getQueryFunc(query)(root||d.doc)); // dojo.NodeList
6794         }
6795
6796         /*
6797         // exposing this was a mistake
6798         d.query.attrs = attrs;
6799         */
6800         // exposing this because new pseudo matches are only executed through the
6801         // DOM query path (never through the xpath optimizing branch)
6802         d.query.pseudos = pseudos;
6803
6804         // one-off function for filtering a NodeList based on a simple selector
6805         d._filterQueryResult = function(nodeList, simpleFilter){
6806                 var tnl = new d.NodeList();
6807                 var ff = (simpleFilter) ? getFilterFunc(getQueryParts(simpleFilter)[0]) : function(){ return true; };
6808                 for(var x=0, te; te = nodeList[x]; x++){
6809                         if(ff(te)){ tnl.push(te); }
6810                 }
6811                 return tnl;
6812         }
6813 })();
6814
6815 }
6816
6817 if(!dojo._hasResource["dojo._base.xhr"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
6818 dojo._hasResource["dojo._base.xhr"] = true;
6819 dojo.provide("dojo._base.xhr");
6820
6821
6822
6823
6824
6825 (function(){
6826         var _d = dojo;
6827         function setValue(/*Object*/obj, /*String*/name, /*String*/value){
6828                 //summary:
6829                 //              For the nameed property in object, set the value. If a value
6830                 //              already exists and it is a string, convert the value to be an
6831                 //              array of values.
6832                 var val = obj[name];
6833                 if(_d.isString(val)){
6834                         obj[name] = [val, value];
6835                 }else if(_d.isArray(val)){
6836                         val.push(value);
6837                 }else{
6838                         obj[name] = value;
6839                 }
6840         }
6841
6842         dojo.formToObject = function(/*DOMNode||String*/ formNode){
6843                 // summary:
6844                 //              dojo.formToObject returns the values encoded in an HTML form as
6845                 //              string properties in an object which it then returns. Disabled form
6846                 //              elements, buttons, and other non-value form elements are skipped.
6847                 //              Multi-select elements are returned as an array of string values.
6848                 // description:
6849                 //              This form:
6850                 //
6851                 //              |       <form id="test_form">
6852                 //              |               <input type="text" name="blah" value="blah">
6853                 //              |               <input type="text" name="no_value" value="blah" disabled>
6854                 //              |               <input type="button" name="no_value2" value="blah">
6855                 //              |               <select type="select" multiple name="multi" size="5">
6856                 //              |                       <option value="blah">blah</option>
6857                 //              |                       <option value="thud" selected>thud</option>
6858                 //              |                       <option value="thonk" selected>thonk</option>
6859                 //              |               </select>
6860                 //              |       </form>
6861                 //
6862                 //              yields this object structure as the result of a call to
6863                 //              formToObject():
6864                 //
6865                 //              |       { 
6866                 //              |               blah: "blah",
6867                 //              |               multi: [
6868                 //              |                       "thud",
6869                 //              |                       "thonk"
6870                 //              |               ]
6871                 //              |       };
6872         
6873                 var ret = {};
6874                 var iq = "input:not([type=file]):not([type=submit]):not([type=image]):not([type=reset]):not([type=button]), select, textarea";
6875                 _d.query(iq, formNode).filter(function(node){
6876                         return !node.disabled && node.name;
6877                 }).forEach(function(item){
6878                         var _in = item.name;
6879                         var type = (item.type||"").toLowerCase();
6880                         if(type == "radio" || type == "checkbox"){
6881                                 if(item.checked){ setValue(ret, _in, item.value); }
6882                         }else if(item.multiple){
6883                                 ret[_in] = [];
6884                                 _d.query("option", item).forEach(function(opt){
6885                                         if(opt.selected){
6886                                                 setValue(ret, _in, opt.value);
6887                                         }
6888                                 });
6889                         }else{ 
6890                                 setValue(ret, _in, item.value);
6891                                 if(type == "image"){
6892                                         ret[_in+".x"] = ret[_in+".y"] = ret[_in].x = ret[_in].y = 0;
6893                                 }
6894                         }
6895                 });
6896                 return ret; // Object
6897         }
6898
6899         dojo.objectToQuery = function(/*Object*/ map){
6900                 //      summary:
6901                 //              takes a name/value mapping object and returns a string representing
6902                 //              a URL-encoded version of that object.
6903                 //      example:
6904                 //              this object:
6905                 //
6906                 //              |       { 
6907                 //              |               blah: "blah",
6908                 //              |               multi: [
6909                 //              |                       "thud",
6910                 //              |                       "thonk"
6911                 //              |               ]
6912                 //              |       };
6913                 //
6914                 //      yields the following query string:
6915                 //      
6916                 //      |       "blah=blah&multi=thud&multi=thonk"
6917
6918                 // FIXME: need to implement encodeAscii!!
6919                 var enc = encodeURIComponent;
6920                 var pairs = [];
6921                 var backstop = {};
6922                 for(var name in map){
6923                         var value = map[name];
6924                         if(value != backstop[name]){
6925                                 var assign = enc(name) + "=";
6926                                 if(_d.isArray(value)){
6927                                         for(var i=0; i < value.length; i++){
6928                                                 pairs.push(assign + enc(value[i]));
6929                                         }
6930                                 }else{
6931                                         pairs.push(assign + enc(value));
6932                                 }
6933                         }
6934                 }
6935                 return pairs.join("&"); // String
6936         }
6937
6938         dojo.formToQuery = function(/*DOMNode||String*/ formNode){
6939                 // summary:
6940                 //              Returns a URL-encoded string representing the form passed as either a
6941                 //              node or string ID identifying the form to serialize
6942                 return _d.objectToQuery(_d.formToObject(formNode)); // String
6943         }
6944
6945         dojo.formToJson = function(/*DOMNode||String*/ formNode, /*Boolean?*/prettyPrint){
6946                 // summary:
6947                 //              return a serialized JSON string from a form node or string
6948                 //              ID identifying the form to serialize
6949                 return _d.toJson(_d.formToObject(formNode), prettyPrint); // String
6950         }
6951
6952         dojo.queryToObject = function(/*String*/ str){
6953                 // summary:
6954                 //              returns an object representing a de-serialized query section of a
6955                 //              URL. Query keys with multiple values are returned in an array.
6956                 // description:
6957                 //              This string:
6958                 //
6959                 //      |               "foo=bar&foo=baz&thinger=%20spaces%20=blah&zonk=blarg&"
6960                 //              
6961                 //              results in this object structure:
6962                 //
6963                 //      |               {
6964                 //      |                       foo: [ "bar", "baz" ],
6965                 //      |                       thinger: " spaces =blah",
6966                 //      |                       zonk: "blarg"
6967                 //      |               }
6968                 //      
6969                 //              Note that spaces and other urlencoded entities are correctly
6970                 //              handled.
6971
6972                 // FIXME: should we grab the URL string if we're not passed one?
6973                 var ret = {};
6974                 var qp = str.split("&");
6975                 var dec = decodeURIComponent;
6976                 _d.forEach(qp, function(item){
6977                         if(item.length){
6978                                 var parts = item.split("=");
6979                                 var name = dec(parts.shift());
6980                                 var val = dec(parts.join("="));
6981                                 if(_d.isString(ret[name])){
6982                                         ret[name] = [ret[name]];
6983                                 }
6984                                 if(_d.isArray(ret[name])){
6985                                         ret[name].push(val);
6986                                 }else{
6987                                         ret[name] = val;
6988                                 }
6989                         }
6990                 });
6991                 return ret; // Object
6992         }
6993
6994         /*
6995                 from refactor.txt:
6996
6997                 all bind() replacement APIs take the following argument structure:
6998
6999                         {
7000                                 url: "blah.html",
7001
7002                                 // all below are optional, but must be supported in some form by
7003                                 // every IO API
7004                                 timeout: 1000, // milliseconds
7005                                 handleAs: "text", // replaces the always-wrong "mimetype"
7006                                 content: { 
7007                                         key: "value"
7008                                 },
7009
7010                                 // browser-specific, MAY be unsupported
7011                                 sync: true, // defaults to false
7012                                 form: dojo.byId("someForm") 
7013                         }
7014         */
7015
7016         // need to block async callbacks from snatching this thread as the result
7017         // of an async callback might call another sync XHR, this hangs khtml forever
7018         // must checked by watchInFlight()
7019
7020         dojo._blockAsync = false;
7021
7022         dojo._contentHandlers = {
7023                 "text": function(xhr){ return xhr.responseText; },
7024                 "json": function(xhr){
7025                         if(!dojo.config.usePlainJson){
7026                                 console.warn("Consider using mimetype:text/json-comment-filtered"
7027                                         + " to avoid potential security issues with JSON endpoints"
7028                                         + " (use djConfig.usePlainJson=true to turn off this message)");
7029                         }
7030                         return (xhr.status == 204) ? undefined : _d.fromJson(xhr.responseText);
7031                 },
7032                 "json-comment-filtered": function(xhr){ 
7033                         // NOTE: we provide the json-comment-filtered option as one solution to
7034                         // the "JavaScript Hijacking" issue noted by Fortify and others. It is
7035                         // not appropriate for all circumstances.
7036
7037                         var value = xhr.responseText;
7038                         var cStartIdx = value.indexOf("\/*");
7039                         var cEndIdx = value.lastIndexOf("*\/");
7040                         if(cStartIdx == -1 || cEndIdx == -1){
7041                                 throw new Error("JSON was not comment filtered");
7042                         }
7043                         return (xhr.status == 204) ? undefined :
7044                                 _d.fromJson(value.substring(cStartIdx+2, cEndIdx));
7045                 },
7046                 "javascript": function(xhr){ 
7047                         // FIXME: try Moz and IE specific eval variants?
7048                         return _d.eval(xhr.responseText);
7049                 },
7050                 "xml": function(xhr){ 
7051                         var result = xhr.responseXML;
7052                         if(_d.isIE && (!result || window.location.protocol == "file:")){
7053                                 _d.forEach(["MSXML2", "Microsoft", "MSXML", "MSXML3"], function(prefix){
7054                                         try{
7055                                                 var dom = new ActiveXObject(prefix + ".XMLDOM");
7056                                                 dom.async = false;
7057                                                 dom.loadXML(xhr.responseText);
7058                                                 result = dom;
7059                                         }catch(e){ /* Not available. Squelch and try next one. */ }
7060                                 });
7061                         }
7062                         return result; // DOMDocument
7063                 }
7064         };
7065
7066         dojo._contentHandlers["json-comment-optional"] = function(xhr){
7067                 var handlers = _d._contentHandlers;
7068                 try{
7069                         return handlers["json-comment-filtered"](xhr);
7070                 }catch(e){
7071                         return handlers["json"](xhr);
7072                 }
7073         };
7074
7075         /*=====
7076         dojo.__IoArgs = function(){
7077                 //      url: String
7078                 //              URL to server endpoint.
7079                 //      content: Object?
7080                 //              Contains properties with string values. These
7081                 //              properties will be serialized as name1=value2 and
7082                 //              passed in the request.
7083                 //      timeout: Integer?
7084                 //              Milliseconds to wait for the response. If this time
7085                 //              passes, the then error callbacks are called.
7086                 //      form: DOMNode?
7087                 //              DOM node for a form. Used to extract the form values
7088                 //              and send to the server.
7089                 //      preventCache: Boolean?
7090                 //              Default is false. If true, then a
7091                 //              "dojo.preventCache" parameter is sent in the request
7092                 //              with a value that changes with each request
7093                 //              (timestamp). Useful only with GET-type requests.
7094                 //      handleAs: String?
7095                 //              Acceptable values depend on the type of IO
7096                 //              transport (see specific IO calls for more information).
7097                 //      load: Function?
7098                 //              function(response, ioArgs){}. response is an Object, ioArgs
7099                 //              is of type dojo.__IoCallbackArgs. The load function will be
7100                 //              called on a successful response.
7101                 //      error: Function?
7102                 //              function(response, ioArgs){}. response is an Object, ioArgs
7103                 //              is of type dojo.__IoCallbackArgs. The error function will
7104                 //              be called in an error case. 
7105                 //      handle: Function?
7106                 //              function(response, ioArgs){}. response is an Object, ioArgs
7107                 //              is of type dojo.__IoCallbackArgs. The handle function will
7108                 //              be called in either the successful or error case.  For
7109                 //              the load, error and handle functions, the ioArgs object
7110                 //              will contain the following properties: 
7111                 this.url = url;
7112                 this.content = content;
7113                 this.timeout = timeout;
7114                 this.form = form;
7115                 this.preventCache = preventCache;
7116                 this.handleAs = handleAs;
7117                 this.load = load;
7118                 this.error = error;
7119                 this.handle = handle;
7120         }
7121         =====*/
7122
7123         /*=====
7124         dojo.__IoCallbackArgs = function(args, xhr, url, query, handleAs, id, canDelete, json){
7125                 //      args: Object
7126                 //              the original object argument to the IO call.
7127                 //      xhr: XMLHttpRequest
7128                 //              For XMLHttpRequest calls only, the
7129                 //              XMLHttpRequest object that was used for the
7130                 //              request.
7131                 //      url: String
7132                 //              The final URL used for the call. Many times it
7133                 //              will be different than the original args.url
7134                 //              value.
7135                 //      query: String
7136                 //              For non-GET requests, the
7137                 //              name1=value1&name2=value2 parameters sent up in
7138                 //              the request.
7139                 //      handleAs: String
7140                 //              The final indicator on how the response will be
7141                 //              handled.
7142                 //      id: String
7143                 //              For dojo.io.script calls only, the internal
7144                 //              script ID used for the request.
7145                 //      canDelete: Boolean
7146                 //              For dojo.io.script calls only, indicates
7147                 //              whether the script tag that represents the
7148                 //              request can be deleted after callbacks have
7149                 //              been called. Used internally to know when
7150                 //              cleanup can happen on JSONP-type requests.
7151                 //      json: Object
7152                 //              For dojo.io.script calls only: holds the JSON
7153                 //              response for JSONP-type requests. Used
7154                 //              internally to hold on to the JSON responses.
7155                 //              You should not need to access it directly --
7156                 //              the same object should be passed to the success
7157                 //              callbacks directly.
7158                 this.args = args;
7159                 this.xhr = xhr;
7160                 this.url = url;
7161                 this.query = query;
7162                 this.handleAs = handleAs;
7163                 this.id = id;
7164                 this.canDelete = canDelete;
7165                 this.json = json;
7166         }
7167         =====*/
7168
7169
7170
7171         dojo._ioSetArgs = function(/*dojo.__IoArgs*/args,
7172                         /*Function*/canceller,
7173                         /*Function*/okHandler,
7174                         /*Function*/errHandler){
7175                 //      summary: 
7176                 //              sets up the Deferred and ioArgs property on the Deferred so it
7177                 //              can be used in an io call.
7178                 //      args:
7179                 //              The args object passed into the public io call. Recognized properties on
7180                 //              the args object are:
7181                 //      canceller:
7182                 //              The canceller function used for the Deferred object. The function
7183                 //              will receive one argument, the Deferred object that is related to the
7184                 //              canceller.
7185                 //      okHandler:
7186                 //              The first OK callback to be registered with Deferred. It has the opportunity
7187                 //              to transform the OK response. It will receive one argument -- the Deferred
7188                 //              object returned from this function.
7189                 //      errHandler:
7190                 //              The first error callback to be registered with Deferred. It has the opportunity
7191                 //              to do cleanup on an error. It will receive two arguments: error (the 
7192                 //              Error object) and dfd, the Deferred object returned from this function.
7193
7194                 var ioArgs = {args: args, url: args.url};
7195
7196                 //Get values from form if requestd.
7197                 var formObject = null;
7198                 if(args.form){ 
7199                         var form = _d.byId(args.form);
7200                         //IE requires going through getAttributeNode instead of just getAttribute in some form cases, 
7201                         //so use it for all.  See #2844
7202                         var actnNode = form.getAttributeNode("action");
7203                         ioArgs.url = ioArgs.url || (actnNode ? actnNode.value : null); 
7204                         formObject = _d.formToObject(form);
7205                 }
7206
7207                 // set up the query params
7208                 var miArgs = [{}];
7209         
7210                 if(formObject){
7211                         // potentially over-ride url-provided params w/ form values
7212                         miArgs.push(formObject);
7213                 }
7214                 if(args.content){
7215                         // stuff in content over-rides what's set by form
7216                         miArgs.push(args.content);
7217                 }
7218                 if(args.preventCache){
7219                         miArgs.push({"dojo.preventCache": new Date().valueOf()});
7220                 }
7221                 ioArgs.query = _d.objectToQuery(_d.mixin.apply(null, miArgs));
7222         
7223                 // .. and the real work of getting the deferred in order, etc.
7224                 ioArgs.handleAs = args.handleAs || "text";
7225                 var d = new _d.Deferred(canceller);
7226                 d.addCallbacks(okHandler, function(error){
7227                         return errHandler(error, d);
7228                 });
7229
7230                 //Support specifying load, error and handle callback functions from the args.
7231                 //For those callbacks, the "this" object will be the args object.
7232                 //The callbacks will get the deferred result value as the
7233                 //first argument and the ioArgs object as the second argument.
7234                 var ld = args.load;
7235                 if(ld && _d.isFunction(ld)){
7236                         d.addCallback(function(value){
7237                                 return ld.call(args, value, ioArgs);
7238                         });
7239                 }
7240                 var err = args.error;
7241                 if(err && _d.isFunction(err)){
7242                         d.addErrback(function(value){
7243                                 return err.call(args, value, ioArgs);
7244                         });
7245                 }
7246                 var handle = args.handle;
7247                 if(handle && _d.isFunction(handle)){
7248                         d.addBoth(function(value){
7249                                 return handle.call(args, value, ioArgs);
7250                         });
7251                 }
7252                 
7253                 d.ioArgs = ioArgs;
7254         
7255                 // FIXME: need to wire up the xhr object's abort method to something
7256                 // analagous in the Deferred
7257                 return d;
7258         }
7259
7260         var _deferredCancel = function(/*Deferred*/dfd){
7261                 //summary: canceller function for dojo._ioSetArgs call.
7262                 
7263                 dfd.canceled = true;
7264                 var xhr = dfd.ioArgs.xhr;
7265                 var _at = typeof xhr.abort;
7266                 if(_at == "function" || _at == "unknown"){
7267                         xhr.abort();
7268                 }
7269                 var err = new Error("xhr cancelled");
7270                 err.dojoType = "cancel";
7271                 return err;
7272         }
7273         var _deferredOk = function(/*Deferred*/dfd){
7274                 //summary: okHandler function for dojo._ioSetArgs call.
7275
7276                 return _d._contentHandlers[dfd.ioArgs.handleAs](dfd.ioArgs.xhr);
7277         }
7278         var _deferError = function(/*Error*/error, /*Deferred*/dfd){
7279                 //summary: errHandler function for dojo._ioSetArgs call.
7280                 
7281                 // console.debug("xhr error in:", dfd.ioArgs.xhr);
7282                 console.debug(error);
7283                 return error;
7284         }
7285
7286         var _makeXhrDeferred = function(/*dojo.__XhrArgs*/args){
7287                 //summary: makes the Deferred object for this xhr request.
7288                 var dfd = _d._ioSetArgs(args, _deferredCancel, _deferredOk, _deferError);
7289                 //Pass the args to _xhrObj, to allow xhr iframe proxy interceptions.
7290                 dfd.ioArgs.xhr = _d._xhrObj(dfd.ioArgs.args);
7291                 return dfd;
7292         }
7293
7294         // avoid setting a timer per request. It degrades performance on IE
7295         // something fierece if we don't use unified loops.
7296         var _inFlightIntvl = null;
7297         var _inFlight = [];
7298         var _watchInFlight = function(){
7299                 //summary: 
7300                 //              internal method that checks each inflight XMLHttpRequest to see
7301                 //              if it has completed or if the timeout situation applies.
7302                 
7303                 var now = (new Date()).getTime();
7304                 // make sure sync calls stay thread safe, if this callback is called
7305                 // during a sync call and this results in another sync call before the
7306                 // first sync call ends the browser hangs
7307                 if(!_d._blockAsync){
7308                         // we need manual loop because we often modify _inFlight (and therefore 'i') while iterating
7309                         // note: the second clause is an assigment on purpose, lint may complain
7310                         for(var i = 0, tif; i < _inFlight.length && (tif = _inFlight[i]); i++){
7311                                 var dfd = tif.dfd;
7312                                 try{
7313                                         if(!dfd || dfd.canceled || !tif.validCheck(dfd)){
7314                                                 _inFlight.splice(i--, 1); 
7315                                         }else if(tif.ioCheck(dfd)){
7316                                                 _inFlight.splice(i--, 1);
7317                                                 tif.resHandle(dfd);
7318                                         }else if(dfd.startTime){
7319                                                 //did we timeout?
7320                                                 if(dfd.startTime + (dfd.ioArgs.args.timeout || 0) < now){
7321                                                         _inFlight.splice(i--, 1);
7322                                                         var err = new Error("timeout exceeded");
7323                                                         err.dojoType = "timeout";
7324                                                         dfd.errback(err);
7325                                                         //Cancel the request so the io module can do appropriate cleanup.
7326                                                         dfd.cancel();
7327                                                 }
7328                                         }
7329                                 }catch(e){
7330                                         // FIXME: make sure we errback! (fixed?  remove console.debug?)
7331                                         console.debug(e);
7332                                         dfd.errback(new Error("_watchInFlightError!"));
7333                                 }
7334                         }
7335                 }
7336
7337                 if(!_inFlight.length){
7338                         clearInterval(_inFlightIntvl);
7339                         _inFlightIntvl = null;
7340                         return;
7341                 }
7342
7343         }
7344
7345         dojo._ioCancelAll = function(){
7346                 //summary: Cancels all pending IO requests, regardless of IO type
7347                 //(xhr, script, iframe).
7348                 try{
7349                         _d.forEach(_inFlight, function(i){
7350                                 i.dfd.cancel();
7351                         });
7352                 }catch(e){/*squelch*/}
7353         }
7354
7355         //Automatically call cancel all io calls on unload
7356         //in IE for trac issue #2357.
7357         if(_d.isIE){
7358                 _d.addOnUnload(_d._ioCancelAll);
7359         }
7360
7361         _d._ioWatch = function(/*Deferred*/dfd,
7362                 /*Function*/validCheck,
7363                 /*Function*/ioCheck,
7364                 /*Function*/resHandle){
7365                 //summary: watches the io request represented by dfd to see if it completes.
7366                 //dfd:
7367                 //              The Deferred object to watch.
7368                 //validCheck:
7369                 //              Function used to check if the IO request is still valid. Gets the dfd
7370                 //              object as its only argument.
7371                 //ioCheck:
7372                 //              Function used to check if basic IO call worked. Gets the dfd
7373                 //              object as its only argument.
7374                 //resHandle:
7375                 //              Function used to process response. Gets the dfd
7376                 //              object as its only argument.
7377                 if(dfd.ioArgs.args.timeout){
7378                         dfd.startTime = (new Date()).getTime();
7379                 }
7380                 _inFlight.push({dfd: dfd, validCheck: validCheck, ioCheck: ioCheck, resHandle: resHandle});
7381                 if(!_inFlightIntvl){
7382                         _inFlightIntvl = setInterval(_watchInFlight, 50);
7383                 }
7384                 _watchInFlight(); // handle sync requests
7385         }
7386
7387         var _defaultContentType = "application/x-www-form-urlencoded";
7388
7389         var _validCheck = function(/*Deferred*/dfd){
7390                 return dfd.ioArgs.xhr.readyState; //boolean
7391         }
7392         var _ioCheck = function(/*Deferred*/dfd){
7393                 return 4 == dfd.ioArgs.xhr.readyState; //boolean
7394         }
7395         var _resHandle = function(/*Deferred*/dfd){
7396                 var xhr = dfd.ioArgs.xhr;
7397                 if(_d._isDocumentOk(xhr)){
7398                         dfd.callback(dfd);
7399                 }else{
7400                         var err = new Error("Unable to load " + dfd.ioArgs.url + " status:" + xhr.status);
7401                         err.status = xhr.status;
7402                         err.responseText = xhr.responseText;
7403                         dfd.errback(err);
7404                 }
7405         }
7406
7407         var _doIt = function(/*String*/type, /*Deferred*/dfd){
7408                 // IE 6 is a steaming pile. It won't let you call apply() on the native function (xhr.open).
7409                 // workaround for IE6's apply() "issues"
7410                 var ioArgs = dfd.ioArgs;
7411                 var args = ioArgs.args;
7412                 var xhr = ioArgs.xhr;
7413                 xhr.open(type, ioArgs.url, args.sync !== true, args.user || undefined, args.password || undefined);
7414                 if(args.headers){
7415                         for(var hdr in args.headers){
7416                                 if(hdr.toLowerCase() === "content-type" && !args.contentType){
7417                                         args.contentType = args.headers[hdr];
7418                                 }else{
7419                                         xhr.setRequestHeader(hdr, args.headers[hdr]);
7420                                 }
7421                         }
7422                 }
7423                 // FIXME: is this appropriate for all content types?
7424                 xhr.setRequestHeader("Content-Type", args.contentType || _defaultContentType);
7425                 if(!args.headers || !args.headers["X-Requested-With"]){
7426                         xhr.setRequestHeader("X-Requested-With", "XMLHttpRequest");
7427                 }
7428                 // FIXME: set other headers here!
7429                 try{
7430                         xhr.send(ioArgs.query);
7431                 }catch(e){
7432                         dfd.cancel();
7433                 }
7434                 _d._ioWatch(dfd, _validCheck, _ioCheck, _resHandle);
7435                 xhr = null;
7436                 return dfd; //Deferred
7437         }
7438
7439         dojo._ioAddQueryToUrl = function(/*dojo.__IoCallbackArgs*/ioArgs){
7440                 //summary: Adds query params discovered by the io deferred construction to the URL.
7441                 //Only use this for operations which are fundamentally GET-type operations.
7442                 if(ioArgs.query.length){
7443                         ioArgs.url += (ioArgs.url.indexOf("?") == -1 ? "?" : "&") + ioArgs.query;
7444                         ioArgs.query = null;
7445                 }               
7446         }
7447
7448         /*=====
7449         dojo.declare("dojo.__XhrArgs", dojo.__IoArgs, {
7450                 constructor: function(){
7451                         //      summary:
7452                         //              In addition to the properties listed for the dojo._IoArgs type,
7453                         //              the following properties are allowed for dojo.xhr* methods.
7454                         //      handleAs: String?
7455                         //              Acceptable values are: text (default), json, json-comment-optional,
7456                         //              json-comment-filtered, javascript, xml
7457                         //      sync: Boolean?
7458                         //              false is default. Indicates whether the request should
7459                         //              be a synchronous (blocking) request.
7460                         //      headers: Object?
7461                         //              Additional HTTP headers to send in the request.
7462                         this.handleAs = handleAs;
7463                         this.sync = sync;
7464                         this.headers = headers;
7465                 }
7466         });
7467         =====*/
7468
7469         dojo.xhr = function(/*String*/ method, /*dojo.__XhrArgs*/ args, /*Boolean?*/ hasBody){
7470                 //      summary: 
7471                 //              Sends an HTTP request with the given method. If the request has an 
7472                 //              HTTP body, then pass true for hasBody. The method argument should be uppercase.
7473                 //              Also look at dojo.xhrGet(), xhrPost(), xhrPut() and dojo.xhrDelete() for shortcuts
7474                 //              for those HTTP methods. There are also methods for "raw" PUT and POST methods
7475                 //              via dojo.rawXhrPut() and dojo.rawXhrPost() respectively.
7476                 var dfd = _makeXhrDeferred(args);
7477                 if(!hasBody){
7478                         _d._ioAddQueryToUrl(dfd.ioArgs);
7479                 }
7480                 return _doIt(method, dfd); // dojo.Deferred
7481         }
7482
7483         dojo.xhrGet = function(/*dojo.__XhrArgs*/ args){
7484                 //      summary: 
7485                 //              Sends an HTTP GET request to the server.
7486                 return _d.xhr("GET", args); //dojo.Deferred
7487         }
7488
7489         dojo.xhrPost = function(/*dojo.__XhrArgs*/ args){
7490                 //summary: 
7491                 //              Sends an HTTP POST request to the server.
7492                 return _d.xhr("POST", args, true); // dojo.Deferred
7493         }
7494
7495         dojo.rawXhrPost = function(/*dojo.__XhrArgs*/ args){
7496                 //      summary:
7497                 //              Sends an HTTP POST request to the server. In addtion to the properties
7498                 //              listed for the dojo.__XhrArgs type, the following property is allowed:
7499                 //      postData:
7500                 //              String. The raw data to send in the body of the POST request.
7501                 var dfd = _makeXhrDeferred(args);
7502                 dfd.ioArgs.query = args.postData;
7503                 return _doIt("POST", dfd); // dojo.Deferred
7504         }
7505
7506         dojo.xhrPut = function(/*dojo.__XhrArgs*/ args){
7507                 //      summary:
7508                 //              Sends an HTTP PUT request to the server.
7509                 return _d.xhr("PUT", args, true); // dojo.Deferred
7510         }
7511
7512         dojo.rawXhrPut = function(/*dojo.__XhrArgs*/ args){
7513                 //      summary:
7514                 //              Sends an HTTP PUT request to the server. In addtion to the properties
7515                 //              listed for the dojo.__XhrArgs type, the following property is allowed:
7516                 //      putData:
7517                 //              String. The raw data to send in the body of the PUT request.
7518                 var dfd = _makeXhrDeferred(args);
7519                 var ioArgs = dfd.ioArgs;
7520                 if(args.putData){
7521                         ioArgs.query = args.putData;
7522                         args.putData = null;
7523                 }
7524                 return _doIt("PUT", dfd); // dojo.Deferred
7525         }
7526
7527         dojo.xhrDelete = function(/*dojo.__XhrArgs*/ args){
7528                 //      summary:
7529                 //              Sends an HTTP DELETE request to the server.
7530                 return _d.xhr("DELETE", args); //dojo.Deferred
7531         }
7532
7533         /*
7534         dojo.wrapForm = function(formNode){
7535                 //summary:
7536                 //              A replacement for FormBind, but not implemented yet.
7537
7538                 // FIXME: need to think harder about what extensions to this we might
7539                 // want. What should we allow folks to do w/ this? What events to
7540                 // set/send?
7541                 throw new Error("dojo.wrapForm not yet implemented");
7542         }
7543         */
7544 })();
7545
7546 }
7547
7548 if(!dojo._hasResource["dojo._base.fx"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
7549 dojo._hasResource["dojo._base.fx"] = true;
7550 dojo.provide("dojo._base.fx");
7551
7552
7553
7554
7555
7556
7557 /*
7558         Animation losely package based on Dan Pupius' work, contributed under CLA: 
7559                 http://pupius.co.uk/js/Toolkit.Drawing.js
7560 */
7561 (function(){ 
7562
7563         var d = dojo;
7564         
7565         dojo._Line = function(/*int*/ start, /*int*/ end){
7566                 //      summary:
7567                 //              dojo._Line is the object used to generate values from a start value
7568                 //              to an end value
7569                 //      start: int
7570                 //              Beginning value for range
7571                 //      end: int
7572                 //              Ending value for range
7573                 this.start = start;
7574                 this.end = end;
7575                 this.getValue = function(/*float*/ n){
7576                         //      summary: returns the point on the line
7577                         //      n: a floating point number greater than 0 and less than 1
7578                         return ((this.end - this.start) * n) + this.start; // Decimal
7579                 }
7580         }
7581         
7582         d.declare("dojo._Animation", null, {
7583                 //      summary
7584                 //              A generic animation class that fires callbacks into its handlers
7585                 //              object at various states. Nearly all dojo animation functions
7586                 //              return an instance of this method, usually without calling the
7587                 //              .play() method beforehand. Therefore, you will likely need to
7588                 //              call .play() on instances of dojo._Animation when one is
7589                 //              returned.
7590                 constructor: function(/*Object*/ args){
7591                         d.mixin(this, args);
7592                         if(d.isArray(this.curve)){
7593                                 /* curve: Array
7594                                         pId: a */
7595                                 this.curve = new d._Line(this.curve[0], this.curve[1]);
7596                         }
7597                 },
7598                 
7599                 // duration: Integer
7600                 //      The time in milliseonds the animation will take to run
7601                 duration: 350,
7602         
7603         /*=====
7604                 // curve: dojo._Line||Array
7605                 //      A two element array of start and end values, or a dojo._Line instance to be
7606                 //      used in the Animation. 
7607                 curve: null,
7608         
7609                 // easing: Function
7610                 //      A Function to adjust the acceleration (or deceleration) of the progress 
7611                 //      across a dojo._Line
7612                 easing: null,
7613         =====*/
7614         
7615                 // repeat: Integer
7616                 //      The number of times to loop the animation
7617                 repeat: 0,
7618         
7619                 // rate: Integer
7620                 //      the time in milliseconds to wait before advancing to next frame 
7621                 //      (used as a fps timer: rate/1000 = fps)
7622                 rate: 10 /* 100 fps */,
7623         
7624         /*===== 
7625                 // delay: Integer
7626                 //      The time in milliseconds to wait before starting animation after it has been .play()'ed
7627                 delay: null,
7628         
7629                 // events
7630                 //
7631                 // beforeBegin: Event
7632                 //      Synthetic event fired before a dojo._Animation begins playing (synchronous)
7633                 beforeBegin: null,
7634         
7635                 // onBegin: Event
7636                 //      Synthetic event fired as a dojo._Animation begins playing (useful?)
7637                 onBegin: null,
7638         
7639                 // onAnimate: Event
7640                 //      Synthetic event fired at each interval of a dojo._Animation
7641                 onAnimate: null,
7642         
7643                 // onEnd: Event
7644                 //      Synthetic event fired after the final frame of a dojo._Animation
7645                 onEnd: null,
7646         
7647                 // onPlay: Event
7648                 //      Synthetic event fired any time a dojo._Animation is play()'ed
7649                 onPlay: null,
7650         
7651                 // onPause: Event
7652                 //      Synthetic event fired when a dojo._Animation is paused
7653                 onPause: null,
7654         
7655                 // onStop: Event
7656                 //      Synthetic event fires when a dojo._Animation is stopped
7657                 onStop: null,
7658         
7659         =====*/
7660         
7661                 _percent: 0,
7662                 _startRepeatCount: 0,
7663         
7664                 _fire: function(/*Event*/ evt, /*Array?*/ args){
7665                         //      summary:
7666                         //              Convenience function.  Fire event "evt" and pass it the
7667                         //              arguments specified in "args".
7668                         //      evt:
7669                         //              The event to fire.
7670                         //      args:
7671                         //              The arguments to pass to the event.
7672                         try{
7673                                 if(this[evt]){
7674                                         this[evt].apply(this, args||[]);
7675                                 }
7676                         }catch(e){
7677                                 // squelch and log because we shouldn't allow exceptions in
7678                                 // synthetic event handlers to cause the internal timer to run
7679                                 // amuck, potentially pegging the CPU. I'm not a fan of this
7680                                 // squelch, but hopefully logging will make it clear what's
7681                                 // going on
7682                                 console.error("exception in animation handler for:", evt);
7683                                 console.error(e);
7684                         }
7685                         return this; // dojo._Animation
7686                 },
7687         
7688                 play: function(/*int?*/ delay, /*Boolean?*/ gotoStart){
7689                         // summary:
7690                         //              Start the animation.
7691                         // delay:
7692                         //              How many milliseconds to delay before starting.
7693                         // gotoStart:
7694                         //              If true, starts the animation from the beginning; otherwise,
7695                         //              starts it from its current position.
7696                         var _t = this;
7697                         if(gotoStart){
7698                                 _t._stopTimer();
7699                                 _t._active = _t._paused = false;
7700                                 _t._percent = 0;
7701                         }else if(_t._active && !_t._paused){
7702                                 return _t; // dojo._Animation
7703                         }
7704         
7705                         _t._fire("beforeBegin");
7706         
7707                         var de = delay||_t.delay;
7708                         var _p = dojo.hitch(_t, "_play", gotoStart);
7709                         if(de > 0){
7710                                 setTimeout(_p, de);
7711                                 return _t; // dojo._Animation
7712                         }
7713                         _p();
7714                         return _t;
7715                 },
7716         
7717                 _play: function(gotoStart){
7718                         var _t = this;
7719                         _t._startTime = new Date().valueOf();
7720                         if(_t._paused){
7721                                 _t._startTime -= _t.duration * _t._percent;
7722                         }
7723                         _t._endTime = _t._startTime + _t.duration;
7724         
7725                         _t._active = true;
7726                         _t._paused = false;
7727         
7728                         var value = _t.curve.getValue(_t._percent);
7729                         if(!_t._percent){
7730                                 if(!_t._startRepeatCount){
7731                                         _t._startRepeatCount = _t.repeat;
7732                                 }
7733                                 _t._fire("onBegin", [value]);
7734                         }
7735         
7736                         _t._fire("onPlay", [value]);
7737         
7738                         _t._cycle();
7739                         return _t; // dojo._Animation
7740                 },
7741         
7742                 pause: function(){
7743                         // summary: Pauses a running animation.
7744                         this._stopTimer();
7745                         if(!this._active){ return this; /*dojo._Animation*/ }
7746                         this._paused = true;
7747                         this._fire("onPause", [this.curve.getValue(this._percent)]);
7748                         return this; // dojo._Animation
7749                 },
7750         
7751                 gotoPercent: function(/*Decimal*/ percent, /*Boolean?*/ andPlay){
7752                         //      summary:
7753                         //              Sets the progress of the animation.
7754                         //      percent:
7755                         //              A percentage in decimal notation (between and including 0.0 and 1.0).
7756                         //      andPlay:
7757                         //              If true, play the animation after setting the progress.
7758                         this._stopTimer();
7759                         this._active = this._paused = true;
7760                         this._percent = percent;
7761                         if(andPlay){ this.play(); }
7762                         return this; // dojo._Animation
7763                 },
7764         
7765                 stop: function(/*boolean?*/ gotoEnd){
7766                         // summary: Stops a running animation.
7767                         // gotoEnd: If true, the animation will end.
7768                         if(!this._timer){ return this; /* dojo._Animation */ }
7769                         this._stopTimer();
7770                         if(gotoEnd){
7771                                 this._percent = 1;
7772                         }
7773                         this._fire("onStop", [this.curve.getValue(this._percent)]);
7774                         this._active = this._paused = false;
7775                         return this; // dojo._Animation
7776                 },
7777         
7778                 status: function(){
7779                         // summary: Returns a string token representation of the status of
7780                         //                      the animation, one of: "paused", "playing", "stopped"
7781                         if(this._active){
7782                                 return this._paused ? "paused" : "playing"; // String
7783                         }
7784                         return "stopped"; // String
7785                 },
7786         
7787                 _cycle: function(){
7788                         var _t = this;
7789                         if(_t._active){
7790                                 var curr = new Date().valueOf();
7791                                 var step = (curr - _t._startTime) / (_t._endTime - _t._startTime);
7792         
7793                                 if(step >= 1){
7794                                         step = 1;
7795                                 }
7796                                 _t._percent = step;
7797         
7798                                 // Perform easing
7799                                 if(_t.easing){
7800                                         step = _t.easing(step);
7801                                 }
7802         
7803                                 _t._fire("onAnimate", [_t.curve.getValue(step)]);
7804         
7805                                 if(_t._percent < 1){
7806                                         _t._startTimer();
7807                                 }else{
7808                                         _t._active = false;
7809         
7810                                         if(_t.repeat > 0){
7811                                                 _t.repeat--;
7812                                                 _t.play(null, true);
7813                                         }else if(_t.repeat == -1){
7814                                                 _t.play(null, true);
7815                                         }else{
7816                                                 if(_t._startRepeatCount){
7817                                                         _t.repeat = _t._startRepeatCount;
7818                                                         _t._startRepeatCount = 0;
7819                                                 }
7820                                         }
7821                                         _t._percent = 0;
7822                                         _t._fire("onEnd");
7823                                         _t._stopTimer();
7824                                 }
7825                         }
7826                         return _t; // dojo._Animation
7827                 }
7828         });
7829
7830         var ctr = 0;
7831         var _globalTimerList = [];
7832         var runner = {
7833                 run: function(){ }
7834         };
7835         var timer = null;
7836         dojo._Animation.prototype._startTimer = function(){
7837                 // this._timer = setTimeout(dojo.hitch(this, "_cycle"), this.rate);
7838                 if(!this._timer){
7839                         this._timer = d.connect(runner, "run", this, "_cycle");
7840                         ctr++;
7841                 }
7842                 if(!timer){
7843                         timer = setInterval(d.hitch(runner, "run"), this.rate);
7844                 }
7845         };
7846
7847         dojo._Animation.prototype._stopTimer = function(){
7848                 if(this._timer){
7849                         d.disconnect(this._timer);
7850                         this._timer = null;
7851                         ctr--;
7852                 }
7853                 if(ctr <= 0){
7854                         clearInterval(timer);
7855                         timer = null;
7856                         ctr = 0;
7857                 }
7858         };
7859
7860         var _makeFadeable = (d.isIE) ? function(node){
7861                 // only set the zoom if the "tickle" value would be the same as the
7862                 // default
7863                 var ns = node.style;
7864                 if(!ns.zoom.length && d.style(node, "zoom") == "normal"){
7865                         // make sure the node "hasLayout"
7866                         // NOTE: this has been tested with larger and smaller user-set text
7867                         // sizes and works fine
7868                         ns.zoom = "1";
7869                         // node.style.zoom = "normal";
7870                 }
7871                 // don't set the width to auto if it didn't already cascade that way.
7872                 // We don't want to f anyones designs
7873                 if(!ns.width.length && d.style(node, "width") == "auto"){
7874                         ns.width = "auto";
7875                 }
7876         } : function(){};
7877
7878         dojo._fade = function(/*Object*/ args){
7879                 //      summary: 
7880                 //              Returns an animation that will fade the node defined by
7881                 //              args.node from the start to end values passed (args.start
7882                 //              args.end) (end is mandatory, start is optional)
7883
7884                 args.node = d.byId(args.node);
7885                 var fArgs = d.mixin({ properties: {} }, args);
7886                 var props = (fArgs.properties.opacity = {});
7887                 props.start = !("start" in fArgs) ?
7888                         function(){ 
7889                                 return Number(d.style(fArgs.node, "opacity")); 
7890                         } : fArgs.start;
7891                 props.end = fArgs.end;
7892
7893                 var anim = d.animateProperty(fArgs);
7894                 d.connect(anim, "beforeBegin", d.partial(_makeFadeable, fArgs.node));
7895
7896                 return anim; // dojo._Animation
7897         }
7898
7899         /*=====
7900         dojo.__FadeArgs = function(node, duration, easing){
7901                 //      node: DOMNode|String
7902                 //              The node referenced in the animation
7903                 //      duration: Integer?
7904                 //              Duration of the animation in milliseconds.
7905                 //      easing: Function?
7906                 //              An easing function.
7907                 this.node = node;
7908                 this.duration = duration;
7909                 this.easing = easing;
7910         }
7911         =====*/
7912
7913         dojo.fadeIn = function(/*dojo.__FadeArgs*/ args){
7914                 // summary: 
7915                 //              Returns an animation that will fade node defined in 'args' from
7916                 //              its current opacity to fully opaque.
7917                 return d._fade(d.mixin({ end: 1 }, args)); // dojo._Animation
7918         }
7919
7920         dojo.fadeOut = function(/*dojo.__FadeArgs*/  args){
7921                 // summary: 
7922                 //              Returns an animation that will fade node defined in 'args'
7923                 //              from its current opacity to fully transparent.
7924                 return d._fade(d.mixin({ end: 0 }, args)); // dojo._Animation
7925         }
7926
7927         dojo._defaultEasing = function(/*Decimal?*/ n){
7928                 // summary: The default easing function for dojo._Animation(s)
7929                 return 0.5 + ((Math.sin((n + 1.5) * Math.PI))/2);
7930         }
7931
7932         var PropLine = function(properties){
7933                 // PropLine is an internal class which is used to model the values of
7934                 // an a group of CSS properties across an animation lifecycle. In
7935                 // particular, the "getValue" function handles getting interpolated
7936                 // values between start and end for a particular CSS value.
7937                 this._properties = properties;
7938                 for(var p in properties){
7939                         var prop = properties[p];
7940                         if(prop.start instanceof d.Color){
7941                                 // create a reusable temp color object to keep intermediate results
7942                                 prop.tempColor = new d.Color();
7943                         }
7944                 }
7945                 this.getValue = function(r){
7946                         var ret = {};
7947                         for(var p in this._properties){
7948                                 var prop = this._properties[p];
7949                                 var start = prop.start;
7950                                 if(start instanceof d.Color){
7951                                         ret[p] = d.blendColors(start, prop.end, r, prop.tempColor).toCss();
7952                                 }else if(!d.isArray(start)){
7953                                         ret[p] = ((prop.end - start) * r) + start + (p != "opacity" ? prop.units||"px" : "");
7954                                 }
7955                         }
7956                         return ret;
7957                 }
7958         }
7959
7960         /*=====
7961         dojo.declare("dojo.__AnimArgs", [dojo.__FadeArgs], {
7962                 // Properties: Object?
7963                 //      A hash map of style properties to Objects describing the transition,
7964                 //      such as the properties of dojo._Line with an additional 'unit' property
7965                 properties: {}
7966                 
7967                 //TODOC: add event callbacks
7968         });
7969         =====*/
7970
7971         dojo.animateProperty = function(/*dojo.__AnimArgs*/ args){
7972                 //      summary: 
7973                 //              Returns an animation that will transition the properties of
7974                 //              node defined in 'args' depending how they are defined in
7975                 //              'args.properties'
7976                 //
7977                 // description:
7978                 //              dojo.animateProperty is the foundation of most dojo.fx
7979                 //              animations. It takes an object of "properties" corresponding to
7980                 //              style properties, and animates them in parallel over a set
7981                 //              duration.
7982                 //      
7983                 //      example:
7984                 //              A simple animation that changes the width of the specified node.
7985                 //      |       dojo.animateProperty({ 
7986                 //      |               node: "nodeId",
7987                 //      |               properties: { width: 400 },
7988                 //      |       }).play();
7989                 //              Dojo figures out the start value for the width and converts the
7990                 //              integer specified for the width to the more expressive but
7991                 //              verbose form `{ width: { end: '400', units: 'px' } }` which you
7992                 //              can also specify directly
7993                 //      example:
7994                 //              animate width, height, and padding over 2 seconds...the
7995                 //              pedantic way:
7996                 //      |       dojo.animateProperty({ node: node, duration:2000,
7997                 //      |               properties: {
7998                 //      |                       width: { start: '200', end: '400', unit:"px" },
7999                 //      |                       height: { start:'200', end: '400', unit:"px" },
8000                 //      |                       paddingTop: { start:'5', end:'50', unit:"px" } 
8001                 //      |               }
8002                 //      |       }).play();
8003                 //
8004                 //      example:
8005                 //              plug in a different easing function and register a callback for
8006                 //              when the animation ends. Easing functions accept values between
8007                 //              zero and one and return a value on that basis. In this case, an
8008                 //              exponential-in curve.
8009                 //      |       dojo.animateProperty({ 
8010                 //      |               node: "nodeId",
8011                 //      |               // dojo figures out the start value
8012                 //      |               properties: { width: { end: 400 } },
8013                 //      |               easing: function(n){
8014                 //      |                       return (n==0) ? 0 : Math.pow(2, 10 * (n - 1));
8015                 //      |               },
8016                 //      |               onEnd: function(){
8017                 //      |                       // called when the animation finishes
8018                 //      |               }
8019                 //      |       }).play(500); // delay playing half a second
8020
8021                 args.node = d.byId(args.node);
8022                 if(!args.easing){ args.easing = d._defaultEasing; }
8023
8024                 var anim = new d._Animation(args);
8025                 d.connect(anim, "beforeBegin", anim, function(){
8026                         var pm = {};
8027                         for(var p in this.properties){
8028                                 // Make shallow copy of properties into pm because we overwrite
8029                                 // some values below. In particular if start/end are functions
8030                                 // we don't want to overwrite them or the functions won't be
8031                                 // called if the animation is reused.
8032                                 if(p == "width" || p == "height"){
8033                                         this.node.display = "block";
8034                                 }
8035                                 var prop = this.properties[p];
8036                                 prop = pm[p] = d.mixin({}, (d.isObject(prop) ? prop: { end: prop }));
8037
8038                                 if(d.isFunction(prop.start)){
8039                                         prop.start = prop.start();
8040                                 }
8041                                 if(d.isFunction(prop.end)){
8042                                         prop.end = prop.end();
8043                                 }
8044                                 var isColor = (p.toLowerCase().indexOf("color") >= 0);
8045                                 function getStyle(node, p){
8046                                         // dojo.style(node, "height") can return "auto" or "" on IE; this is more reliable:
8047                                         var v = ({height: node.offsetHeight, width: node.offsetWidth})[p];
8048                                         if(v !== undefined){ return v; }
8049                                         v = d.style(node, p);
8050                                         return (p=="opacity") ? Number(v) : (isColor ? v : parseFloat(v));
8051                                 }
8052                                 if(!("end" in prop)){
8053                                         prop.end = getStyle(this.node, p);
8054                                 }else if(!("start" in prop)){
8055                                         prop.start = getStyle(this.node, p);
8056                                 }
8057
8058                                 if(isColor){
8059                                         prop.start = new d.Color(prop.start);
8060                                         prop.end = new d.Color(prop.end);
8061                                 }else{
8062                                         prop.start = (p == "opacity") ? Number(prop.start) : parseFloat(prop.start);
8063                                 }
8064                         }
8065                         this.curve = new PropLine(pm);
8066                 });
8067                 d.connect(anim, "onAnimate", anim, function(propValues){
8068                         // try{
8069                         for(var s in propValues){
8070                                 d.style(this.node, s, propValues[s]);
8071                                 // this.node.style[s] = propValues[s];
8072                         }
8073                 });
8074                 return anim; // dojo._Animation
8075         }
8076
8077         dojo.anim = function(   /*DOMNode|String*/      node, 
8078                                                         /*Object*/                      properties, 
8079                                                         /*Integer?*/            duration, 
8080                                                         /*Function?*/           easing, 
8081                                                         /*Function?*/           onEnd,
8082                                                         /*Integer?*/            delay){
8083                 //      summary:
8084                 //              A simpler interface to `dojo.animateProperty()`, also returns
8085                 //              an instance of `dojo._Animation` but begins the animation
8086                 //              immediately, unlike nearly every other Dojo animation API.
8087                 //      description:
8088                 //              `dojo.anim` is a simpler (but somewhat less powerful) version
8089                 //              of `dojo.animateProperty`.  It uses defaults for many basic properties
8090                 //              and allows for positional parameters to be used in place of the
8091                 //              packed "property bag" which is used for other Dojo animation
8092                 //              methods.
8093                 //
8094                 //              The `dojo._Animation` object returned from `dojo.anim` will be
8095                 //              already playing when it is returned from this function, so
8096                 //              calling play() on it again is (usually) a no-op.
8097                 //      node:
8098                 //              a DOM node or the id of a node to animate CSS properties on
8099                 //      duration:
8100                 //              The number of milliseconds over which the animation
8101                 //              should run. Defaults to the global animation default duration
8102                 //              (350ms).
8103                 //      easing:
8104                 //              An easing function over which to calculate acceleration
8105                 //              and deceleration of the animation through its duration.
8106                 //              A default easing algorithm is provided, but you may
8107                 //              plug in any you wish. A large selection of easing algorithms
8108                 //              are available in `dojox.fx.easing`.
8109                 //      onEnd:
8110                 //              A function to be called when the animation finishes
8111                 //              running.
8112                 //      delay:
8113                 //              The number of milliseconds to delay beginning the
8114                 //              animation by. The default is 0.
8115                 //      example:
8116                 //              Fade out a node
8117                 //      |       dojo.anim("id", { opacity: 0 });
8118                 //      example:
8119                 //              Fade out a node over a full second
8120                 //      |       dojo.anim("id", { opacity: 0 }, 1000);
8121                 return d.animateProperty({ 
8122                         node: node,
8123                         duration: duration||d._Animation.prototype.duration,
8124                         properties: properties,
8125                         easing: easing,
8126                         onEnd: onEnd 
8127                 }).play(delay||0);
8128         }
8129 })();
8130
8131 }
8132
8133 if(!dojo._hasResource["dojo._base.browser"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
8134 dojo._hasResource["dojo._base.browser"] = true;
8135 dojo.provide("dojo._base.browser");
8136
8137
8138
8139
8140
8141
8142
8143
8144
8145 //Need this to be the last code segment in base, so do not place any
8146 //dojo.requireIf calls in this file. Otherwise, due to how the build system
8147 //puts all requireIf dependencies after the current file, the require calls
8148 //could be called before all of base is defined.
8149 if(dojo.config.require){
8150         dojo.forEach(dojo.config.require, "dojo['require'](item);");
8151 }
8152
8153 }
8154
8155
8156         if(dojo.config.afterOnLoad && dojo.isBrowser){
8157                 //Dojo is being added to the page after page load, so just trigger
8158                 //the init sequence after a timeout. Using a timeout so the rest of this
8159                 //script gets evaluated properly. This work needs to happen after the
8160                 //dojo.config.require work done in dojo._base.
8161                 window.setTimeout(dojo._fakeLoadInit, 1000);
8162         }
8163
8164 })();
8165