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