[PerformanceTests] Each Dromaeo test needs its landing html.
authormorrita@google.com <morrita@google.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Mon, 6 Feb 2012 23:44:33 +0000 (23:44 +0000)
committermorrita@google.com <morrita@google.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Mon, 6 Feb 2012 23:44:33 +0000 (23:44 +0000)
https://bugs.webkit.org/show_bug.cgi?id=77504

Reviewed by Ryosuke Niwa.

PerformanceTests:

- Added landing pages for each test which are listed in MANIFEST.json
- Removed some tests which depends on the library whose license is incompatible to WebKit.
- Added local copy of corresponding library. And replace the references to the remote sources
  to the local copies.
- Removed old library files under Dromaeo/resources/dromaeo/web/lib/.
- Skipped Sunsupier and v8 test. Such JS centric test should have its own test instead of
  running as a part of Dromaeo.

* Dromaeo/cssquery-dojo.html: Added.
* Dromaeo/cssquery-jquery.html: Added.
* Dromaeo/cssquery-prototype.html: Added.
* Dromaeo/dom-attr.html: Added.
* Dromaeo/dom-modify.html: Added.
* Dromaeo/dom-traverse.html: Added.
* Dromaeo/dromaeo-3d-cube.html: Added.
* Dromaeo/dromaeo-core-eval.html: Added.
* Dromaeo/dromaeo-object-array.html: Added.
* Dromaeo/dromaeo-object-regexp.html: Added.
* Dromaeo/dromaeo-object-string.html: Added.
* Dromaeo/dromaeo-string-base64.html: Added.
* Dromaeo/jslib-attr-jquery.html: Added.
* Dromaeo/jslib-attr-prototype.html: Added.
* Dromaeo/jslib-event-jquery.html: Added.
* Dromaeo/jslib-event-prototype.html: Added.
* Dromaeo/jslib-modify-jquery.html: Added.
* Dromaeo/jslib-modify-prototype.html: Added.
* Dromaeo/jslib-style-jquery.html: Added.
* Dromaeo/jslib-style-prototype.html: Added.
* Dromaeo/jslib-traverse-jquery.html: Added.
* Dromaeo/jslib-traverse-prototype.html: Added.
* Dromaeo/resources/dromaeo/web/lib/dojo.js: Removed.
* Dromaeo/resources/dromaeo/web/lib/dojo-1.6.1.js: Added.
* Dromaeo/resources/dromaeo/web/lib/jquery.js: Removed.
* Dromaeo/resources/dromaeo/web/lib/jquery-1.6.4.js: Added.
* Dromaeo/resources/dromaeo/web/lib/mootools.js: Removed.
* Dromaeo/resources/dromaeo/web/lib/prototype.js: Removed.
* Dromaeo/resources/dromaeo/web/lib/prototype-1.7.js: Added.
* Dromaeo/resources/dromaeo/web/tests/cssquery-dojo.html:
* Dromaeo/resources/dromaeo/web/tests/cssquery-jquery.html:
* Dromaeo/resources/dromaeo/web/tests/cssquery-mootools.html: Removed.
* Dromaeo/resources/dromaeo/web/tests/cssquery-prototype.html:
* Dromaeo/resources/dromaeo/web/tests/jslib-attr-jquery.html:
* Dromaeo/resources/dromaeo/web/tests/jslib-attr-prototype.html:
* Dromaeo/resources/dromaeo/web/tests/jslib-event-jquery.html:
* Dromaeo/resources/dromaeo/web/tests/jslib-event-prototype.html:
* Dromaeo/resources/dromaeo/web/tests/jslib-modify-jquery.html:
* Dromaeo/resources/dromaeo/web/tests/jslib-modify-prototype.html:
* Dromaeo/resources/dromaeo/web/tests/jslib-style-jquery.html:
* Dromaeo/resources/dromaeo/web/tests/jslib-style-prototype.html:
* Dromaeo/resources/dromaeo/web/tests/jslib-traverse-jquery.html:
* Dromaeo/resources/dromaeo/web/tests/jslib-traverse-prototype.html:
* Dromaeo/sunspider-3d-morph.html: Added.
* Dromaeo/sunspider-3d-raytrace.html: Added.
* Dromaeo/sunspider-access-binary-trees.html: Added.
* Dromaeo/sunspider-access-fannkuch.html: Added.
* Dromaeo/sunspider-access-nbody.html: Added.
* Dromaeo/sunspider-access-nsieve.html: Added.
* Dromaeo/sunspider-bitops-3bit-bits-in-byte.html: Added.
* Dromaeo/sunspider-bitops-bits-in-byte.html: Added.
* Dromaeo/sunspider-bitops-bitwise-and.html: Added.
* Dromaeo/sunspider-bitops-nsieve-bits.html: Added.
* Dromaeo/sunspider-controlflow-recursive.html: Added.
* Dromaeo/sunspider-crypto-aes.html: Added.
* Dromaeo/sunspider-crypto-md5.html: Added.
* Dromaeo/sunspider-crypto-sha1.html: Added.
* Dromaeo/sunspider-date-format-tofte.html: Added.
* Dromaeo/sunspider-date-format-xparb.html: Added.
* Dromaeo/sunspider-math-cordic.html: Added.
* Dromaeo/sunspider-math-partial-sums.html: Added.
* Dromaeo/sunspider-math-spectral-norm.html: Added.
* Dromaeo/sunspider-regexp-dna.html: Added.
* Dromaeo/sunspider-string-fasta.html: Added.
* Dromaeo/sunspider-string-tagcloud.html: Added.
* Dromaeo/sunspider-string-unpack-code.html: Added.
* Dromaeo/sunspider-string-validate-input.html: Added.
* Dromaeo/v8-crypto.html: Added.
* Dromaeo/v8-deltablue.html: Added.
* Dromaeo/v8-earley-boyer.html: Added.
* Dromaeo/v8-raytrace.html: Added.
* Dromaeo/v8-richards.html: Added.
* Skipped:

Tools:

Added an ignorable pattern which happens in some Dromaeo tests.

* Scripts/webkitpy/performance_tests/perftestsrunner.py:
(PerfTestsRunner):

git-svn-id: http://svn.webkit.org/repository/webkit/trunk@106865 268f45cc-cd09-0410-ab3c-d52691b4dbfc

77 files changed:
PerformanceTests/ChangeLog
PerformanceTests/Dromaeo/cssquery-dojo.html [new file with mode: 0644]
PerformanceTests/Dromaeo/cssquery-jquery.html [new file with mode: 0644]
PerformanceTests/Dromaeo/cssquery-prototype.html [new file with mode: 0644]
PerformanceTests/Dromaeo/dom-attr.html [new file with mode: 0644]
PerformanceTests/Dromaeo/dom-modify.html [new file with mode: 0644]
PerformanceTests/Dromaeo/dom-traverse.html [new file with mode: 0644]
PerformanceTests/Dromaeo/dromaeo-3d-cube.html [new file with mode: 0644]
PerformanceTests/Dromaeo/dromaeo-core-eval.html [new file with mode: 0644]
PerformanceTests/Dromaeo/dromaeo-object-array.html [new file with mode: 0644]
PerformanceTests/Dromaeo/dromaeo-object-regexp.html [new file with mode: 0644]
PerformanceTests/Dromaeo/dromaeo-object-string.html [new file with mode: 0644]
PerformanceTests/Dromaeo/dromaeo-string-base64.html [new file with mode: 0644]
PerformanceTests/Dromaeo/jslib-attr-jquery.html [new file with mode: 0644]
PerformanceTests/Dromaeo/jslib-attr-prototype.html [new file with mode: 0644]
PerformanceTests/Dromaeo/jslib-event-jquery.html [new file with mode: 0644]
PerformanceTests/Dromaeo/jslib-event-prototype.html [new file with mode: 0644]
PerformanceTests/Dromaeo/jslib-modify-jquery.html [new file with mode: 0644]
PerformanceTests/Dromaeo/jslib-modify-prototype.html [new file with mode: 0644]
PerformanceTests/Dromaeo/jslib-style-jquery.html [new file with mode: 0644]
PerformanceTests/Dromaeo/jslib-style-prototype.html [new file with mode: 0644]
PerformanceTests/Dromaeo/jslib-traverse-jquery.html [new file with mode: 0644]
PerformanceTests/Dromaeo/jslib-traverse-prototype.html [new file with mode: 0644]
PerformanceTests/Dromaeo/resources/dromaeo/web/index.html
PerformanceTests/Dromaeo/resources/dromaeo/web/lib/dojo-1.6.1.js [new file with mode: 0644]
PerformanceTests/Dromaeo/resources/dromaeo/web/lib/dojo.js [deleted file]
PerformanceTests/Dromaeo/resources/dromaeo/web/lib/jquery-1.6.4.js [new file with mode: 0644]
PerformanceTests/Dromaeo/resources/dromaeo/web/lib/jquery.js [deleted file]
PerformanceTests/Dromaeo/resources/dromaeo/web/lib/mootools.js [deleted file]
PerformanceTests/Dromaeo/resources/dromaeo/web/lib/prototype-1.7.js [new file with mode: 0644]
PerformanceTests/Dromaeo/resources/dromaeo/web/lib/prototype.js [deleted file]
PerformanceTests/Dromaeo/resources/dromaeo/web/tests/cssquery-dojo.html
PerformanceTests/Dromaeo/resources/dromaeo/web/tests/cssquery-jquery.html
PerformanceTests/Dromaeo/resources/dromaeo/web/tests/cssquery-mootools.html [deleted file]
PerformanceTests/Dromaeo/resources/dromaeo/web/tests/cssquery-prototype.html
PerformanceTests/Dromaeo/resources/dromaeo/web/tests/jslib-attr-jquery.html
PerformanceTests/Dromaeo/resources/dromaeo/web/tests/jslib-attr-prototype.html
PerformanceTests/Dromaeo/resources/dromaeo/web/tests/jslib-event-jquery.html
PerformanceTests/Dromaeo/resources/dromaeo/web/tests/jslib-event-prototype.html
PerformanceTests/Dromaeo/resources/dromaeo/web/tests/jslib-modify-jquery.html
PerformanceTests/Dromaeo/resources/dromaeo/web/tests/jslib-modify-prototype.html
PerformanceTests/Dromaeo/resources/dromaeo/web/tests/jslib-style-jquery.html
PerformanceTests/Dromaeo/resources/dromaeo/web/tests/jslib-style-prototype.html
PerformanceTests/Dromaeo/resources/dromaeo/web/tests/jslib-traverse-jquery.html
PerformanceTests/Dromaeo/resources/dromaeo/web/tests/jslib-traverse-prototype.html
PerformanceTests/Dromaeo/sunspider-3d-morph.html [new file with mode: 0644]
PerformanceTests/Dromaeo/sunspider-3d-raytrace.html [new file with mode: 0644]
PerformanceTests/Dromaeo/sunspider-access-binary-trees.html [new file with mode: 0644]
PerformanceTests/Dromaeo/sunspider-access-fannkuch.html [new file with mode: 0644]
PerformanceTests/Dromaeo/sunspider-access-nbody.html [new file with mode: 0644]
PerformanceTests/Dromaeo/sunspider-access-nsieve.html [new file with mode: 0644]
PerformanceTests/Dromaeo/sunspider-bitops-3bit-bits-in-byte.html [new file with mode: 0644]
PerformanceTests/Dromaeo/sunspider-bitops-bits-in-byte.html [new file with mode: 0644]
PerformanceTests/Dromaeo/sunspider-bitops-bitwise-and.html [new file with mode: 0644]
PerformanceTests/Dromaeo/sunspider-bitops-nsieve-bits.html [new file with mode: 0644]
PerformanceTests/Dromaeo/sunspider-controlflow-recursive.html [new file with mode: 0644]
PerformanceTests/Dromaeo/sunspider-crypto-aes.html [new file with mode: 0644]
PerformanceTests/Dromaeo/sunspider-crypto-md5.html [new file with mode: 0644]
PerformanceTests/Dromaeo/sunspider-crypto-sha1.html [new file with mode: 0644]
PerformanceTests/Dromaeo/sunspider-date-format-tofte.html [new file with mode: 0644]
PerformanceTests/Dromaeo/sunspider-date-format-xparb.html [new file with mode: 0644]
PerformanceTests/Dromaeo/sunspider-math-cordic.html [new file with mode: 0644]
PerformanceTests/Dromaeo/sunspider-math-partial-sums.html [new file with mode: 0644]
PerformanceTests/Dromaeo/sunspider-math-spectral-norm.html [new file with mode: 0644]
PerformanceTests/Dromaeo/sunspider-regexp-dna.html [new file with mode: 0644]
PerformanceTests/Dromaeo/sunspider-string-fasta.html [new file with mode: 0644]
PerformanceTests/Dromaeo/sunspider-string-tagcloud.html [new file with mode: 0644]
PerformanceTests/Dromaeo/sunspider-string-unpack-code.html [new file with mode: 0644]
PerformanceTests/Dromaeo/sunspider-string-validate-input.html [new file with mode: 0644]
PerformanceTests/Dromaeo/v8-crypto.html [new file with mode: 0644]
PerformanceTests/Dromaeo/v8-deltablue.html [new file with mode: 0644]
PerformanceTests/Dromaeo/v8-earley-boyer.html [new file with mode: 0644]
PerformanceTests/Dromaeo/v8-raytrace.html [new file with mode: 0644]
PerformanceTests/Dromaeo/v8-richards.html [new file with mode: 0644]
PerformanceTests/Skipped
Tools/ChangeLog
Tools/Scripts/webkitpy/performance_tests/perftestsrunner.py

index 7ef7311..d28557c 100644 (file)
@@ -1,3 +1,92 @@
+2012-02-02  Hajime Morrita  <morrita@chromium.org>
+
+        [PerformanceTests] Each Dromaeo test needs its landing html.
+        https://bugs.webkit.org/show_bug.cgi?id=77504
+
+        Reviewed by Ryosuke Niwa.
+
+        - Added landing pages for each test which are listed in MANIFEST.json
+        - Removed some tests which depends on the library whose license is incompatible to WebKit.
+        - Added local copy of corresponding library. And replace the references to the remote sources
+          to the local copies.
+        - Removed old library files under Dromaeo/resources/dromaeo/web/lib/.
+        - Skipped Sunsupier and v8 test. Such JS centric test should have its own test instead of
+          running as a part of Dromaeo.
+
+        * Dromaeo/cssquery-dojo.html: Added.
+        * Dromaeo/cssquery-jquery.html: Added.
+        * Dromaeo/cssquery-prototype.html: Added.
+        * Dromaeo/dom-attr.html: Added.
+        * Dromaeo/dom-modify.html: Added.
+        * Dromaeo/dom-traverse.html: Added.
+        * Dromaeo/dromaeo-3d-cube.html: Added.
+        * Dromaeo/dromaeo-core-eval.html: Added.
+        * Dromaeo/dromaeo-object-array.html: Added.
+        * Dromaeo/dromaeo-object-regexp.html: Added.
+        * Dromaeo/dromaeo-object-string.html: Added.
+        * Dromaeo/dromaeo-string-base64.html: Added.
+        * Dromaeo/jslib-attr-jquery.html: Added.
+        * Dromaeo/jslib-attr-prototype.html: Added.
+        * Dromaeo/jslib-event-jquery.html: Added.
+        * Dromaeo/jslib-event-prototype.html: Added.
+        * Dromaeo/jslib-modify-jquery.html: Added.
+        * Dromaeo/jslib-modify-prototype.html: Added.
+        * Dromaeo/jslib-style-jquery.html: Added.
+        * Dromaeo/jslib-style-prototype.html: Added.
+        * Dromaeo/jslib-traverse-jquery.html: Added.
+        * Dromaeo/jslib-traverse-prototype.html: Added.
+        * Dromaeo/resources/dromaeo/web/lib/dojo.js: Removed.
+        * Dromaeo/resources/dromaeo/web/lib/dojo-1.6.1.js: Added.
+        * Dromaeo/resources/dromaeo/web/lib/jquery.js: Removed.
+        * Dromaeo/resources/dromaeo/web/lib/jquery-1.6.4.js: Added.
+        * Dromaeo/resources/dromaeo/web/lib/mootools.js: Removed.
+        * Dromaeo/resources/dromaeo/web/lib/prototype.js: Removed.
+        * Dromaeo/resources/dromaeo/web/lib/prototype-1.7.js: Added.
+        * Dromaeo/resources/dromaeo/web/tests/cssquery-dojo.html:
+        * Dromaeo/resources/dromaeo/web/tests/cssquery-jquery.html:
+        * Dromaeo/resources/dromaeo/web/tests/cssquery-mootools.html: Removed.
+        * Dromaeo/resources/dromaeo/web/tests/cssquery-prototype.html:
+        * Dromaeo/resources/dromaeo/web/tests/jslib-attr-jquery.html:
+        * Dromaeo/resources/dromaeo/web/tests/jslib-attr-prototype.html:
+        * Dromaeo/resources/dromaeo/web/tests/jslib-event-jquery.html:
+        * Dromaeo/resources/dromaeo/web/tests/jslib-event-prototype.html:
+        * Dromaeo/resources/dromaeo/web/tests/jslib-modify-jquery.html:
+        * Dromaeo/resources/dromaeo/web/tests/jslib-modify-prototype.html:
+        * Dromaeo/resources/dromaeo/web/tests/jslib-style-jquery.html:
+        * Dromaeo/resources/dromaeo/web/tests/jslib-style-prototype.html:
+        * Dromaeo/resources/dromaeo/web/tests/jslib-traverse-jquery.html:
+        * Dromaeo/resources/dromaeo/web/tests/jslib-traverse-prototype.html:
+        * Dromaeo/sunspider-3d-morph.html: Added.
+        * Dromaeo/sunspider-3d-raytrace.html: Added.
+        * Dromaeo/sunspider-access-binary-trees.html: Added.
+        * Dromaeo/sunspider-access-fannkuch.html: Added.
+        * Dromaeo/sunspider-access-nbody.html: Added.
+        * Dromaeo/sunspider-access-nsieve.html: Added.
+        * Dromaeo/sunspider-bitops-3bit-bits-in-byte.html: Added.
+        * Dromaeo/sunspider-bitops-bits-in-byte.html: Added.
+        * Dromaeo/sunspider-bitops-bitwise-and.html: Added.
+        * Dromaeo/sunspider-bitops-nsieve-bits.html: Added.
+        * Dromaeo/sunspider-controlflow-recursive.html: Added.
+        * Dromaeo/sunspider-crypto-aes.html: Added.
+        * Dromaeo/sunspider-crypto-md5.html: Added.
+        * Dromaeo/sunspider-crypto-sha1.html: Added.
+        * Dromaeo/sunspider-date-format-tofte.html: Added.
+        * Dromaeo/sunspider-date-format-xparb.html: Added.
+        * Dromaeo/sunspider-math-cordic.html: Added.
+        * Dromaeo/sunspider-math-partial-sums.html: Added.
+        * Dromaeo/sunspider-math-spectral-norm.html: Added.
+        * Dromaeo/sunspider-regexp-dna.html: Added.
+        * Dromaeo/sunspider-string-fasta.html: Added.
+        * Dromaeo/sunspider-string-tagcloud.html: Added.
+        * Dromaeo/sunspider-string-unpack-code.html: Added.
+        * Dromaeo/sunspider-string-validate-input.html: Added.
+        * Dromaeo/v8-crypto.html: Added.
+        * Dromaeo/v8-deltablue.html: Added.
+        * Dromaeo/v8-earley-boyer.html: Added.
+        * Dromaeo/v8-raytrace.html: Added.
+        * Dromaeo/v8-richards.html: Added.
+        * Skipped:
+
 2012-02-02  Sheriff Bot  <webkit.review.bot@gmail.com>
 
         Unreviewed, rolling out r106543.
diff --git a/PerformanceTests/Dromaeo/cssquery-dojo.html b/PerformanceTests/Dromaeo/cssquery-dojo.html
new file mode 100644 (file)
index 0000000..15f537c
--- /dev/null
@@ -0,0 +1,15 @@
+<!DOCTYPE html>
+<html>
+<head>
+<script src="../resources/runner.js"></script>
+<script src="resources/dromaeo/web/jquery.js"></script>
+<script src="resources/dromaeorunner.js"></script>
+<script>
+$(document).ready(function() {
+    DRT.setup("cssquery-dojo");
+});
+</script>
+</head>
+<body>
+</body>
+</html>
diff --git a/PerformanceTests/Dromaeo/cssquery-jquery.html b/PerformanceTests/Dromaeo/cssquery-jquery.html
new file mode 100644 (file)
index 0000000..964f5e8
--- /dev/null
@@ -0,0 +1,15 @@
+<!DOCTYPE html>
+<html>
+<head>
+<script src="../resources/runner.js"></script>
+<script src="resources/dromaeo/web/jquery.js"></script>
+<script src="resources/dromaeorunner.js"></script>
+<script>
+$(document).ready(function() {
+    DRT.setup("cssquery-jquery");
+});
+</script>
+</head>
+<body>
+</body>
+</html>
diff --git a/PerformanceTests/Dromaeo/cssquery-prototype.html b/PerformanceTests/Dromaeo/cssquery-prototype.html
new file mode 100644 (file)
index 0000000..67a5951
--- /dev/null
@@ -0,0 +1,15 @@
+<!DOCTYPE html>
+<html>
+<head>
+<script src="../resources/runner.js"></script>
+<script src="resources/dromaeo/web/jquery.js"></script>
+<script src="resources/dromaeorunner.js"></script>
+<script>
+$(document).ready(function() {
+    DRT.setup("cssquery-prototype");
+});
+</script>
+</head>
+<body>
+</body>
+</html>
diff --git a/PerformanceTests/Dromaeo/dom-attr.html b/PerformanceTests/Dromaeo/dom-attr.html
new file mode 100644 (file)
index 0000000..1a45947
--- /dev/null
@@ -0,0 +1,15 @@
+<!DOCTYPE html>
+<html>
+<head>
+<script src="../resources/runner.js"></script>
+<script src="resources/dromaeo/web/jquery.js"></script>
+<script src="resources/dromaeorunner.js"></script>
+<script>
+$(document).ready(function() {
+    DRT.setup("dom-attr");
+});
+</script>
+</head>
+<body>
+</body>
+</html>
diff --git a/PerformanceTests/Dromaeo/dom-modify.html b/PerformanceTests/Dromaeo/dom-modify.html
new file mode 100644 (file)
index 0000000..5bf08e1
--- /dev/null
@@ -0,0 +1,15 @@
+<!DOCTYPE html>
+<html>
+<head>
+<script src="../resources/runner.js"></script>
+<script src="resources/dromaeo/web/jquery.js"></script>
+<script src="resources/dromaeorunner.js"></script>
+<script>
+$(document).ready(function() {
+    DRT.setup("dom-modify");
+});
+</script>
+</head>
+<body>
+</body>
+</html>
diff --git a/PerformanceTests/Dromaeo/dom-traverse.html b/PerformanceTests/Dromaeo/dom-traverse.html
new file mode 100644 (file)
index 0000000..dc6375c
--- /dev/null
@@ -0,0 +1,15 @@
+<!DOCTYPE html>
+<html>
+<head>
+<script src="../resources/runner.js"></script>
+<script src="resources/dromaeo/web/jquery.js"></script>
+<script src="resources/dromaeorunner.js"></script>
+<script>
+$(document).ready(function() {
+    DRT.setup("dom-traverse");
+});
+</script>
+</head>
+<body>
+</body>
+</html>
diff --git a/PerformanceTests/Dromaeo/dromaeo-3d-cube.html b/PerformanceTests/Dromaeo/dromaeo-3d-cube.html
new file mode 100644 (file)
index 0000000..21d0c96
--- /dev/null
@@ -0,0 +1,15 @@
+<!DOCTYPE html>
+<html>
+<head>
+<script src="../resources/runner.js"></script>
+<script src="resources/dromaeo/web/jquery.js"></script>
+<script src="resources/dromaeorunner.js"></script>
+<script>
+$(document).ready(function() {
+    DRT.setup("dromaeo-3d-cube");
+});
+</script>
+</head>
+<body>
+</body>
+</html>
diff --git a/PerformanceTests/Dromaeo/dromaeo-core-eval.html b/PerformanceTests/Dromaeo/dromaeo-core-eval.html
new file mode 100644 (file)
index 0000000..4873d14
--- /dev/null
@@ -0,0 +1,15 @@
+<!DOCTYPE html>
+<html>
+<head>
+<script src="../resources/runner.js"></script>
+<script src="resources/dromaeo/web/jquery.js"></script>
+<script src="resources/dromaeorunner.js"></script>
+<script>
+$(document).ready(function() {
+    DRT.setup("dromaeo-core-eval");
+});
+</script>
+</head>
+<body>
+</body>
+</html>
diff --git a/PerformanceTests/Dromaeo/dromaeo-object-array.html b/PerformanceTests/Dromaeo/dromaeo-object-array.html
new file mode 100644 (file)
index 0000000..5e8c73c
--- /dev/null
@@ -0,0 +1,15 @@
+<!DOCTYPE html>
+<html>
+<head>
+<script src="../resources/runner.js"></script>
+<script src="resources/dromaeo/web/jquery.js"></script>
+<script src="resources/dromaeorunner.js"></script>
+<script>
+$(document).ready(function() {
+    DRT.setup("dromaeo-object-array");
+});
+</script>
+</head>
+<body>
+</body>
+</html>
diff --git a/PerformanceTests/Dromaeo/dromaeo-object-regexp.html b/PerformanceTests/Dromaeo/dromaeo-object-regexp.html
new file mode 100644 (file)
index 0000000..fc76ebc
--- /dev/null
@@ -0,0 +1,15 @@
+<!DOCTYPE html>
+<html>
+<head>
+<script src="../resources/runner.js"></script>
+<script src="resources/dromaeo/web/jquery.js"></script>
+<script src="resources/dromaeorunner.js"></script>
+<script>
+$(document).ready(function() {
+    DRT.setup("dromaeo-object-regexp");
+});
+</script>
+</head>
+<body>
+</body>
+</html>
diff --git a/PerformanceTests/Dromaeo/dromaeo-object-string.html b/PerformanceTests/Dromaeo/dromaeo-object-string.html
new file mode 100644 (file)
index 0000000..5ffb792
--- /dev/null
@@ -0,0 +1,15 @@
+<!DOCTYPE html>
+<html>
+<head>
+<script src="../resources/runner.js"></script>
+<script src="resources/dromaeo/web/jquery.js"></script>
+<script src="resources/dromaeorunner.js"></script>
+<script>
+$(document).ready(function() {
+    DRT.setup("dromaeo-object-string");
+});
+</script>
+</head>
+<body>
+</body>
+</html>
diff --git a/PerformanceTests/Dromaeo/dromaeo-string-base64.html b/PerformanceTests/Dromaeo/dromaeo-string-base64.html
new file mode 100644 (file)
index 0000000..6147a56
--- /dev/null
@@ -0,0 +1,15 @@
+<!DOCTYPE html>
+<html>
+<head>
+<script src="../resources/runner.js"></script>
+<script src="resources/dromaeo/web/jquery.js"></script>
+<script src="resources/dromaeorunner.js"></script>
+<script>
+$(document).ready(function() {
+    DRT.setup("dromaeo-string-base64");
+});
+</script>
+</head>
+<body>
+</body>
+</html>
diff --git a/PerformanceTests/Dromaeo/jslib-attr-jquery.html b/PerformanceTests/Dromaeo/jslib-attr-jquery.html
new file mode 100644 (file)
index 0000000..812fc45
--- /dev/null
@@ -0,0 +1,15 @@
+<!DOCTYPE html>
+<html>
+<head>
+<script src="../resources/runner.js"></script>
+<script src="resources/dromaeo/web/jquery.js"></script>
+<script src="resources/dromaeorunner.js"></script>
+<script>
+$(document).ready(function() {
+    DRT.setup("jslib-attr-jquery");
+});
+</script>
+</head>
+<body>
+</body>
+</html>
diff --git a/PerformanceTests/Dromaeo/jslib-attr-prototype.html b/PerformanceTests/Dromaeo/jslib-attr-prototype.html
new file mode 100644 (file)
index 0000000..02c7fbc
--- /dev/null
@@ -0,0 +1,15 @@
+<!DOCTYPE html>
+<html>
+<head>
+<script src="../resources/runner.js"></script>
+<script src="resources/dromaeo/web/jquery.js"></script>
+<script src="resources/dromaeorunner.js"></script>
+<script>
+$(document).ready(function() {
+    DRT.setup("jslib-attr-prototype");
+});
+</script>
+</head>
+<body>
+</body>
+</html>
diff --git a/PerformanceTests/Dromaeo/jslib-event-jquery.html b/PerformanceTests/Dromaeo/jslib-event-jquery.html
new file mode 100644 (file)
index 0000000..fdd1788
--- /dev/null
@@ -0,0 +1,15 @@
+<!DOCTYPE html>
+<html>
+<head>
+<script src="../resources/runner.js"></script>
+<script src="resources/dromaeo/web/jquery.js"></script>
+<script src="resources/dromaeorunner.js"></script>
+<script>
+$(document).ready(function() {
+    DRT.setup("jslib-event-jquery");
+});
+</script>
+</head>
+<body>
+</body>
+</html>
diff --git a/PerformanceTests/Dromaeo/jslib-event-prototype.html b/PerformanceTests/Dromaeo/jslib-event-prototype.html
new file mode 100644 (file)
index 0000000..c5cf7d9
--- /dev/null
@@ -0,0 +1,15 @@
+<!DOCTYPE html>
+<html>
+<head>
+<script src="../resources/runner.js"></script>
+<script src="resources/dromaeo/web/jquery.js"></script>
+<script src="resources/dromaeorunner.js"></script>
+<script>
+$(document).ready(function() {
+    DRT.setup("jslib-event-prototype");
+});
+</script>
+</head>
+<body>
+</body>
+</html>
diff --git a/PerformanceTests/Dromaeo/jslib-modify-jquery.html b/PerformanceTests/Dromaeo/jslib-modify-jquery.html
new file mode 100644 (file)
index 0000000..6e3c8d5
--- /dev/null
@@ -0,0 +1,15 @@
+<!DOCTYPE html>
+<html>
+<head>
+<script src="../resources/runner.js"></script>
+<script src="resources/dromaeo/web/jquery.js"></script>
+<script src="resources/dromaeorunner.js"></script>
+<script>
+$(document).ready(function() {
+    DRT.setup("jslib-modify-jquery");
+});
+</script>
+</head>
+<body>
+</body>
+</html>
diff --git a/PerformanceTests/Dromaeo/jslib-modify-prototype.html b/PerformanceTests/Dromaeo/jslib-modify-prototype.html
new file mode 100644 (file)
index 0000000..16b2a7d
--- /dev/null
@@ -0,0 +1,15 @@
+<!DOCTYPE html>
+<html>
+<head>
+<script src="../resources/runner.js"></script>
+<script src="resources/dromaeo/web/jquery.js"></script>
+<script src="resources/dromaeorunner.js"></script>
+<script>
+$(document).ready(function() {
+    DRT.setup("jslib-modify-prototype");
+});
+</script>
+</head>
+<body>
+</body>
+</html>
diff --git a/PerformanceTests/Dromaeo/jslib-style-jquery.html b/PerformanceTests/Dromaeo/jslib-style-jquery.html
new file mode 100644 (file)
index 0000000..f96e63e
--- /dev/null
@@ -0,0 +1,15 @@
+<!DOCTYPE html>
+<html>
+<head>
+<script src="../resources/runner.js"></script>
+<script src="resources/dromaeo/web/jquery.js"></script>
+<script src="resources/dromaeorunner.js"></script>
+<script>
+$(document).ready(function() {
+    DRT.setup("jslib-style-jquery");
+});
+</script>
+</head>
+<body>
+</body>
+</html>
diff --git a/PerformanceTests/Dromaeo/jslib-style-prototype.html b/PerformanceTests/Dromaeo/jslib-style-prototype.html
new file mode 100644 (file)
index 0000000..baca04a
--- /dev/null
@@ -0,0 +1,15 @@
+<!DOCTYPE html>
+<html>
+<head>
+<script src="../resources/runner.js"></script>
+<script src="resources/dromaeo/web/jquery.js"></script>
+<script src="resources/dromaeorunner.js"></script>
+<script>
+$(document).ready(function() {
+    DRT.setup("jslib-style-prototype");
+});
+</script>
+</head>
+<body>
+</body>
+</html>
diff --git a/PerformanceTests/Dromaeo/jslib-traverse-jquery.html b/PerformanceTests/Dromaeo/jslib-traverse-jquery.html
new file mode 100644 (file)
index 0000000..6107af1
--- /dev/null
@@ -0,0 +1,15 @@
+<!DOCTYPE html>
+<html>
+<head>
+<script src="../resources/runner.js"></script>
+<script src="resources/dromaeo/web/jquery.js"></script>
+<script src="resources/dromaeorunner.js"></script>
+<script>
+$(document).ready(function() {
+    DRT.setup("jslib-traverse-jquery");
+});
+</script>
+</head>
+<body>
+</body>
+</html>
diff --git a/PerformanceTests/Dromaeo/jslib-traverse-prototype.html b/PerformanceTests/Dromaeo/jslib-traverse-prototype.html
new file mode 100644 (file)
index 0000000..6baa358
--- /dev/null
@@ -0,0 +1,15 @@
+<!DOCTYPE html>
+<html>
+<head>
+<script src="../resources/runner.js"></script>
+<script src="resources/dromaeo/web/jquery.js"></script>
+<script src="resources/dromaeorunner.js"></script>
+<script>
+$(document).ready(function() {
+    DRT.setup("jslib-traverse-prototype");
+});
+</script>
+</head>
+<body>
+</body>
+</html>
index 1a995d0..418d700 100644 (file)
@@ -9,6 +9,9 @@
   <script defer type="text/javascript" src="pngfix.js"></script>
   <![endif]-->
   <link href="application.css" rel="stylesheet" type="text/css" />
+<!--
+  <script src="lib/jquery-1.6.4.js"></script>
+  -->
   <script src="jquery.js"></script>
   <script src="json.js"></script>
   <script src="webrunner.js"></script>
diff --git a/PerformanceTests/Dromaeo/resources/dromaeo/web/lib/dojo-1.6.1.js b/PerformanceTests/Dromaeo/resources/dromaeo/web/lib/dojo-1.6.1.js
new file mode 100644 (file)
index 0000000..674e0ad
--- /dev/null
@@ -0,0 +1,11363 @@
+/*
+        Copyright (c) 2004-2011, The Dojo Foundation All Rights Reserved.
+        Available via Academic Free License >= 2.1 OR the modified BSD license.
+        see: http://dojotoolkit.org/license for details
+*/
+
+/*
+        This is an optimized version of Dojo, built for deployment and not for
+        development. To get sources and documentation, please visit:
+
+                http://dojotoolkit.org
+*/
+
+;(function(){
+
+        /*
+        dojo, dijit, and dojox must always be the first three, and in that order.
+        djConfig.scopeMap = [
+                ["dojo", "fojo"],
+                ["dijit", "fijit"],
+                ["dojox", "fojox"]
+        
+        ]
+        */
+
+        /**Build will replace this comment with a scoped djConfig **/
+
+        //The null below can be relaced by a build-time value used instead of djConfig.scopeMap.
+        var sMap = null;
+
+        //See if new scopes need to be defined.
+        if((sMap || (typeof djConfig != "undefined" && djConfig.scopeMap)) && (typeof window != "undefined")){
+                var scopeDef = "", scopePrefix = "", scopeSuffix = "", scopeMap = {}, scopeMapRev = {};
+                sMap = sMap || djConfig.scopeMap;
+                for(var i = 0; i < sMap.length; i++){
+                        //Make local variables, then global variables that use the locals.
+                        var newScope = sMap[i];
+                        scopeDef += "var " + newScope[0] + " = {}; " + newScope[1] + " = " + newScope[0] + ";" + newScope[1] + "._scopeName = '" + newScope[1] + "';";
+                        scopePrefix += (i == 0 ? "" : ",") + newScope[0];
+                        scopeSuffix += (i == 0 ? "" : ",") + newScope[1];
+                        scopeMap[newScope[0]] = newScope[1];
+                        scopeMapRev[newScope[1]] = newScope[0];
+                }
+
+                eval(scopeDef + "dojo._scopeArgs = [" + scopeSuffix + "];");
+
+                dojo._scopePrefixArgs = scopePrefix;
+                dojo._scopePrefix = "(function(" + scopePrefix + "){";
+                dojo._scopeSuffix = "})(" + scopeSuffix + ")";
+                dojo._scopeMap = scopeMap;
+                dojo._scopeMapRev = scopeMapRev;
+        }
+
+/*=====
+// note:
+//              'djConfig' does not exist under 'dojo.*' so that it can be set before the
+//              'dojo' variable exists.
+// note:
+//              Setting any of these variables *after* the library has loaded does
+//              nothing at all.
+
+djConfig = {
+        // summary:
+        //              Application code can set the global 'djConfig' prior to loading
+        //              the library to override certain global settings for how dojo works.
+        //
+        // isDebug: Boolean
+        //              Defaults to `false`. If set to `true`, ensures that Dojo provides
+        //              extended debugging feedback via Firebug. If Firebug is not available
+        //              on your platform, setting `isDebug` to `true` will force Dojo to
+        //              pull in (and display) the version of Firebug Lite which is
+        //              integrated into the Dojo distribution, thereby always providing a
+        //              debugging/logging console when `isDebug` is enabled. Note that
+        //              Firebug's `console.*` methods are ALWAYS defined by Dojo. If
+        //              `isDebug` is false and you are on a platform without Firebug, these
+        //              methods will be defined as no-ops.
+        isDebug: false,
+        // debugAtAllCosts: Boolean
+        //              Defaults to `false`. If set to `true`, this triggers an alternate
+        //              mode of the package system in which dependencies are detected and
+        //              only then are resources evaluated in dependency order via
+        //              `<script>` tag inclusion. This may double-request resources and
+        //              cause problems with scripts which expect `dojo.require()` to
+        //              preform synchronously. `debugAtAllCosts` can be an invaluable
+        //              debugging aid, but when using it, ensure that all code which
+        //              depends on Dojo modules is wrapped in `dojo.addOnLoad()` handlers.
+        //              Due to the somewhat unpredictable side-effects of using
+        //              `debugAtAllCosts`, it is strongly recommended that you enable this
+        //              flag as a last resort. `debugAtAllCosts` has no effect when loading
+        //              resources across domains. For usage information, see the
+        //              [Dojo Book](http://dojotoolkit.org/book/book-dojo/part-4-meta-dojo-making-your-dojo-code-run-faster-and-better/debugging-facilities/deb)
+        debugAtAllCosts: false,
+        // locale: String
+        //              The locale to assume for loading localized resources in this page,
+        //              specified according to [RFC 3066](http://www.ietf.org/rfc/rfc3066.txt).
+        //              Must be specified entirely in lowercase, e.g. `en-us` and `zh-cn`.
+        //              See the documentation for `dojo.i18n` and `dojo.requireLocalization`
+        //              for details on loading localized resources. If no locale is specified,
+        //              Dojo assumes the locale of the user agent, according to `navigator.userLanguage`
+        //              or `navigator.language` properties.
+        locale: undefined,
+        // extraLocale: Array
+        //              No default value. Specifies additional locales whose
+        //              resources should also be loaded alongside the default locale when
+        //              calls to `dojo.requireLocalization()` are processed.
+        extraLocale: undefined,
+        // baseUrl: String
+        //              The directory in which `dojo.js` is located. Under normal
+        //              conditions, Dojo auto-detects the correct location from which it
+        //              was loaded. You may need to manually configure `baseUrl` in cases
+        //              where you have renamed `dojo.js` or in which `<base>` tags confuse
+        //              some browsers (e.g. IE 6). The variable `dojo.baseUrl` is assigned
+        //              either the value of `djConfig.baseUrl` if one is provided or the
+        //              auto-detected root if not. Other modules are located relative to
+        //              this path. The path should end in a slash.
+        baseUrl: undefined,
+        // modulePaths: Object
+        //              A map of module names to paths relative to `dojo.baseUrl`. The
+        //              key/value pairs correspond directly to the arguments which
+        //              `dojo.registerModulePath` accepts. Specifiying
+        //              `djConfig.modulePaths = { "foo": "../../bar" }` is the equivalent
+        //              of calling `dojo.registerModulePath("foo", "../../bar");`. Multiple
+        //              modules may be configured via `djConfig.modulePaths`.
+        modulePaths: {},
+        // afterOnLoad: Boolean
+        //              Indicates Dojo was added to the page after the page load. In this case
+        //              Dojo will not wait for the page DOMContentLoad/load events and fire
+        //              its dojo.addOnLoad callbacks after making sure all outstanding
+        //              dojo.required modules have loaded. Only works with a built dojo.js,
+        //              it does not work the dojo.js directly from source control.
+        afterOnLoad: false,
+        // addOnLoad: Function or Array
+        //              Adds a callback via dojo.addOnLoad. Useful when Dojo is added after
+        //              the page loads and djConfig.afterOnLoad is true. Supports the same
+        //              arguments as dojo.addOnLoad. When using a function reference, use
+        //              `djConfig.addOnLoad = function(){};`. For object with function name use
+        //              `djConfig.addOnLoad = [myObject, "functionName"];` and for object with
+        //              function reference use
+        //              `djConfig.addOnLoad = [myObject, function(){}];`
+        addOnLoad: null,
+        // require: Array
+        //              An array of module names to be loaded immediately after dojo.js has been included
+        //              in a page.
+        require: [],
+        // defaultDuration: Array
+        //              Default duration, in milliseconds, for wipe and fade animations within dijits.
+        //              Assigned to dijit.defaultDuration.
+        defaultDuration: 200,
+        // dojoBlankHtmlUrl: String
+        //              Used by some modules to configure an empty iframe. Used by dojo.io.iframe and
+        //              dojo.back, and dijit popup support in IE where an iframe is needed to make sure native
+        //              controls do not bleed through the popups. Normally this configuration variable
+        //              does not need to be set, except when using cross-domain/CDN Dojo builds.
+        //              Save dojo/resources/blank.html to your domain and set `djConfig.dojoBlankHtmlUrl`
+        //              to the path on your domain your copy of blank.html.
+        dojoBlankHtmlUrl: undefined,
+        //      ioPublish: Boolean?
+        //              Set this to true to enable publishing of topics for the different phases of
+        //              IO operations. Publishing is done via dojo.publish. See dojo.__IoPublish for a list
+        //              of topics that are published.
+        ioPublish: false,
+        //  useCustomLogger: Anything?
+        //              If set to a value that evaluates to true such as a string or array and
+        //              isDebug is true and Firebug is not available or running, then it bypasses
+        //              the creation of Firebug Lite allowing you to define your own console object.
+        useCustomLogger: undefined,
+        // transparentColor: Array
+        //              Array containing the r, g, b components used as transparent color in dojo.Color;
+        //              if undefined, [255,255,255] (white) will be used.
+        transparentColor: undefined,
+        // skipIeDomLoaded: Boolean
+        //              For IE only, skip the DOMContentLoaded hack used. Sometimes it can cause an Operation
+        //              Aborted error if the rest of the page triggers script defers before the DOM is ready.
+        //              If this is config value is set to true, then dojo.addOnLoad callbacks will not be
+        //              triggered until the page load event, which is after images and iframes load. If you
+        //              want to trigger the callbacks sooner, you can put a script block in the bottom of
+        //              your HTML that calls dojo._loadInit();. If you are using multiversion support, change
+        //              "dojo." to the appropriate scope name for dojo.
+        skipIeDomLoaded: false
+}
+=====*/
+
+(function(){
+        // firebug stubs
+
+        if(typeof this["loadFirebugConsole"] == "function"){
+                // for Firebug 1.2
+                this["loadFirebugConsole"]();
+        }else{
+                this.console = this.console || {};
+
+                //      Be careful to leave 'log' always at the end
+                var cn = [
+                        "assert", "count", "debug", "dir", "dirxml", "error", "group",
+                        "groupEnd", "info", "profile", "profileEnd", "time", "timeEnd",
+                        "trace", "warn", "log"
+                ];
+                var i = 0, tn;
+                while((tn=cn[i++])){
+                        if(!console[tn]){
+                                (function(){
+                                        var tcn = tn+"";
+                                        console[tcn] = ('log' in console) ? function(){
+                                                var a = Array.apply({}, arguments);
+                                                a.unshift(tcn+":");
+                                                console["log"](a.join(" "));
+                                        } : function(){}
+                                        console[tcn]._fake = true;
+                                })();
+                        }
+                }
+        }
+
+        //TODOC:  HOW TO DOC THIS?
+        // dojo is the root variable of (almost all) our public symbols -- make sure it is defined.
+        if(typeof dojo == "undefined"){
+                dojo = {
+                        _scopeName: "dojo",
+                        _scopePrefix: "",
+                        _scopePrefixArgs: "",
+                        _scopeSuffix: "",
+                        _scopeMap: {},
+                        _scopeMapRev: {}
+                };
+        }
+
+        var d = dojo;
+
+        //Need placeholders for dijit and dojox for scoping code.
+        if(typeof dijit == "undefined"){
+                dijit = {_scopeName: "dijit"};
+        }
+        if(typeof dojox == "undefined"){
+                dojox = {_scopeName: "dojox"};
+        }
+
+        if(!d._scopeArgs){
+                d._scopeArgs = [dojo, dijit, dojox];
+        }
+
+/*=====
+dojo.global = {
+        //      summary:
+        //              Alias for the global scope
+        //              (e.g. the window object in a browser).
+        //      description:
+        //              Refer to 'dojo.global' rather than referring to window to ensure your
+        //              code runs correctly in contexts other than web browsers (e.g. Rhino on a server).
+}
+=====*/
+        d.global = this;
+
+        d.config =/*===== djConfig = =====*/{
+                isDebug: false,
+                debugAtAllCosts: false
+        };
+
+        // FIXME: 2.0, drop djConfig support. Use dojoConfig exclusively for global config.
+        var cfg = typeof djConfig != "undefined" ? djConfig :
+                typeof dojoConfig != "undefined" ? dojoConfig : null;
+                
+        if(cfg){
+                for(var c in cfg){
+                        d.config[c] = cfg[c];
+                }
+        }
+
+/*=====
+        // Override locale setting, if specified
+        dojo.locale = {
+                // summary: the locale as defined by Dojo (read-only)
+        };
+=====*/
+        dojo.locale = d.config.locale;
+
+        var rev = "$Rev: 24595 $".match(/\d+/);
+
+/*=====
+        dojo.version = function(){
+                // summary:
+                //              Version number of the Dojo Toolkit
+                // major: Integer
+                //              Major version. If total version is "1.2.0beta1", will be 1
+                // minor: Integer
+                //              Minor version. If total version is "1.2.0beta1", will be 2
+                // patch: Integer
+                //              Patch version. If total version is "1.2.0beta1", will be 0
+                // flag: String
+                //              Descriptor flag. If total version is "1.2.0beta1", will be "beta1"
+                // revision: Number
+                //              The SVN rev from which dojo was pulled
+                this.major = 0;
+                this.minor = 0;
+                this.patch = 0;
+                this.flag = "";
+                this.revision = 0;
+        }
+=====*/
+        dojo.version = {
+                major: 1, minor: 6, patch: 1, flag: "",
+                revision: rev ? +rev[0] : NaN,
+                toString: function(){
+                        with(d.version){
+                                return major + "." + minor + "." + patch + flag + " (" + revision + ")";        // String
+                        }
+                }
+        }
+
+                // Register with the OpenAjax hub
+        if(typeof OpenAjax != "undefined"){
+                OpenAjax.hub.registerLibrary(dojo._scopeName, "http://dojotoolkit.org", d.version.toString());
+        }
+        
+        var extraNames, extraLen, empty = {};
+        for(var i in {toString: 1}){ extraNames = []; break; }
+        dojo._extraNames = extraNames = extraNames || ["hasOwnProperty", "valueOf", "isPrototypeOf",
+                "propertyIsEnumerable", "toLocaleString", "toString", "constructor"];
+        extraLen = extraNames.length;
+
+        dojo._mixin = function(/*Object*/ target, /*Object*/ source){
+                // summary:
+                //              Adds all properties and methods of source to target. This addition
+                //              is "prototype extension safe", so that instances of objects
+                //              will not pass along prototype defaults.
+                var name, s, i;
+                for(name in source){
+                        // the "tobj" condition avoid copying properties in "source"
+                        // inherited from Object.prototype.  For example, if target has a custom
+                        // toString() method, don't overwrite it with the toString() method
+                        // that source inherited from Object.prototype
+                        s = source[name];
+                        if(!(name in target) || (target[name] !== s && (!(name in empty) || empty[name] !== s))){
+                                target[name] = s;
+                        }
+                }
+                                // IE doesn't recognize some custom functions in for..in
+                if(extraLen && source){
+                        for(i = 0; i < extraLen; ++i){
+                                name = extraNames[i];
+                                s = source[name];
+                                if(!(name in target) || (target[name] !== s && (!(name in empty) || empty[name] !== s))){
+                                        target[name] = s;
+                                }
+                        }
+                }
+                                return target; // Object
+        }
+
+        dojo.mixin = function(/*Object*/obj, /*Object...*/props){
+                // summary:
+                //              Adds all properties and methods of props to obj and returns the
+                //              (now modified) obj.
+                //      description:
+                //              `dojo.mixin` can mix multiple source objects into a
+                //              destination object which is then returned. Unlike regular
+                //              `for...in` iteration, `dojo.mixin` is also smart about avoiding
+                //              extensions which other toolkits may unwisely add to the root
+                //              object prototype
+                //      obj:
+                //              The object to mix properties into. Also the return value.
+                //      props:
+                //              One or more objects whose values are successively copied into
+                //              obj. If more than one of these objects contain the same value,
+                //              the one specified last in the function call will "win".
+                //      example:
+                //              make a shallow copy of an object
+                //      |       var copy = dojo.mixin({}, source);
+                //      example:
+                //              many class constructors often take an object which specifies
+                //              values to be configured on the object. In this case, it is
+                //              often simplest to call `dojo.mixin` on the `this` object:
+                //      |       dojo.declare("acme.Base", null, {
+                //      |               constructor: function(properties){
+                //      |                       // property configuration:
+                //      |                       dojo.mixin(this, properties);
+                //      |
+                //      |                       console.log(this.quip);
+                //      |                       //  ...
+                //      |               },
+                //      |               quip: "I wasn't born yesterday, you know - I've seen movies.",
+                //      |               // ...
+                //      |       });
+                //      |
+                //      |       // create an instance of the class and configure it
+                //      |       var b = new acme.Base({quip: "That's what it does!" });
+                //      example:
+                //              copy in properties from multiple objects
+                //      |       var flattened = dojo.mixin(
+                //      |               {
+                //      |                       name: "Frylock",
+                //      |                       braces: true
+                //      |               },
+                //      |               {
+                //      |                       name: "Carl Brutanananadilewski"
+                //      |               }
+                //      |       );
+                //      |
+                //      |       // will print "Carl Brutanananadilewski"
+                //      |       console.log(flattened.name);
+                //      |       // will print "true"
+                //      |       console.log(flattened.braces);
+                if(!obj){ obj = {}; }
+                for(var i=1, l=arguments.length; i<l; i++){
+                        d._mixin(obj, arguments[i]);
+                }
+                return obj; // Object
+        }
+
+        dojo._getProp = function(/*Array*/parts, /*Boolean*/create, /*Object*/context){
+                var obj=context || d.global;
+                for(var i=0, p; obj && (p=parts[i]); i++){
+                        if(i == 0 && d._scopeMap[p]){
+                                p = d._scopeMap[p];
+                        }
+                        obj = (p in obj ? obj[p] : (create ? obj[p]={} : undefined));
+                }
+                return obj; // mixed
+        }
+
+        dojo.setObject = function(/*String*/name, /*Object*/value, /*Object?*/context){
+                // summary:
+                //              Set a property from a dot-separated string, such as "A.B.C"
+                //      description:
+                //              Useful for longer api chains where you have to test each object in
+                //              the chain, or when you have an object reference in string format.
+                //              Objects are created as needed along `path`. Returns the passed
+                //              value if setting is successful or `undefined` if not.
+                //      name:
+                //              Path to a property, in the form "A.B.C".
+                //      context:
+                //              Optional. Object to use as root of path. Defaults to
+                //              `dojo.global`.
+                //      example:
+                //              set the value of `foo.bar.baz`, regardless of whether
+                //              intermediate objects already exist:
+                //      |       dojo.setObject("foo.bar.baz", value);
+                //      example:
+                //              without `dojo.setObject`, we often see code like this:
+                //      |       // ensure that intermediate objects are available
+                //      |       if(!obj["parent"]){ obj.parent = {}; }
+                //      |       if(!obj.parent["child"]){ obj.parent.child= {}; }
+                //      |       // now we can safely set the property
+                //      |       obj.parent.child.prop = "some value";
+                //              wheras with `dojo.setObject`, we can shorten that to:
+                //      |       dojo.setObject("parent.child.prop", "some value", obj);
+                var parts=name.split("."), p=parts.pop(), obj=d._getProp(parts, true, context);
+                return obj && p ? (obj[p]=value) : undefined; // Object
+        }
+
+        dojo.getObject = function(/*String*/name, /*Boolean?*/create, /*Object?*/context){
+                // summary:
+                //              Get a property from a dot-separated string, such as "A.B.C"
+                //      description:
+                //              Useful for longer api chains where you have to test each object in
+                //              the chain, or when you have an object reference in string format.
+                //      name:
+                //              Path to an property, in the form "A.B.C".
+                //      create:
+                //              Optional. Defaults to `false`. If `true`, Objects will be
+                //              created at any point along the 'path' that is undefined.
+                //      context:
+                //              Optional. Object to use as root of path. Defaults to
+                //              'dojo.global'. Null may be passed.
+                return d._getProp(name.split("."), create, context); // Object
+        }
+
+        dojo.exists = function(/*String*/name, /*Object?*/obj){
+                //      summary:
+                //              determine if an object supports a given method
+                //      description:
+                //              useful for longer api chains where you have to test each object in
+                //              the chain. Useful for object and method detection.
+                //      name:
+                //              Path to an object, in the form "A.B.C".
+                //      obj:
+                //              Object to use as root of path. Defaults to
+                //              'dojo.global'. Null may be passed.
+                //      example:
+                //      |       // define an object
+                //      |       var foo = {
+                //      |               bar: { }
+                //      |       };
+                //      |
+                //      |       // search the global scope
+                //      |       dojo.exists("foo.bar"); // true
+                //      |       dojo.exists("foo.bar.baz"); // false
+                //      |
+                //      |       // search from a particular scope
+                //      |       dojo.exists("bar", foo); // true
+                //      |       dojo.exists("bar.baz", foo); // false
+                return d.getObject(name, false, obj) !== undefined; // Boolean
+        }
+
+        dojo["eval"] = function(/*String*/ scriptFragment){
+                //      summary:
+                //              A legacy method created for use exclusively by internal Dojo methods. Do not use
+                //              this method directly, the behavior of this eval will differ from the normal
+                //              browser eval.
+                //      description:
+                //              Placed in a separate function to minimize size of trapped
+                //              exceptions. Calling eval() directly from some other scope may
+                //              complicate tracebacks on some platforms.
+                //      returns:
+                //              The result of the evaluation. Often `undefined`
+                return d.global.eval ? d.global.eval(scriptFragment) : eval(scriptFragment);    // Object
+        }
+
+        /*=====
+                dojo.deprecated = function(behaviour, extra, removal){
+                        //      summary:
+                        //              Log a debug message to indicate that a behavior has been
+                        //              deprecated.
+                        //      behaviour: String
+                        //              The API or behavior being deprecated. Usually in the form
+                        //              of "myApp.someFunction()".
+                        //      extra: String?
+                        //              Text to append to the message. Often provides advice on a
+                        //              new function or facility to achieve the same goal during
+                        //              the deprecation period.
+                        //      removal: String?
+                        //              Text to indicate when in the future the behavior will be
+                        //              removed. Usually a version number.
+                        //      example:
+                        //      |       dojo.deprecated("myApp.getTemp()", "use myApp.getLocaleTemp() instead", "1.0");
+                }
+
+                dojo.experimental = function(moduleName, extra){
+                        //      summary: Marks code as experimental.
+                        //      description:
+                        //              This can be used to mark a function, file, or module as
+                        //              experimental.  Experimental code is not ready to be used, and the
+                        //              APIs are subject to change without notice.  Experimental code may be
+                        //              completed deleted without going through the normal deprecation
+                        //              process.
+                        //      moduleName: String
+                        //              The name of a module, or the name of a module file or a specific
+                        //              function
+                        //      extra: String?
+                        //              some additional message for the user
+                        //      example:
+                        //      |       dojo.experimental("dojo.data.Result");
+                        //      example:
+                        //      |       dojo.experimental("dojo.weather.toKelvin()", "PENDING approval from NOAA");
+                }
+        =====*/
+
+        //Real functions declared in dojo._firebug.firebug.
+        d.deprecated = d.experimental = function(){};
+
+})();
+// vim:ai:ts=4:noet
+
+/*
+ * loader.js - A bootstrap module.  Runs before the hostenv_*.js file. Contains
+ * all of the package loading methods.
+ */
+(function(){
+        var d = dojo, currentModule;
+
+        d.mixin(d, {
+                _loadedModules: {},
+                _inFlightCount: 0,
+                _hasResource: {},
+
+                _modulePrefixes: {
+                        dojo:   {       name: "dojo", value: "." },
+                        // dojox:       {       name: "dojox", value: "../dojox" },
+                        // dijit:       {       name: "dijit", value: "../dijit" },
+                        doh:    {       name: "doh", value: "../util/doh" },
+                        tests:  {       name: "tests", value: "tests" }
+                },
+
+                _moduleHasPrefix: function(/*String*/module){
+                        // summary: checks to see if module has been established
+                        var mp = d._modulePrefixes;
+                        return !!(mp[module] && mp[module].value); // Boolean
+                },
+
+                _getModulePrefix: function(/*String*/module){
+                        // summary: gets the prefix associated with module
+                        var mp = d._modulePrefixes;
+                        if(d._moduleHasPrefix(module)){
+                                return mp[module].value; // String
+                        }
+                        return module; // String
+                },
+
+                _loadedUrls: [],
+
+                //WARNING:
+                //              This variable is referenced by packages outside of bootstrap:
+                //              FloatingPane.js and undo/browser.js
+                _postLoad: false,
+
+                //Egad! Lots of test files push on this directly instead of using dojo.addOnLoad.
+                _loaders: [],
+                _unloaders: [],
+                _loadNotifying: false
+        });
+
+
+                dojo._loadPath = function(/*String*/relpath, /*String?*/module, /*Function?*/cb){
+                //      summary:
+                //              Load a Javascript module given a relative path
+                //
+                //      description:
+                //              Loads and interprets the script located at relpath, which is
+                //              relative to the script root directory.  If the script is found but
+                //              its interpretation causes a runtime exception, that exception is
+                //              not caught by us, so the caller will see it.  We return a true
+                //              value if and only if the script is found.
+                //
+                // relpath:
+                //              A relative path to a script (no leading '/', and typically ending
+                //              in '.js').
+                // module:
+                //              A module whose existance to check for after loading a path.  Can be
+                //              used to determine success or failure of the load.
+                // cb:
+                //              a callback function to pass the result of evaluating the script
+
+                var uri = ((relpath.charAt(0) == '/' || relpath.match(/^\w+:/)) ? "" : d.baseUrl) + relpath;
+                try{
+                        currentModule = module;
+                        return !module ? d._loadUri(uri, cb) : d._loadUriAndCheck(uri, module, cb); // Boolean
+                }catch(e){
+                        console.error(e);
+                        return false; // Boolean
+                }finally{
+                        currentModule = null;
+                }
+        }
+
+        dojo._loadUri = function(/*String*/uri, /*Function?*/cb){
+                //      summary:
+                //              Loads JavaScript from a URI
+                //      description:
+                //              Reads the contents of the URI, and evaluates the contents.  This is
+                //              used to load modules as well as resource bundles. Returns true if
+                //              it succeeded. Returns false if the URI reading failed.  Throws if
+                //              the evaluation throws.
+                //      uri: a uri which points at the script to be loaded
+                //      cb:
+                //              a callback function to process the result of evaluating the script
+                //              as an expression, typically used by the resource bundle loader to
+                //              load JSON-style resources
+
+                if(d._loadedUrls[uri]){
+                        return true; // Boolean
+                }
+                d._inFlightCount++; // block addOnLoad calls that arrive while we're busy downloading
+                var contents = d._getText(uri, true);
+                if(contents){ // not 404, et al
+                        d._loadedUrls[uri] = true;
+                        d._loadedUrls.push(uri);
+                        if(cb){
+                                //conditional to support script-inject i18n bundle format
+                                contents = /^define\(/.test(contents) ? contents : '('+contents+')';
+                        }else{
+                                //Only do the scoping if no callback. If a callback is specified,
+                                //it is most likely the i18n bundle stuff.
+                                contents = d._scopePrefix + contents + d._scopeSuffix;
+                        }
+                        if(!d.isIE){ contents += "\r\n//@ sourceURL=" + uri; } // debugging assist for Firebug
+                        var value = d["eval"](contents);
+                        if(cb){ cb(value); }
+                }
+                // Check to see if we need to call _callLoaded() due to an addOnLoad() that arrived while we were busy downloading
+                if(--d._inFlightCount == 0 && d._postLoad && d._loaders.length){
+                        // We shouldn't be allowed to get here but Firefox allows an event
+                        // (mouse, keybd, async xhrGet) to interrupt a synchronous xhrGet.
+                        // If the current script block contains multiple require() statements, then after each
+                        // require() returns, inFlightCount == 0, but we want to hold the _callLoaded() until
+                        // all require()s are done since the out-of-sequence addOnLoad() presumably needs them all.
+                        // setTimeout allows the next require() to start (if needed), and then we check this again.
+                        setTimeout(function(){
+                                // If inFlightCount > 0, then multiple require()s are running sequentially and
+                                // the next require() started after setTimeout() was executed but before we got here.
+                                if(d._inFlightCount == 0){
+                                        d._callLoaded();
+                                }
+                        }, 0);
+                }
+                return !!contents; // Boolean: contents? true : false
+        }
+        
+        // FIXME: probably need to add logging to this method
+        dojo._loadUriAndCheck = function(/*String*/uri, /*String*/moduleName, /*Function?*/cb){
+                // summary: calls loadUri then findModule and returns true if both succeed
+                var ok = false;
+                try{
+                        ok = d._loadUri(uri, cb);
+                }catch(e){
+                        console.error("failed loading " + uri + " with error: " + e);
+                }
+                return !!(ok && d._loadedModules[moduleName]); // Boolean
+        }
+
+        dojo.loaded = function(){
+                // summary:
+                //              signal fired when initial environment and package loading is
+                //              complete. You should use dojo.addOnLoad() instead of doing a
+                //              direct dojo.connect() to this method in order to handle
+                //              initialization tasks that require the environment to be
+                //              initialized. In a browser host, declarative widgets will
+                //              be constructed when this function finishes runing.
+                d._loadNotifying = true;
+                d._postLoad = true;
+                var mll = d._loaders;
+
+                //Clear listeners so new ones can be added
+                //For other xdomain package loads after the initial load.
+                d._loaders = [];
+
+                for(var x = 0; x < mll.length; x++){
+                        mll[x]();
+                }
+
+                d._loadNotifying = false;
+                
+                //Make sure nothing else got added to the onload queue
+                //after this first run. If something did, and we are not waiting for any
+                //more inflight resources, run again.
+                if(d._postLoad && d._inFlightCount == 0 && mll.length){
+                        d._callLoaded();
+                }
+        }
+
+        dojo.unloaded = function(){
+                // summary:
+                //              signal fired by impending environment destruction. You should use
+                //              dojo.addOnUnload() instead of doing a direct dojo.connect() to this
+                //              method to perform page/application cleanup methods. See
+                //              dojo.addOnUnload for more info.
+                var mll = d._unloaders;
+                while(mll.length){
+                        (mll.pop())();
+                }
+        }
+
+        d._onto = function(arr, obj, fn){
+                if(!fn){
+                        arr.push(obj);
+                }else if(fn){
+                        var func = (typeof fn == "string") ? obj[fn] : fn;
+                        arr.push(function(){ func.call(obj); });
+                }
+        }
+
+        dojo.ready = dojo.addOnLoad = function(/*Object*/obj, /*String|Function?*/functionName){
+                // summary:
+                //              Registers a function to be triggered after the DOM and dojo.require() calls
+                //              have finished loading.
+                //
+                // description:
+                //              Registers a function to be triggered after the DOM has finished
+                //              loading and `dojo.require` modules have loaded. Widgets declared in markup
+                //              have been instantiated if `djConfig.parseOnLoad` is true when this fires.
+                //
+                //              Images and CSS files may or may not have finished downloading when
+                //              the specified function is called.  (Note that widgets' CSS and HTML
+                //              code is guaranteed to be downloaded before said widgets are
+                //              instantiated, though including css resouces BEFORE any script elements
+                //              is highly recommended).
+                //
+                // example:
+                //      Register an anonymous function to run when everything is ready
+                //      |       dojo.addOnLoad(function(){ doStuff(); });
+                //
+                // example:
+                //      Register a function to run when everything is ready by pointer:
+                //      |       var init = function(){ doStuff(); }
+                //      |       dojo.addOnLoad(init);
+                //
+                // example:
+                //      Register a function to run scoped to `object`, either by name or anonymously:
+                //      |       dojo.addOnLoad(object, "functionName");
+                //      |       dojo.addOnLoad(object, function(){ doStuff(); });
+
+                d._onto(d._loaders, obj, functionName);
+
+                //Added for xdomain loading. dojo.addOnLoad is used to
+                //indicate callbacks after doing some dojo.require() statements.
+                //In the xdomain case, if all the requires are loaded (after initial
+                //page load), then immediately call any listeners.
+                if(d._postLoad && d._inFlightCount == 0 && !d._loadNotifying){
+                        d._callLoaded();
+                }
+        }
+
+        //Support calling dojo.addOnLoad via djConfig.addOnLoad. Support all the
+        //call permutations of dojo.addOnLoad. Mainly useful when dojo is added
+        //to the page after the page has loaded.
+        var dca = d.config.addOnLoad;
+        if(dca){
+                d.addOnLoad[(dca instanceof Array ? "apply" : "call")](d, dca);
+        }
+
+        dojo._modulesLoaded = function(){
+                if(d._postLoad){ return; }
+                if(d._inFlightCount > 0){
+                        console.warn("files still in flight!");
+                        return;
+                }
+                d._callLoaded();
+        }
+
+        dojo._callLoaded = function(){
+
+                // The "object" check is for IE, and the other opera check fixes an
+                // issue in Opera where it could not find the body element in some
+                // widget test cases.  For 0.9, maybe route all browsers through the
+                // setTimeout (need protection still for non-browser environments
+                // though). This might also help the issue with FF 2.0 and freezing
+                // issues where we try to do sync xhr while background css images are
+                // being loaded (trac #2572)? Consider for 0.9.
+                if(typeof setTimeout == "object" || (d.config.useXDomain && d.isOpera)){
+                        setTimeout(
+                                d.isAIR ? function(){ d.loaded(); } : d._scopeName + ".loaded();",
+                                0);
+                }else{
+                        d.loaded();
+                }
+        }
+
+        dojo._getModuleSymbols = function(/*String*/modulename){
+                // summary:
+                //              Converts a module name in dotted JS notation to an array
+                //              representing the path in the source tree
+                var syms = modulename.split(".");
+                for(var i = syms.length; i>0; i--){
+                        var parentModule = syms.slice(0, i).join(".");
+                        if(i == 1 && !d._moduleHasPrefix(parentModule)){
+                                // Support default module directory (sibling of dojo) for top-level modules
+                                syms[0] = "../" + syms[0];
+                        }else{
+                                var parentModulePath = d._getModulePrefix(parentModule);
+                                if(parentModulePath != parentModule){
+                                        syms.splice(0, i, parentModulePath);
+                                        break;
+                                }
+                        }
+                }
+                return syms; // Array
+        }
+
+        dojo._global_omit_module_check = false;
+
+        dojo.loadInit = function(/*Function*/init){
+                //      summary:
+                //              Executes a function that needs to be executed for the loader's dojo.requireIf
+                //              resolutions to work. This is needed mostly for the xdomain loader case where
+                //              a function needs to be executed to set up the possible values for a dojo.requireIf
+                //              call.
+                //      init:
+                //              a function reference. Executed immediately.
+                //      description: This function is mainly a marker for the xdomain loader to know parts of
+                //              code that needs be executed outside the function wrappper that is placed around modules.
+                //              The init function could be executed more than once, and it should make no assumptions
+                //              on what is loaded, or what modules are available. Only the functionality in Dojo Base
+                //              is allowed to be used. Avoid using this method. For a valid use case,
+                //              see the source for dojox.gfx.
+                init();
+        }
+
+        dojo._loadModule = dojo.require = function(/*String*/moduleName, /*Boolean?*/omitModuleCheck){
+                //      summary:
+                //              loads a Javascript module from the appropriate URI
+                //
+                //      moduleName: String
+                //              module name to load, using periods for separators,
+                //               e.g. "dojo.date.locale".  Module paths are de-referenced by dojo's
+                //              internal mapping of locations to names and are disambiguated by
+                //              longest prefix. See `dojo.registerModulePath()` for details on
+                //              registering new modules.
+                //
+                //      omitModuleCheck: Boolean?
+                //              if `true`, omitModuleCheck skips the step of ensuring that the
+                //              loaded file actually defines the symbol it is referenced by.
+                //              For example if it called as `dojo.require("a.b.c")` and the
+                //              file located at `a/b/c.js` does not define an object `a.b.c`,
+                //              and exception will be throws whereas no exception is raised
+                //              when called as `dojo.require("a.b.c", true)`
+                //
+                //      description:
+                //              Modules are loaded via dojo.require by using one of two loaders: the normal loader
+                //              and the xdomain loader. The xdomain loader is used when dojo was built with a
+                //              custom build that specified loader=xdomain and the module lives on a modulePath
+                //              that is a whole URL, with protocol and a domain. The versions of Dojo that are on
+                //              the Google and AOL CDNs use the xdomain loader.
+                //
+                //              If the module is loaded via the xdomain loader, it is an asynchronous load, since
+                //              the module is added via a dynamically created script tag. This
+                //              means that dojo.require() can return before the module has loaded. However, this
+                //              should only happen in the case where you do dojo.require calls in the top-level
+                //              HTML page, or if you purposely avoid the loader checking for dojo.require
+                //              dependencies in your module by using a syntax like dojo["require"] to load the module.
+                //
+                //              Sometimes it is useful to not have the loader detect the dojo.require calls in the
+                //              module so that you can dynamically load the modules as a result of an action on the
+                //              page, instead of right at module load time.
+                //
+                //              Also, for script blocks in an HTML page, the loader does not pre-process them, so
+                //              it does not know to download the modules before the dojo.require calls occur.
+                //
+                //              So, in those two cases, when you want on-the-fly module loading or for script blocks
+                //              in the HTML page, special care must be taken if the dojo.required code is loaded
+                //              asynchronously. To make sure you can execute code that depends on the dojo.required
+                //              modules, be sure to add the code that depends on the modules in a dojo.addOnLoad()
+                //              callback. dojo.addOnLoad waits for all outstanding modules to finish loading before
+                //              executing.
+                //
+                //              This type of syntax works with both xdomain and normal loaders, so it is good
+                //              practice to always use this idiom for on-the-fly code loading and in HTML script
+                //              blocks. If at some point you change loaders and where the code is loaded from,
+                //              it will all still work.
+                //
+                //              More on how dojo.require
+                //              `dojo.require("A.B")` first checks to see if symbol A.B is
+                //              defined. If it is, it is simply returned (nothing to do).
+                //
+                //              If it is not defined, it will look for `A/B.js` in the script root
+                //              directory.
+                //
+                //              `dojo.require` throws an exception if it cannot find a file
+                //              to load, or if the symbol `A.B` is not defined after loading.
+                //
+                //              It returns the object `A.B`, but note the caveats above about on-the-fly loading and
+                //              HTML script blocks when the xdomain loader is loading a module.
+                //
+                //              `dojo.require()` does nothing about importing symbols into
+                //              the current namespace.  It is presumed that the caller will
+                //              take care of that.
+                //
+                //      example:
+                //              To use dojo.require in conjunction with dojo.ready:
+                //
+                //              |       dojo.require("foo");
+                //              |       dojo.require("bar");
+                //              |       dojo.addOnLoad(function(){
+                //              |               //you can now safely do something with foo and bar
+                //              |       });
+                //
+                //      example:
+                //              For example, to import all symbols into a local block, you might write:
+                //
+                //              |       with (dojo.require("A.B")) {
+                //              |               ...
+                //              |       }
+                //
+                //              And to import just the leaf symbol to a local variable:
+                //
+                //              |       var B = dojo.require("A.B");
+                //              |       ...
+                //
+                //      returns:
+                //              the required namespace object
+                omitModuleCheck = d._global_omit_module_check || omitModuleCheck;
+
+                //Check if it is already loaded.
+                var module = d._loadedModules[moduleName];
+                if(module){
+                        return module;
+                }
+
+                // convert periods to slashes
+                var relpath = d._getModuleSymbols(moduleName).join("/") + '.js';
+                var modArg = !omitModuleCheck ? moduleName : null;
+                var ok = d._loadPath(relpath, modArg);
+                if(!ok && !omitModuleCheck){
+                        throw new Error("Could not load '" + moduleName + "'; last tried '" + relpath + "'");
+                }
+
+                // check that the symbol was defined
+                // Don't bother if we're doing xdomain (asynchronous) loading.
+                if(!omitModuleCheck && !d._isXDomain){
+                        // pass in false so we can give better error
+                        module = d._loadedModules[moduleName];
+                        if(!module){
+                                throw new Error("symbol '" + moduleName + "' is not defined after loading '" + relpath + "'");
+                        }
+                }
+
+                return module;
+        }
+
+        dojo.provide = function(/*String*/ resourceName){
+                //      summary:
+                //              Register a resource with the package system. Works in conjunction with `dojo.require`
+                //
+                //      description:
+                //              Each javascript source file is called a resource.  When a
+                //              resource is loaded by the browser, `dojo.provide()` registers
+                //              that it has been loaded.
+                //
+                //              Each javascript source file must have at least one
+                //              `dojo.provide()` call at the top of the file, corresponding to
+                //              the file name.  For example, `js/dojo/foo.js` must have
+                //              `dojo.provide("dojo.foo");` before any calls to
+                //              `dojo.require()` are made.
+                //
+                //              For backwards compatibility reasons, in addition to registering
+                //              the resource, `dojo.provide()` also ensures that the javascript
+                //              object for the module exists.  For example,
+                //              `dojo.provide("dojox.data.FlickrStore")`, in addition to
+                //              registering that `FlickrStore.js` is a resource for the
+                //              `dojox.data` module, will ensure that the `dojox.data`
+                //              javascript object exists, so that calls like
+                //              `dojo.data.foo = function(){ ... }` don't fail.
+                //
+                //              In the case of a build where multiple javascript source files
+                //              are combined into one bigger file (similar to a .lib or .jar
+                //              file), that file may contain multiple dojo.provide() calls, to
+                //              note that it includes multiple resources.
+                //
+                // resourceName: String
+                //              A dot-sperated string identifying a resource.
+                //
+                // example:
+                //      Safely create a `my` object, and make dojo.require("my.CustomModule") work
+                //      |       dojo.provide("my.CustomModule");
+
+                //Make sure we have a string.
+                resourceName = resourceName + "";
+                return (d._loadedModules[resourceName] = d.getObject(resourceName, true)); // Object
+        }
+
+        //Start of old bootstrap2:
+
+        dojo.platformRequire = function(/*Object*/modMap){
+                //      summary:
+                //              require one or more modules based on which host environment
+                //              Dojo is currently operating in
+                //      description:
+                //              This method takes a "map" of arrays which one can use to
+                //              optionally load dojo modules. The map is indexed by the
+                //              possible dojo.name_ values, with two additional values:
+                //              "default" and "common". The items in the "default" array will
+                //              be loaded if none of the other items have been choosen based on
+                //              dojo.name_, set by your host environment. The items in the
+                //              "common" array will *always* be loaded, regardless of which
+                //              list is chosen.
+                //      example:
+                //              |       dojo.platformRequire({
+                //              |               browser: [
+                //              |                       "foo.sample", // simple module
+                //              |                       "foo.test",
+                //              |                       ["foo.bar.baz", true] // skip object check in _loadModule (dojo.require)
+                //              |               ],
+                //              |               default: [ "foo.sample._base" ],
+                //              |               common: [ "important.module.common" ]
+                //              |       });
+
+                var common = modMap.common || [];
+                var result = common.concat(modMap[d._name] || modMap["default"] || []);
+
+                for(var x=0; x<result.length; x++){
+                        var curr = result[x];
+                        if(curr.constructor == Array){
+                                d._loadModule.apply(d, curr);
+                        }else{
+                                d._loadModule(curr);
+                        }
+                }
+        }
+
+        dojo.requireIf = function(/*Boolean*/ condition, /*String*/ resourceName){
+                // summary:
+                //              If the condition is true then call `dojo.require()` for the specified
+                //              resource
+                //
+                // example:
+                //      |       dojo.requireIf(dojo.isBrowser, "my.special.Module");
+                
+                if(condition === true){
+                        // FIXME: why do we support chained require()'s here? does the build system?
+                        var args = [];
+                        for(var i = 1; i < arguments.length; i++){
+                                args.push(arguments[i]);
+                        }
+                        d.require.apply(d, args);
+                }
+        }
+
+        dojo.requireAfterIf = d.requireIf;
+
+        dojo.registerModulePath = function(/*String*/module, /*String*/prefix){
+                //      summary:
+                //              Maps a module name to a path
+                //      description:
+                //              An unregistered module is given the default path of ../[module],
+                //              relative to Dojo root. For example, module acme is mapped to
+                //              ../acme.  If you want to use a different module name, use
+                //              dojo.registerModulePath.
+                //      example:
+                //              If your dojo.js is located at this location in the web root:
+                //      |       /myapp/js/dojo/dojo/dojo.js
+                //              and your modules are located at:
+                //      |       /myapp/js/foo/bar.js
+                //      |       /myapp/js/foo/baz.js
+                //      |       /myapp/js/foo/thud/xyzzy.js
+                //              Your application can tell Dojo to locate the "foo" namespace by calling:
+                //      |       dojo.registerModulePath("foo", "../../foo");
+                //              At which point you can then use dojo.require() to load the
+                //              modules (assuming they provide() the same things which are
+                //              required). The full code might be:
+                //      |       <script type="text/javascript"
+                //      |               src="/myapp/js/dojo/dojo/dojo.js"></script>
+                //      |       <script type="text/javascript">
+                //      |               dojo.registerModulePath("foo", "../../foo");
+                //      |               dojo.require("foo.bar");
+                //      |               dojo.require("foo.baz");
+                //      |               dojo.require("foo.thud.xyzzy");
+                //      |       </script>
+                d._modulePrefixes[module] = { name: module, value: prefix };
+        };
+        
+        dojo.requireLocalization = function(/*String*/moduleName, /*String*/bundleName, /*String?*/locale, /*String?*/availableFlatLocales){
+                // summary:
+                //              Declares translated resources and loads them if necessary, in the
+                //              same style as dojo.require.  Contents of the resource bundle are
+                //              typically strings, but may be any name/value pair, represented in
+                //              JSON format.  See also `dojo.i18n.getLocalization`.
+                //
+                // description:
+                //              Load translated resource bundles provided underneath the "nls"
+                //              directory within a package.  Translated resources may be located in
+                //              different packages throughout the source tree.
+                //
+                //              Each directory is named for a locale as specified by RFC 3066,
+                //              (http://www.ietf.org/rfc/rfc3066.txt), normalized in lowercase.
+                //              Note that the two bundles in the example do not define all the
+                //              same variants.  For a given locale, bundles will be loaded for
+                //              that locale and all more general locales above it, including a
+                //              fallback at the root directory.  For example, a declaration for
+                //              the "de-at" locale will first load `nls/de-at/bundleone.js`,
+                //              then `nls/de/bundleone.js` and finally `nls/bundleone.js`.  The
+                //              data will be flattened into a single Object so that lookups
+                //              will follow this cascading pattern.  An optional build step can
+                //              preload the bundles to avoid data redundancy and the multiple
+                //              network hits normally required to load these resources.
+                //
+                // moduleName:
+                //              name of the package containing the "nls" directory in which the
+                //              bundle is found
+                //
+                // bundleName:
+                //              bundle name, i.e. the filename without the '.js' suffix. Using "nls" as a
+                //              a bundle name is not supported, since "nls" is the name of the folder
+                //              that holds bundles. Using "nls" as the bundle name will cause problems
+                //              with the custom build.
+                //
+                // locale:
+                //              the locale to load (optional)  By default, the browser's user
+                //              locale as defined by dojo.locale
+                //
+                // availableFlatLocales:
+                //              A comma-separated list of the available, flattened locales for this
+                //              bundle. This argument should only be set by the build process.
+                //
+                //      example:
+                //              A particular widget may define one or more resource bundles,
+                //              structured in a program as follows, where moduleName is
+                //              mycode.mywidget and bundleNames available include bundleone and
+                //              bundletwo:
+                //      |               ...
+                //      |       mycode/
+                //      |               mywidget/
+                //      |                       nls/
+                //      |                               bundleone.js (the fallback translation, English in this example)
+                //      |                               bundletwo.js (also a fallback translation)
+                //      |                               de/
+                //      |                                       bundleone.js
+                //      |                                       bundletwo.js
+                //      |                               de-at/
+                //      |                                       bundleone.js
+                //      |                               en/
+                //      |                                       (empty; use the fallback translation)
+                //      |                               en-us/
+                //      |                                       bundleone.js
+                //      |                               en-gb/
+                //      |                                       bundleone.js
+                //      |                               es/
+                //      |                                       bundleone.js
+                //      |                                       bundletwo.js
+                //      |                                 ...etc
+                //      |                               ...
+                //
+
+                d.require("dojo.i18n");
+                d.i18n._requireLocalization.apply(d.hostenv, arguments);
+        };
+
+
+        var ore = new RegExp("^(([^:/?#]+):)?(//([^/?#]*))?([^?#]*)(\\?([^#]*))?(#(.*))?$"),
+                ire = new RegExp("^((([^\\[:]+):)?([^@]+)@)?(\\[([^\\]]+)\\]|([^\\[:]*))(:([0-9]+))?$");
+
+        dojo._Url = function(/*dojo._Url|String...*/){
+                // summary:
+                //              Constructor to create an object representing a URL.
+                //              It is marked as private, since we might consider removing
+                //              or simplifying it.
+                // description:
+                //              Each argument is evaluated in order relative to the next until
+                //              a canonical uri is produced. To get an absolute Uri relative to
+                //              the current document use:
+                //              new dojo._Url(document.baseURI, url)
+
+                var n = null,
+                        _a = arguments,
+                        uri = [_a[0]];
+                // resolve uri components relative to each other
+                for(var i = 1; i<_a.length; i++){
+                        if(!_a[i]){ continue; }
+
+                        // Safari doesn't support this.constructor so we have to be explicit
+                        // FIXME: Tracked (and fixed) in Webkit bug 3537.
+                        //              http://bugs.webkit.org/show_bug.cgi?id=3537
+                        var relobj = new d._Url(_a[i]+""),
+                                uriobj = new d._Url(uri[0]+"");
+
+                        if(
+                                relobj.path == "" &&
+                                !relobj.scheme &&
+                                !relobj.authority &&
+                                !relobj.query
+                        ){
+                                if(relobj.fragment != n){
+                                        uriobj.fragment = relobj.fragment;
+                                }
+                                relobj = uriobj;
+                        }else if(!relobj.scheme){
+                                relobj.scheme = uriobj.scheme;
+
+                                if(!relobj.authority){
+                                        relobj.authority = uriobj.authority;
+
+                                        if(relobj.path.charAt(0) != "/"){
+                                                var path = uriobj.path.substring(0,
+                                                        uriobj.path.lastIndexOf("/") + 1) + relobj.path;
+
+                                                var segs = path.split("/");
+                                                for(var j = 0; j < segs.length; j++){
+                                                        if(segs[j] == "."){
+                                                                // flatten "./" references
+                                                                if(j == segs.length - 1){
+                                                                        segs[j] = "";
+                                                                }else{
+                                                                        segs.splice(j, 1);
+                                                                        j--;
+                                                                }
+                                                        }else if(j > 0 && !(j == 1 && segs[0] == "") &&
+                                                                segs[j] == ".." && segs[j-1] != ".."){
+                                                                // flatten "../" references
+                                                                if(j == (segs.length - 1)){
+                                                                        segs.splice(j, 1);
+                                                                        segs[j - 1] = "";
+                                                                }else{
+                                                                        segs.splice(j - 1, 2);
+                                                                        j -= 2;
+                                                                }
+                                                        }
+                                                }
+                                                relobj.path = segs.join("/");
+                                        }
+                                }
+                        }
+
+                        uri = [];
+                        if(relobj.scheme){
+                                uri.push(relobj.scheme, ":");
+                        }
+                        if(relobj.authority){
+                                uri.push("//", relobj.authority);
+                        }
+                        uri.push(relobj.path);
+                        if(relobj.query){
+                                uri.push("?", relobj.query);
+                        }
+                        if(relobj.fragment){
+                                uri.push("#", relobj.fragment);
+                        }
+                }
+
+                this.uri = uri.join("");
+
+                // break the uri into its main components
+                var r = this.uri.match(ore);
+
+                this.scheme = r[2] || (r[1] ? "" : n);
+                this.authority = r[4] || (r[3] ? "" : n);
+                this.path = r[5]; // can never be undefined
+                this.query = r[7] || (r[6] ? "" : n);
+                this.fragment  = r[9] || (r[8] ? "" : n);
+
+                if(this.authority != n){
+                        // server based naming authority
+                        r = this.authority.match(ire);
+
+                        this.user = r[3] || n;
+                        this.password = r[4] || n;
+                        this.host = r[6] || r[7]; // ipv6 || ipv4
+                        this.port = r[9] || n;
+                }
+        }
+
+        dojo._Url.prototype.toString = function(){ return this.uri; };
+
+        dojo.moduleUrl = function(/*String*/module, /*dojo._Url||String*/url){
+                //      summary:
+                //              Returns a `dojo._Url` object relative to a module.
+                //      example:
+                //      |       var pngPath = dojo.moduleUrl("acme","images/small.png");
+                //      |       console.dir(pngPath); // list the object properties
+                //      |       // create an image and set it's source to pngPath's value:
+                //      |       var img = document.createElement("img");
+                //      |       // NOTE: we assign the string representation of the url object
+                //      |       img.src = pngPath.toString();
+                //      |       // add our image to the document
+                //      |       dojo.body().appendChild(img);
+                //      example:
+                //              you may de-reference as far as you like down the package
+                //              hierarchy.  This is sometimes handy to avoid lenghty relative
+                //              urls or for building portable sub-packages. In this example,
+                //              the `acme.widget` and `acme.util` directories may be located
+                //              under different roots (see `dojo.registerModulePath`) but the
+                //              the modules which reference them can be unaware of their
+                //              relative locations on the filesystem:
+                //      |       // somewhere in a configuration block
+                //      |       dojo.registerModulePath("acme.widget", "../../acme/widget");
+                //      |       dojo.registerModulePath("acme.util", "../../util");
+                //      |
+                //      |       // ...
+                //      |
+                //      |       // code in a module using acme resources
+                //      |       var tmpltPath = dojo.moduleUrl("acme.widget","templates/template.html");
+                //      |       var dataPath = dojo.moduleUrl("acme.util","resources/data.json");
+
+                var loc = d._getModuleSymbols(module).join('/');
+                if(!loc){ return null; }
+                if(loc.lastIndexOf("/") != loc.length-1){
+                        loc += "/";
+                }
+                
+                //If the path is an absolute path (starts with a / or is on another
+                //domain/xdomain) then don't add the baseUrl.
+                var colonIndex = loc.indexOf(":");
+                if(loc.charAt(0) != "/" && (colonIndex == -1 || colonIndex > loc.indexOf("/"))){
+                        loc = d.baseUrl + loc;
+                }
+
+                return new d._Url(loc, url); // dojo._Url
+        };
+
+
+
+})();
+
+/*=====
+dojo.isBrowser = {
+        //      example:
+        //      |       if(dojo.isBrowser){ ... }
+};
+
+dojo.isFF = {
+        //      example:
+        //      |       if(dojo.isFF > 1){ ... }
+};
+
+dojo.isIE = {
+        // example:
+        //      |       if(dojo.isIE > 6){
+        //      |               // we are IE7
+        //      |       }
+};
+
+dojo.isSafari = {
+        //      example:
+        //      |       if(dojo.isSafari){ ... }
+        //      example:
+        //              Detect iPhone:
+        //      |       if(dojo.isSafari && navigator.userAgent.indexOf("iPhone") != -1){
+        //      |               // we are iPhone. Note, iPod touch reports "iPod" above and fails this test.
+        //      |       }
+};
+
+dojo = {
+        // isBrowser: Boolean
+        //              True if the client is a web-browser
+        isBrowser: true,
+        //      isFF: Number | undefined
+        //              Version as a Number if client is FireFox. undefined otherwise. Corresponds to
+        //              major detected FireFox version (1.5, 2, 3, etc.)
+        isFF: 2,
+        //      isIE: Number | undefined
+        //              Version as a Number if client is MSIE(PC). undefined otherwise. Corresponds to
+        //              major detected IE version (6, 7, 8, etc.)
+        isIE: 6,
+        //      isKhtml: Number | undefined
+        //              Version as a Number if client is a KHTML browser. undefined otherwise. Corresponds to major
+        //              detected version.
+        isKhtml: 0,
+        //      isWebKit: Number | undefined
+        //              Version as a Number if client is a WebKit-derived browser (Konqueror,
+        //              Safari, Chrome, etc.). undefined otherwise.
+        isWebKit: 0,
+        //      isMozilla: Number | undefined
+        //              Version as a Number if client is a Mozilla-based browser (Firefox,
+        //              SeaMonkey). undefined otherwise. Corresponds to major detected version.
+        isMozilla: 0,
+        //      isOpera: Number | undefined
+        //              Version as a Number if client is Opera. undefined otherwise. Corresponds to
+        //              major detected version.
+        isOpera: 0,
+        //      isSafari: Number | undefined
+        //              Version as a Number if client is Safari or iPhone. undefined otherwise.
+        isSafari: 0,
+        //      isChrome: Number | undefined
+        //              Version as a Number if client is Chrome browser. undefined otherwise.
+        isChrome: 0
+        //      isMac: Boolean
+        //              True if the client runs on Mac
+}
+=====*/
+if(typeof window != 'undefined'){
+        dojo.isBrowser = true;
+        dojo._name = "browser";
+
+
+        // attempt to figure out the path to dojo if it isn't set in the config
+        (function(){
+                var d = dojo;
+
+                // this is a scope protection closure. We set browser versions and grab
+                // the URL we were loaded from here.
+
+                // grab the node we were loaded from
+                if(document && document.getElementsByTagName){
+                        var scripts = document.getElementsByTagName("script");
+                        var rePkg = /dojo(\.xd)?\.js(\W|$)/i;
+                        for(var i = 0; i < scripts.length; i++){
+                                var src = scripts[i].getAttribute("src");
+                                if(!src){ continue; }
+                                var m = src.match(rePkg);
+                                if(m){
+                                        // find out where we came from
+                                        if(!d.config.baseUrl){
+                                                d.config.baseUrl = src.substring(0, m.index);
+                                        }
+                                        // and find out if we need to modify our behavior
+                                        var cfg = (scripts[i].getAttribute("djConfig") || scripts[i].getAttribute("data-dojo-config"));
+                                        if(cfg){
+                                                var cfgo = eval("({ "+cfg+" })");
+                                                for(var x in cfgo){
+                                                        dojo.config[x] = cfgo[x];
+                                                }
+                                        }
+                                        break; // "first Dojo wins"
+                                }
+                        }
+                }
+                d.baseUrl = d.config.baseUrl;
+
+                // fill in the rendering support information in dojo.render.*
+                var n = navigator;
+                var dua = n.userAgent,
+                        dav = n.appVersion,
+                        tv = parseFloat(dav);
+
+                if(dua.indexOf("Opera") >= 0){ d.isOpera = tv; }
+                if(dua.indexOf("AdobeAIR") >= 0){ d.isAIR = 1; }
+                d.isKhtml = (dav.indexOf("Konqueror") >= 0) ? tv : 0;
+                d.isWebKit = parseFloat(dua.split("WebKit/")[1]) || undefined;
+                d.isChrome = parseFloat(dua.split("Chrome/")[1]) || undefined;
+                d.isMac = dav.indexOf("Macintosh") >= 0;
+
+                // safari detection derived from:
+                //              http://developer.apple.com/internet/safari/faq.html#anchor2
+                //              http://developer.apple.com/internet/safari/uamatrix.html
+                var index = Math.max(dav.indexOf("WebKit"), dav.indexOf("Safari"), 0);
+                if(index && !dojo.isChrome){
+                        // try to grab the explicit Safari version first. If we don't get
+                        // one, look for less than 419.3 as the indication that we're on something
+                        // "Safari 2-ish".
+                        d.isSafari = parseFloat(dav.split("Version/")[1]);
+                        if(!d.isSafari || parseFloat(dav.substr(index + 7)) <= 419.3){
+                                d.isSafari = 2;
+                        }
+                }
+
+                                if(dua.indexOf("Gecko") >= 0 && !d.isKhtml && !d.isWebKit){ d.isMozilla = d.isMoz = tv; }
+                if(d.isMoz){
+                        //We really need to get away from this. Consider a sane isGecko approach for the future.
+                        d.isFF = parseFloat(dua.split("Firefox/")[1] || dua.split("Minefield/")[1]) || undefined;
+                }
+                if(document.all && !d.isOpera){
+                        d.isIE = parseFloat(dav.split("MSIE ")[1]) || undefined;
+                        //In cases where the page has an HTTP header or META tag with
+                        //X-UA-Compatible, then it is in emulation mode.
+                        //Make sure isIE reflects the desired version.
+                        //document.documentMode of 5 means quirks mode.
+                        //Only switch the value if documentMode's major version
+                        //is different from isIE's major version.
+                        var mode = document.documentMode;
+                        if(mode && mode != 5 && Math.floor(d.isIE) != mode){
+                                d.isIE = mode;
+                        }
+                }
+
+                //Workaround to get local file loads of dojo to work on IE 7
+                //by forcing to not use native xhr.
+                if(dojo.isIE && window.location.protocol === "file:"){
+                        dojo.config.ieForceActiveXXhr=true;
+                }
+                
+                d.isQuirks = document.compatMode == "BackCompat";
+
+                // TODO: is the HTML LANG attribute relevant?
+                d.locale = dojo.config.locale || (d.isIE ? n.userLanguage : n.language).toLowerCase();
+
+                // These are in order of decreasing likelihood; this will change in time.
+                                d._XMLHTTP_PROGIDS = ['Msxml2.XMLHTTP', 'Microsoft.XMLHTTP', 'Msxml2.XMLHTTP.4.0'];
+                
+                d._xhrObj = function(){
+                        // summary:
+                        //              does the work of portably generating a new XMLHTTPRequest object.
+                        var http, last_e;
+                                                if(!dojo.isIE || !dojo.config.ieForceActiveXXhr){
+                                                        try{ http = new XMLHttpRequest(); }catch(e){}
+                                                }
+                        if(!http){
+                                for(var i=0; i<3; ++i){
+                                        var progid = d._XMLHTTP_PROGIDS[i];
+                                        try{
+                                                http = new ActiveXObject(progid);
+                                        }catch(e){
+                                                last_e = e;
+                                        }
+
+                                        if(http){
+                                                d._XMLHTTP_PROGIDS = [progid];  // so faster next time
+                                                break;
+                                        }
+                                }
+                        }
+                        
+                        if(!http){
+                                throw new Error("XMLHTTP not available: "+last_e);
+                        }
+
+                        return http; // XMLHTTPRequest instance
+                }
+
+                d._isDocumentOk = function(http){
+                        var stat = http.status || 0,
+                                lp = location.protocol;
+                        return (stat >= 200 && stat < 300) ||   // Boolean
+                                stat == 304 ||                  // allow any 2XX response code
+                                stat == 1223 ||                 // get it out of the cache
+                                                                // Internet Explorer mangled the status code
+                                // Internet Explorer mangled the status code OR we're Titanium/browser chrome/chrome extension requesting a local file
+                                (!stat && (lp == "file:" || lp == "chrome:" || lp == "chrome-extension:" || lp == "app:"));
+                }
+
+                //See if base tag is in use.
+                //This is to fix http://trac.dojotoolkit.org/ticket/3973,
+                //but really, we need to find out how to get rid of the dojo._Url reference
+                //below and still have DOH work with the dojo.i18n test following some other
+                //test that uses the test frame to load a document (trac #2757).
+                //Opera still has problems, but perhaps a larger issue of base tag support
+                //with XHR requests (hasBase is true, but the request is still made to document
+                //path, not base path).
+                var owloc = window.location+"";
+                var base = document.getElementsByTagName("base");
+                var hasBase = (base && base.length > 0);
+
+                d._getText = function(/*URI*/ uri, /*Boolean*/ fail_ok){
+                        // summary: Read the contents of the specified uri and return those contents.
+                        // uri:
+                        //              A relative or absolute uri. If absolute, it still must be in
+                        //              the same "domain" as we are.
+                        // fail_ok:
+                        //              Default false. If fail_ok and loading fails, return null
+                        //              instead of throwing.
+                        // returns: The response text. null is returned when there is a
+                        //              failure and failure is okay (an exception otherwise)
+
+                        // NOTE: must be declared before scope switches ie. this._xhrObj()
+                        var http = d._xhrObj();
+
+                        if(!hasBase && dojo._Url){
+                                uri = (new dojo._Url(owloc, uri)).toString();
+                        }
+
+                        if(d.config.cacheBust){
+                                //Make sure we have a string before string methods are used on uri
+                                uri += "";
+                                uri += (uri.indexOf("?") == -1 ? "?" : "&") + String(d.config.cacheBust).replace(/\W+/g,"");
+                        }
+
+                        http.open('GET', uri, false);
+                        try{
+                                http.send(null);
+                                if(!d._isDocumentOk(http)){
+                                        var err = Error("Unable to load "+uri+" status:"+ http.status);
+                                        err.status = http.status;
+                                        err.responseText = http.responseText;
+                                        throw err;
+                                }
+                        }catch(e){
+                                if(fail_ok){ return null; } // null
+                                // rethrow the exception
+                                throw e;
+                        }
+                        return http.responseText; // String
+                }
+                
+
+                var _w = window;
+                var _handleNodeEvent = function(/*String*/evtName, /*Function*/fp){
+                        // summary:
+                        //              non-destructively adds the specified function to the node's
+                        //              evtName handler.
+                        // evtName: should be in the form "onclick" for "onclick" handlers.
+                        // Make sure you pass in the "on" part.
+                        var _a = _w.attachEvent || _w.addEventListener;
+                        evtName = _w.attachEvent ? evtName : evtName.substring(2);
+                        _a(evtName, function(){
+                                fp.apply(_w, arguments);
+                        }, false);
+                };
+
+
+                d._windowUnloaders = [];
+                
+                d.windowUnloaded = function(){
+                        // summary:
+                        //              signal fired by impending window destruction. You may use
+                        //              dojo.addOnWindowUnload() to register a listener for this
+                        //              event. NOTE: if you wish to dojo.connect() to this method
+                        //              to perform page/application cleanup, be aware that this
+                        //              event WILL NOT fire if no handler has been registered with
+                        //              dojo.addOnWindowUnload. This behavior started in Dojo 1.3.
+                        //              Previous versions always triggered dojo.windowUnloaded. See
+                        //              dojo.addOnWindowUnload for more info.
+                        var mll = d._windowUnloaders;
+                        while(mll.length){
+                                (mll.pop())();
+                        }
+                        d = null;
+                };
+
+                var _onWindowUnloadAttached = 0;
+                d.addOnWindowUnload = function(/*Object?|Function?*/obj, /*String|Function?*/functionName){
+                        // summary:
+                        //              registers a function to be triggered when window.onunload
+                        //              fires.
+                        //      description:
+                        //              The first time that addOnWindowUnload is called Dojo
+                        //              will register a page listener to trigger your unload
+                        //              handler with. Note that registering these handlers may
+                        //              destory "fastback" page caching in browsers that support
+                        //              it. Be careful trying to modify the DOM or access
+                        //              JavaScript properties during this phase of page unloading:
+                        //              they may not always be available. Consider
+                        //              dojo.addOnUnload() if you need to modify the DOM or do
+                        //              heavy JavaScript work since it fires at the eqivalent of
+                        //              the page's "onbeforeunload" event.
+                        // example:
+                        //      |       dojo.addOnWindowUnload(functionPointer)
+                        //      |       dojo.addOnWindowUnload(object, "functionName");
+                        //      |       dojo.addOnWindowUnload(object, function(){ /* ... */});
+
+                        d._onto(d._windowUnloaders, obj, functionName);
+                        if(!_onWindowUnloadAttached){
+                                _onWindowUnloadAttached = 1;
+                                _handleNodeEvent("onunload", d.windowUnloaded);
+                        }
+                };
+
+                var _onUnloadAttached = 0;
+                d.addOnUnload = function(/*Object?|Function?*/obj, /*String|Function?*/functionName){
+                        // summary:
+                        //              registers a function to be triggered when the page unloads.
+                        //      description:
+                        //              The first time that addOnUnload is called Dojo will
+                        //              register a page listener to trigger your unload handler
+                        //              with.
+                        //
+                        //              In a browser enviroment, the functions will be triggered
+                        //              during the window.onbeforeunload event. Be careful of doing
+                        //              too much work in an unload handler. onbeforeunload can be
+                        //              triggered if a link to download a file is clicked, or if
+                        //              the link is a javascript: link. In these cases, the
+                        //              onbeforeunload event fires, but the document is not
+                        //              actually destroyed. So be careful about doing destructive
+                        //              operations in a dojo.addOnUnload callback.
+                        //
+                        //              Further note that calling dojo.addOnUnload will prevent
+                        //              browsers from using a "fast back" cache to make page
+                        //              loading via back button instantaneous.
+                        // example:
+                        //      |       dojo.addOnUnload(functionPointer)
+                        //      |       dojo.addOnUnload(object, "functionName")
+                        //      |       dojo.addOnUnload(object, function(){ /* ... */});
+
+                        d._onto(d._unloaders, obj, functionName);
+                        if(!_onUnloadAttached){
+                                _onUnloadAttached = 1;
+                                _handleNodeEvent("onbeforeunload", dojo.unloaded);
+                        }
+                };
+
+        })();
+
+        //START DOMContentLoaded
+        dojo._initFired = false;
+        dojo._loadInit = function(e){
+                if(dojo._scrollIntervalId){
+                        clearInterval(dojo._scrollIntervalId);
+                        dojo._scrollIntervalId = 0;
+                }
+
+                if(!dojo._initFired){
+                        dojo._initFired = true;
+
+                        //Help out IE to avoid memory leak.
+                        if(!dojo.config.afterOnLoad && window.detachEvent){
+                                window.detachEvent("onload", dojo._loadInit);
+                        }
+
+                        if(dojo._inFlightCount == 0){
+                                dojo._modulesLoaded();
+                        }
+                }
+        }
+
+        if(!dojo.config.afterOnLoad){
+                if(document.addEventListener){
+                        //Standards. Hooray! Assumption here that if standards based,
+                        //it knows about DOMContentLoaded. It is OK if it does not, the fall through
+                        //to window onload should be good enough.
+                        document.addEventListener("DOMContentLoaded", dojo._loadInit, false);
+                        window.addEventListener("load", dojo._loadInit, false);
+                }else if(window.attachEvent){
+                        window.attachEvent("onload", dojo._loadInit);
+
+                        //DOMContentLoaded approximation. Diego Perini found this MSDN article
+                        //that indicates doScroll is available after DOM ready, so do a setTimeout
+                        //to check when it is available.
+                        //http://msdn.microsoft.com/en-us/library/ms531426.aspx
+                        if(!dojo.config.skipIeDomLoaded && self === self.top){
+                                dojo._scrollIntervalId = setInterval(function (){
+                                        try{
+                                                //When dojo is loaded into an iframe in an IE HTML Application
+                                                //(HTA), such as in a selenium test, javascript in the iframe
+                                                //can't see anything outside of it, so self===self.top is true,
+                                                //but the iframe is not the top window and doScroll will be
+                                                //available before document.body is set. Test document.body
+                                                //before trying the doScroll trick
+                                                if(document.body){
+                                                        document.documentElement.doScroll("left");
+                                                        dojo._loadInit();
+                                                }
+                                        }catch (e){}
+                                }, 30);
+                        }
+                }
+        }
+
+                if(dojo.isIE){
+                try{
+                        (function(){
+                                document.namespaces.add("v", "urn:schemas-microsoft-com:vml");
+                                var vmlElems = ["*", "group", "roundrect", "oval", "shape", "rect", "imagedata", "path", "textpath", "text"],
+                                        i = 0, l = 1, s = document.createStyleSheet();
+                                if(dojo.isIE >= 8){
+                                        i = 1;
+                                        l = vmlElems.length;
+                                }
+                                for(; i < l; ++i){
+                                        s.addRule("v\\:" + vmlElems[i], "behavior:url(#default#VML); display:inline-block");
+                                }
+                        })();
+                }catch(e){}
+        }
+                //END DOMContentLoaded
+
+
+        /*
+        OpenAjax.subscribe("OpenAjax", "onload", function(){
+                if(dojo._inFlightCount == 0){
+                        dojo._modulesLoaded();
+                }
+        });
+
+        OpenAjax.subscribe("OpenAjax", "onunload", function(){
+                dojo.unloaded();
+        });
+        */
+} //if (typeof window != 'undefined')
+
+//Register any module paths set up in djConfig. Need to do this
+//in the hostenvs since hostenv_browser can read djConfig from a
+//script tag's attribute.
+(function(){
+        var mp = dojo.config["modulePaths"];
+        if(mp){
+                for(var param in mp){
+                        dojo.registerModulePath(param, mp[param]);
+                }
+        }
+})();
+
+//Load debug code if necessary.
+if(dojo.config.isDebug){
+        dojo.require("dojo._firebug.firebug");
+}
+
+if(dojo.config.debugAtAllCosts){
+        // this breaks the new AMD based module loader. The XDomain won't be necessary
+        // anyway if you switch to the asynchronous loader
+        //dojo.config.useXDomain = true;
+        //dojo.require("dojo._base._loader.loader_xd");
+        dojo.require("dojo._base._loader.loader_debug");
+        dojo.require("dojo.i18n");
+}
+
+
+if(!dojo._hasResource["dojo._base.lang"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dojo._base.lang"] = true;
+dojo.provide("dojo._base.lang");
+
+
+(function(){
+        var d = dojo, opts = Object.prototype.toString;
+
+        // Crockford (ish) functions
+
+        dojo.isString = function(/*anything*/ it){
+                //      summary:
+                //              Return true if it is a String
+                return (typeof it == "string" || it instanceof String); // Boolean
+        };
+
+        dojo.isArray = function(/*anything*/ it){
+                //      summary:
+                //              Return true if it is an Array.
+                //              Does not work on Arrays created in other windows.
+                return it && (it instanceof Array || typeof it == "array"); // Boolean
+        };
+
+        dojo.isFunction = function(/*anything*/ it){
+                // summary:
+                //              Return true if it is a Function
+                return opts.call(it) === "[object Function]";
+        };
+
+        dojo.isObject = function(/*anything*/ it){
+                // summary:
+                //              Returns true if it is a JavaScript object (or an Array, a Function
+                //              or null)
+                return it !== undefined &&
+                        (it === null || typeof it == "object" || d.isArray(it) || d.isFunction(it)); // Boolean
+        };
+
+        dojo.isArrayLike = function(/*anything*/ it){
+                //      summary:
+                //              similar to dojo.isArray() but more permissive
+                //      description:
+                //              Doesn't strongly test for "arrayness".  Instead, settles for "isn't
+                //              a string or number and has a length property". Arguments objects
+                //              and DOM collections will return true when passed to
+                //              dojo.isArrayLike(), but will return false when passed to
+                //              dojo.isArray().
+                //      returns:
+                //              If it walks like a duck and quacks like a duck, return `true`
+                return it && it !== undefined && // Boolean
+                        // keep out built-in constructors (Number, String, ...) which have length
+                        // properties
+                        !d.isString(it) && !d.isFunction(it) &&
+                        !(it.tagName && it.tagName.toLowerCase() == 'form') &&
+                        (d.isArray(it) || isFinite(it.length));
+        };
+
+        dojo.isAlien = function(/*anything*/ it){
+                // summary:
+                //              Returns true if it is a built-in function or some other kind of
+                //              oddball that *should* report as a function but doesn't
+                return it && !d.isFunction(it) && /\{\s*\[native code\]\s*\}/.test(String(it)); // Boolean
+        };
+
+        dojo.extend = function(/*Object*/ constructor, /*Object...*/ props){
+                // summary:
+                //              Adds all properties and methods of props to constructor's
+                //              prototype, making them available to all instances created with
+                //              constructor.
+                for(var i=1, l=arguments.length; i<l; i++){
+                        d._mixin(constructor.prototype, arguments[i]);
+                }
+                return constructor; // Object
+        };
+
+        dojo._hitchArgs = function(scope, method /*,...*/){
+                var pre = d._toArray(arguments, 2);
+                var named = d.isString(method);
+                return function(){
+                        // arrayify arguments
+                        var args = d._toArray(arguments);
+                        // locate our method
+                        var f = named ? (scope||d.global)[method] : method;
+                        // invoke with collected args
+                        return f && f.apply(scope || this, pre.concat(args)); // mixed
+                }; // Function
+        };
+
+        dojo.hitch = function(/*Object*/scope, /*Function|String*/method /*,...*/){
+                //      summary:
+                //              Returns a function that will only ever execute in the a given scope.
+                //              This allows for easy use of object member functions
+                //              in callbacks and other places in which the "this" keyword may
+                //              otherwise not reference the expected scope.
+                //              Any number of default positional arguments may be passed as parameters
+                //              beyond "method".
+                //              Each of these values will be used to "placehold" (similar to curry)
+                //              for the hitched function.
+                //      scope:
+                //              The scope to use when method executes. If method is a string,
+                //              scope is also the object containing method.
+                //      method:
+                //              A function to be hitched to scope, or the name of the method in
+                //              scope to be hitched.
+                //      example:
+                //      |       dojo.hitch(foo, "bar")();
+                //              runs foo.bar() in the scope of foo
+                //      example:
+                //      |       dojo.hitch(foo, myFunction);
+                //              returns a function that runs myFunction in the scope of foo
+                //      example:
+                //              Expansion on the default positional arguments passed along from
+                //              hitch. Passed args are mixed first, additional args after.
+                //      |       var foo = { bar: function(a, b, c){ console.log(a, b, c); } };
+                //      |       var fn = dojo.hitch(foo, "bar", 1, 2);
+                //      |       fn(3); // logs "1, 2, 3"
+                //      example:
+                //      |       var foo = { bar: 2 };
+                //      |       dojo.hitch(foo, function(){ this.bar = 10; })();
+                //              execute an anonymous function in scope of foo
+                
+                if(arguments.length > 2){
+                        return d._hitchArgs.apply(d, arguments); // Function
+                }
+                if(!method){
+                        method = scope;
+                        scope = null;
+                }
+                if(d.isString(method)){
+                        scope = scope || d.global;
+                        if(!scope[method]){ throw(['dojo.hitch: scope["', method, '"] is null (scope="', scope, '")'].join('')); }
+                        return function(){ return scope[method].apply(scope, arguments || []); }; // Function
+                }
+                return !scope ? method : function(){ return method.apply(scope, arguments || []); }; // Function
+        };
+
+        /*=====
+        dojo.delegate = function(obj, props){
+                //      summary:
+                //              Returns a new object which "looks" to obj for properties which it
+                //              does not have a value for. Optionally takes a bag of properties to
+                //              seed the returned object with initially.
+                //      description:
+                //              This is a small implementaton of the Boodman/Crockford delegation
+                //              pattern in JavaScript. An intermediate object constructor mediates
+                //              the prototype chain for the returned object, using it to delegate
+                //              down to obj for property lookup when object-local lookup fails.
+                //              This can be thought of similarly to ES4's "wrap", save that it does
+                //              not act on types but rather on pure objects.
+                //      obj:
+                //              The object to delegate to for properties not found directly on the
+                //              return object or in props.
+                //      props:
+                //              an object containing properties to assign to the returned object
+                //      returns:
+                //              an Object of anonymous type
+                //      example:
+                //      |       var foo = { bar: "baz" };
+                //      |       var thinger = dojo.delegate(foo, { thud: "xyzzy"});
+                //      |       thinger.bar == "baz"; // delegated to foo
+                //      |       foo.thud == undefined; // by definition
+                //      |       thinger.thud == "xyzzy"; // mixed in from props
+                //      |       foo.bar = "thonk";
+                //      |       thinger.bar == "thonk"; // still delegated to foo's bar
+        }
+        =====*/
+
+        dojo.delegate = dojo._delegate = (function(){
+                // boodman/crockford delegation w/ cornford optimization
+                function TMP(){}
+                return function(obj, props){
+                        TMP.prototype = obj;
+                        var tmp = new TMP();
+                        TMP.prototype = null;
+                        if(props){
+                                d._mixin(tmp, props);
+                        }
+                        return tmp; // Object
+                };
+        })();
+
+        /*=====
+        dojo._toArray = function(obj, offset, startWith){
+                //      summary:
+                //              Converts an array-like object (i.e. arguments, DOMCollection) to an
+                //              array. Returns a new Array with the elements of obj.
+                //      obj: Object
+                //              the object to "arrayify". We expect the object to have, at a
+                //              minimum, a length property which corresponds to integer-indexed
+                //              properties.
+                //      offset: Number?
+                //              the location in obj to start iterating from. Defaults to 0.
+                //              Optional.
+                //      startWith: Array?
+                //              An array to pack with the properties of obj. If provided,
+                //              properties in obj are appended at the end of startWith and
+                //              startWith is the returned array.
+        }
+        =====*/
+
+        var efficient = function(obj, offset, startWith){
+                return (startWith||[]).concat(Array.prototype.slice.call(obj, offset||0));
+        };
+
+                var slow = function(obj, offset, startWith){
+                var arr = startWith||[];
+                for(var x = offset || 0; x < obj.length; x++){
+                        arr.push(obj[x]);
+                }
+                return arr;
+        };
+        
+        dojo._toArray =
+                                d.isIE ?  function(obj){
+                        return ((obj.item) ? slow : efficient).apply(this, arguments);
+                } :
+                                efficient;
+
+        dojo.partial = function(/*Function|String*/method /*, ...*/){
+                //      summary:
+                //              similar to hitch() except that the scope object is left to be
+                //              whatever the execution context eventually becomes.
+                //      description:
+                //              Calling dojo.partial is the functional equivalent of calling:
+                //              |       dojo.hitch(null, funcName, ...);
+                var arr = [ null ];
+                return d.hitch.apply(d, arr.concat(d._toArray(arguments))); // Function
+        };
+
+        var extraNames = d._extraNames, extraLen = extraNames.length, empty = {};
+
+        dojo.clone = function(/*anything*/ o){
+                // summary:
+                //              Clones objects (including DOM nodes) and all children.
+                //              Warning: do not clone cyclic structures.
+                if(!o || typeof o != "object" || d.isFunction(o)){
+                        // null, undefined, any non-object, or function
+                        return o;       // anything
+                }
+                if(o.nodeType && "cloneNode" in o){
+                        // DOM Node
+                        return o.cloneNode(true); // Node
+                }
+                if(o instanceof Date){
+                        // Date
+                        return new Date(o.getTime());   // Date
+                }
+                if(o instanceof RegExp){
+                        // RegExp
+                        return new RegExp(o);   // RegExp
+                }
+                var r, i, l, s, name;
+                if(d.isArray(o)){
+                        // array
+                        r = [];
+                        for(i = 0, l = o.length; i < l; ++i){
+                                if(i in o){
+                                        r.push(d.clone(o[i]));
+                                }
+                        }
+// we don't clone functions for performance reasons
+//              }else if(d.isFunction(o)){
+//                      // function
+//                      r = function(){ return o.apply(this, arguments); };
+                }else{
+                        // generic objects
+                        r = o.constructor ? new o.constructor() : {};
+                }
+                for(name in o){
+                        // the "tobj" condition avoid copying properties in "source"
+                        // inherited from Object.prototype.  For example, if target has a custom
+                        // toString() method, don't overwrite it with the toString() method
+                        // that source inherited from Object.prototype
+                        s = o[name];
+                        if(!(name in r) || (r[name] !== s && (!(name in empty) || empty[name] !== s))){
+                                r[name] = d.clone(s);
+                        }
+                }
+                                // IE doesn't recognize some custom functions in for..in
+                if(extraLen){
+                        for(i = 0; i < extraLen; ++i){
+                                name = extraNames[i];
+                                s = o[name];
+                                if(!(name in r) || (r[name] !== s && (!(name in empty) || empty[name] !== s))){
+                                        r[name] = s; // functions only, we don't clone them
+                                }
+                        }
+                }
+                                return r; // Object
+        };
+
+        /*=====
+        dojo.trim = function(str){
+                //      summary:
+                //              Trims whitespace from both sides of the string
+                //      str: String
+                //              String to be trimmed
+                //      returns: String
+                //              Returns the trimmed string
+                //      description:
+                //              This version of trim() was selected for inclusion into the base due
+                //              to its compact size and relatively good performance
+                //              (see [Steven Levithan's blog](http://blog.stevenlevithan.com/archives/faster-trim-javascript)
+                //              Uses String.prototype.trim instead, if available.
+                //              The fastest but longest version of this function is located at
+                //              dojo.string.trim()
+                return "";      // String
+        }
+        =====*/
+
+        dojo.trim = String.prototype.trim ?
+                function(str){ return str.trim(); } :
+                function(str){ return str.replace(/^\s\s*/, '').replace(/\s\s*$/, ''); };
+
+        /*=====
+        dojo.replace = function(tmpl, map, pattern){
+                //      summary:
+                //              Performs parameterized substitutions on a string. Throws an
+                //              exception if any parameter is unmatched.
+                //      tmpl: String
+                //              String to be used as a template.
+                //      map: Object|Function
+                //              If an object, it is used as a dictionary to look up substitutions.
+                //              If a function, it is called for every substitution with following
+                //              parameters: a whole match, a name, an offset, and the whole template
+                //              string (see https://developer.mozilla.org/en/Core_JavaScript_1.5_Reference/Global_Objects/String/replace
+                //              for more details).
+                //      pattern: RegEx?
+                //              Optional regular expression objects that overrides the default pattern.
+                //              Must be global and match one item. The default is: /\{([^\}]+)\}/g,
+                //              which matches patterns like that: "{xxx}", where "xxx" is any sequence
+                //              of characters, which doesn't include "}".
+                //      returns: String
+                //              Returns the substituted string.
+                //      example:
+                //      |       // uses a dictionary for substitutions:
+                //      |       dojo.replace("Hello, {name.first} {name.last} AKA {nick}!",
+                //      |         {
+                //      |           nick: "Bob",
+                //      |           name: {
+                //      |             first:  "Robert",
+                //      |             middle: "X",
+                //      |             last:   "Cringely"
+                //      |           }
+                //      |         });
+                //      |       // returns: Hello, Robert Cringely AKA Bob!
+                //      example:
+                //      |       // uses an array for substitutions:
+                //      |       dojo.replace("Hello, {0} {2}!",
+                //      |         ["Robert", "X", "Cringely"]);
+                //      |       // returns: Hello, Robert Cringely!
+                //      example:
+                //      |       // uses a function for substitutions:
+                //      |       function sum(a){
+                //      |         var t = 0;
+                //      |         dojo.forEach(a, function(x){ t += x; });
+                //      |         return t;
+                //      |       }
+                //      |       dojo.replace(
+                //      |         "{count} payments averaging {avg} USD per payment.",
+                //      |         dojo.hitch(
+                //      |           { payments: [11, 16, 12] },
+                //      |           function(_, key){
+                //      |             switch(key){
+                //      |               case "count": return this.payments.length;
+                //      |               case "min":   return Math.min.apply(Math, this.payments);
+                //      |               case "max":   return Math.max.apply(Math, this.payments);
+                //      |               case "sum":   return sum(this.payments);
+                //      |               case "avg":   return sum(this.payments) / this.payments.length;
+                //      |             }
+                //      |           }
+                //      |         )
+                //      |       );
+                //      |       // prints: 3 payments averaging 13 USD per payment.
+                //      example:
+                //      |       // uses an alternative PHP-like pattern for substitutions:
+                //      |       dojo.replace("Hello, ${0} ${2}!",
+                //      |         ["Robert", "X", "Cringely"], /\$\{([^\}]+)\}/g);
+                //      |       // returns: Hello, Robert Cringely!
+                return "";      // String
+        }
+        =====*/
+
+        var _pattern = /\{([^\}]+)\}/g;
+        dojo.replace = function(tmpl, map, pattern){
+                return tmpl.replace(pattern || _pattern, d.isFunction(map) ?
+                        map : function(_, k){ return d.getObject(k, false, map); });
+        };
+})();
+
+}
+
+if(!dojo._hasResource["dojo._base.array"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dojo._base.array"] = true;
+dojo.provide("dojo._base.array");
+
+
+
+(function(){
+        var _getParts = function(arr, obj, cb){
+                return [
+                        (typeof arr == "string") ? arr.split("") : arr,
+                        obj || dojo.global,
+                        // FIXME: cache the anonymous functions we create here?
+                        (typeof cb == "string") ? new Function("item", "index", "array", cb) : cb
+                ];
+        };
+
+        var everyOrSome = function(/*Boolean*/every, /*Array|String*/arr, /*Function|String*/callback, /*Object?*/thisObject){
+                var _p = _getParts(arr, thisObject, callback); arr = _p[0];
+                for(var i=0,l=arr.length; i<l; ++i){
+                        var result = !!_p[2].call(_p[1], arr[i], i, arr);
+                        if(every ^ result){
+                                return result; // Boolean
+                        }
+                }
+                return every; // Boolean
+        };
+
+        dojo.mixin(dojo, {
+                indexOf: function(      /*Array*/               array,
+                                                        /*Object*/              value,
+                                                        /*Integer?*/    fromIndex,
+                                                        /*Boolean?*/    findLast){
+                        // summary:
+                        //              locates the first index of the provided value in the
+                        //              passed array. If the value is not found, -1 is returned.
+                        // description:
+                        //              This method corresponds to the JavaScript 1.6 Array.indexOf method, with one difference: when
+                        //              run over sparse arrays, the Dojo function invokes the callback for every index whereas JavaScript
+                        //              1.6's indexOf skips the holes in the sparse array.
+                        //              For details on this method, see:
+                        //                      https://developer.mozilla.org/en/Core_JavaScript_1.5_Reference/Objects/Array/indexOf
+
+                        var step = 1, end = array.length || 0, i = 0;
+                        if(findLast){
+                                i = end - 1;
+                                step = end = -1;
+                        }
+                        if(fromIndex != undefined){ i = fromIndex; }
+                        if((findLast && i > end) || i < end){
+                                for(; i != end; i += step){
+                                        if(array[i] == value){ return i; }
+                                }
+                        }
+                        return -1;      // Number
+                },
+
+                lastIndexOf: function(/*Array*/array, /*Object*/value, /*Integer?*/fromIndex){
+                        // summary:
+                        //              locates the last index of the provided value in the passed
+                        //              array. If the value is not found, -1 is returned.
+                        // description:
+                        //              This method corresponds to the JavaScript 1.6 Array.lastIndexOf method, with one difference: when
+                        //              run over sparse arrays, the Dojo function invokes the callback for every index whereas JavaScript
+                        //              1.6's lastIndexOf skips the holes in the sparse array.
+                        //              For details on this method, see:
+                        //                      https://developer.mozilla.org/en/Core_JavaScript_1.5_Reference/Objects/Array/lastIndexOf
+                        return dojo.indexOf(array, value, fromIndex, true); // Number
+                },
+
+                forEach: function(/*Array|String*/arr, /*Function|String*/callback, /*Object?*/thisObject){
+                        //      summary:
+                        //              for every item in arr, callback is invoked. Return values are ignored.
+                        //              If you want to break out of the loop, consider using dojo.every() or dojo.some().
+                        //              forEach does not allow breaking out of the loop over the items in arr.
+                        //      arr:
+                        //              the array to iterate over. If a string, operates on individual characters.
+                        //      callback:
+                        //              a function is invoked with three arguments: item, index, and array
+                        //      thisObject:
+                        //              may be used to scope the call to callback
+                        //      description:
+                        //              This function corresponds to the JavaScript 1.6 Array.forEach() method, with one difference: when
+                        //              run over sparse arrays, this implemenation passes the "holes" in the sparse array to
+                        //              the callback function with a value of undefined. JavaScript 1.6's forEach skips the holes in the sparse array.
+                        //              For more details, see:
+                        //                      https://developer.mozilla.org/en/Core_JavaScript_1.5_Reference/Objects/Array/forEach
+                        //      example:
+                        //      |       // log out all members of the array:
+                        //      |       dojo.forEach(
+                        //      |               [ "thinger", "blah", "howdy", 10 ],
+                        //      |               function(item){
+                        //      |                       console.log(item);
+                        //      |               }
+                        //      |       );
+                        //      example:
+                        //      |       // log out the members and their indexes
+                        //      |       dojo.forEach(
+                        //      |               [ "thinger", "blah", "howdy", 10 ],
+                        //      |               function(item, idx, arr){
+                        //      |                       console.log(item, "at index:", idx);
+                        //      |               }
+                        //      |       );
+                        //      example:
+                        //      |       // use a scoped object member as the callback
+                        //      |
+                        //      |       var obj = {
+                        //      |               prefix: "logged via obj.callback:",
+                        //      |               callback: function(item){
+                        //      |                       console.log(this.prefix, item);
+                        //      |               }
+                        //      |       };
+                        //      |
+                        //      |       // specifying the scope function executes the callback in that scope
+                        //      |       dojo.forEach(
+                        //      |               [ "thinger", "blah", "howdy", 10 ],
+                        //      |               obj.callback,
+                        //      |               obj
+                        //      |       );
+                        //      |
+                        //      |       // alternately, we can accomplish the same thing with dojo.hitch()
+                        //      |       dojo.forEach(
+                        //      |               [ "thinger", "blah", "howdy", 10 ],
+                        //      |               dojo.hitch(obj, "callback")
+                        //      |       );
+
+                        // match the behavior of the built-in forEach WRT empty arrs
+                        if(!arr || !arr.length){ return; }
+
+                        // FIXME: there are several ways of handilng thisObject. Is
+                        // dojo.global always the default context?
+                        var _p = _getParts(arr, thisObject, callback); arr = _p[0];
+                        for(var i=0,l=arr.length; i<l; ++i){
+                                _p[2].call(_p[1], arr[i], i, arr);
+                        }
+                },
+
+                every: function(/*Array|String*/arr, /*Function|String*/callback, /*Object?*/thisObject){
+                        // summary:
+                        //              Determines whether or not every item in arr satisfies the
+                        //              condition implemented by callback.
+                        // arr:
+                        //              the array to iterate on. If a string, operates on individual characters.
+                        // callback:
+                        //              a function is invoked with three arguments: item, index,
+                        //              and array and returns true if the condition is met.
+                        // thisObject:
+                        //              may be used to scope the call to callback
+                        // description:
+                        //              This function corresponds to the JavaScript 1.6 Array.every() method, with one difference: when
+                        //              run over sparse arrays, this implemenation passes the "holes" in the sparse array to
+                        //              the callback function with a value of undefined. JavaScript 1.6's every skips the holes in the sparse array.
+                        //              For more details, see:
+                        //                      https://developer.mozilla.org/en/Core_JavaScript_1.5_Reference/Objects/Array/every
+                        // example:
+                        //      |       // returns false
+                        //      |       dojo.every([1, 2, 3, 4], function(item){ return item>1; });
+                        // example:
+                        //      |       // returns true
+                        //      |       dojo.every([1, 2, 3, 4], function(item){ return item>0; });
+                        return everyOrSome(true, arr, callback, thisObject); // Boolean
+                },
+
+                some: function(/*Array|String*/arr, /*Function|String*/callback, /*Object?*/thisObject){
+                        // summary:
+                        //              Determines whether or not any item in arr satisfies the
+                        //              condition implemented by callback.
+                        // arr:
+                        //              the array to iterate over. If a string, operates on individual characters.
+                        // callback:
+                        //              a function is invoked with three arguments: item, index,
+                        //              and array and returns true if the condition is met.
+                        // thisObject:
+                        //              may be used to scope the call to callback
+                        // description:
+                        //              This function corresponds to the JavaScript 1.6 Array.some() method, with one difference: when
+                        //              run over sparse arrays, this implemenation passes the "holes" in the sparse array to
+                        //              the callback function with a value of undefined. JavaScript 1.6's some skips the holes in the sparse array.
+                        //              For more details, see:
+                        //                      https://developer.mozilla.org/en/Core_JavaScript_1.5_Reference/Objects/Array/some
+                        // example:
+                        //      |       // is true
+                        //      |       dojo.some([1, 2, 3, 4], function(item){ return item>1; });
+                        // example:
+                        //      |       // is false
+                        //      |       dojo.some([1, 2, 3, 4], function(item){ return item<1; });
+                        return everyOrSome(false, arr, callback, thisObject); // Boolean
+                },
+
+                map: function(/*Array|String*/arr, /*Function|String*/callback, /*Function?*/thisObject){
+                        // summary:
+                        //              applies callback to each element of arr and returns
+                        //              an Array with the results
+                        // arr:
+                        //              the array to iterate on. If a string, operates on
+                        //              individual characters.
+                        // callback:
+                        //              a function is invoked with three arguments, (item, index,
+                        //              array),  and returns a value
+                        // thisObject:
+                        //              may be used to scope the call to callback
+                        // description:
+                        //              This function corresponds to the JavaScript 1.6 Array.map() method, with one difference: when
+                        //              run over sparse arrays, this implemenation passes the "holes" in the sparse array to
+                        //              the callback function with a value of undefined. JavaScript 1.6's map skips the holes in the sparse array.
+                        //              For more details, see:
+                        //                      https://developer.mozilla.org/en/Core_JavaScript_1.5_Reference/Objects/Array/map
+                        // example:
+                        //      |       // returns [2, 3, 4, 5]
+                        //      |       dojo.map([1, 2, 3, 4], function(item){ return item+1 });
+
+                        var _p = _getParts(arr, thisObject, callback); arr = _p[0];
+                        var outArr = (arguments[3] ? (new arguments[3]()) : []);
+                        for(var i=0,l=arr.length; i<l; ++i){
+                                outArr.push(_p[2].call(_p[1], arr[i], i, arr));
+                        }
+                        return outArr; // Array
+                },
+
+                filter: function(/*Array*/arr, /*Function|String*/callback, /*Object?*/thisObject){
+                        // summary:
+                        //              Returns a new Array with those items from arr that match the
+                        //              condition implemented by callback.
+                        // arr:
+                        //              the array to iterate over.
+                        // callback:
+                        //              a function that is invoked with three arguments (item,
+                        //              index, array). The return of this function is expected to
+                        //              be a boolean which determines whether the passed-in item
+                        //              will be included in the returned array.
+                        // thisObject:
+                        //              may be used to scope the call to callback
+                        // description:
+                        //              This function corresponds to the JavaScript 1.6 Array.filter() method, with one difference: when
+                        //              run over sparse arrays, this implemenation passes the "holes" in the sparse array to
+                        //              the callback function with a value of undefined. JavaScript 1.6's filter skips the holes in the sparse array.
+                        //              For more details, see:
+                        //                      https://developer.mozilla.org/en/Core_JavaScript_1.5_Reference/Objects/Array/filter
+                        // example:
+                        //      |       // returns [2, 3, 4]
+                        //      |       dojo.filter([1, 2, 3, 4], function(item){ return item>1; });
+
+                        var _p = _getParts(arr, thisObject, callback); arr = _p[0];
+                        var outArr = [];
+                        for(var i=0,l=arr.length; i<l; ++i){
+                                if(_p[2].call(_p[1], arr[i], i, arr)){
+                                        outArr.push(arr[i]);
+                                }
+                        }
+                        return outArr; // Array
+                }
+        });
+})();
+/*
+*/
+
+}
+
+if(!dojo._hasResource["dojo._base.declare"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dojo._base.declare"] = true;
+dojo.provide("dojo._base.declare");
+
+
+
+
+(function(){
+        var d = dojo, mix = d._mixin, op = Object.prototype, opts = op.toString,
+                xtor = new Function, counter = 0, cname = "constructor";
+
+        function err(msg, cls){ throw new Error("declare" + (cls ? " " + cls : "") + ": " + msg); }
+
+        // C3 Method Resolution Order (see http://www.python.org/download/releases/2.3/mro/)
+        function c3mro(bases, className){
+                var result = [], roots = [{cls: 0, refs: []}], nameMap = {}, clsCount = 1,
+                        l = bases.length, i = 0, j, lin, base, top, proto, rec, name, refs;
+
+                // build a list of bases naming them if needed
+                for(; i < l; ++i){
+                        base = bases[i];
+                        if(!base){
+                                err("mixin #" + i + " is unknown. Did you use dojo.require to pull it in?", className);
+                        }else if(opts.call(base) != "[object Function]"){
+                                err("mixin #" + i + " is not a callable constructor.", className);
+                        }
+                        lin = base._meta ? base._meta.bases : [base];
+                        top = 0;
+                        // add bases to the name map
+                        for(j = lin.length - 1; j >= 0; --j){
+                                proto = lin[j].prototype;
+                                if(!proto.hasOwnProperty("declaredClass")){
+                                        proto.declaredClass = "uniqName_" + (counter++);
+                                }
+                                name = proto.declaredClass;
+                                if(!nameMap.hasOwnProperty(name)){
+                                        nameMap[name] = {count: 0, refs: [], cls: lin[j]};
+                                        ++clsCount;
+                                }
+                                rec = nameMap[name];
+                                if(top && top !== rec){
+                                        rec.refs.push(top);
+                                        ++top.count;
+                                }
+                                top = rec;
+                        }
+                        ++top.count;
+                        roots[0].refs.push(top);
+                }
+
+                // remove classes without external references recursively
+                while(roots.length){
+                        top = roots.pop();
+                        result.push(top.cls);
+                        --clsCount;
+                        // optimization: follow a single-linked chain
+                        while(refs = top.refs, refs.length == 1){
+                                top = refs[0];
+                                if(!top || --top.count){
+                                        // branch or end of chain => do not end to roots
+                                        top = 0;
+                                        break;
+                                }
+                                result.push(top.cls);
+                                --clsCount;
+                        }
+                        if(top){
+                                // branch
+                                for(i = 0, l = refs.length; i < l; ++i){
+                                        top = refs[i];
+                                        if(!--top.count){
+                                                roots.push(top);
+                                        }
+                                }
+                        }
+                }
+                if(clsCount){
+                        err("can't build consistent linearization", className);
+                }
+
+                // calculate the superclass offset
+                base = bases[0];
+                result[0] = base ?
+                        base._meta && base === result[result.length - base._meta.bases.length] ?
+                                base._meta.bases.length : 1 : 0;
+
+                return result;
+        }
+
+        function inherited(args, a, f){
+                var name, chains, bases, caller, meta, base, proto, opf, pos,
+                        cache = this._inherited = this._inherited || {};
+
+                // crack arguments
+                if(typeof args == "string"){
+                        name = args;
+                        args = a;
+                        a = f;
+                }
+                f = 0;
+
+                caller = args.callee;
+                name = name || caller.nom;
+                if(!name){
+                        err("can't deduce a name to call inherited()", this.declaredClass);
+                }
+
+                meta = this.constructor._meta;
+                bases = meta.bases;
+
+                pos = cache.p;
+                if(name != cname){
+                        // method
+                        if(cache.c !== caller){
+                                // cache bust
+                                pos = 0;
+                                base = bases[0];
+                                meta = base._meta;
+                                if(meta.hidden[name] !== caller){
+                                        // error detection
+                                        chains = meta.chains;
+                                        if(chains && typeof chains[name] == "string"){
+                                                err("calling chained method with inherited: " + name, this.declaredClass);
+                                        }
+                                        // find caller
+                                        do{
+                                                meta = base._meta;
+                                                proto = base.prototype;
+                                                if(meta && (proto[name] === caller && proto.hasOwnProperty(name) || meta.hidden[name] === caller)){
+                                                        break;
+                                                }
+                                        }while(base = bases[++pos]); // intentional assignment
+                                        pos = base ? pos : -1;
+                                }
+                        }
+                        // find next
+                        base = bases[++pos];
+                        if(base){
+                                proto = base.prototype;
+                                if(base._meta && proto.hasOwnProperty(name)){
+                                        f = proto[name];
+                                }else{
+                                        opf = op[name];
+                                        do{
+                                                proto = base.prototype;
+                                                f = proto[name];
+                                                if(f && (base._meta ? proto.hasOwnProperty(name) : f !== opf)){
+                                                        break;
+                                                }
+                                        }while(base = bases[++pos]); // intentional assignment
+                                }
+                        }
+                        f = base && f || op[name];
+                }else{
+                        // constructor
+                        if(cache.c !== caller){
+                                // cache bust
+                                pos = 0;
+                                meta = bases[0]._meta;
+                                if(meta && meta.ctor !== caller){
+                                        // error detection
+                                        chains = meta.chains;
+                                        if(!chains || chains.constructor !== "manual"){
+                                                err("calling chained constructor with inherited", this.declaredClass);
+                                        }
+                                        // find caller
+                                        while(base = bases[++pos]){ // intentional assignment
+                                                meta = base._meta;
+                                                if(meta && meta.ctor === caller){
+                                                        break;
+                                                }
+                                        }
+                                        pos = base ? pos : -1;
+                                }
+                        }
+                        // find next
+                        while(base = bases[++pos]){     // intentional assignment
+                                meta = base._meta;
+                                f = meta ? meta.ctor : base;
+                                if(f){
+                                        break;
+                                }
+                        }
+                        f = base && f;
+                }
+
+                // cache the found super method
+                cache.c = f;
+                cache.p = pos;
+
+                // now we have the result
+                if(f){
+                        return a === true ? f : f.apply(this, a || args);
+                }
+                // intentionally if a super method was not found
+        }
+
+        function getInherited(name, args){
+                if(typeof name == "string"){
+                        return this.inherited(name, args, true);
+                }
+                return this.inherited(name, true);
+        }
+
+        // emulation of "instanceof"
+        function isInstanceOf(cls){
+                var bases = this.constructor._meta.bases;
+                for(var i = 0, l = bases.length; i < l; ++i){
+                        if(bases[i] === cls){
+                                return true;
+                        }
+                }
+                return this instanceof cls;
+        }
+
+        function mixOwn(target, source){
+                var name, i = 0, l = d._extraNames.length;
+                // add props adding metadata for incoming functions skipping a constructor
+                for(name in source){
+                        if(name != cname && source.hasOwnProperty(name)){
+                                target[name] = source[name];
+                        }
+                }
+                // process unenumerable methods on IE
+                for(; i < l; ++i){
+                        name = d._extraNames[i];
+                        if(name != cname && source.hasOwnProperty(name)){
+                                target[name] = source[name];
+                        }
+                }
+        }
+
+        // implementation of safe mixin function
+        function safeMixin(target, source){
+                var name, t, i = 0, l = d._extraNames.length;
+                // add props adding metadata for incoming functions skipping a constructor
+                for(name in source){
+                        t = source[name];
+                        if((t !== op[name] || !(name in op)) && name != cname){
+                                if(opts.call(t) == "[object Function]"){
+                                        // non-trivial function method => attach its name
+                                        t.nom = name;
+                                }
+                                target[name] = t;
+                        }
+                }
+                // process unenumerable methods on IE
+                for(; i < l; ++i){
+                        name = d._extraNames[i];
+                        t = source[name];
+                        if((t !== op[name] || !(name in op)) && name != cname){
+                                if(opts.call(t) == "[object Function]"){
+                                        // non-trivial function method => attach its name
+                                        t.nom = name;
+                                }
+                                target[name] = t;
+                        }
+                }
+                return target;
+        }
+
+        function extend(source){
+                safeMixin(this.prototype, source);
+                return this;
+        }
+
+        // chained constructor compatible with the legacy dojo.declare()
+        function chainedConstructor(bases, ctorSpecial){
+                return function(){
+                        var a = arguments, args = a, a0 = a[0], f, i, m,
+                                l = bases.length, preArgs;
+
+                        if(!(this instanceof a.callee)){
+                                // not called via new, so force it
+                                return applyNew(a);
+                        }
+
+                        //this._inherited = {};
+                        // perform the shaman's rituals of the original dojo.declare()
+                        // 1) call two types of the preamble
+                        if(ctorSpecial && (a0 && a0.preamble || this.preamble)){
+                                // full blown ritual
+                                preArgs = new Array(bases.length);
+                                // prepare parameters
+                                preArgs[0] = a;
+                                for(i = 0;;){
+                                        // process the preamble of the 1st argument
+                                        a0 = a[0];
+                                        if(a0){
+                                                f = a0.preamble;
+                                                if(f){
+                                                        a = f.apply(this, a) || a;
+                                                }
+                                        }
+                                        // process the preamble of this class
+                                        f = bases[i].prototype;
+                                        f = f.hasOwnProperty("preamble") && f.preamble;
+                                        if(f){
+                                                a = f.apply(this, a) || a;
+                                        }
+                                        // one peculiarity of the preamble:
+                                        // it is called if it is not needed,
+                                        // e.g., there is no constructor to call
+                                        // let's watch for the last constructor
+                                        // (see ticket #9795)
+                                        if(++i == l){
+                                                break;
+                                        }
+                                        preArgs[i] = a;
+                                }
+                        }
+                        // 2) call all non-trivial constructors using prepared arguments
+                        for(i = l - 1; i >= 0; --i){
+                                f = bases[i];
+                                m = f._meta;
+                                f = m ? m.ctor : f;
+                                if(f){
+                                        f.apply(this, preArgs ? preArgs[i] : a);
+                                }
+                        }
+                        // 3) continue the original ritual: call the postscript
+                        f = this.postscript;
+                        if(f){
+                                f.apply(this, args);
+                        }
+                };
+        }
+
+
+        // chained constructor compatible with the legacy dojo.declare()
+        function singleConstructor(ctor, ctorSpecial){
+                return function(){
+                        var a = arguments, t = a, a0 = a[0], f;
+
+                        if(!(this instanceof a.callee)){
+                                // not called via new, so force it
+                                return applyNew(a);
+                        }
+
+                        //this._inherited = {};
+                        // perform the shaman's rituals of the original dojo.declare()
+                        // 1) call two types of the preamble
+                        if(ctorSpecial){
+                                // full blown ritual
+                                if(a0){
+                                        // process the preamble of the 1st argument
+                                        f = a0.preamble;
+                                        if(f){
+                                                t = f.apply(this, t) || t;
+                                        }
+                                }
+                                f = this.preamble;
+                                if(f){
+                                        // process the preamble of this class
+                                        f.apply(this, t);
+                                        // one peculiarity of the preamble:
+                                        // it is called even if it is not needed,
+                                        // e.g., there is no constructor to call
+                                        // let's watch for the last constructor
+                                        // (see ticket #9795)
+                                }
+                        }
+                        // 2) call a constructor
+                        if(ctor){
+                                ctor.apply(this, a);
+                        }
+                        // 3) continue the original ritual: call the postscript
+                        f = this.postscript;
+                        if(f){
+                                f.apply(this, a);
+                        }
+                };
+        }
+
+        // plain vanilla constructor (can use inherited() to call its base constructor)
+        function simpleConstructor(bases){
+                return function(){
+                        var a = arguments, i = 0, f, m;
+
+                        if(!(this instanceof a.callee)){
+                                // not called via new, so force it
+                                return applyNew(a);
+                        }
+
+                        //this._inherited = {};
+                        // perform the shaman's rituals of the original dojo.declare()
+                        // 1) do not call the preamble
+                        // 2) call the top constructor (it can use this.inherited())
+                        for(; f = bases[i]; ++i){ // intentional assignment
+                                m = f._meta;
+                                f = m ? m.ctor : f;
+                                if(f){
+                                        f.apply(this, a);
+                                        break;
+                                }
+                        }
+                        // 3) call the postscript
+                        f = this.postscript;
+                        if(f){
+                                f.apply(this, a);
+                        }
+                };
+        }
+
+        function chain(name, bases, reversed){
+                return function(){
+                        var b, m, f, i = 0, step = 1;
+                        if(reversed){
+                                i = bases.length - 1;
+                                step = -1;
+                        }
+                        for(; b = bases[i]; i += step){ // intentional assignment
+                                m = b._meta;
+                                f = (m ? m.hidden : b.prototype)[name];
+                                if(f){
+                                        f.apply(this, arguments);
+                                }
+                        }
+                };
+        }
+
+        // forceNew(ctor)
+        // return a new object that inherits from ctor.prototype but
+        // without actually running ctor on the object.
+        function forceNew(ctor){
+                // create object with correct prototype using a do-nothing
+                // constructor
+                xtor.prototype = ctor.prototype;
+                var t = new xtor;
+                xtor.prototype = null;  // clean up
+                return t;
+        }
+
+        // applyNew(args)
+        // just like 'new ctor()' except that the constructor and its arguments come
+        // from args, which must be an array or an arguments object
+        function applyNew(args){
+                // create an object with ctor's prototype but without
+                // calling ctor on it.
+                var ctor = args.callee, t = forceNew(ctor);
+                // execute the real constructor on the new object
+                ctor.apply(t, args);
+                return t;
+        }
+
+        d.declare = function(className, superclass, props){
+                // crack parameters
+                if(typeof className != "string"){
+                        props = superclass;
+                        superclass = className;
+                        className = "";
+                }
+                props = props || {};
+
+                var proto, i, t, ctor, name, bases, chains, mixins = 1, parents = superclass;
+
+                // build a prototype
+                if(opts.call(superclass) == "[object Array]"){
+                        // C3 MRO
+                        bases = c3mro(superclass, className);
+                        t = bases[0];
+                        mixins = bases.length - t;
+                        superclass = bases[mixins];
+                }else{
+                        bases = [0];
+                        if(superclass){
+                                if(opts.call(superclass) == "[object Function]"){
+                                        t = superclass._meta;
+                                        bases = bases.concat(t ? t.bases : superclass);
+                                }else{
+                                        err("base class is not a callable constructor.", className);
+                                }
+                        }else if(superclass !== null){
+                                err("unknown base class. Did you use dojo.require to pull it in?", className);
+                        }
+                }
+                if(superclass){
+                        for(i = mixins - 1;; --i){
+                                proto = forceNew(superclass);
+                                if(!i){
+                                        // stop if nothing to add (the last base)
+                                        break;
+                                }
+                                // mix in properties
+                                t = bases[i];
+                                (t._meta ? mixOwn : mix)(proto, t.prototype);
+                                // chain in new constructor
+                                ctor = new Function;
+                                ctor.superclass = superclass;
+                                ctor.prototype = proto;
+                                superclass = proto.constructor = ctor;
+                        }
+                }else{
+                        proto = {};
+                }
+                // add all properties
+                safeMixin(proto, props);
+                // add constructor
+                t = props.constructor;
+                if(t !== op.constructor){
+                        t.nom = cname;
+                        proto.constructor = t;
+                }
+
+                // collect chains and flags
+                for(i = mixins - 1; i; --i){ // intentional assignment
+                        t = bases[i]._meta;
+                        if(t && t.chains){
+                                chains = mix(chains || {}, t.chains);
+                        }
+                }
+                if(proto["-chains-"]){
+                        chains = mix(chains || {}, proto["-chains-"]);
+                }
+
+                // build ctor
+                t = !chains || !chains.hasOwnProperty(cname);
+                bases[0] = ctor = (chains && chains.constructor === "manual") ? simpleConstructor(bases) :
+                        (bases.length == 1 ? singleConstructor(props.constructor, t) : chainedConstructor(bases, t));
+
+                // add meta information to the constructor
+                ctor._meta  = {bases: bases, hidden: props, chains: chains,
+                        parents: parents, ctor: props.constructor};
+                ctor.superclass = superclass && superclass.prototype;
+                ctor.extend = extend;
+                ctor.prototype = proto;
+                proto.constructor = ctor;
+
+                // add "standard" methods to the prototype
+                proto.getInherited = getInherited;
+                proto.inherited = inherited;
+                proto.isInstanceOf = isInstanceOf;
+
+                // add name if specified
+                if(className){
+                        proto.declaredClass = className;
+                        d.setObject(className, ctor);
+                }
+
+                // build chains and add them to the prototype
+                if(chains){
+                        for(name in chains){
+                                if(proto[name] && typeof chains[name] == "string" && name != cname){
+                                        t = proto[name] = chain(name, bases, chains[name] === "after");
+                                        t.nom = name;
+                                }
+                        }
+                }
+                // chained methods do not return values
+                // no need to chain "invisible" functions
+
+                return ctor;    // Function
+        };
+
+        d.safeMixin = safeMixin;
+
+        /*=====
+        dojo.declare = function(className, superclass, props){
+                //      summary:
+                //              Create a feature-rich constructor from compact notation.
+                //      className: String?:
+                //              The optional name of the constructor (loosely, a "class")
+                //              stored in the "declaredClass" property in the created prototype.
+                //              It will be used as a global name for a created constructor.
+                //      superclass: Function|Function[]:
+                //              May be null, a Function, or an Array of Functions. This argument
+                //              specifies a list of bases (the left-most one is the most deepest
+                //              base).
+                //      props: Object:
+                //              An object whose properties are copied to the created prototype.
+                //              Add an instance-initialization function by making it a property
+                //              named "constructor".
+                //      returns:
+                //              New constructor function.
+                //      description:
+                //              Create a constructor using a compact notation for inheritance and
+                //              prototype extension.
+                //
+                //              Mixin ancestors provide a type of multiple inheritance.
+                //              Prototypes of mixin ancestors are copied to the new class:
+                //              changes to mixin prototypes will not affect classes to which
+                //              they have been mixed in.
+                //
+                //              Ancestors can be compound classes created by this version of
+                //              dojo.declare. In complex cases all base classes are going to be
+                //              linearized according to C3 MRO algorithm
+                //              (see http://www.python.org/download/releases/2.3/mro/ for more
+                //              details).
+                //
+                //              "className" is cached in "declaredClass" property of the new class,
+                //              if it was supplied. The immediate super class will be cached in
+                //              "superclass" property of the new class.
+                //
+                //              Methods in "props" will be copied and modified: "nom" property
+                //              (the declared name of the method) will be added to all copied
+                //              functions to help identify them for the internal machinery. Be
+                //              very careful, while reusing methods: if you use the same
+                //              function under different names, it can produce errors in some
+                //              cases.
+                //
+                //              It is possible to use constructors created "manually" (without
+                //              dojo.declare) as bases. They will be called as usual during the
+                //              creation of an instance, their methods will be chained, and even
+                //              called by "this.inherited()".
+                //
+                //              Special property "-chains-" governs how to chain methods. It is
+                //              a dictionary, which uses method names as keys, and hint strings
+                //              as values. If a hint string is "after", this method will be
+                //              called after methods of its base classes. If a hint string is
+                //              "before", this method will be called before methods of its base
+                //              classes.
+                //
+                //              If "constructor" is not mentioned in "-chains-" property, it will
+                //              be chained using the legacy mode: using "after" chaining,
+                //              calling preamble() method before each constructor, if available,
+                //              and calling postscript() after all constructors were executed.
+                //              If the hint is "after", it is chained as a regular method, but
+                //              postscript() will be called after the chain of constructors.
+                //              "constructor" cannot be chained "before", but it allows
+                //              a special hint string: "manual", which means that constructors
+                //              are not going to be chained in any way, and programmer will call
+                //              them manually using this.inherited(). In the latter case
+                //              postscript() will be called after the construction.
+                //
+                //              All chaining hints are "inherited" from base classes and
+                //              potentially can be overridden. Be very careful when overriding
+                //              hints! Make sure that all chained methods can work in a proposed
+                //              manner of chaining.
+                //
+                //              Once a method was chained, it is impossible to unchain it. The
+                //              only exception is "constructor". You don't need to define a
+                //              method in order to supply a chaining hint.
+                //
+                //              If a method is chained, it cannot use this.inherited() because
+                //              all other methods in the hierarchy will be called automatically.
+                //
+                //              Usually constructors and initializers of any kind are chained
+                //              using "after" and destructors of any kind are chained as
+                //              "before". Note that chaining assumes that chained methods do not
+                //              return any value: any returned value will be discarded.
+                //
+                //      example:
+                //      |       dojo.declare("my.classes.bar", my.classes.foo, {
+                //      |               // properties to be added to the class prototype
+                //      |               someValue: 2,
+                //      |               // initialization function
+                //      |               constructor: function(){
+                //      |                       this.myComplicatedObject = new ReallyComplicatedObject();
+                //      |               },
+                //      |               // other functions
+                //      |               someMethod: function(){
+                //      |                       doStuff();
+                //      |               }
+                //      |       });
+                //
+                //      example:
+                //      |       var MyBase = dojo.declare(null, {
+                //      |               // constructor, properties, and methods go here
+                //      |               // ...
+                //      |       });
+                //      |       var MyClass1 = dojo.declare(MyBase, {
+                //      |               // constructor, properties, and methods go here
+                //      |               // ...
+                //      |       });
+                //      |       var MyClass2 = dojo.declare(MyBase, {
+                //      |               // constructor, properties, and methods go here
+                //      |               // ...
+                //      |       });
+                //      |       var MyDiamond = dojo.declare([MyClass1, MyClass2], {
+                //      |               // constructor, properties, and methods go here
+                //      |               // ...
+                //      |       });
+                //
+                //      example:
+                //      |       var F = function(){ console.log("raw constructor"); };
+                //      |       F.prototype.method = function(){
+                //      |               console.log("raw method");
+                //      |       };
+                //      |       var A = dojo.declare(F, {
+                //      |               constructor: function(){
+                //      |                       console.log("A.constructor");
+                //      |               },
+                //      |               method: function(){
+                //      |                       console.log("before calling F.method...");
+                //      |                       this.inherited(arguments);
+                //      |                       console.log("...back in A");
+                //      |               }
+                //      |       });
+                //      |       new A().method();
+                //      |       // will print:
+                //      |       // raw constructor
+                //      |       // A.constructor
+                //      |       // before calling F.method...
+                //      |       // raw method
+                //      |       // ...back in A
+                //
+                //      example:
+                //      |       var A = dojo.declare(null, {
+                //      |               "-chains-": {
+                //      |                       destroy: "before"
+                //      |               }
+                //      |       });
+                //      |       var B = dojo.declare(A, {
+                //      |               constructor: function(){
+                //      |                       console.log("B.constructor");
+                //      |               },
+                //      |               destroy: function(){
+                //      |                       console.log("B.destroy");
+                //      |               }
+                //      |       });
+                //      |       var C = dojo.declare(B, {
+                //      |               constructor: function(){
+                //      |                       console.log("C.constructor");
+                //      |               },
+                //      |               destroy: function(){
+                //      |                       console.log("C.destroy");
+                //      |               }
+                //      |       });
+                //      |       new C().destroy();
+                //      |       // prints:
+                //      |       // B.constructor
+                //      |       // C.constructor
+                //      |       // C.destroy
+                //      |       // B.destroy
+                //
+                //      example:
+                //      |       var A = dojo.declare(null, {
+                //      |               "-chains-": {
+                //      |                       constructor: "manual"
+                //      |               }
+                //      |       });
+                //      |       var B = dojo.declare(A, {
+                //      |               constructor: function(){
+                //      |                       // ...
+                //      |                       // call the base constructor with new parameters
+                //      |                       this.inherited(arguments, [1, 2, 3]);
+                //      |                       // ...
+                //      |               }
+                //      |       });
+                //
+                //      example:
+                //      |       var A = dojo.declare(null, {
+                //      |               "-chains-": {
+                //      |                       m1: "before"
+                //      |               },
+                //      |               m1: function(){
+                //      |                       console.log("A.m1");
+                //      |               },
+                //      |               m2: function(){
+                //      |                       console.log("A.m2");
+                //      |               }
+                //      |       });
+                //      |       var B = dojo.declare(A, {
+                //      |               "-chains-": {
+                //      |                       m2: "after"
+                //      |               },
+                //      |               m1: function(){
+                //      |                       console.log("B.m1");
+                //      |               },
+                //      |               m2: function(){
+                //      |                       console.log("B.m2");
+                //      |               }
+                //      |       });
+                //      |       var x = new B();
+                //      |       x.m1();
+                //      |       // prints:
+                //      |       // B.m1
+                //      |       // A.m1
+                //      |       x.m2();
+                //      |       // prints:
+                //      |       // A.m2
+                //      |       // B.m2
+                return new Function(); // Function
+        };
+        =====*/
+
+        /*=====
+        dojo.safeMixin = function(target, source){
+                //      summary:
+                //              Mix in properties skipping a constructor and decorating functions
+                //              like it is done by dojo.declare.
+                //      target: Object
+                //              Target object to accept new properties.
+                //      source: Object
+                //              Source object for new properties.
+                //      description:
+                //              This function is used to mix in properties like dojo._mixin does,
+                //              but it skips a constructor property and decorates functions like
+                //              dojo.declare does.
+                //
+                //              It is meant to be used with classes and objects produced with
+                //              dojo.declare. Functions mixed in with dojo.safeMixin can use
+                //              this.inherited() like normal methods.
+                //
+                //              This function is used to implement extend() method of a constructor
+                //              produced with dojo.declare().
+                //
+                //      example:
+                //      |       var A = dojo.declare(null, {
+                //      |               m1: function(){
+                //      |                       console.log("A.m1");
+                //      |               },
+                //      |               m2: function(){
+                //      |                       console.log("A.m2");
+                //      |               }
+                //      |       });
+                //      |       var B = dojo.declare(A, {
+                //      |               m1: function(){
+                //      |                       this.inherited(arguments);
+                //      |                       console.log("B.m1");
+                //      |               }
+                //      |       });
+                //      |       B.extend({
+                //      |               m2: function(){
+                //      |                       this.inherited(arguments);
+                //      |                       console.log("B.m2");
+                //      |               }
+                //      |       });
+                //      |       var x = new B();
+                //      |       dojo.safeMixin(x, {
+                //      |               m1: function(){
+                //      |                       this.inherited(arguments);
+                //      |                       console.log("X.m1");
+                //      |               },
+                //      |               m2: function(){
+                //      |                       this.inherited(arguments);
+                //      |                       console.log("X.m2");
+                //      |               }
+                //      |       });
+                //      |       x.m2();
+                //      |       // prints:
+                //      |       // A.m1
+                //      |       // B.m1
+                //      |       // X.m1
+        };
+        =====*/
+
+        /*=====
+        Object.inherited = function(name, args, newArgs){
+                //      summary:
+                //              Calls a super method.
+                //      name: String?
+                //              The optional method name. Should be the same as the caller's
+                //              name. Usually "name" is specified in complex dynamic cases, when
+                //              the calling method was dynamically added, undecorated by
+                //              dojo.declare, and it cannot be determined.
+                //      args: Arguments
+                //              The caller supply this argument, which should be the original
+                //              "arguments".
+                //      newArgs: Object?
+                //              If "true", the found function will be returned without
+                //              executing it.
+                //              If Array, it will be used to call a super method. Otherwise
+                //              "args" will be used.
+                //      returns:
+                //              Whatever is returned by a super method, or a super method itself,
+                //              if "true" was specified as newArgs.
+                //      description:
+                //              This method is used inside method of classes produced with
+                //              dojo.declare to call a super method (next in the chain). It is
+                //              used for manually controlled chaining. Consider using the regular
+                //              chaining, because it is faster. Use "this.inherited()" only in
+                //              complex cases.
+                //
+                //              This method cannot me called from automatically chained
+                //              constructors including the case of a special (legacy)
+                //              constructor chaining. It cannot be called from chained methods.
+                //
+                //              If "this.inherited()" cannot find the next-in-chain method, it
+                //              does nothing and returns "undefined". The last method in chain
+                //              can be a default method implemented in Object, which will be
+                //              called last.
+                //
+                //              If "name" is specified, it is assumed that the method that
+                //              received "args" is the parent method for this call. It is looked
+                //              up in the chain list and if it is found the next-in-chain method
+                //              is called. If it is not found, the first-in-chain method is
+                //              called.
+                //
+                //              If "name" is not specified, it will be derived from the calling
+                //              method (using a methoid property "nom").
+                //
+                //      example:
+                //      |       var B = dojo.declare(A, {
+                //      |               method1: function(a, b, c){
+                //      |                       this.inherited(arguments);
+                //      |               },
+                //      |               method2: function(a, b){
+                //      |                       return this.inherited(arguments, [a + b]);
+                //      |               }
+                //      |       });
+                //      |       // next method is not in the chain list because it is added
+                //      |       // manually after the class was created.
+                //      |       B.prototype.method3 = function(){
+                //      |               console.log("This is a dynamically-added method.");
+                //      |               this.inherited("method3", arguments);
+                //      |       };
+                //      example:
+                //      |       var B = dojo.declare(A, {
+                //      |               method: function(a, b){
+                //      |                       var super = this.inherited(arguments, true);
+                //      |                       // ...
+                //      |                       if(!super){
+                //      |                               console.log("there is no super method");
+                //      |                               return 0;
+                //      |                       }
+                //      |                       return super.apply(this, arguments);
+                //      |               }
+                //      |       });
+                return  {};     // Object
+        }
+        =====*/
+
+        /*=====
+        Object.getInherited = function(name, args){
+                //      summary:
+                //              Returns a super method.
+                //      name: String?
+                //              The optional method name. Should be the same as the caller's
+                //              name. Usually "name" is specified in complex dynamic cases, when
+                //              the calling method was dynamically added, undecorated by
+                //              dojo.declare, and it cannot be determined.
+                //      args: Arguments
+                //              The caller supply this argument, which should be the original
+                //              "arguments".
+                //      returns:
+                //              Returns a super method (Function) or "undefined".
+                //      description:
+                //              This method is a convenience method for "this.inherited()".
+                //              It uses the same algorithm but instead of executing a super
+                //              method, it returns it, or "undefined" if not found.
+                //
+                //      example:
+                //      |       var B = dojo.declare(A, {
+                //      |               method: function(a, b){
+                //      |                       var super = this.getInherited(arguments);
+                //      |                       // ...
+                //      |                       if(!super){
+                //      |                               console.log("there is no super method");
+                //      |                               return 0;
+                //      |                       }
+                //      |                       return super.apply(this, arguments);
+                //      |               }
+                //      |       });
+                return  {};     // Object
+        }
+        =====*/
+
+        /*=====
+        Object.isInstanceOf = function(cls){
+                //      summary:
+                //              Checks the inheritance chain to see if it is inherited from this
+                //              class.
+                //      cls: Function
+                //              Class constructor.
+                //      returns:
+                //              "true", if this object is inherited from this class, "false"
+                //              otherwise.
+                //      description:
+                //              This method is used with instances of classes produced with
+                //              dojo.declare to determine of they support a certain interface or
+                //              not. It models "instanceof" operator.
+                //
+                //      example:
+                //      |       var A = dojo.declare(null, {
+                //      |               // constructor, properties, and methods go here
+                //      |               // ...
+                //      |       });
+                //      |       var B = dojo.declare(null, {
+                //      |               // constructor, properties, and methods go here
+                //      |               // ...
+                //      |       });
+                //      |       var C = dojo.declare([A, B], {
+                //      |               // constructor, properties, and methods go here
+                //      |               // ...
+                //      |       });
+                //      |       var D = dojo.declare(A, {
+                //      |               // constructor, properties, and methods go here
+                //      |               // ...
+                //      |       });
+                //      |
+                //      |       var a = new A(), b = new B(), c = new C(), d = new D();
+                //      |
+                //      |       console.log(a.isInstanceOf(A)); // true
+                //      |       console.log(b.isInstanceOf(A)); // false
+                //      |       console.log(c.isInstanceOf(A)); // true
+                //      |       console.log(d.isInstanceOf(A)); // true
+                //      |
+                //      |       console.log(a.isInstanceOf(B)); // false
+                //      |       console.log(b.isInstanceOf(B)); // true
+                //      |       console.log(c.isInstanceOf(B)); // true
+                //      |       console.log(d.isInstanceOf(B)); // false
+                //      |
+                //      |       console.log(a.isInstanceOf(C)); // false
+                //      |       console.log(b.isInstanceOf(C)); // false
+                //      |       console.log(c.isInstanceOf(C)); // true
+                //      |       console.log(d.isInstanceOf(C)); // false
+                //      |
+                //      |       console.log(a.isInstanceOf(D)); // false
+                //      |       console.log(b.isInstanceOf(D)); // false
+                //      |       console.log(c.isInstanceOf(D)); // false
+                //      |       console.log(d.isInstanceOf(D)); // true
+                return  {};     // Object
+        }
+        =====*/
+
+        /*=====
+        Object.extend = function(source){
+                //      summary:
+                //              Adds all properties and methods of source to constructor's
+                //              prototype, making them available to all instances created with
+                //              constructor. This method is specific to constructors created with
+                //              dojo.declare.
+                //      source: Object
+                //              Source object which properties are going to be copied to the
+                //              constructor's prototype.
+                //      description:
+                //              Adds source properties to the constructor's prototype. It can
+                //              override existing properties.
+                //
+                //              This method is similar to dojo.extend function, but it is specific
+                //              to constructors produced by dojo.declare. It is implemented
+                //              using dojo.safeMixin, and it skips a constructor property,
+                //              and properly decorates copied functions.
+                //
+                //      example:
+                //      |       var A = dojo.declare(null, {
+                //      |               m1: function(){},
+                //      |               s1: "Popokatepetl"
+                //      |       });
+                //      |       A.extend({
+                //      |               m1: function(){},
+                //      |               m2: function(){},
+                //      |               f1: true,
+                //      |               d1: 42
+                //      |       });
+        };
+        =====*/
+})();
+
+}
+
+if(!dojo._hasResource["dojo._base.connect"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dojo._base.connect"] = true;
+dojo.provide("dojo._base.connect");
+
+
+
+// this file courtesy of the TurboAjax Group, licensed under a Dojo CLA
+
+// low-level delegation machinery
+dojo._listener = {
+        // create a dispatcher function
+        getDispatcher: function(){
+                // following comments pulled out-of-line to prevent cloning them
+                // in the returned function.
+                // - indices (i) that are really in the array of listeners (ls) will
+                //   not be in Array.prototype. This is the 'sparse array' trick
+                //   that keeps us safe from libs that take liberties with built-in
+                //   objects
+                // - listener is invoked with current scope (this)
+                return function(){
+                        var ap = Array.prototype, c = arguments.callee, ls = c._listeners, t = c.target,
+                        // return value comes from original target function
+                                r = t && t.apply(this, arguments),
+                        // make local copy of listener array so it is immutable during processing
+                                i, lls = [].concat(ls)
+                        ;
+
+                        // invoke listeners after target function
+                        for(i in lls){
+                                if(!(i in ap)){
+                                        lls[i].apply(this, arguments);
+                                }
+                        }
+                        // return value comes from original target function
+                        return r;
+                };
+        },
+        // add a listener to an object
+        add: function(/*Object*/ source, /*String*/ method, /*Function*/ listener){
+                // Whenever 'method' is invoked, 'listener' will have the same scope.
+                // Trying to supporting a context object for the listener led to
+                // complexity.
+                // Non trivial to provide 'once' functionality here
+                // because listener could be the result of a dojo.hitch call,
+                // in which case two references to the same hitch target would not
+                // be equivalent.
+                source = source || dojo.global;
+                // The source method is either null, a dispatcher, or some other function
+                var f = source[method];
+                // Ensure a dispatcher
+                if(!f || !f._listeners){
+                        var d = dojo._listener.getDispatcher();
+                        // original target function is special
+                        d.target = f;
+                        // dispatcher holds a list of listeners
+                        d._listeners = [];
+                        // redirect source to dispatcher
+                        f = source[method] = d;
+                }
+                // The contract is that a handle is returned that can
+                // identify this listener for disconnect.
+                //
+                // The type of the handle is private. Here is it implemented as Integer.
+                // DOM event code has this same contract but handle is Function
+                // in non-IE browsers.
+                //
+                // We could have separate lists of before and after listeners.
+                return f._listeners.push(listener); /*Handle*/
+        },
+        // remove a listener from an object
+        remove: function(/*Object*/ source, /*String*/ method, /*Handle*/ handle){
+                var f = (source || dojo.global)[method];
+                // remember that handle is the index+1 (0 is not a valid handle)
+                if(f && f._listeners && handle--){
+                        delete f._listeners[handle];
+                }
+        }
+};
+
+// Multiple delegation for arbitrary methods.
+
+// This unit knows nothing about DOM, but we include DOM aware documentation
+// and dontFix argument here to help the autodocs. Actual DOM aware code is in
+// event.js.
+
+dojo.connect = function(/*Object|null*/ obj,
+                                                /*String*/ event,
+                                                /*Object|null*/ context,
+                                                /*String|Function*/ method,
+                                                /*Boolean?*/ dontFix){
+        // summary:
+        //              `dojo.connect` is the core event handling and delegation method in
+        //              Dojo. It allows one function to "listen in" on the execution of
+        //              any other, triggering the second whenever the first is called. Many
+        //              listeners may be attached to a function, and source functions may
+        //              be either regular function calls or DOM events.
+        //
+        // description:
+        //              Connects listeners to actions, so that after event fires, a
+        //              listener is called with the same arguments passed to the original
+        //              function.
+        //
+        //              Since `dojo.connect` allows the source of events to be either a
+        //              "regular" JavaScript function or a DOM event, it provides a uniform
+        //              interface for listening to all the types of events that an
+        //              application is likely to deal with though a single, unified
+        //              interface. DOM programmers may want to think of it as
+        //              "addEventListener for everything and anything".
+        //
+        //              When setting up a connection, the `event` parameter must be a
+        //              string that is the name of the method/event to be listened for. If
+        //              `obj` is null, `dojo.global` is assumed, meaning that connections
+        //              to global methods are supported but also that you may inadvertently
+        //              connect to a global by passing an incorrect object name or invalid
+        //              reference.
+        //
+        //              `dojo.connect` generally is forgiving. If you pass the name of a
+        //              function or method that does not yet exist on `obj`, connect will
+        //              not fail, but will instead set up a stub method. Similarly, null
+        //              arguments may simply be omitted such that fewer than 4 arguments
+        //              may be required to set up a connection See the examples for details.
+        //
+        //              The return value is a handle that is needed to
+        //              remove this connection with `dojo.disconnect`.
+        //
+        // obj:
+        //              The source object for the event function.
+        //              Defaults to `dojo.global` if null.
+        //              If obj is a DOM node, the connection is delegated
+        //              to the DOM event manager (unless dontFix is true).
+        //
+        // event:
+        //              String name of the event function in obj.
+        //              I.e. identifies a property `obj[event]`.
+        //
+        // context:
+        //              The object that method will receive as "this".
+        //
+        //              If context is null and method is a function, then method
+        //              inherits the context of event.
+        //
+        //              If method is a string then context must be the source
+        //              object object for method (context[method]). If context is null,
+        //              dojo.global is used.
+        //
+        // method:
+        //              A function reference, or name of a function in context.
+        //              The function identified by method fires after event does.
+        //              method receives the same arguments as the event.
+        //              See context argument comments for information on method's scope.
+        //
+        // dontFix:
+        //              If obj is a DOM node, set dontFix to true to prevent delegation
+        //              of this connection to the DOM event manager.
+        //
+        // example:
+        //              When obj.onchange(), do ui.update():
+        //      |       dojo.connect(obj, "onchange", ui, "update");
+        //      |       dojo.connect(obj, "onchange", ui, ui.update); // same
+        //
+        // example:
+        //              Using return value for disconnect:
+        //      |       var link = dojo.connect(obj, "onchange", ui, "update");
+        //      |       ...
+        //      |       dojo.disconnect(link);
+        //
+        // example:
+        //              When onglobalevent executes, watcher.handler is invoked:
+        //      |       dojo.connect(null, "onglobalevent", watcher, "handler");
+        //
+        // example:
+        //              When ob.onCustomEvent executes, customEventHandler is invoked:
+        //      |       dojo.connect(ob, "onCustomEvent", null, "customEventHandler");
+        //      |       dojo.connect(ob, "onCustomEvent", "customEventHandler"); // same
+        //
+        // example:
+        //              When ob.onCustomEvent executes, customEventHandler is invoked
+        //              with the same scope (this):
+        //      |       dojo.connect(ob, "onCustomEvent", null, customEventHandler);
+        //      |       dojo.connect(ob, "onCustomEvent", customEventHandler); // same
+        //
+        // example:
+        //              When globalEvent executes, globalHandler is invoked
+        //              with the same scope (this):
+        //      |       dojo.connect(null, "globalEvent", null, globalHandler);
+        //      |       dojo.connect("globalEvent", globalHandler); // same
+
+        // normalize arguments
+        var a=arguments, args=[], i=0;
+        // if a[0] is a String, obj was omitted
+        args.push(dojo.isString(a[0]) ? null : a[i++], a[i++]);
+        // if the arg-after-next is a String or Function, context was NOT omitted
+        var a1 = a[i+1];
+        args.push(dojo.isString(a1)||dojo.isFunction(a1) ? a[i++] : null, a[i++]);
+        // absorb any additional arguments
+        for(var l=a.length; i<l; i++){  args.push(a[i]); }
+        // do the actual work
+        return dojo._connect.apply(this, args); /*Handle*/
+}
+
+// used by non-browser hostenvs. always overriden by event.js
+dojo._connect = function(obj, event, context, method){
+        var l=dojo._listener, h=l.add(obj, event, dojo.hitch(context, method));
+        return [obj, event, h, l]; // Handle
+};
+
+dojo.disconnect = function(/*Handle*/ handle){
+        // summary:
+        //              Remove a link created by dojo.connect.
+        // description:
+        //              Removes the connection between event and the method referenced by handle.
+        // handle:
+        //              the return value of the dojo.connect call that created the connection.
+        if(handle && handle[0] !== undefined){
+                dojo._disconnect.apply(this, handle);
+                // let's not keep this reference
+                delete handle[0];
+        }
+};
+
+dojo._disconnect = function(obj, event, handle, listener){
+        listener.remove(obj, event, handle);
+};
+
+// topic publish/subscribe
+
+dojo._topics = {};
+
+dojo.subscribe = function(/*String*/ topic, /*Object|null*/ context, /*String|Function*/ method){
+        //      summary:
+        //              Attach a listener to a named topic. The listener function is invoked whenever the
+        //              named topic is published (see: dojo.publish).
+        //              Returns a handle which is needed to unsubscribe this listener.
+        //      context:
+        //              Scope in which method will be invoked, or null for default scope.
+        //      method:
+        //              The name of a function in context, or a function reference. This is the function that
+        //              is invoked when topic is published.
+        //      example:
+        //      |       dojo.subscribe("alerts", null, function(caption, message){ alert(caption + "\n" + message); });
+        //      |       dojo.publish("alerts", [ "read this", "hello world" ]);
+
+        // support for 2 argument invocation (omitting context) depends on hitch
+        return [topic, dojo._listener.add(dojo._topics, topic, dojo.hitch(context, method))]; /*Handle*/
+};
+
+dojo.unsubscribe = function(/*Handle*/ handle){
+        //      summary:
+        //              Remove a topic listener.
+        //      handle:
+        //              The handle returned from a call to subscribe.
+        //      example:
+        //      |       var alerter = dojo.subscribe("alerts", null, function(caption, message){ alert(caption + "\n" + message); };
+        //      |       ...
+        //      |       dojo.unsubscribe(alerter);
+        if(handle){
+                dojo._listener.remove(dojo._topics, handle[0], handle[1]);
+        }
+};
+
+dojo.publish = function(/*String*/ topic, /*Array*/ args){
+        //      summary:
+        //              Invoke all listener method subscribed to topic.
+        //      topic:
+        //              The name of the topic to publish.
+        //      args:
+        //              An array of arguments. The arguments will be applied
+        //              to each topic subscriber (as first class parameters, via apply).
+        //      example:
+        //      |       dojo.subscribe("alerts", null, function(caption, message){ alert(caption + "\n" + message); };
+        //      |       dojo.publish("alerts", [ "read this", "hello world" ]);
+
+        // Note that args is an array, which is more efficient vs variable length
+        // argument list.  Ideally, var args would be implemented via Array
+        // throughout the APIs.
+        var f = dojo._topics[topic];
+        if(f){
+                f.apply(this, args||[]);
+        }
+};
+
+dojo.connectPublisher = function(       /*String*/ topic,
+                                                                        /*Object|null*/ obj,
+                                                                        /*String*/ event){
+        //      summary:
+        //              Ensure that every time obj.event() is called, a message is published
+        //              on the topic. Returns a handle which can be passed to
+        //              dojo.disconnect() to disable subsequent automatic publication on
+        //              the topic.
+        //      topic:
+        //              The name of the topic to publish.
+        //      obj:
+        //              The source object for the event function. Defaults to dojo.global
+        //              if null.
+        //      event:
+        //              The name of the event function in obj.
+        //              I.e. identifies a property obj[event].
+        //      example:
+        //      |       dojo.connectPublisher("/ajax/start", dojo, "xhrGet");
+        var pf = function(){ dojo.publish(topic, arguments); }
+        return event ? dojo.connect(obj, event, pf) : dojo.connect(obj, pf); //Handle
+};
+
+}
+
+if(!dojo._hasResource["dojo._base.Deferred"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dojo._base.Deferred"] = true;
+dojo.provide("dojo._base.Deferred");
+
+
+
+(function(){
+        var mutator = function(){};
+        var freeze = Object.freeze || function(){};
+        // A deferred provides an API for creating and resolving a promise.
+        dojo.Deferred = function(/*Function?*/canceller){
+        // summary:
+        //              Deferreds provide a generic means for encapsulating an asynchronous
+        //              operation and notifying users of the completion and result of the operation.
+        // description:
+        //              The dojo.Deferred API is based on the concept of promises that provide a
+        //              generic interface into the eventual completion of an asynchronous action.
+        //              The motivation for promises fundamentally is about creating a
+        //              separation of concerns that allows one to achieve the same type of
+        //              call patterns and logical data flow in asynchronous code as can be
+        //              achieved in synchronous code. Promises allows one
+        //              to be able to call a function purely with arguments needed for
+        //              execution, without conflating the call with concerns of whether it is
+        //              sync or async. One shouldn't need to alter a call's arguments if the
+        //              implementation switches from sync to async (or vice versa). By having
+        //              async functions return promises, the concerns of making the call are
+        //              separated from the concerns of asynchronous interaction (which are
+        //              handled by the promise).
+        //
+        //      The dojo.Deferred is a type of promise that provides methods for fulfilling the
+        //              promise with a successful result or an error. The most important method for
+        //              working with Dojo's promises is the then() method, which follows the
+        //              CommonJS proposed promise API. An example of using a Dojo promise:
+        //
+        //              |       var resultingPromise = someAsyncOperation.then(function(result){
+        //              |               ... handle result ...
+        //              |       },
+        //              |       function(error){
+        //              |               ... handle error ...
+        //              |       });
+        //
+        //              The .then() call returns a new promise that represents the result of the
+        //              execution of the callback. The callbacks will never affect the original promises value.
+        //
+        //              The dojo.Deferred instances also provide the following functions for backwards compatibility:
+        //
+        //                      * addCallback(handler)
+        //                      * addErrback(handler)
+        //                      * callback(result)
+        //                      * errback(result)
+        //
+        //              Callbacks are allowed to return promises themselves, so
+        //              you can build complicated sequences of events with ease.
+        //
+        //              The creator of the Deferred may specify a canceller.  The canceller
+        //              is a function that will be called if Deferred.cancel is called
+        //              before the Deferred fires. You can use this to implement clean
+        //              aborting of an XMLHttpRequest, etc. Note that cancel will fire the
+        //              deferred with a CancelledError (unless your canceller returns
+        //              another kind of error), so the errbacks should be prepared to
+        //              handle that error for cancellable Deferreds.
+        // example:
+        //      |       var deferred = new dojo.Deferred();
+        //      |       setTimeout(function(){ deferred.callback({success: true}); }, 1000);
+        //      |       return deferred;
+        // example:
+        //              Deferred objects are often used when making code asynchronous. It
+        //              may be easiest to write functions in a synchronous manner and then
+        //              split code using a deferred to trigger a response to a long-lived
+        //              operation. For example, instead of register a callback function to
+        //              denote when a rendering operation completes, the function can
+        //              simply return a deferred:
+        //
+        //              |       // callback style:
+        //              |       function renderLotsOfData(data, callback){
+        //              |               var success = false
+        //              |               try{
+        //              |                       for(var x in data){
+        //              |                               renderDataitem(data[x]);
+        //              |                       }
+        //              |                       success = true;
+        //              |               }catch(e){ }
+        //              |               if(callback){
+        //              |                       callback(success);
+        //              |               }
+        //              |       }
+        //
+        //              |       // using callback style
+        //              |       renderLotsOfData(someDataObj, function(success){
+        //              |               // handles success or failure
+        //              |               if(!success){
+        //              |                       promptUserToRecover();
+        //              |               }
+        //              |       });
+        //              |       // NOTE: no way to add another callback here!!
+        // example:
+        //              Using a Deferred doesn't simplify the sending code any, but it
+        //              provides a standard interface for callers and senders alike,
+        //              providing both with a simple way to service multiple callbacks for
+        //              an operation and freeing both sides from worrying about details
+        //              such as "did this get called already?". With Deferreds, new
+        //              callbacks can be added at any time.
+        //
+        //              |       // Deferred style:
+        //              |       function renderLotsOfData(data){
+        //              |               var d = new dojo.Deferred();
+        //              |               try{
+        //              |                       for(var x in data){
+        //              |                               renderDataitem(data[x]);
+        //              |                       }
+        //              |                       d.callback(true);
+        //              |               }catch(e){
+        //              |                       d.errback(new Error("rendering failed"));
+        //              |               }
+        //              |               return d;
+        //              |       }
+        //
+        //              |       // using Deferred style
+        //              |       renderLotsOfData(someDataObj).then(null, function(){
+        //              |               promptUserToRecover();
+        //              |       });
+        //              |       // NOTE: addErrback and addCallback both return the Deferred
+        //              |       // again, so we could chain adding callbacks or save the
+        //              |       // deferred for later should we need to be notified again.
+        // example:
+        //              In this example, renderLotsOfData is synchronous and so both
+        //              versions are pretty artificial. Putting the data display on a
+        //              timeout helps show why Deferreds rock:
+        //
+        //              |       // Deferred style and async func
+        //              |       function renderLotsOfData(data){
+        //              |               var d = new dojo.Deferred();
+        //              |               setTimeout(function(){
+        //              |                       try{
+        //              |                               for(var x in data){
+        //              |                                       renderDataitem(data[x]);
+        //              |                               }
+        //              |                               d.callback(true);
+        //              |                       }catch(e){
+        //              |                               d.errback(new Error("rendering failed"));
+        //              |                       }
+        //              |               }, 100);
+        //              |               return d;
+        //              |       }
+        //
+        //              |       // using Deferred style
+        //              |       renderLotsOfData(someDataObj).then(null, function(){
+        //              |               promptUserToRecover();
+        //              |       });
+        //
+        //              Note that the caller doesn't have to change his code at all to
+        //              handle the asynchronous case.
+                var result, finished, isError, head, nextListener;
+                var promise = (this.promise = {});
+                
+                function complete(value){
+                        if(finished){
+                                throw new Error("This deferred has already been resolved");
+                        }
+                        result = value;
+                        finished = true;
+                        notify();
+                }
+                function notify(){
+                        var mutated;
+                        while(!mutated && nextListener){
+                                var listener = nextListener;
+                                nextListener = nextListener.next;
+                                if((mutated = (listener.progress == mutator))){ // assignment and check
+                                        finished = false;
+                                }
+                                var func = (isError ? listener.error : listener.resolved);
+                                if (func) {
+                                        try {
+                                                var newResult = func(result);
+                                                if (newResult && typeof newResult.then === "function") {
+                                                        newResult.then(dojo.hitch(listener.deferred, "resolve"), dojo.hitch(listener.deferred, "reject"));
+                                                        continue;
+                                                }
+                                                var unchanged = mutated && newResult === undefined;
+                                                if(mutated && !unchanged){
+                                                        isError = newResult instanceof Error;
+                                                }
+                                                listener.deferred[unchanged && isError ? "reject" : "resolve"](unchanged ? result : newResult);
+                                        }
+                                        catch (e) {
+                                                listener.deferred.reject(e);
+                                        }
+                                }else {
+                                        if(isError){
+                                                listener.deferred.reject(result);
+                                        }else{
+                                                listener.deferred.resolve(result);
+                                        }
+                                }
+                        }
+                }
+                // calling resolve will resolve the promise
+                this.resolve = this.callback = function(value){
+                        // summary:
+                        //              Fulfills the Deferred instance successfully with the provide value
+                        this.fired = 0;
+                        this.results = [value, null];
+                        complete(value);
+                };
+                
+                
+                // calling error will indicate that the promise failed
+                this.reject = this.errback = function(error){
+                        // summary:
+                        //              Fulfills the Deferred instance as an error with the provided error
+                        isError = true;
+                        this.fired = 1;
+                        complete(error);
+                        this.results = [null, error];
+                        if(!error || error.log !== false){
+                                (dojo.config.deferredOnError || function(x){ console.error(x); })(error);
+                        }
+                };
+                // call progress to provide updates on the progress on the completion of the promise
+                this.progress = function(update){
+                        // summary
+                        //              Send progress events to all listeners
+                        var listener = nextListener;
+                        while(listener){
+                                var progress = listener.progress;
+                                progress && progress(update);
+                                listener = listener.next;
+                        }
+                };
+                this.addCallbacks = function(/*Function?*/callback, /*Function?*/errback){
+                        this.then(callback, errback, mutator);
+                        return this;
+                };
+                // provide the implementation of the promise
+                this.then = promise.then = function(/*Function?*/resolvedCallback, /*Function?*/errorCallback, /*Function?*/progressCallback){
+                        // summary:
+                        //              Adds a fulfilledHandler, errorHandler, and progressHandler to be called for
+                        //              completion of a promise. The fulfilledHandler is called when the promise
+                        //              is fulfilled. The errorHandler is called when a promise fails. The
+                        //              progressHandler is called for progress events. All arguments are optional
+                        //              and non-function values are ignored. The progressHandler is not only an
+                        //              optional argument, but progress events are purely optional. Promise
+                        //              providers are not required to ever create progress events.
+                        //
+                        //              This function will return a new promise that is fulfilled when the given
+                        //              fulfilledHandler or errorHandler callback is finished. This allows promise
+                        //              operations to be chained together. The value returned from the callback
+                        //              handler is the fulfillment value for the returned promise. If the callback
+                        //              throws an error, the returned promise will be moved to failed state.
+                        //
+                        // example:
+                        //              An example of using a CommonJS compliant promise:
+                        //              |       asyncComputeTheAnswerToEverything().
+                        //              |               then(addTwo).
+                        //              |               then(printResult, onError);
+                        //              |       >44
+                        //
+                        var returnDeferred = progressCallback == mutator ? this : new dojo.Deferred(promise.cancel);
+                        var listener = {
+                                resolved: resolvedCallback,
+                                error: errorCallback,
+                                progress: progressCallback,
+                                deferred: returnDeferred
+                        };
+                        if(nextListener){
+                                head = head.next = listener;
+                        }
+                        else{
+                                nextListener = head = listener;
+                        }
+                        if(finished){
+                                notify();
+                        }
+                        return returnDeferred.promise;
+                };
+                var deferred = this;
+                this.cancel = promise.cancel = function () {
+                        // summary:
+                        //              Cancels the asynchronous operation
+                        if(!finished){
+                                var error = canceller && canceller(deferred);
+                                if(!finished){
+                                        if (!(error instanceof Error)) {
+                                                error = new Error(error);
+                                        }
+                                        error.log = false;
+                                        deferred.reject(error);
+                                }
+                        }
+                };
+                freeze(promise);
+        };
+        dojo.extend(dojo.Deferred, {
+                addCallback: function (/*Function*/callback) {
+                        return this.addCallbacks(dojo.hitch.apply(dojo, arguments));
+                },
+        
+                addErrback: function (/*Function*/errback) {
+                        return this.addCallbacks(null, dojo.hitch.apply(dojo, arguments));
+                },
+        
+                addBoth: function (/*Function*/callback) {
+                        var enclosed = dojo.hitch.apply(dojo, arguments);
+                        return this.addCallbacks(enclosed, enclosed);
+                },
+                fired: -1
+        });
+})();
+dojo.when = function(promiseOrValue, /*Function?*/callback, /*Function?*/errback, /*Function?*/progressHandler){
+        // summary:
+        //              This provides normalization between normal synchronous values and
+        //              asynchronous promises, so you can interact with them in a common way
+        //      example:
+        //              |       function printFirstAndList(items){
+        //              |               dojo.when(findFirst(items), console.log);
+        //              |               dojo.when(findLast(items), console.log);
+        //              |       }
+        //              |       function findFirst(items){
+        //              |               return dojo.when(items, function(items){
+        //              |                       return items[0];
+        //              |               });
+        //              |       }
+        //              |       function findLast(items){
+        //              |               return dojo.when(items, function(items){
+        //              |                       return items[items.length];
+        //              |               });
+        //              |       }
+        //              And now all three of his functions can be used sync or async.
+        //              |       printFirstAndLast([1,2,3,4]) will work just as well as
+        //              |       printFirstAndLast(dojo.xhrGet(...));
+        
+        if(promiseOrValue && typeof promiseOrValue.then === "function"){
+                return promiseOrValue.then(callback, errback, progressHandler);
+        }
+        return callback(promiseOrValue);
+};
+
+}
+
+if(!dojo._hasResource["dojo._base.json"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dojo._base.json"] = true;
+dojo.provide("dojo._base.json");
+
+
+dojo.fromJson = function(/*String*/ json){
+        // summary:
+        //              Parses a [JSON](http://json.org) string to return a JavaScript object.
+        // description:
+        //              Throws for invalid JSON strings, but it does not use a strict JSON parser. It
+        //              delegates to eval().  The content passed to this method must therefore come
+        //              from a trusted source.
+        // json:
+        //              a string literal of a JSON item, for instance:
+        //                      `'{ "foo": [ "bar", 1, { "baz": "thud" } ] }'`
+
+        return eval("(" + json + ")"); // Object
+};
+
+dojo._escapeString = function(/*String*/str){
+        //summary:
+        //              Adds escape sequences for non-visual characters, double quote and
+        //              backslash and surrounds with double quotes to form a valid string
+        //              literal.
+        return ('"' + str.replace(/(["\\])/g, '\\$1') + '"').
+                replace(/[\f]/g, "\\f").replace(/[\b]/g, "\\b").replace(/[\n]/g, "\\n").
+                replace(/[\t]/g, "\\t").replace(/[\r]/g, "\\r"); // string
+};
+
+dojo.toJsonIndentStr = "\t";
+dojo.toJson = function(/*Object*/ it, /*Boolean?*/ prettyPrint, /*String?*/ _indentStr){
+        //      summary:
+        //              Returns a [JSON](http://json.org) serialization of an object.
+        //      description:
+        //              Returns a [JSON](http://json.org) serialization of an object.
+        //              Note that this doesn't check for infinite recursion, so don't do that!
+        //      it:
+        //              an object to be serialized. Objects may define their own
+        //              serialization via a special "__json__" or "json" function
+        //              property. If a specialized serializer has been defined, it will
+        //              be used as a fallback.
+        //      prettyPrint:
+        //              if true, we indent objects and arrays to make the output prettier.
+        //              The variable `dojo.toJsonIndentStr` is used as the indent string --
+        //              to use something other than the default (tab), change that variable
+        //              before calling dojo.toJson().
+        //      _indentStr:
+        //              private variable for recursive calls when pretty printing, do not use.
+        //      example:
+        //              simple serialization of a trivial object
+        //              |       var jsonStr = dojo.toJson({ howdy: "stranger!", isStrange: true });
+        //              |       doh.is('{"howdy":"stranger!","isStrange":true}', jsonStr);
+        //      example:
+        //              a custom serializer for an objects of a particular class:
+        //              |       dojo.declare("Furby", null, {
+        //              |               furbies: "are strange",
+        //              |               furbyCount: 10,
+        //              |               __json__: function(){
+        //              |               },
+        //              |       });
+
+        if(it === undefined){
+                return "undefined";
+        }
+        var objtype = typeof it;
+        if(objtype == "number" || objtype == "boolean"){
+                return it + "";
+        }
+        if(it === null){
+                return "null";
+        }
+        if(dojo.isString(it)){
+                return dojo._escapeString(it);
+        }
+        // recurse
+        var recurse = arguments.callee;
+        // short-circuit for objects that support "json" serialization
+        // if they return "self" then just pass-through...
+        var newObj;
+        _indentStr = _indentStr || "";
+        var nextIndent = prettyPrint ? _indentStr + dojo.toJsonIndentStr : "";
+        var tf = it.__json__||it.json;
+        if(dojo.isFunction(tf)){
+                newObj = tf.call(it);
+                if(it !== newObj){
+                        return recurse(newObj, prettyPrint, nextIndent);
+                }
+        }
+        if(it.nodeType && it.cloneNode){ // isNode
+                // we can't seriailize DOM nodes as regular objects because they have cycles
+                // DOM nodes could be serialized with something like outerHTML, but
+                // that can be provided by users in the form of .json or .__json__ function.
+                throw new Error("Can't serialize DOM nodes");
+        }
+
+        var sep = prettyPrint ? " " : "";
+        var newLine = prettyPrint ? "\n" : "";
+
+        // array
+        if(dojo.isArray(it)){
+                var res = dojo.map(it, function(obj){
+                        var val = recurse(obj, prettyPrint, nextIndent);
+                        if(typeof val != "string"){
+                                val = "undefined";
+                        }
+                        return newLine + nextIndent + val;
+                });
+                return "[" + res.join("," + sep) + newLine + _indentStr + "]";
+        }
+        /*
+        // look in the registry
+        try {
+                window.o = it;
+                newObj = dojo.json.jsonRegistry.match(it);
+                return recurse(newObj, prettyPrint, nextIndent);
+        }catch(e){
+                // console.log(e);
+        }
+        // it's a function with no adapter, skip it
+        */
+        if(objtype == "function"){
+                return null; // null
+        }
+        // generic object code path
+        var output = [], key;
+        for(key in it){
+                var keyStr, val;
+                if(typeof key == "number"){
+                        keyStr = '"' + key + '"';
+                }else if(typeof key == "string"){
+                        keyStr = dojo._escapeString(key);
+                }else{
+                        // skip non-string or number keys
+                        continue;
+                }
+                val = recurse(it[key], prettyPrint, nextIndent);
+                if(typeof val != "string"){
+                        // skip non-serializable values
+                        continue;
+                }
+                // FIXME: use += on Moz!!
+                //       MOW NOTE: using += is a pain because you have to account for the dangling comma...
+                output.push(newLine + nextIndent + keyStr + ":" + sep + val);
+        }
+        return "{" + output.join("," + sep) + newLine + _indentStr + "}"; // String
+};
+
+}
+
+if(!dojo._hasResource["dojo._base.Color"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dojo._base.Color"] = true;
+dojo.provide("dojo._base.Color");
+
+
+
+
+(function(){
+
+        var d = dojo;
+
+        dojo.Color = function(/*Array|String|Object*/ color){
+                // summary:
+                //              Takes a named string, hex string, array of rgb or rgba values,
+                //              an object with r, g, b, and a properties, or another `dojo.Color` object
+                //              and creates a new Color instance to work from.
+                //
+                // example:
+                //              Work with a Color instance:
+                //       | var c = new dojo.Color();
+                //       | c.setColor([0,0,0]); // black
+                //       | var hex = c.toHex(); // #000000
+                //
+                // example:
+                //              Work with a node's color:
+                //       | var color = dojo.style("someNode", "backgroundColor");
+                //       | var n = new dojo.Color(color);
+                //       | // adjust the color some
+                //       | n.r *= .5;
+                //       | console.log(n.toString()); // rgb(128, 255, 255);
+                if(color){ this.setColor(color); }
+        };
+
+        // FIXME:
+        //      there's got to be a more space-efficient way to encode or discover
+        //      these!!  Use hex?
+        dojo.Color.named = {
+                black:      [0,0,0],
+                silver:     [192,192,192],
+                gray:       [128,128,128],
+                white:      [255,255,255],
+                maroon:         [128,0,0],
+                red:        [255,0,0],
+                purple:         [128,0,128],
+                fuchsia:        [255,0,255],
+                green:      [0,128,0],
+                lime:       [0,255,0],
+                olive:          [128,128,0],
+                yellow:         [255,255,0],
+                navy:       [0,0,128],
+                blue:       [0,0,255],
+                teal:           [0,128,128],
+                aqua:           [0,255,255],
+                transparent: d.config.transparentColor || [255,255,255]
+        };
+
+        dojo.extend(dojo.Color, {
+                r: 255, g: 255, b: 255, a: 1,
+                _set: function(r, g, b, a){
+                        var t = this; t.r = r; t.g = g; t.b = b; t.a = a;
+                },
+                setColor: function(/*Array|String|Object*/ color){
+                        // summary:
+                        //              Takes a named string, hex string, array of rgb or rgba values,
+                        //              an object with r, g, b, and a properties, or another `dojo.Color` object
+                        //              and sets this color instance to that value.
+                        //
+                        // example:
+                        //      |       var c = new dojo.Color(); // no color
+                        //      |       c.setColor("#ededed"); // greyish
+                        if(d.isString(color)){
+                                d.colorFromString(color, this);
+                        }else if(d.isArray(color)){
+                                d.colorFromArray(color, this);
+                        }else{
+                                this._set(color.r, color.g, color.b, color.a);
+                                if(!(color instanceof d.Color)){ this.sanitize(); }
+                        }
+                        return this;    // dojo.Color
+                },
+                sanitize: function(){
+                        // summary:
+                        //              Ensures the object has correct attributes
+                        // description:
+                        //              the default implementation does nothing, include dojo.colors to
+                        //              augment it with real checks
+                        return this;    // dojo.Color
+                },
+                toRgb: function(){
+                        // summary:
+                        //              Returns 3 component array of rgb values
+                        // example:
+                        //      |       var c = new dojo.Color("#000000");
+                        //      |       console.log(c.toRgb()); // [0,0,0]
+                        var t = this;
+                        return [t.r, t.g, t.b]; // Array
+                },
+                toRgba: function(){
+                        // summary:
+                        //              Returns a 4 component array of rgba values from the color
+                        //              represented by this object.
+                        var t = this;
+                        return [t.r, t.g, t.b, t.a];    // Array
+                },
+                toHex: function(){
+                        // summary:
+                        //              Returns a CSS color string in hexadecimal representation
+                        // example:
+                        //      |       console.log(new dojo.Color([0,0,0]).toHex()); // #000000
+                        var arr = d.map(["r", "g", "b"], function(x){
+                                var s = this[x].toString(16);
+                                return s.length < 2 ? "0" + s : s;
+                        }, this);
+                        return "#" + arr.join("");      // String
+                },
+                toCss: function(/*Boolean?*/ includeAlpha){
+                        // summary:
+                        //              Returns a css color string in rgb(a) representation
+                        // example:
+                        //      |       var c = new dojo.Color("#FFF").toCss();
+                        //      |       console.log(c); // rgb('255','255','255')
+                        var t = this, rgb = t.r + ", " + t.g + ", " + t.b;
+                        return (includeAlpha ? "rgba(" + rgb + ", " + t.a : "rgb(" + rgb) + ")";        // String
+                },
+                toString: function(){
+                        // summary:
+                        //              Returns a visual representation of the color
+                        return this.toCss(true); // String
+                }
+        });
+
+        dojo.blendColors = function(
+                /*dojo.Color*/ start,
+                /*dojo.Color*/ end,
+                /*Number*/ weight,
+                /*dojo.Color?*/ obj
+        ){
+                // summary:
+                //              Blend colors end and start with weight from 0 to 1, 0.5 being a 50/50 blend,
+                //              can reuse a previously allocated dojo.Color object for the result
+                var t = obj || new d.Color();
+                d.forEach(["r", "g", "b", "a"], function(x){
+                        t[x] = start[x] + (end[x] - start[x]) * weight;
+                        if(x != "a"){ t[x] = Math.round(t[x]); }
+                });
+                return t.sanitize();    // dojo.Color
+        };
+
+        dojo.colorFromRgb = function(/*String*/ color, /*dojo.Color?*/ obj){
+                // summary:
+                //              Returns a `dojo.Color` instance from a string of the form
+                //              "rgb(...)" or "rgba(...)". Optionally accepts a `dojo.Color`
+                //              object to update with the parsed value and return instead of
+                //              creating a new object.
+                // returns:
+                //              A dojo.Color object. If obj is passed, it will be the return value.
+                var m = color.toLowerCase().match(/^rgba?\(([\s\.,0-9]+)\)/);
+                return m && dojo.colorFromArray(m[1].split(/\s*,\s*/), obj);    // dojo.Color
+        };
+
+        dojo.colorFromHex = function(/*String*/ color, /*dojo.Color?*/ obj){
+                // summary:
+                //              Converts a hex string with a '#' prefix to a color object.
+                //              Supports 12-bit #rgb shorthand. Optionally accepts a
+                //              `dojo.Color` object to update with the parsed value.
+                //
+                // returns:
+                //              A dojo.Color object. If obj is passed, it will be the return value.
+                //
+                // example:
+                //       | var thing = dojo.colorFromHex("#ededed"); // grey, longhand
+                //
+                // example:
+                //      | var thing = dojo.colorFromHex("#000"); // black, shorthand
+                var t = obj || new d.Color(),
+                        bits = (color.length == 4) ? 4 : 8,
+                        mask = (1 << bits) - 1;
+                color = Number("0x" + color.substr(1));
+                if(isNaN(color)){
+                        return null; // dojo.Color
+                }
+                d.forEach(["b", "g", "r"], function(x){
+                        var c = color & mask;
+                        color >>= bits;
+                        t[x] = bits == 4 ? 17 * c : c;
+                });
+                t.a = 1;
+                return t;       // dojo.Color
+        };
+
+        dojo.colorFromArray = function(/*Array*/ a, /*dojo.Color?*/ obj){
+                // summary:
+                //              Builds a `dojo.Color` from a 3 or 4 element array, mapping each
+                //              element in sequence to the rgb(a) values of the color.
+                // example:
+                //              | var myColor = dojo.colorFromArray([237,237,237,0.5]); // grey, 50% alpha
+                // returns:
+                //              A dojo.Color object. If obj is passed, it will be the return value.
+                var t = obj || new d.Color();
+                t._set(Number(a[0]), Number(a[1]), Number(a[2]), Number(a[3]));
+                if(isNaN(t.a)){ t.a = 1; }
+                return t.sanitize();    // dojo.Color
+        };
+
+        dojo.colorFromString = function(/*String*/ str, /*dojo.Color?*/ obj){
+                // summary:
+                //              Parses `str` for a color value. Accepts hex, rgb, and rgba
+                //              style color values.
+                // description:
+                //              Acceptable input values for str may include arrays of any form
+                //              accepted by dojo.colorFromArray, hex strings such as "#aaaaaa", or
+                //              rgb or rgba strings such as "rgb(133, 200, 16)" or "rgba(10, 10,
+                //              10, 50)"
+                // returns:
+                //              A dojo.Color object. If obj is passed, it will be the return value.
+                var a = d.Color.named[str];
+                return a && d.colorFromArray(a, obj) || d.colorFromRgb(str, obj) || d.colorFromHex(str, obj);
+        };
+})();
+
+}
+
+if(!dojo._hasResource["dojo._base.window"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dojo._base.window"] = true;
+dojo.provide("dojo._base.window");
+
+
+/*=====
+dojo.doc = {
+        // summary:
+        //              Alias for the current document. 'dojo.doc' can be modified
+        //              for temporary context shifting. Also see dojo.withDoc().
+        // description:
+        //    Refer to dojo.doc rather
+        //    than referring to 'window.document' to ensure your code runs
+        //    correctly in managed contexts.
+        // example:
+        //      |       n.appendChild(dojo.doc.createElement('div'));
+}
+=====*/
+dojo.doc = window["document"] || null;
+
+dojo.body = function(){
+        // summary:
+        //              Return the body element of the document
+        //              return the body object associated with dojo.doc
+        // example:
+        //      |       dojo.body().appendChild(dojo.doc.createElement('div'));
+
+        // Note: document.body is not defined for a strict xhtml document
+        // Would like to memoize this, but dojo.doc can change vi dojo.withDoc().
+        return dojo.doc.body || dojo.doc.getElementsByTagName("body")[0]; // Node
+};
+
+dojo.setContext = function(/*Object*/globalObject, /*DocumentElement*/globalDocument){
+        // summary:
+        //              changes the behavior of many core Dojo functions that deal with
+        //              namespace and DOM lookup, changing them to work in a new global
+        //              context (e.g., an iframe). The varibles dojo.global and dojo.doc
+        //              are modified as a result of calling this function and the result of
+        //              `dojo.body()` likewise differs.
+        dojo.global = globalObject;
+        dojo.doc = globalDocument;
+};
+
+dojo.withGlobal = function(     /*Object*/globalObject,
+                                                        /*Function*/callback,
+                                                        /*Object?*/thisObject,
+                                                        /*Array?*/cbArguments){
+        // summary:
+        //              Invoke callback with globalObject as dojo.global and
+        //              globalObject.document as dojo.doc.
+        // description:
+        //              Invoke callback with globalObject as dojo.global and
+        //              globalObject.document as dojo.doc. If provided, globalObject
+        //              will be executed in the context of object thisObject
+        //              When callback() returns or throws an error, the dojo.global
+        //              and dojo.doc will be restored to its previous state.
+
+        var oldGlob = dojo.global;
+        try{
+                dojo.global = globalObject;
+                return dojo.withDoc.call(null, globalObject.document, callback, thisObject, cbArguments);
+        }finally{
+                dojo.global = oldGlob;
+        }
+};
+
+dojo.withDoc = function(        /*DocumentElement*/documentObject,
+                                                        /*Function*/callback,
+                                                        /*Object?*/thisObject,
+                                                        /*Array?*/cbArguments){
+        // summary:
+        //              Invoke callback with documentObject as dojo.doc.
+        // description:
+        //              Invoke callback with documentObject as dojo.doc. If provided,
+        //              callback will be executed in the context of object thisObject
+        //              When callback() returns or throws an error, the dojo.doc will
+        //              be restored to its previous state.
+
+        var oldDoc = dojo.doc,
+                oldLtr = dojo._bodyLtr,
+                oldQ = dojo.isQuirks;
+
+        try{
+                dojo.doc = documentObject;
+                delete dojo._bodyLtr; // uncache
+                dojo.isQuirks = dojo.doc.compatMode == "BackCompat"; // no need to check for QuirksMode which was Opera 7 only
+
+                if(thisObject && typeof callback == "string"){
+                        callback = thisObject[callback];
+                }
+
+                return callback.apply(thisObject, cbArguments || []);
+        }finally{
+                dojo.doc = oldDoc;
+                delete dojo._bodyLtr; // in case it was undefined originally, and set to true/false by the alternate document
+                if(oldLtr !== undefined){ dojo._bodyLtr = oldLtr; }
+                dojo.isQuirks = oldQ;
+        }
+};
+
+}
+
+if(!dojo._hasResource["dojo._base.event"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dojo._base.event"] = true;
+dojo.provide("dojo._base.event");
+
+
+
+// this file courtesy of the TurboAjax Group, licensed under a Dojo CLA
+
+(function(){
+        // DOM event listener machinery
+        var del = (dojo._event_listener = {
+                add: function(/*DOMNode*/ node, /*String*/ name, /*Function*/ fp){
+                        if(!node){return;}
+                        name = del._normalizeEventName(name);
+                        fp = del._fixCallback(name, fp);
+                        if(
+                                                                !dojo.isIE &&
+                                                                (name == "mouseenter" || name == "mouseleave")
+                        ){
+                                var ofp = fp;
+                                name = (name == "mouseenter") ? "mouseover" : "mouseout";
+                                fp = function(e){
+                                        if(!dojo.isDescendant(e.relatedTarget, node)){
+                                                // e.type = oname; // FIXME: doesn't take? SJM: event.type is generally immutable.
+                                                return ofp.call(this, e);
+                                        }
+                                }
+                        }
+                        node.addEventListener(name, fp, false);
+                        return fp; /*Handle*/
+                },
+                remove: function(/*DOMNode*/ node, /*String*/ event, /*Handle*/ handle){
+                        // summary:
+                        //              clobbers the listener from the node
+                        // node:
+                        //              DOM node to attach the event to
+                        // event:
+                        //              the name of the handler to remove the function from
+                        // handle:
+                        //              the handle returned from add
+                        if(node){
+                                event = del._normalizeEventName(event);
+                                if(!dojo.isIE && (event == "mouseenter" || event == "mouseleave")){
+                                        event = (event == "mouseenter") ? "mouseover" : "mouseout";
+                                }
+
+                                node.removeEventListener(event, handle, false);
+                        }
+                },
+                _normalizeEventName: function(/*String*/ name){
+                        // Generally, name should be lower case, unless it is special
+                        // somehow (e.g. a Mozilla DOM event).
+                        // Remove 'on'.
+                        return name.slice(0,2) =="on" ? name.slice(2) : name;
+                },
+                _fixCallback: function(/*String*/ name, fp){
+                        // By default, we only invoke _fixEvent for 'keypress'
+                        // If code is added to _fixEvent for other events, we have
+                        // to revisit this optimization.
+                        // This also applies to _fixEvent overrides for Safari and Opera
+                        // below.
+                        return name != "keypress" ? fp : function(e){ return fp.call(this, del._fixEvent(e, this)); };
+                },
+                _fixEvent: function(evt, sender){
+                        // _fixCallback only attaches us to keypress.
+                        // Switch on evt.type anyway because we might
+                        // be called directly from dojo.fixEvent.
+                        switch(evt.type){
+                                case "keypress":
+                                        del._setKeyChar(evt);
+                                        break;
+                        }
+                        return evt;
+                },
+                _setKeyChar: function(evt){
+                        evt.keyChar = evt.charCode >= 32 ? String.fromCharCode(evt.charCode) : '';
+                        evt.charOrCode = evt.keyChar || evt.keyCode;
+                },
+                // For IE and Safari: some ctrl-key combinations (mostly w/punctuation) do not emit a char code in IE
+                // we map those virtual key codes to ascii here
+                // not valid for all (non-US) keyboards, so maybe we shouldn't bother
+                _punctMap: {
+                        106:42,
+                        111:47,
+                        186:59,
+                        187:43,
+                        188:44,
+                        189:45,
+                        190:46,
+                        191:47,
+                        192:96,
+                        219:91,
+                        220:92,
+                        221:93,
+                        222:39
+                }
+        });
+
+        // DOM events
+        
+        dojo.fixEvent = function(/*Event*/ evt, /*DOMNode*/ sender){
+                // summary:
+                //              normalizes properties on the event object including event
+                //              bubbling methods, keystroke normalization, and x/y positions
+                // evt: Event
+                //              native event object
+                // sender: DOMNode
+                //              node to treat as "currentTarget"
+                return del._fixEvent(evt, sender);
+        };
+
+        dojo.stopEvent = function(/*Event*/ evt){
+                // summary:
+                //              prevents propagation and clobbers the default action of the
+                //              passed event
+                // evt: Event
+                //              The event object. If omitted, window.event is used on IE.
+                evt.preventDefault();
+                evt.stopPropagation();
+                // NOTE: below, this method is overridden for IE
+        };
+
+        // the default listener to use on dontFix nodes, overriden for IE
+        var node_listener = dojo._listener;
+        
+        // Unify connect and event listeners
+        dojo._connect = function(obj, event, context, method, dontFix){
+                // FIXME: need a more strict test
+                var isNode = obj && (obj.nodeType||obj.attachEvent||obj.addEventListener);
+                // choose one of three listener options: raw (connect.js), DOM event on a Node, custom event on a Node
+                // we need the third option to provide leak prevention on broken browsers (IE)
+                var lid = isNode ? (dontFix ? 2 : 1) : 0, l = [dojo._listener, del, node_listener][lid];
+                // create a listener
+                var h = l.add(obj, event, dojo.hitch(context, method));
+                // formerly, the disconnect package contained "l" directly, but if client code
+                // leaks the disconnect package (by connecting it to a node), referencing "l"
+                // compounds the problem.
+                // instead we return a listener id, which requires custom _disconnect below.
+                // return disconnect package
+                return [ obj, event, h, lid ];
+        };
+
+        dojo._disconnect = function(obj, event, handle, listener){
+                ([dojo._listener, del, node_listener][listener]).remove(obj, event, handle);
+        };
+
+        // Constants
+
+        // Public: client code should test
+        // keyCode against these named constants, as the
+        // actual codes can vary by browser.
+        dojo.keys = {
+                // summary:
+                //              Definitions for common key values
+                BACKSPACE: 8,
+                TAB: 9,
+                CLEAR: 12,
+                ENTER: 13,
+                SHIFT: 16,
+                CTRL: 17,
+                ALT: 18,
+                META: dojo.isSafari ? 91 : 224,         // the apple key on macs
+                PAUSE: 19,
+                CAPS_LOCK: 20,
+                ESCAPE: 27,
+                SPACE: 32,
+                PAGE_UP: 33,
+                PAGE_DOWN: 34,
+                END: 35,
+                HOME: 36,
+                LEFT_ARROW: 37,
+                UP_ARROW: 38,
+                RIGHT_ARROW: 39,
+                DOWN_ARROW: 40,
+                INSERT: 45,
+                DELETE: 46,
+                HELP: 47,
+                LEFT_WINDOW: 91,
+                RIGHT_WINDOW: 92,
+                SELECT: 93,
+                NUMPAD_0: 96,
+                NUMPAD_1: 97,
+                NUMPAD_2: 98,
+                NUMPAD_3: 99,
+                NUMPAD_4: 100,
+                NUMPAD_5: 101,
+                NUMPAD_6: 102,
+                NUMPAD_7: 103,
+                NUMPAD_8: 104,
+                NUMPAD_9: 105,
+                NUMPAD_MULTIPLY: 106,
+                NUMPAD_PLUS: 107,
+                NUMPAD_ENTER: 108,
+                NUMPAD_MINUS: 109,
+                NUMPAD_PERIOD: 110,
+                NUMPAD_DIVIDE: 111,
+                F1: 112,
+                F2: 113,
+                F3: 114,
+                F4: 115,
+                F5: 116,
+                F6: 117,
+                F7: 118,
+                F8: 119,
+                F9: 120,
+                F10: 121,
+                F11: 122,
+                F12: 123,
+                F13: 124,
+                F14: 125,
+                F15: 126,
+                NUM_LOCK: 144,
+                SCROLL_LOCK: 145,
+                // virtual key mapping
+                copyKey: dojo.isMac && !dojo.isAIR ? (dojo.isSafari ? 91 : 224 ) : 17
+        };
+        
+        var evtCopyKey = dojo.isMac ? "metaKey" : "ctrlKey";
+        
+        dojo.isCopyKey = function(e){
+                // summary:
+                //              Checks an event for the copy key (meta on Mac, and ctrl anywhere else)
+                // e: Event
+                //              Event object to examine
+                return e[evtCopyKey];   // Boolean
+        };
+
+        // Public: decoding mouse buttons from events
+
+/*=====
+        dojo.mouseButtons = {
+                // LEFT: Number
+                //              Numeric value of the left mouse button for the platform.
+                LEFT:   0,
+                // MIDDLE: Number
+                //              Numeric value of the middle mouse button for the platform.
+                MIDDLE: 1,
+                // RIGHT: Number
+                //              Numeric value of the right mouse button for the platform.
+                RIGHT:  2,
+        
+                isButton: function(e, button){
+                        // summary:
+                        //              Checks an event object for a pressed button
+                        // e: Event
+                        //              Event object to examine
+                        // button: Number
+                        //              The button value (example: dojo.mouseButton.LEFT)
+                        return e.button == button; // Boolean
+                },
+                isLeft: function(e){
+                        // summary:
+                        //              Checks an event object for the pressed left button
+                        // e: Event
+                        //              Event object to examine
+                        return e.button == 0; // Boolean
+                },
+                isMiddle: function(e){
+                        // summary:
+                        //              Checks an event object for the pressed middle button
+                        // e: Event
+                        //              Event object to examine
+                        return e.button == 1; // Boolean
+                },
+                isRight: function(e){
+                        // summary:
+                        //              Checks an event object for the pressed right button
+                        // e: Event
+                        //              Event object to examine
+                        return e.button == 2; // Boolean
+                }
+        };
+=====*/
+
+                if(dojo.isIE < 9 || (dojo.isIE && dojo.isQuirks)){
+                dojo.mouseButtons = {
+                        LEFT:   1,
+                        MIDDLE: 4,
+                        RIGHT:  2,
+                        // helper functions
+                        isButton: function(e, button){ return e.button & button; },
+                        isLeft:   function(e){ return e.button & 1; },
+                        isMiddle: function(e){ return e.button & 4; },
+                        isRight:  function(e){ return e.button & 2; }
+                };
+        }else{
+                        dojo.mouseButtons = {
+                        LEFT:   0,
+                        MIDDLE: 1,
+                        RIGHT:  2,
+                        // helper functions
+                        isButton: function(e, button){ return e.button == button; },
+                        isLeft:   function(e){ return e.button == 0; },
+                        isMiddle: function(e){ return e.button == 1; },
+                        isRight:  function(e){ return e.button == 2; }
+                };
+                }
+        
+                // IE event normalization
+        if(dojo.isIE){
+                var _trySetKeyCode = function(e, code){
+                        try{
+                                // squelch errors when keyCode is read-only
+                                // (e.g. if keyCode is ctrl or shift)
+                                return (e.keyCode = code);
+                        }catch(e){
+                                return 0;
+                        }
+                };
+
+                // by default, use the standard listener
+                var iel = dojo._listener;
+                var listenersName = (dojo._ieListenersName = "_" + dojo._scopeName + "_listeners");
+                // dispatcher tracking property
+                if(!dojo.config._allow_leaks){
+                        // custom listener that handles leak protection for DOM events
+                        node_listener = iel = dojo._ie_listener = {
+                                // support handler indirection: event handler functions are
+                                // referenced here. Event dispatchers hold only indices.
+                                handlers: [],
+                                // add a listener to an object
+                                add: function(/*Object*/ source, /*String*/ method, /*Function*/ listener){
+                                        source = source || dojo.global;
+                                        var f = source[method];
+                                        if(!f||!f[listenersName]){
+                                                var d = dojo._getIeDispatcher();
+                                                // original target function is special
+                                                d.target = f && (ieh.push(f) - 1);
+                                                // dispatcher holds a list of indices into handlers table
+                                                d[listenersName] = [];
+                                                // redirect source to dispatcher
+                                                f = source[method] = d;
+                                        }
+                                        return f[listenersName].push(ieh.push(listener) - 1) ; /*Handle*/
+                                },
+                                // remove a listener from an object
+                                remove: function(/*Object*/ source, /*String*/ method, /*Handle*/ handle){
+                                        var f = (source||dojo.global)[method], l = f && f[listenersName];
+                                        if(f && l && handle--){
+                                                delete ieh[l[handle]];
+                                                delete l[handle];
+                                        }
+                                }
+                        };
+                        // alias used above
+                        var ieh = iel.handlers;
+                }
+
+                dojo.mixin(del, {
+                        add: function(/*DOMNode*/ node, /*String*/ event, /*Function*/ fp){
+                                if(!node){return;} // undefined
+                                event = del._normalizeEventName(event);
+                                if(event=="onkeypress"){
+                                        // we need to listen to onkeydown to synthesize
+                                        // keypress events that otherwise won't fire
+                                        // on IE
+                                        var kd = node.onkeydown;
+                                        if(!kd || !kd[listenersName] || !kd._stealthKeydownHandle){
+                                                var h = del.add(node, "onkeydown", del._stealthKeyDown);
+                                                kd = node.onkeydown;
+                                                kd._stealthKeydownHandle = h;
+                                                kd._stealthKeydownRefs = 1;
+                                        }else{
+                                                kd._stealthKeydownRefs++;
+                                        }
+                                }
+                                return iel.add(node, event, del._fixCallback(fp));
+                        },
+                        remove: function(/*DOMNode*/ node, /*String*/ event, /*Handle*/ handle){
+                                event = del._normalizeEventName(event);
+                                iel.remove(node, event, handle);
+                                if(event=="onkeypress"){
+                                        var kd = node.onkeydown;
+                                        if(--kd._stealthKeydownRefs <= 0){
+                                                iel.remove(node, "onkeydown", kd._stealthKeydownHandle);
+                                                delete kd._stealthKeydownHandle;
+                                        }
+                                }
+                        },
+                        _normalizeEventName: function(/*String*/ eventName){
+                                // Generally, eventName should be lower case, unless it is
+                                // special somehow (e.g. a Mozilla event)
+                                // ensure 'on'
+                                return eventName.slice(0,2) != "on" ? "on" + eventName : eventName;
+                        },
+                        _nop: function(){},
+                        _fixEvent: function(/*Event*/ evt, /*DOMNode*/ sender){
+                                // summary:
+                                //              normalizes properties on the event object including event
+                                //              bubbling methods, keystroke normalization, and x/y positions
+                                // evt:
+                                //              native event object
+                                // sender:
+                                //              node to treat as "currentTarget"
+                                if(!evt){
+                                        var w = sender && (sender.ownerDocument || sender.document || sender).parentWindow || window;
+                                        evt = w.event;
+                                }
+                                if(!evt){return(evt);}
+                                evt.target = evt.srcElement;
+                                evt.currentTarget = (sender || evt.srcElement);
+                                evt.layerX = evt.offsetX;
+                                evt.layerY = evt.offsetY;
+                                // FIXME: scroll position query is duped from dojo.html to
+                                // avoid dependency on that entire module. Now that HTML is in
+                                // Base, we should convert back to something similar there.
+                                var se = evt.srcElement, doc = (se && se.ownerDocument) || document;
+                                // DO NOT replace the following to use dojo.body(), in IE, document.documentElement should be used
+                                // here rather than document.body
+                                var docBody = ((dojo.isIE < 6) || (doc["compatMode"] == "BackCompat")) ? doc.body : doc.documentElement;
+                                var offset = dojo._getIeDocumentElementOffset();
+                                evt.pageX = evt.clientX + dojo._fixIeBiDiScrollLeft(docBody.scrollLeft || 0) - offset.x;
+                                evt.pageY = evt.clientY + (docBody.scrollTop || 0) - offset.y;
+                                if(evt.type == "mouseover"){
+                                        evt.relatedTarget = evt.fromElement;
+                                }
+                                if(evt.type == "mouseout"){
+                                        evt.relatedTarget = evt.toElement;
+                                }
+                                if (dojo.isIE < 9 || dojo.isQuirks) {
+                                        evt.stopPropagation = del._stopPropagation;
+                                        evt.preventDefault = del._preventDefault;
+                                }
+                                return del._fixKeys(evt);
+                        },
+                        _fixKeys: function(evt){
+                                switch(evt.type){
+                                        case "keypress":
+                                                var c = ("charCode" in evt ? evt.charCode : evt.keyCode);
+                                                if (c==10){
+                                                        // CTRL-ENTER is CTRL-ASCII(10) on IE, but CTRL-ENTER on Mozilla
+                                                        c=0;
+                                                        evt.keyCode = 13;
+                                                }else if(c==13||c==27){
+                                                        c=0; // Mozilla considers ENTER and ESC non-printable
+                                                }else if(c==3){
+                                                        c=99; // Mozilla maps CTRL-BREAK to CTRL-c
+                                                }
+                                                // Mozilla sets keyCode to 0 when there is a charCode
+                                                // but that stops the event on IE.
+                                                evt.charCode = c;
+                                                del._setKeyChar(evt);
+                                                break;
+                                }
+                                return evt;
+                        },
+                        _stealthKeyDown: function(evt){
+                                // IE doesn't fire keypress for most non-printable characters.
+                                // other browsers do, we simulate it here.
+                                var kp = evt.currentTarget.onkeypress;
+                                // only works if kp exists and is a dispatcher
+                                if(!kp || !kp[listenersName]){ return; }
+                                // munge key/charCode
+                                var k=evt.keyCode;
+                                // These are Windows Virtual Key Codes
+                                // http://msdn.microsoft.com/library/default.asp?url=/library/en-us/winui/WinUI/WindowsUserInterface/UserInput/VirtualKeyCodes.asp
+                                var unprintable = (k!=13 || (dojo.isIE >= 9 && !dojo.isQuirks)) && k!=32 && k!=27 && (k<48||k>90) && (k<96||k>111) && (k<186||k>192) && (k<219||k>222);
+
+                                // synthesize keypress for most unprintables and CTRL-keys
+                                if(unprintable||evt.ctrlKey){
+                                        var c = unprintable ? 0 : k;
+                                        if(evt.ctrlKey){
+                                                if(k==3 || k==13){
+                                                        return; // IE will post CTRL-BREAK, CTRL-ENTER as keypress natively
+                                                }else if(c>95 && c<106){
+                                                        c -= 48; // map CTRL-[numpad 0-9] to ASCII
+                                                }else if((!evt.shiftKey)&&(c>=65&&c<=90)){
+                                                        c += 32; // map CTRL-[A-Z] to lowercase
+                                                }else{
+                                                        c = del._punctMap[c] || c; // map other problematic CTRL combinations to ASCII
+                                                }
+                                        }
+                                        // simulate a keypress event
+                                        var faux = del._synthesizeEvent(evt, {type: 'keypress', faux: true, charCode: c});
+                                        kp.call(evt.currentTarget, faux);
+                                        if(dojo.isIE < 9 || (dojo.isIE && dojo.isQuirks)){
+                                                evt.cancelBubble = faux.cancelBubble;
+                                        }
+                                        evt.returnValue = faux.returnValue;
+                                        _trySetKeyCode(evt, faux.keyCode);
+                                }
+                        },
+                        // Called in Event scope
+                        _stopPropagation: function(){
+                                this.cancelBubble = true;
+                        },
+                        _preventDefault: function(){
+                                // Setting keyCode to 0 is the only way to prevent certain keypresses (namely
+                                // ctrl-combinations that correspond to menu accelerator keys).
+                                // Otoh, it prevents upstream listeners from getting this information
+                                // Try to split the difference here by clobbering keyCode only for ctrl
+                                // combinations. If you still need to access the key upstream, bubbledKeyCode is
+                                // provided as a workaround.
+                                this.bubbledKeyCode = this.keyCode;
+                                if(this.ctrlKey){_trySetKeyCode(this, 0);}
+                                this.returnValue = false;
+                        }
+                });
+                                
+                // override stopEvent for IE
+                dojo.stopEvent = (dojo.isIE < 9 || dojo.isQuirks) ? function(evt){
+                        evt = evt || window.event;
+                        del._stopPropagation.call(evt);
+                        del._preventDefault.call(evt);
+                } : dojo.stopEvent;
+        }
+        
+        del._synthesizeEvent = function(evt, props){
+                        var faux = dojo.mixin({}, evt, props);
+                        del._setKeyChar(faux);
+                        // FIXME: would prefer to use dojo.hitch: dojo.hitch(evt, evt.preventDefault);
+                        // but it throws an error when preventDefault is invoked on Safari
+                        // does Event.preventDefault not support "apply" on Safari?
+                        faux.preventDefault = function(){ evt.preventDefault(); };
+                        faux.stopPropagation = function(){ evt.stopPropagation(); };
+                        return faux;
+        };
+        
+                // Opera event normalization
+        if(dojo.isOpera){
+                dojo.mixin(del, {
+                        _fixEvent: function(evt, sender){
+                                switch(evt.type){
+                                        case "keypress":
+                                                var c = evt.which;
+                                                if(c==3){
+                                                        c=99; // Mozilla maps CTRL-BREAK to CTRL-c
+                                                }
+                                                // can't trap some keys at all, like INSERT and DELETE
+                                                // there is no differentiating info between DELETE and ".", or INSERT and "-"
+                                                c = c<41 && !evt.shiftKey ? 0 : c;
+                                                if(evt.ctrlKey && !evt.shiftKey && c>=65 && c<=90){
+                                                        // lowercase CTRL-[A-Z] keys
+                                                        c += 32;
+                                                }
+                                                return del._synthesizeEvent(evt, { charCode: c });
+                                }
+                                return evt;
+                        }
+                });
+        }
+        
+                // Webkit event normalization
+        if(dojo.isWebKit){
+                                del._add = del.add;
+                del._remove = del.remove;
+
+                dojo.mixin(del, {
+                        add: function(/*DOMNode*/ node, /*String*/ event, /*Function*/ fp){
+                                if(!node){return;} // undefined
+                                var handle = del._add(node, event, fp);
+                                if(del._normalizeEventName(event) == "keypress"){
+                                        // we need to listen to onkeydown to synthesize
+                                        // keypress events that otherwise won't fire
+                                        // in Safari 3.1+: https://lists.webkit.org/pipermail/webkit-dev/2007-December/002992.html
+                                        handle._stealthKeyDownHandle = del._add(node, "keydown", function(evt){
+                                                //A variation on the IE _stealthKeydown function
+                                                //Synthesize an onkeypress event, but only for unprintable characters.
+                                                var k=evt.keyCode;
+                                                // These are Windows Virtual Key Codes
+                                                // http://msdn.microsoft.com/library/default.asp?url=/library/en-us/winui/WinUI/WindowsUserInterface/UserInput/VirtualKeyCodes.asp
+                                                var unprintable = k!=13 && k!=32 && (k<48 || k>90) && (k<96 || k>111) && (k<186 || k>192) && (k<219 || k>222);
+                                                // synthesize keypress for most unprintables and CTRL-keys
+                                                if(unprintable || evt.ctrlKey){
+                                                        var c = unprintable ? 0 : k;
+                                                        if(evt.ctrlKey){
+                                                                if(k==3 || k==13){
+                                                                        return; // IE will post CTRL-BREAK, CTRL-ENTER as keypress natively
+                                                                }else if(c>95 && c<106){
+                                                                        c -= 48; // map CTRL-[numpad 0-9] to ASCII
+                                                                }else if(!evt.shiftKey && c>=65 && c<=90){
+                                                                        c += 32; // map CTRL-[A-Z] to lowercase
+                                                                }else{
+                                                                        c = del._punctMap[c] || c; // map other problematic CTRL combinations to ASCII
+                                                                }
+                                                        }
+                                                        // simulate a keypress event
+                                                        var faux = del._synthesizeEvent(evt, {type: 'keypress', faux: true, charCode: c});
+                                                        fp.call(evt.currentTarget, faux);
+                                                }
+                                        });
+                                }
+                                return handle; /*Handle*/
+                        },
+
+                        remove: function(/*DOMNode*/ node, /*String*/ event, /*Handle*/ handle){
+                                if(node){
+                                        if(handle._stealthKeyDownHandle){
+                                                del._remove(node, "keydown", handle._stealthKeyDownHandle);
+                                        }
+                                        del._remove(node, event, handle);
+                                }
+                        },
+                        _fixEvent: function(evt, sender){
+                                switch(evt.type){
+                                        case "keypress":
+                                                if(evt.faux){ return evt; }
+                                                var c = evt.charCode;
+                                                c = c>=32 ? c : 0;
+                                                return del._synthesizeEvent(evt, {charCode: c, faux: true});
+                                }
+                                return evt;
+                        }
+                });
+                }
+        })();
+
+if(dojo.isIE){
+        // keep this out of the closure
+        // closing over 'iel' or 'ieh' b0rks leak prevention
+        // ls[i] is an index into the master handler array
+        dojo._ieDispatcher = function(args, sender){
+                var ap = Array.prototype,
+                        h = dojo._ie_listener.handlers,
+                        c = args.callee,
+                        ls = c[dojo._ieListenersName],
+                        t = h[c.target];
+                // return value comes from original target function
+                var r = t && t.apply(sender, args);
+                // make local copy of listener array so it's immutable during processing
+                var lls = [].concat(ls);
+                // invoke listeners after target function
+                for(var i in lls){
+                        var f = h[lls[i]];
+                        if(!(i in ap) && f){
+                                f.apply(sender, args);
+                        }
+                }
+                return r;
+        };
+        dojo._getIeDispatcher = function(){
+                // ensure the returned function closes over nothing ("new Function" apparently doesn't close)
+                return new Function(dojo._scopeName + "._ieDispatcher(arguments, this)"); // function
+        };
+        // keep this out of the closure to reduce RAM allocation
+        dojo._event_listener._fixCallback = function(fp){
+                var f = dojo._event_listener._fixEvent;
+                return function(e){ return fp.call(this, f(e, this)); };
+        };
+}
+
+}
+
+if(!dojo._hasResource["dojo._base.html"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dojo._base.html"] = true;
+dojo.provide("dojo._base.html");
+
+
+
+// FIXME: need to add unit tests for all the semi-public methods
+
+try{
+        document.execCommand("BackgroundImageCache", false, true);
+}catch(e){
+        // sane browsers don't have cache "issues"
+}
+
+// =============================
+// DOM Functions
+// =============================
+
+/*=====
+dojo.byId = function(id, doc){
+        //      summary:
+        //              Returns DOM node with matching `id` attribute or `null`
+        //              if not found. If `id` is a DomNode, this function is a no-op.
+        //
+        //      id: String|DOMNode
+        //              A string to match an HTML id attribute or a reference to a DOM Node
+        //
+        //      doc: Document?
+        //              Document to work in. Defaults to the current value of
+        //              dojo.doc.  Can be used to retrieve
+        //              node references from other documents.
+        //
+        //      example:
+        //      Look up a node by ID:
+        //      |       var n = dojo.byId("foo");
+        //
+        //      example:
+        //      Check if a node exists, and use it.
+        //      |       var n = dojo.byId("bar");
+        //      |       if(n){ doStuff() ... }
+        //
+        //      example:
+        //      Allow string or DomNode references to be passed to a custom function:
+        //      |       var foo = function(nodeOrId){
+        //      |               nodeOrId = dojo.byId(nodeOrId);
+        //      |               // ... more stuff
+        //      |       }
+=====*/
+
+if(dojo.isIE){
+        dojo.byId = function(id, doc){
+                if(typeof id != "string"){
+                        return id;
+                }
+                var _d = doc || dojo.doc, te = _d.getElementById(id);
+                // attributes.id.value is better than just id in case the
+                // user has a name=id inside a form
+                if(te && (te.attributes.id.value == id || te.id == id)){
+                        return te;
+                }else{
+                        var eles = _d.all[id];
+                        if(!eles || eles.nodeName){
+                                eles = [eles];
+                        }
+                        // if more than 1, choose first with the correct id
+                        var i=0;
+                        while((te=eles[i++])){
+                                if((te.attributes && te.attributes.id && te.attributes.id.value == id)
+                                        || te.id == id){
+                                        return te;
+                                }
+                        }
+                }
+        };
+}else{
+        dojo.byId = function(id, doc){
+                // inline'd type check.
+                // be sure to return null per documentation, to match IE branch.
+                return ((typeof id == "string") ? (doc || dojo.doc).getElementById(id) : id) || null; // DomNode
+        };
+}
+/*=====
+};
+=====*/
+
+(function(){
+        var d = dojo;
+        var byId = d.byId;
+
+        var _destroyContainer = null,
+                _destroyDoc;
+                d.addOnWindowUnload(function(){
+                _destroyContainer = null; //prevent IE leak
+        });
+        
+/*=====
+        dojo._destroyElement = function(node){
+                // summary:
+                //              Existing alias for `dojo.destroy`. Deprecated, will be removed
+                //              in 2.0
+        }
+=====*/
+        dojo._destroyElement = dojo.destroy = function(/*String|DomNode*/node){
+                //      summary:
+                //              Removes a node from its parent, clobbering it and all of its
+                //              children.
+                //
+                //      description:
+                //              Removes a node from its parent, clobbering it and all of its
+                //              children. Function only works with DomNodes, and returns nothing.
+                //
+                //      node:
+                //              A String ID or DomNode reference of the element to be destroyed
+                //
+                //      example:
+                //      Destroy a node byId:
+                //      |       dojo.destroy("someId");
+                //
+                //      example:
+                //      Destroy all nodes in a list by reference:
+                //      |       dojo.query(".someNode").forEach(dojo.destroy);
+
+                node = byId(node);
+                try{
+                        var doc = node.ownerDocument;
+                        // cannot use _destroyContainer.ownerDocument since this can throw an exception on IE
+                        if(!_destroyContainer || _destroyDoc != doc){
+                                _destroyContainer = doc.createElement("div");
+                                _destroyDoc = doc;
+                        }
+                        _destroyContainer.appendChild(node.parentNode ? node.parentNode.removeChild(node) : node);
+                        // NOTE: see http://trac.dojotoolkit.org/ticket/2931. This may be a bug and not a feature
+                        _destroyContainer.innerHTML = "";
+                }catch(e){
+                        /* squelch */
+                }
+        };
+
+        dojo.isDescendant = function(/*DomNode|String*/node, /*DomNode|String*/ancestor){
+                //      summary:
+                //              Returns true if node is a descendant of ancestor
+                //      node: string id or node reference to test
+                //      ancestor: string id or node reference of potential parent to test against
+                //
+                // example:
+                //      Test is node id="bar" is a descendant of node id="foo"
+                //      |       if(dojo.isDescendant("bar", "foo")){ ... }
+                try{
+                        node = byId(node);
+                        ancestor = byId(ancestor);
+                        while(node){
+                                if(node == ancestor){
+                                        return true; // Boolean
+                                }
+                                node = node.parentNode;
+                        }
+                }catch(e){ /* squelch, return false */ }
+                return false; // Boolean
+        };
+
+        dojo.setSelectable = function(/*DomNode|String*/node, /*Boolean*/selectable){
+                //      summary:
+                //              Enable or disable selection on a node
+                //      node:
+                //              id or reference to node
+                //      selectable:
+                //              state to put the node in. false indicates unselectable, true
+                //              allows selection.
+                //      example:
+                //      Make the node id="bar" unselectable
+                //      |       dojo.setSelectable("bar");
+                //      example:
+                //      Make the node id="bar" selectable
+                //      |       dojo.setSelectable("bar", true);
+                node = byId(node);
+                                if(d.isMozilla){
+                        node.style.MozUserSelect = selectable ? "" : "none";
+                }else if(d.isKhtml || d.isWebKit){
+                                        node.style.KhtmlUserSelect = selectable ? "auto" : "none";
+                                }else if(d.isIE){
+                        var v = (node.unselectable = selectable ? "" : "on");
+                        d.query("*", node).forEach("item.unselectable = '"+v+"'");
+                }
+                                //FIXME: else?  Opera?
+        };
+
+        var _insertBefore = function(/*DomNode*/node, /*DomNode*/ref){
+                var parent = ref.parentNode;
+                if(parent){
+                        parent.insertBefore(node, ref);
+                }
+        };
+
+        var _insertAfter = function(/*DomNode*/node, /*DomNode*/ref){
+                //      summary:
+                //              Try to insert node after ref
+                var parent = ref.parentNode;
+                if(parent){
+                        if(parent.lastChild == ref){
+                                parent.appendChild(node);
+                        }else{
+                                parent.insertBefore(node, ref.nextSibling);
+                        }
+                }
+        };
+
+        dojo.place = function(node, refNode, position){
+                //      summary:
+                //              Attempt to insert node into the DOM, choosing from various positioning options.
+                //              Returns the first argument resolved to a DOM node.
+                //
+                //      node: String|DomNode
+                //              id or node reference, or HTML fragment starting with "<" to place relative to refNode
+                //
+                //      refNode: String|DomNode
+                //              id or node reference to use as basis for placement
+                //
+                //      position: String|Number?
+                //              string noting the position of node relative to refNode or a
+                //              number indicating the location in the childNodes collection of refNode.
+                //              Accepted string values are:
+                //      |       * before
+                //      |       * after
+                //      |       * replace
+                //      |       * only
+                //      |       * first
+                //      |       * last
+                //              "first" and "last" indicate positions as children of refNode, "replace" replaces refNode,
+                //              "only" replaces all children.  position defaults to "last" if not specified
+                //
+                //      returns: DomNode
+                //              Returned values is the first argument resolved to a DOM node.
+                //
+                //              .place() is also a method of `dojo.NodeList`, allowing `dojo.query` node lookups.
+                //
+                // example:
+                //              Place a node by string id as the last child of another node by string id:
+                //      |       dojo.place("someNode", "anotherNode");
+                //
+                // example:
+                //              Place a node by string id before another node by string id
+                //      |       dojo.place("someNode", "anotherNode", "before");
+                //
+                // example:
+                //              Create a Node, and place it in the body element (last child):
+                //      |       dojo.place("<div></div>", dojo.body());
+                //
+                // example:
+                //              Put a new LI as the first child of a list by id:
+                //      |       dojo.place("<li></li>", "someUl", "first");
+
+                refNode = byId(refNode);
+                if(typeof node == "string"){ // inline'd type check
+                        node = /^\s*</.test(node) ? d._toDom(node, refNode.ownerDocument) : byId(node);
+                }
+                if(typeof position == "number"){ // inline'd type check
+                        var cn = refNode.childNodes;
+                        if(!cn.length || cn.length <= position){
+                                refNode.appendChild(node);
+                        }else{
+                                _insertBefore(node, cn[position < 0 ? 0 : position]);
+                        }
+                }else{
+                        switch(position){
+                                case "before":
+                                        _insertBefore(node, refNode);
+                                        break;
+                                case "after":
+                                        _insertAfter(node, refNode);
+                                        break;
+                                case "replace":
+                                        refNode.parentNode.replaceChild(node, refNode);
+                                        break;
+                                case "only":
+                                        d.empty(refNode);
+                                        refNode.appendChild(node);
+                                        break;
+                                case "first":
+                                        if(refNode.firstChild){
+                                                _insertBefore(node, refNode.firstChild);
+                                                break;
+                                        }
+                                        // else fallthrough...
+                                default: // aka: last
+                                        refNode.appendChild(node);
+                        }
+                }
+                return node; // DomNode
+        };
+
+        // Box functions will assume this model.
+        // On IE/Opera, BORDER_BOX will be set if the primary document is in quirks mode.
+        // Can be set to change behavior of box setters.
+
+        // can be either:
+        //      "border-box"
+        //      "content-box" (default)
+        dojo.boxModel = "content-box";
+
+        // We punt per-node box mode testing completely.
+        // If anybody cares, we can provide an additional (optional) unit
+        // that overrides existing code to include per-node box sensitivity.
+
+        // Opera documentation claims that Opera 9 uses border-box in BackCompat mode.
+        // but experiments (Opera 9.10.8679 on Windows Vista) indicate that it actually continues to use content-box.
+        // IIRC, earlier versions of Opera did in fact use border-box.
+        // Opera guys, this is really confusing. Opera being broken in quirks mode is not our fault.
+
+                if(d.isIE /*|| dojo.isOpera*/){
+                // client code may have to adjust if compatMode varies across iframes
+                d.boxModel = document.compatMode == "BackCompat" ? "border-box" : "content-box";
+        }
+        
+        // =============================
+        // Style Functions
+        // =============================
+
+        // getComputedStyle drives most of the style code.
+        // Wherever possible, reuse the returned object.
+        //
+        // API functions below that need to access computed styles accept an
+        // optional computedStyle parameter.
+        // If this parameter is omitted, the functions will call getComputedStyle themselves.
+        // This way, calling code can access computedStyle once, and then pass the reference to
+        // multiple API functions.
+
+/*=====
+        dojo.getComputedStyle = function(node){
+                //      summary:
+                //              Returns a "computed style" object.
+                //
+                //      description:
+                //              Gets a "computed style" object which can be used to gather
+                //              information about the current state of the rendered node.
+                //
+                //              Note that this may behave differently on different browsers.
+                //              Values may have different formats and value encodings across
+                //              browsers.
+                //
+                //              Note also that this method is expensive.  Wherever possible,
+                //              reuse the returned object.
+                //
+                //              Use the dojo.style() method for more consistent (pixelized)
+                //              return values.
+                //
+                //      node: DOMNode
+                //              A reference to a DOM node. Does NOT support taking an
+                //              ID string for speed reasons.
+                //      example:
+                //      |       dojo.getComputedStyle(dojo.byId('foo')).borderWidth;
+                //
+                //      example:
+                //      Reusing the returned object, avoiding multiple lookups:
+                //      |       var cs = dojo.getComputedStyle(dojo.byId("someNode"));
+                //      |       var w = cs.width, h = cs.height;
+                return; // CSS2Properties
+        }
+=====*/
+
+        // Although we normally eschew argument validation at this
+        // level, here we test argument 'node' for (duck)type,
+        // by testing nodeType, ecause 'document' is the 'parentNode' of 'body'
+        // it is frequently sent to this function even
+        // though it is not Element.
+        var gcs;
+                if(d.isWebKit){
+                        gcs = function(/*DomNode*/node){
+                        var s;
+                        if(node.nodeType == 1){
+                                var dv = node.ownerDocument.defaultView;
+                                s = dv.getComputedStyle(node, null);
+                                if(!s && node.style){
+                                        node.style.display = "";
+                                        s = dv.getComputedStyle(node, null);
+                                }
+                        }
+                        return s || {};
+                };
+                }else if(d.isIE){
+                gcs = function(node){
+                        // IE (as of 7) doesn't expose Element like sane browsers
+                        return node.nodeType == 1 /* ELEMENT_NODE*/ ? node.currentStyle : {};
+                };
+        }else{
+                gcs = function(node){
+                        return node.nodeType == 1 ?
+                                node.ownerDocument.defaultView.getComputedStyle(node, null) : {};
+                };
+        }
+                dojo.getComputedStyle = gcs;
+
+                if(!d.isIE){
+                        d._toPixelValue = function(element, value){
+                        // style values can be floats, client code may want
+                        // to round for integer pixels.
+                        return parseFloat(value) || 0;
+                };
+                }else{
+                d._toPixelValue = function(element, avalue){
+                        if(!avalue){ return 0; }
+                        // on IE7, medium is usually 4 pixels
+                        if(avalue == "medium"){ return 4; }
+                        // style values can be floats, client code may
+                        // want to round this value for integer pixels.
+                        if(avalue.slice && avalue.slice(-2) == 'px'){ return parseFloat(avalue); }
+                        with(element){
+                                var sLeft = style.left;
+                                var rsLeft = runtimeStyle.left;
+                                runtimeStyle.left = currentStyle.left;
+                                try{
+                                        // 'avalue' may be incompatible with style.left, which can cause IE to throw
+                                        // this has been observed for border widths using "thin", "medium", "thick" constants
+                                        // those particular constants could be trapped by a lookup
+                                        // but perhaps there are more
+                                        style.left = avalue;
+                                        avalue = style.pixelLeft;
+                                }catch(e){
+                                        avalue = 0;
+                                }
+                                style.left = sLeft;
+                                runtimeStyle.left = rsLeft;
+                        }
+                        return avalue;
+                };
+        }
+                var px = d._toPixelValue;
+
+        // FIXME: there opacity quirks on FF that we haven't ported over. Hrm.
+        /*=====
+        dojo._getOpacity = function(node){
+                        //      summary:
+                        //              Returns the current opacity of the passed node as a
+                        //              floating-point value between 0 and 1.
+                        //      node: DomNode
+                        //              a reference to a DOM node. Does NOT support taking an
+                        //              ID string for speed reasons.
+                        //      returns: Number between 0 and 1
+                        return; // Number
+        }
+        =====*/
+
+                var astr = "DXImageTransform.Microsoft.Alpha";
+        var af = function(n, f){
+                try{
+                        return n.filters.item(astr);
+                }catch(e){
+                        return f ? {} : null;
+                }
+        };
+
+                dojo._getOpacity =
+                        d.isIE < 9 ? function(node){
+                        try{
+                                return af(node).Opacity / 100; // Number
+                        }catch(e){
+                                return 1; // Number
+                        }
+                } :
+                        function(node){
+                        return gcs(node).opacity;
+                };
+
+        /*=====
+        dojo._setOpacity = function(node, opacity){
+                        //      summary:
+                        //              set the opacity of the passed node portably. Returns the
+                        //              new opacity of the node.
+                        //      node: DOMNode
+                        //              a reference to a DOM node. Does NOT support taking an
+                        //              ID string for performance reasons.
+                        //      opacity: Number
+                        //              A Number between 0 and 1. 0 specifies transparent.
+                        //      returns: Number between 0 and 1
+                        return; // Number
+        }
+        =====*/
+
+        dojo._setOpacity =
+                                d.isIE < 9 ? function(/*DomNode*/node, /*Number*/opacity){
+                        var ov = opacity * 100, opaque = opacity == 1;
+                        node.style.zoom = opaque ? "" : 1;
+
+                        if(!af(node)){
+                                if(opaque){
+                                        return opacity;
+                                }
+                                node.style.filter += " progid:" + astr + "(Opacity=" + ov + ")";
+                        }else{
+                                af(node, 1).Opacity = ov;
+                        }
+
+                        // on IE7 Alpha(Filter opacity=100) makes text look fuzzy so disable it altogether (bug #2661),
+                        //but still update the opacity value so we can get a correct reading if it is read later.
+                        af(node, 1).Enabled = !opaque;
+
+                        if(node.nodeName.toLowerCase() == "tr"){
+                                d.query("> td", node).forEach(function(i){
+                                        d._setOpacity(i, opacity);
+                                });
+                        }
+                        return opacity;
+                } :
+                                function(node, opacity){
+                        return node.style.opacity = opacity;
+                };
+
+        var _pixelNamesCache = {
+                left: true, top: true
+        };
+        var _pixelRegExp = /margin|padding|width|height|max|min|offset/;  // |border
+        var _toStyleValue = function(node, type, value){
+                type = type.toLowerCase(); // FIXME: should we really be doing string case conversion here? Should we cache it? Need to profile!
+                                if(d.isIE){
+                        if(value == "auto"){
+                                if(type == "height"){ return node.offsetHeight; }
+                                if(type == "width"){ return node.offsetWidth; }
+                        }
+                        if(type == "fontweight"){
+                                switch(value){
+                                        case 700: return "bold";
+                                        case 400:
+                                        default: return "normal";
+                                }
+                        }
+                }
+                                if(!(type in _pixelNamesCache)){
+                        _pixelNamesCache[type] = _pixelRegExp.test(type);
+                }
+                return _pixelNamesCache[type] ? px(node, value) : value;
+        };
+
+        var _floatStyle = d.isIE ? "styleFloat" : "cssFloat",
+                _floatAliases = { "cssFloat": _floatStyle, "styleFloat": _floatStyle, "float": _floatStyle }
+        ;
+
+        // public API
+
+        dojo.style = function(  /*DomNode|String*/ node,
+                                                        /*String?|Object?*/ style,
+                                                        /*String?*/ value){
+                //      summary:
+                //              Accesses styles on a node. If 2 arguments are
+                //              passed, acts as a getter. If 3 arguments are passed, acts
+                //              as a setter.
+                //      description:
+                //              Getting the style value uses the computed style for the node, so the value
+                //              will be a calculated value, not just the immediate node.style value.
+                //              Also when getting values, use specific style names,
+                //              like "borderBottomWidth" instead of "border" since compound values like
+                //              "border" are not necessarily reflected as expected.
+                //              If you want to get node dimensions, use `dojo.marginBox()`,
+                //              `dojo.contentBox()` or `dojo.position()`.
+                //      node:
+                //              id or reference to node to get/set style for
+                //      style:
+                //              the style property to set in DOM-accessor format
+                //              ("borderWidth", not "border-width") or an object with key/value
+                //              pairs suitable for setting each property.
+                //      value:
+                //              If passed, sets value on the node for style, handling
+                //              cross-browser concerns.  When setting a pixel value,
+                //              be sure to include "px" in the value. For instance, top: "200px".
+                //              Otherwise, in some cases, some browsers will not apply the style.
+                //      example:
+                //              Passing only an ID or node returns the computed style object of
+                //              the node:
+                //      |       dojo.style("thinger");
+                //      example:
+                //              Passing a node and a style property returns the current
+                //              normalized, computed value for that property:
+                //      |       dojo.style("thinger", "opacity"); // 1 by default
+                //
+                //      example:
+                //              Passing a node, a style property, and a value changes the
+                //              current display of the node and returns the new computed value
+                //      |       dojo.style("thinger", "opacity", 0.5); // == 0.5
+                //
+                //      example:
+                //              Passing a node, an object-style style property sets each of the values in turn and returns the computed style object of the node:
+                //      |       dojo.style("thinger", {
+                //      |               "opacity": 0.5,
+                //      |               "border": "3px solid black",
+                //      |               "height": "300px"
+                //      |       });
+                //
+                //      example:
+                //              When the CSS style property is hyphenated, the JavaScript property is camelCased.
+                //              font-size becomes fontSize, and so on.
+                //      |       dojo.style("thinger",{
+                //      |               fontSize:"14pt",
+                //      |               letterSpacing:"1.2em"
+                //      |       });
+                //
+                //      example:
+                //              dojo.NodeList implements .style() using the same syntax, omitting the "node" parameter, calling
+                //              dojo.style() on every element of the list. See: `dojo.query()` and `dojo.NodeList()`
+                //      |       dojo.query(".someClassName").style("visibility","hidden");
+                //      |       // or
+                //      |       dojo.query("#baz > div").style({
+                //      |               opacity:0.75,
+                //      |               fontSize:"13pt"
+                //      |       });
+
+                var n = byId(node), args = arguments.length, op = (style == "opacity");
+                style = _floatAliases[style] || style;
+                if(args == 3){
+                        return op ? d._setOpacity(n, value) : n.style[style] = value; /*Number*/
+                }
+                if(args == 2 && op){
+                        return d._getOpacity(n);
+                }
+                var s = gcs(n);
+                if(args == 2 && typeof style != "string"){ // inline'd type check
+                        for(var x in style){
+                                d.style(node, x, style[x]);
+                        }
+                        return s;
+                }
+                return (args == 1) ? s : _toStyleValue(n, style, s[style] || n.style[style]); /* CSS2Properties||String||Number */
+        };
+
+        // =============================
+        // Box Functions
+        // =============================
+
+        dojo._getPadExtents = function(/*DomNode*/n, /*Object*/computedStyle){
+                //      summary:
+                //              Returns object with special values specifically useful for node
+                //              fitting.
+                //      description:
+                //              Returns an object with `w`, `h`, `l`, `t` properties:
+                //      |               l/t = left/top padding (respectively)
+                //      |               w = the total of the left and right padding
+                //      |               h = the total of the top and bottom padding
+                //              If 'node' has position, l/t forms the origin for child nodes.
+                //              The w/h are used for calculating boxes.
+                //              Normally application code will not need to invoke this
+                //              directly, and will use the ...box... functions instead.
+                var
+                        s = computedStyle||gcs(n),
+                        l = px(n, s.paddingLeft),
+                        t = px(n, s.paddingTop);
+                return {
+                        l: l,
+                        t: t,
+                        w: l+px(n, s.paddingRight),
+                        h: t+px(n, s.paddingBottom)
+                };
+        };
+
+        dojo._getBorderExtents = function(/*DomNode*/n, /*Object*/computedStyle){
+                //      summary:
+                //              returns an object with properties useful for noting the border
+                //              dimensions.
+                //      description:
+                //              * l/t = the sum of left/top border (respectively)
+                //              * w = the sum of the left and right border
+                //              * h = the sum of the top and bottom border
+                //
+                //              The w/h are used for calculating boxes.
+                //              Normally application code will not need to invoke this
+                //              directly, and will use the ...box... functions instead.
+                var
+                        ne = "none",
+                        s = computedStyle||gcs(n),
+                        bl = (s.borderLeftStyle != ne ? px(n, s.borderLeftWidth) : 0),
+                        bt = (s.borderTopStyle != ne ? px(n, s.borderTopWidth) : 0);
+                return {
+                        l: bl,
+                        t: bt,
+                        w: bl + (s.borderRightStyle!=ne ? px(n, s.borderRightWidth) : 0),
+                        h: bt + (s.borderBottomStyle!=ne ? px(n, s.borderBottomWidth) : 0)
+                };
+        };
+
+        dojo._getPadBorderExtents = function(/*DomNode*/n, /*Object*/computedStyle){
+                //      summary:
+                //              Returns object with properties useful for box fitting with
+                //              regards to padding.
+                // description:
+                //              * l/t = the sum of left/top padding and left/top border (respectively)
+                //              * w = the sum of the left and right padding and border
+                //              * h = the sum of the top and bottom padding and border
+                //
+                //              The w/h are used for calculating boxes.
+                //              Normally application code will not need to invoke this
+                //              directly, and will use the ...box... functions instead.
+                var
+                        s = computedStyle||gcs(n),
+                        p = d._getPadExtents(n, s),
+                        b = d._getBorderExtents(n, s);
+                return {
+                        l: p.l + b.l,
+                        t: p.t + b.t,
+                        w: p.w + b.w,
+                        h: p.h + b.h
+                };
+        };
+
+        dojo._getMarginExtents = function(n, computedStyle){
+                //      summary:
+                //              returns object with properties useful for box fitting with
+                //              regards to box margins (i.e., the outer-box).
+                //
+                //              * l/t = marginLeft, marginTop, respectively
+                //              * w = total width, margin inclusive
+                //              * h = total height, margin inclusive
+                //
+                //              The w/h are used for calculating boxes.
+                //              Normally application code will not need to invoke this
+                //              directly, and will use the ...box... functions instead.
+                var
+                        s = computedStyle||gcs(n),
+                        l = px(n, s.marginLeft),
+                        t = px(n, s.marginTop),
+                        r = px(n, s.marginRight),
+                        b = px(n, s.marginBottom);
+                if(d.isWebKit && (s.position != "absolute")){
+                        // FIXME: Safari's version of the computed right margin
+                        // is the space between our right edge and the right edge
+                        // of our offsetParent.
+                        // What we are looking for is the actual margin value as
+                        // determined by CSS.
+                        // Hack solution is to assume left/right margins are the same.
+                        r = l;
+                }
+                return {
+                        l: l,
+                        t: t,
+                        w: l+r,
+                        h: t+b
+                };
+        };
+
+        // Box getters work in any box context because offsetWidth/clientWidth
+        // are invariant wrt box context
+        //
+        // They do *not* work for display: inline objects that have padding styles
+        // because the user agent ignores padding (it's bogus styling in any case)
+        //
+        // Be careful with IMGs because they are inline or block depending on
+        // browser and browser mode.
+
+        // Although it would be easier to read, there are not separate versions of
+        // _getMarginBox for each browser because:
+        // 1. the branching is not expensive
+        // 2. factoring the shared code wastes cycles (function call overhead)
+        // 3. duplicating the shared code wastes bytes
+
+        dojo._getMarginBox = function(/*DomNode*/node, /*Object*/computedStyle){
+                // summary:
+                //              returns an object that encodes the width, height, left and top
+                //              positions of the node's margin box.
+                var s = computedStyle || gcs(node), me = d._getMarginExtents(node, s);
+                var l = node.offsetLeft - me.l, t = node.offsetTop - me.t, p = node.parentNode;
+                                if(d.isMoz){
+                        // Mozilla:
+                        // If offsetParent has a computed overflow != visible, the offsetLeft is decreased
+                        // by the parent's border.
+                        // We don't want to compute the parent's style, so instead we examine node's
+                        // computed left/top which is more stable.
+                        var sl = parseFloat(s.left), st = parseFloat(s.top);
+                        if(!isNaN(sl) && !isNaN(st)){
+                                l = sl, t = st;
+                        }else{
+                                // If child's computed left/top are not parseable as a number (e.g. "auto"), we
+                                // have no choice but to examine the parent's computed style.
+                                if(p && p.style){
+                                        var pcs = gcs(p);
+                                        if(pcs.overflow != "visible"){
+                                                var be = d._getBorderExtents(p, pcs);
+                                                l += be.l, t += be.t;
+                                        }
+                                }
+                        }
+                }else if(d.isOpera || (d.isIE > 7 && !d.isQuirks)){
+                        // On Opera and IE 8, offsetLeft/Top includes the parent's border
+                        if(p){
+                                be = d._getBorderExtents(p);
+                                l -= be.l;
+                                t -= be.t;
+                        }
+                }
+                                return {
+                        l: l,
+                        t: t,
+                        w: node.offsetWidth + me.w,
+                        h: node.offsetHeight + me.h
+                };
+        }
+        
+        dojo._getMarginSize = function(/*DomNode*/node, /*Object*/computedStyle){
+                // summary:
+                //      returns an object that encodes the width and height of
+                //      the node's margin box
+                node = byId(node);
+                var me = d._getMarginExtents(node, computedStyle || gcs(node));
+
+                var size = node.getBoundingClientRect();
+                return {
+                        w: (size.right - size.left) + me.w,
+                        h: (size.bottom - size.top) + me.h
+                }
+        }
+
+        dojo._getContentBox = function(node, computedStyle){
+                // summary:
+                //              Returns an object that encodes the width, height, left and top
+                //              positions of the node's content box, irrespective of the
+                //              current box model.
+
+                // clientWidth/Height are important since the automatically account for scrollbars
+                // fallback to offsetWidth/Height for special cases (see #3378)
+                var s = computedStyle || gcs(node),
+                        pe = d._getPadExtents(node, s),
+                        be = d._getBorderExtents(node, s),
+                        w = node.clientWidth,
+                        h
+                ;
+                if(!w){
+                        w = node.offsetWidth, h = node.offsetHeight;
+                }else{
+                        h = node.clientHeight, be.w = be.h = 0;
+                }
+                // On Opera, offsetLeft includes the parent's border
+                                if(d.isOpera){ pe.l += be.l; pe.t += be.t; };
+                                return {
+                        l: pe.l,
+                        t: pe.t,
+                        w: w - pe.w - be.w,
+                        h: h - pe.h - be.h
+                };
+        };
+
+        dojo._getBorderBox = function(node, computedStyle){
+                var s = computedStyle || gcs(node),
+                        pe = d._getPadExtents(node, s),
+                        cb = d._getContentBox(node, s)
+                ;
+                return {
+                        l: cb.l - pe.l,
+                        t: cb.t - pe.t,
+                        w: cb.w + pe.w,
+                        h: cb.h + pe.h
+                };
+        };
+
+        // Box setters depend on box context because interpretation of width/height styles
+        // vary wrt box context.
+        //
+        // The value of dojo.boxModel is used to determine box context.
+        // dojo.boxModel can be set directly to change behavior.
+        //
+        // Beware of display: inline objects that have padding styles
+        // because the user agent ignores padding (it's a bogus setup anyway)
+        //
+        // Be careful with IMGs because they are inline or block depending on
+        // browser and browser mode.
+        //
+        // Elements other than DIV may have special quirks, like built-in
+        // margins or padding, or values not detectable via computedStyle.
+        // In particular, margins on TABLE do not seems to appear
+        // at all in computedStyle on Mozilla.
+
+        dojo._setBox = function(/*DomNode*/node, /*Number?*/l, /*Number?*/t, /*Number?*/w, /*Number?*/h, /*String?*/u){
+                //      summary:
+                //              sets width/height/left/top in the current (native) box-model
+                //              dimentions. Uses the unit passed in u.
+                //      node:
+                //              DOM Node reference. Id string not supported for performance
+                //              reasons.
+                //      l:
+                //              left offset from parent.
+                //      t:
+                //              top offset from parent.
+                //      w:
+                //              width in current box model.
+                //      h:
+                //              width in current box model.
+                //      u:
+                //              unit measure to use for other measures. Defaults to "px".
+                u = u || "px";
+                var s = node.style;
+                if(!isNaN(l)){ s.left = l + u; }
+                if(!isNaN(t)){ s.top = t + u; }
+                if(w >= 0){ s.width = w + u; }
+                if(h >= 0){ s.height = h + u; }
+        };
+
+        dojo._isButtonTag = function(/*DomNode*/node) {
+                // summary:
+                //              True if the node is BUTTON or INPUT.type="button".
+                return node.tagName == "BUTTON"
+                        || node.tagName=="INPUT" && (node.getAttribute("type")||'').toUpperCase() == "BUTTON"; // boolean
+        };
+
+        dojo._usesBorderBox = function(/*DomNode*/node){
+                //      summary:
+                //              True if the node uses border-box layout.
+
+                // We could test the computed style of node to see if a particular box
+                // has been specified, but there are details and we choose not to bother.
+
+                // TABLE and BUTTON (and INPUT type=button) are always border-box by default.
+                // If you have assigned a different box to either one via CSS then
+                // box functions will break.
+
+                var n = node.tagName;
+                return d.boxModel=="border-box" || n=="TABLE" || d._isButtonTag(node); // boolean
+        };
+
+        dojo._setContentSize = function(/*DomNode*/node, /*Number*/widthPx, /*Number*/heightPx, /*Object*/computedStyle){
+                //      summary:
+                //              Sets the size of the node's contents, irrespective of margins,
+                //              padding, or borders.
+                if(d._usesBorderBox(node)){
+                        var pb = d._getPadBorderExtents(node, computedStyle);
+                        if(widthPx >= 0){ widthPx += pb.w; }
+                        if(heightPx >= 0){ heightPx += pb.h; }
+                }
+                d._setBox(node, NaN, NaN, widthPx, heightPx);
+        };
+
+        dojo._setMarginBox = function(/*DomNode*/node,  /*Number?*/leftPx, /*Number?*/topPx,
+                                                                                                        /*Number?*/widthPx, /*Number?*/heightPx,
+                                                                                                        /*Object*/computedStyle){
+                //      summary:
+                //              sets the size of the node's margin box and placement
+                //              (left/top), irrespective of box model. Think of it as a
+                //              passthrough to dojo._setBox that handles box-model vagaries for
+                //              you.
+
+                var s = computedStyle || gcs(node),
+                // Some elements have special padding, margin, and box-model settings.
+                // To use box functions you may need to set padding, margin explicitly.
+                // Controlling box-model is harder, in a pinch you might set dojo.boxModel.
+                        bb = d._usesBorderBox(node),
+                        pb = bb ? _nilExtents : d._getPadBorderExtents(node, s)
+                ;
+                if(d.isWebKit){
+                        // on Safari (3.1.2), button nodes with no explicit size have a default margin
+                        // setting an explicit size eliminates the margin.
+                        // We have to swizzle the width to get correct margin reading.
+                        if(d._isButtonTag(node)){
+                                var ns = node.style;
+                                if(widthPx >= 0 && !ns.width) { ns.width = "4px"; }
+                                if(heightPx >= 0 && !ns.height) { ns.height = "4px"; }
+                        }
+                }
+                var mb = d._getMarginExtents(node, s);
+                if(widthPx >= 0){ widthPx = Math.max(widthPx - pb.w - mb.w, 0); }
+                if(heightPx >= 0){ heightPx = Math.max(heightPx - pb.h - mb.h, 0); }
+                d._setBox(node, leftPx, topPx, widthPx, heightPx);
+        };
+
+        var _nilExtents = { l:0, t:0, w:0, h:0 };
+
+        // public API
+
+        dojo.marginBox = function(/*DomNode|String*/node, /*Object?*/box){
+                //      summary:
+                //              Getter/setter for the margin-box of node.
+                //      description:
+                //              Getter/setter for the margin-box of node.
+                //              Returns an object in the expected format of box (regardless
+                //              if box is passed). The object might look like:
+                //                      `{ l: 50, t: 200, w: 300: h: 150 }`
+                //              for a node offset from its parent 50px to the left, 200px from
+                //              the top with a margin width of 300px and a margin-height of
+                //              150px.
+                //      node:
+                //              id or reference to DOM Node to get/set box for
+                //      box:
+                //              If passed, denotes that dojo.marginBox() should
+                //              update/set the margin box for node. Box is an object in the
+                //              above format. All properties are optional if passed.
+                //      example:
+                //      Retrieve the marginbox of a passed node
+                //      |       var box = dojo.marginBox("someNodeId");
+                //      |       console.dir(box);
+                //
+                //      example:
+                //      Set a node's marginbox to the size of another node
+                //      |       var box = dojo.marginBox("someNodeId");
+                //      |       dojo.marginBox("someOtherNode", box);
+                
+                var n = byId(node), s = gcs(n), b = box;
+                return !b ? d._getMarginBox(n, s) : d._setMarginBox(n, b.l, b.t, b.w, b.h, s); // Object
+        };
+
+        dojo.contentBox = function(/*DomNode|String*/node, /*Object?*/box){
+                //      summary:
+                //              Getter/setter for the content-box of node.
+                //      description:
+                //              Returns an object in the expected format of box (regardless if box is passed).
+                //              The object might look like:
+                //                      `{ l: 50, t: 200, w: 300: h: 150 }`
+                //              for a node offset from its parent 50px to the left, 200px from
+                //              the top with a content width of 300px and a content-height of
+                //              150px. Note that the content box may have a much larger border
+                //              or margin box, depending on the box model currently in use and
+                //              CSS values set/inherited for node.
+                //              While the getter will return top and left values, the
+                //              setter only accepts setting the width and height.
+                //      node:
+                //              id or reference to DOM Node to get/set box for
+                //      box:
+                //              If passed, denotes that dojo.contentBox() should
+                //              update/set the content box for node. Box is an object in the
+                //              above format, but only w (width) and h (height) are supported.
+                //              All properties are optional if passed.
+                var n = byId(node), s = gcs(n), b = box;
+                return !b ? d._getContentBox(n, s) : d._setContentSize(n, b.w, b.h, s); // Object
+        };
+
+        // =============================
+        // Positioning
+        // =============================
+
+        var _sumAncestorProperties = function(node, prop){
+                if(!(node = (node||0).parentNode)){return 0;}
+                var val, retVal = 0, _b = d.body();
+                while(node && node.style){
+                        if(gcs(node).position == "fixed"){
+                                return 0;
+                        }
+                        val = node[prop];
+                        if(val){
+                                retVal += val - 0;
+                                // opera and khtml #body & #html has the same values, we only
+                                // need one value
+                                if(node == _b){ break; }
+                        }
+                        node = node.parentNode;
+                }
+                return retVal;  //      integer
+        };
+
+        dojo._docScroll = function(){
+                var n = d.global;
+                return "pageXOffset" in n
+                        ? { x:n.pageXOffset, y:n.pageYOffset }
+                        : (n = d.isQuirks? d.doc.body : d.doc.documentElement, { x:d._fixIeBiDiScrollLeft(n.scrollLeft || 0), y:n.scrollTop || 0 });
+        };
+
+        dojo._isBodyLtr = function(){
+                return "_bodyLtr" in d? d._bodyLtr :
+                        d._bodyLtr = (d.body().dir || d.doc.documentElement.dir || "ltr").toLowerCase() == "ltr"; // Boolean
+        };
+
+                dojo._getIeDocumentElementOffset = function(){
+                //      summary:
+                //              returns the offset in x and y from the document body to the
+                //              visual edge of the page
+                //      description:
+                // The following values in IE contain an offset:
+                //      |               event.clientX
+                //      |               event.clientY
+                //      |               node.getBoundingClientRect().left
+                //      |               node.getBoundingClientRect().top
+                //              But other position related values do not contain this offset,
+                //              such as node.offsetLeft, node.offsetTop, node.style.left and
+                //              node.style.top. The offset is always (2, 2) in LTR direction.
+                //              When the body is in RTL direction, the offset counts the width
+                //              of left scroll bar's width.  This function computes the actual
+                //              offset.
+
+                //NOTE: assumes we're being called in an IE browser
+
+                var de = d.doc.documentElement; // only deal with HTML element here, _abs handles body/quirks
+
+                if(d.isIE < 8){
+                        var r = de.getBoundingClientRect(); // works well for IE6+
+                        //console.debug('rect left,top = ' + r.left+','+r.top + ', html client left/top = ' + de.clientLeft+','+de.clientTop + ', rtl = ' + (!d._isBodyLtr()) + ', quirks = ' + d.isQuirks);
+                        var l = r.left,
+                            t = r.top;
+                        if(d.isIE < 7){
+                                l += de.clientLeft;     // scrollbar size in strict/RTL, or,
+                                t += de.clientTop;      // HTML border size in strict
+                        }
+                        return {
+                                x: l < 0? 0 : l, // FRAME element border size can lead to inaccurate negative values
+                                y: t < 0? 0 : t
+                        };
+                }else{
+                        return {
+                                x: 0,
+                                y: 0
+                        };
+                }
+
+        };
+        
+        dojo._fixIeBiDiScrollLeft = function(/*Integer*/ scrollLeft){
+                // In RTL direction, scrollLeft should be a negative value, but IE
+                // returns a positive one. All codes using documentElement.scrollLeft
+                // must call this function to fix this error, otherwise the position
+                // will offset to right when there is a horizontal scrollbar.
+
+                                var ie = d.isIE;
+                if(ie && !d._isBodyLtr()){
+                        var qk = d.isQuirks,
+                                de = qk ? d.doc.body : d.doc.documentElement;
+                        if(ie == 6 && !qk && d.global.frameElement && de.scrollHeight > de.clientHeight){
+                                scrollLeft += de.clientLeft; // workaround ie6+strict+rtl+iframe+vertical-scrollbar bug where clientWidth is too small by clientLeft pixels
+                        }
+                        return (ie < 8 || qk) ? (scrollLeft + de.clientWidth - de.scrollWidth) : -scrollLeft; // Integer
+                }
+                                return scrollLeft; // Integer
+        };
+
+        // FIXME: need a setter for coords or a moveTo!!
+        dojo._abs = dojo.position = function(/*DomNode*/node, /*Boolean?*/includeScroll){
+                //      summary:
+                //              Gets the position and size of the passed element relative to
+                //              the viewport (if includeScroll==false), or relative to the
+                //              document root (if includeScroll==true).
+                //
+                //      description:
+                //              Returns an object of the form:
+                //                      { x: 100, y: 300, w: 20, h: 15 }
+                //              If includeScroll==true, the x and y values will include any
+                //              document offsets that may affect the position relative to the
+                //              viewport.
+                //              Uses the border-box model (inclusive of border and padding but
+                //              not margin).  Does not act as a setter.
+
+                node = byId(node);
+                var     db = d.body(),
+                        dh = db.parentNode,
+                        ret = node.getBoundingClientRect();
+                        ret = { x: ret.left, y: ret.top, w: ret.right - ret.left, h: ret.bottom - ret.top };
+                                        if(d.isIE){
+                                // On IE there's a 2px offset that we need to adjust for, see _getIeDocumentElementOffset()
+                                var offset = d._getIeDocumentElementOffset();
+
+                                // fixes the position in IE, quirks mode
+                                ret.x -= offset.x + (d.isQuirks ? db.clientLeft+db.offsetLeft : 0);
+                                ret.y -= offset.y + (d.isQuirks ? db.clientTop+db.offsetTop : 0);
+                        }else if(d.isFF == 3){
+                                // In FF3 you have to subtract the document element margins.
+                                // Fixed in FF3.5 though.
+                                var cs = gcs(dh);
+                                ret.x -= px(dh, cs.marginLeft) + px(dh, cs.borderLeftWidth);
+                                ret.y -= px(dh, cs.marginTop) + px(dh, cs.borderTopWidth);
+                        }
+                                // account for document scrolling
+                if(includeScroll){
+                        var scroll = d._docScroll();
+                        ret.x += scroll.x;
+                        ret.y += scroll.y;
+                }
+
+                return ret; // Object
+        };
+
+        dojo.coords = function(/*DomNode|String*/node, /*Boolean?*/includeScroll){
+                //      summary:
+                //              Deprecated: Use position() for border-box x/y/w/h
+                //              or marginBox() for margin-box w/h/l/t.
+                //              Returns an object representing a node's size and position.
+                //
+                //      description:
+                //              Returns an object that measures margin-box (w)idth/(h)eight
+                //              and absolute position x/y of the border-box. Also returned
+                //              is computed (l)eft and (t)op values in pixels from the
+                //              node's offsetParent as returned from marginBox().
+                //              Return value will be in the form:
+                //|                     { l: 50, t: 200, w: 300: h: 150, x: 100, y: 300 }
+                //              Does not act as a setter. If includeScroll is passed, the x and
+                //              y params are affected as one would expect in dojo.position().
+                var n = byId(node), s = gcs(n), mb = d._getMarginBox(n, s);
+                var abs = d.position(n, includeScroll);
+                mb.x = abs.x;
+                mb.y = abs.y;
+                return mb;
+        };
+
+        // =============================
+        // Element attribute Functions
+        // =============================
+
+        // dojo.attr() should conform to http://www.w3.org/TR/DOM-Level-2-Core/
+
+        var _propNames = {
+                        // properties renamed to avoid clashes with reserved words
+                        "class":   "className",
+                        "for":     "htmlFor",
+                        // properties written as camelCase
+                        tabindex:  "tabIndex",
+                        readonly:  "readOnly",
+                        colspan:   "colSpan",
+                        frameborder: "frameBorder",
+                        rowspan:   "rowSpan",
+                        valuetype: "valueType"
+                },
+                _attrNames = {
+                        // original attribute names
+                        classname: "class",
+                        htmlfor:   "for",
+                        // for IE
+                        tabindex:  "tabIndex",
+                        readonly:  "readOnly"
+                },
+                _forcePropNames = {
+                        innerHTML: 1,
+                        className: 1,
+                        htmlFor:   d.isIE,
+                        value:     1
+                };
+
+        var _fixAttrName = function(/*String*/ name){
+                return _attrNames[name.toLowerCase()] || name;
+        };
+
+        var _hasAttr = function(node, name){
+                var attr = node.getAttributeNode && node.getAttributeNode(name);
+                return attr && attr.specified; // Boolean
+        };
+
+        // There is a difference in the presence of certain properties and their default values
+        // between browsers. For example, on IE "disabled" is present on all elements,
+        // but it is value is "false"; "tabIndex" of <div> returns 0 by default on IE, yet other browsers
+        // can return -1.
+
+        dojo.hasAttr = function(/*DomNode|String*/node, /*String*/name){
+                //      summary:
+                //              Returns true if the requested attribute is specified on the
+                //              given element, and false otherwise.
+                //      node:
+                //              id or reference to the element to check
+                //      name:
+                //              the name of the attribute
+                //      returns:
+                //              true if the requested attribute is specified on the
+                //              given element, and false otherwise
+                var lc = name.toLowerCase();
+                return _forcePropNames[_propNames[lc] || name] || _hasAttr(byId(node), _attrNames[lc] || name); // Boolean
+        };
+
+        var _evtHdlrMap = {}, _ctr = 0,
+                _attrId = dojo._scopeName + "attrid",
+                // the next dictionary lists elements with read-only innerHTML on IE
+                _roInnerHtml = {col: 1, colgroup: 1,
+                        // frameset: 1, head: 1, html: 1, style: 1,
+                        table: 1, tbody: 1, tfoot: 1, thead: 1, tr: 1, title: 1};
+
+        dojo.attr = function(/*DomNode|String*/node, /*String|Object*/name, /*String?*/value){
+                //      summary:
+                //              Gets or sets an attribute on an HTML element.
+                //      description:
+                //              Handles normalized getting and setting of attributes on DOM
+                //              Nodes. If 2 arguments are passed, and a the second argumnt is a
+                //              string, acts as a getter.
+                //
+                //              If a third argument is passed, or if the second argument is a
+                //              map of attributes, acts as a setter.
+                //
+                //              When passing functions as values, note that they will not be
+                //              directly assigned to slots on the node, but rather the default
+                //              behavior will be removed and the new behavior will be added
+                //              using `dojo.connect()`, meaning that event handler properties
+                //              will be normalized and that some caveats with regards to
+                //              non-standard behaviors for onsubmit apply. Namely that you
+                //              should cancel form submission using `dojo.stopEvent()` on the
+                //              passed event object instead of returning a boolean value from
+                //              the handler itself.
+                //      node:
+                //              id or reference to the element to get or set the attribute on
+                //      name:
+                //              the name of the attribute to get or set.
+                //      value:
+                //              The value to set for the attribute
+                //      returns:
+                //              when used as a getter, the value of the requested attribute
+                //              or null if that attribute does not have a specified or
+                //              default value;
+                //
+                //              when used as a setter, the DOM node
+                //
+                //      example:
+                //      |       // get the current value of the "foo" attribute on a node
+                //      |       dojo.attr(dojo.byId("nodeId"), "foo");
+                //      |       // or we can just pass the id:
+                //      |       dojo.attr("nodeId", "foo");
+                //
+                //      example:
+                //      |       // use attr() to set the tab index
+                //      |       dojo.attr("nodeId", "tabIndex", 3);
+                //      |
+                //
+                //      example:
+                //      Set multiple values at once, including event handlers:
+                //      |       dojo.attr("formId", {
+                //      |               "foo": "bar",
+                //      |               "tabIndex": -1,
+                //      |               "method": "POST",
+                //      |               "onsubmit": function(e){
+                //      |                       // stop submitting the form. Note that the IE behavior
+                //      |                       // of returning true or false will have no effect here
+                //      |                       // since our handler is connect()ed to the built-in
+                //      |                       // onsubmit behavior and so we need to use
+                //      |                       // dojo.stopEvent() to ensure that the submission
+                //      |                       // doesn't proceed.
+                //      |                       dojo.stopEvent(e);
+                //      |
+                //      |                       // submit the form with Ajax
+                //      |                       dojo.xhrPost({ form: "formId" });
+                //      |               }
+                //      |       });
+                //
+                //      example:
+                //      Style is s special case: Only set with an object hash of styles
+                //      |       dojo.attr("someNode",{
+                //      |               id:"bar",
+                //      |               style:{
+                //      |                       width:"200px", height:"100px", color:"#000"
+                //      |               }
+                //      |       });
+                //
+                //      example:
+                //      Again, only set style as an object hash of styles:
+                //      |       var obj = { color:"#fff", backgroundColor:"#000" };
+                //      |       dojo.attr("someNode", "style", obj);
+                //      |
+                //      |       // though shorter to use `dojo.style()` in this case:
+                //      |       dojo.style("someNode", obj);
+
+                node = byId(node);
+                var args = arguments.length, prop;
+                if(args == 2 && typeof name != "string"){ // inline'd type check
+                        // the object form of setter: the 2nd argument is a dictionary
+                        for(var x in name){
+                                d.attr(node, x, name[x]);
+                        }
+                        return node; // DomNode
+                }
+                var lc = name.toLowerCase(),
+                        propName = _propNames[lc] || name,
+                        forceProp = _forcePropNames[propName],
+                        attrName = _attrNames[lc] || name;
+                if(args == 3){
+                        // setter
+                        do{
+                                if(propName == "style" && typeof value != "string"){ // inline'd type check
+                                        // special case: setting a style
+                                        d.style(node, value);
+                                        break;
+                                }
+                                if(propName == "innerHTML"){
+                                        // special case: assigning HTML
+                                                                                if(d.isIE && node.tagName.toLowerCase() in _roInnerHtml){
+                                                d.empty(node);
+                                                node.appendChild(d._toDom(value, node.ownerDocument));
+                                        }else{
+                                                                                        node[propName] = value;
+                                                                                }
+                                                                                break;
+                                }
+                                if(d.isFunction(value)){
+                                        // special case: assigning an event handler
+                                        // clobber if we can
+                                        var attrId = d.attr(node, _attrId);
+                                        if(!attrId){
+                                                attrId = _ctr++;
+                                                d.attr(node, _attrId, attrId);
+                                        }
+                                        if(!_evtHdlrMap[attrId]){
+                                                _evtHdlrMap[attrId] = {};
+                                        }
+                                        var h = _evtHdlrMap[attrId][propName];
+                                        if(h){
+                                                d.disconnect(h);
+                                        }else{
+                                                try{
+                                                        delete node[propName];
+                                                }catch(e){}
+                                        }
+                                        // ensure that event objects are normalized, etc.
+                                        _evtHdlrMap[attrId][propName] = d.connect(node, propName, value);
+                                        break;
+                                }
+                                if(forceProp || typeof value == "boolean"){
+                                        // special case: forcing assignment to the property
+                                        // special case: setting boolean to a property instead of attribute
+                                        node[propName] = value;
+                                        break;
+                                }
+                                // node's attribute
+                                node.setAttribute(attrName, value);
+                        }while(false);
+                        return node; // DomNode
+                }
+                // getter
+                // should we access this attribute via a property or
+                // via getAttribute()?
+                value = node[propName];
+                if(forceProp && typeof value != "undefined"){
+                        // node's property
+                        return value;   // Anything
+                }
+                if(propName != "href" && (typeof value == "boolean" || d.isFunction(value))){
+                        // node's property
+                        return value;   // Anything
+                }
+                // node's attribute
+                // we need _hasAttr() here to guard against IE returning a default value
+                return _hasAttr(node, attrName) ? node.getAttribute(attrName) : null; // Anything
+        };
+
+        dojo.removeAttr = function(/*DomNode|String*/ node, /*String*/ name){
+                //      summary:
+                //              Removes an attribute from an HTML element.
+                //      node:
+                //              id or reference to the element to remove the attribute from
+                //      name:
+                //              the name of the attribute to remove
+                byId(node).removeAttribute(_fixAttrName(name));
+        };
+
+        dojo.getNodeProp = function(/*DomNode|String*/ node, /*String*/ name){
+                //      summary:
+                //              Returns an effective value of a property or an attribute.
+                //      node:
+                //              id or reference to the element to remove the attribute from
+                //      name:
+                //              the name of the attribute
+                node = byId(node);
+                var lc = name.toLowerCase(),
+                        propName = _propNames[lc] || name;
+                if((propName in node) && propName != "href"){
+                        // node's property
+                        return node[propName];  // Anything
+                }
+                // node's attribute
+                var attrName = _attrNames[lc] || name;
+                return _hasAttr(node, attrName) ? node.getAttribute(attrName) : null; // Anything
+        };
+
+        dojo.create = function(tag, attrs, refNode, pos){
+                //      summary:
+                //              Create an element, allowing for optional attribute decoration
+                //              and placement.
+                //
+                // description:
+                //              A DOM Element creation function. A shorthand method for creating a node or
+                //              a fragment, and allowing for a convenient optional attribute setting step,
+                //              as well as an optional DOM placement reference.
+                //|
+                //              Attributes are set by passing the optional object through `dojo.attr`.
+                //              See `dojo.attr` for noted caveats and nuances, and API if applicable.
+                //|
+                //              Placement is done via `dojo.place`, assuming the new node to be the action
+                //              node, passing along the optional reference node and position.
+                //
+                // tag: String|DomNode
+                //              A string of the element to create (eg: "div", "a", "p", "li", "script", "br"),
+                //              or an existing DOM node to process.
+                //
+                // attrs: Object
+                //              An object-hash of attributes to set on the newly created node.
+                //              Can be null, if you don't want to set any attributes/styles.
+                //              See: `dojo.attr` for a description of available attributes.
+                //
+                // refNode: String?|DomNode?
+                //              Optional reference node. Used by `dojo.place` to place the newly created
+                //              node somewhere in the dom relative to refNode. Can be a DomNode reference
+                //              or String ID of a node.
+                //
+                // pos: String?
+                //              Optional positional reference. Defaults to "last" by way of `dojo.place`,
+                //              though can be set to "first","after","before","last", "replace" or "only"
+                //              to further control the placement of the new node relative to the refNode.
+                //              'refNode' is required if a 'pos' is specified.
+                //
+                // returns: DomNode
+                //
+                // example:
+                //      Create a DIV:
+                //      |       var n = dojo.create("div");
+                //
+                // example:
+                //      Create a DIV with content:
+                //      |       var n = dojo.create("div", { innerHTML:"<p>hi</p>" });
+                //
+                // example:
+                //      Place a new DIV in the BODY, with no attributes set
+                //      |       var n = dojo.create("div", null, dojo.body());
+                //
+                // example:
+                //      Create an UL, and populate it with LI's. Place the list as the first-child of a
+                //      node with id="someId":
+                //      |       var ul = dojo.create("ul", null, "someId", "first");
+                //      |       var items = ["one", "two", "three", "four"];
+                //      |       dojo.forEach(items, function(data){
+                //      |               dojo.create("li", { innerHTML: data }, ul);
+                //      |       });
+                //
+                // example:
+                //      Create an anchor, with an href. Place in BODY:
+                //      |       dojo.create("a", { href:"foo.html", title:"Goto FOO!" }, dojo.body());
+                //
+                // example:
+                //      Create a `dojo.NodeList()` from a new element (for syntatic sugar):
+                //      |       dojo.query(dojo.create('div'))
+                //      |               .addClass("newDiv")
+                //      |               .onclick(function(e){ console.log('clicked', e.target) })
+                //      |               .place("#someNode"); // redundant, but cleaner.
+
+                var doc = d.doc;
+                if(refNode){
+                        refNode = byId(refNode);
+                        doc = refNode.ownerDocument;
+                }
+                if(typeof tag == "string"){ // inline'd type check
+                        tag = doc.createElement(tag);
+                }
+                if(attrs){ d.attr(tag, attrs); }
+                if(refNode){ d.place(tag, refNode, pos); }
+                return tag; // DomNode
+        };
+
+        /*=====
+        dojo.empty = function(node){
+                        //      summary:
+                        //              safely removes all children of the node.
+                        //      node: DOMNode|String
+                        //              a reference to a DOM node or an id.
+                        //      example:
+                        //      Destroy node's children byId:
+                        //      |       dojo.empty("someId");
+                        //
+                        //      example:
+                        //      Destroy all nodes' children in a list by reference:
+                        //      |       dojo.query(".someNode").forEach(dojo.empty);
+        }
+        =====*/
+
+        d.empty =
+                                d.isIE ?  function(node){
+                        node = byId(node);
+                        for(var c; c = node.lastChild;){ // intentional assignment
+                                d.destroy(c);
+                        }
+                } :
+                                function(node){
+                        byId(node).innerHTML = "";
+                };
+
+        /*=====
+        dojo._toDom = function(frag, doc){
+                        //      summary:
+                        //              instantiates an HTML fragment returning the corresponding DOM.
+                        //      frag: String
+                        //              the HTML fragment
+                        //      doc: DocumentNode?
+                        //              optional document to use when creating DOM nodes, defaults to
+                        //              dojo.doc if not specified.
+                        //      returns: DocumentFragment
+                        //
+                        //      example:
+                        //      Create a table row:
+                        //      |       var tr = dojo._toDom("<tr><td>First!</td></tr>");
+        }
+        =====*/
+
+        // support stuff for dojo._toDom
+        var tagWrap = {
+                        option: ["select"],
+                        tbody: ["table"],
+                        thead: ["table"],
+                        tfoot: ["table"],
+                        tr: ["table", "tbody"],
+                        td: ["table", "tbody", "tr"],
+                        th: ["table", "thead", "tr"],
+                        legend: ["fieldset"],
+                        caption: ["table"],
+                        colgroup: ["table"],
+                        col: ["table", "colgroup"],
+                        li: ["ul"]
+                },
+                reTag = /<\s*([\w\:]+)/,
+                masterNode = {}, masterNum = 0,
+                masterName = "__" + d._scopeName + "ToDomId";
+
+        // generate start/end tag strings to use
+        // for the injection for each special tag wrap case.
+        for(var param in tagWrap){
+                if(tagWrap.hasOwnProperty(param)){
+                        var tw = tagWrap[param];
+                        tw.pre  = param == "option" ? '<select multiple="multiple">' : "<" + tw.join("><") + ">";
+                        tw.post = "</" + tw.reverse().join("></") + ">";
+                        // the last line is destructive: it reverses the array,
+                        // but we don't care at this point
+                }
+        }
+
+        d._toDom = function(frag, doc){
+                //      summary:
+                //              converts HTML string into DOM nodes.
+
+                doc = doc || d.doc;
+                var masterId = doc[masterName];
+                if(!masterId){
+                        doc[masterName] = masterId = ++masterNum + "";
+                        masterNode[masterId] = doc.createElement("div");
+                }
+
+                // make sure the frag is a string.
+                frag += "";
+
+                // find the starting tag, and get node wrapper
+                var match = frag.match(reTag),
+                        tag = match ? match[1].toLowerCase() : "",
+                        master = masterNode[masterId],
+                        wrap, i, fc, df;
+                if(match && tagWrap[tag]){
+                        wrap = tagWrap[tag];
+                        master.innerHTML = wrap.pre + frag + wrap.post;
+                        for(i = wrap.length; i; --i){
+                                master = master.firstChild;
+                        }
+                }else{
+                        master.innerHTML = frag;
+                }
+
+                // one node shortcut => return the node itself
+                if(master.childNodes.length == 1){
+                        return master.removeChild(master.firstChild); // DOMNode
+                }
+
+                // return multiple nodes as a document fragment
+                df = doc.createDocumentFragment();
+                while(fc = master.firstChild){ // intentional assignment
+                        df.appendChild(fc);
+                }
+                return df; // DOMNode
+        };
+
+        // =============================
+        // (CSS) Class Functions
+        // =============================
+        var _className = "className";
+
+        dojo.hasClass = function(/*DomNode|String*/node, /*String*/classStr){
+                //      summary:
+                //              Returns whether or not the specified classes are a portion of the
+                //              class list currently applied to the node.
+                //
+                //      node:
+                //              String ID or DomNode reference to check the class for.
+                //
+                //      classStr:
+                //              A string class name to look for.
+                //
+                //      example:
+                //      Do something if a node with id="someNode" has class="aSillyClassName" present
+                //      |       if(dojo.hasClass("someNode","aSillyClassName")){ ... }
+
+                return ((" "+ byId(node)[_className] +" ").indexOf(" " + classStr + " ") >= 0);  // Boolean
+        };
+
+        var spaces = /\s+/, a1 = [""],
+                fakeNode = {},
+                str2array = function(s){
+                        if(typeof s == "string" || s instanceof String){
+                                if(s.indexOf(" ") < 0){
+                                        a1[0] = s;
+                                        return a1;
+                                }else{
+                                        return s.split(spaces);
+                                }
+                        }
+                        // assumed to be an array
+                        return s || "";
+                };
+
+        dojo.addClass = function(/*DomNode|String*/node, /*String|Array*/classStr){
+                //      summary:
+                //              Adds the specified classes to the end of the class list on the
+                //              passed node. Will not re-apply duplicate classes.
+                //
+                //      node:
+                //              String ID or DomNode reference to add a class string too
+                //
+                //      classStr:
+                //              A String class name to add, or several space-separated class names,
+                //              or an array of class names.
+                //
+                // example:
+                //      Add a class to some node:
+                //      |       dojo.addClass("someNode", "anewClass");
+                //
+                // example:
+                //      Add two classes at once:
+                //      |       dojo.addClass("someNode", "firstClass secondClass");
+                //
+                // example:
+                //      Add two classes at once (using array):
+                //      |       dojo.addClass("someNode", ["firstClass", "secondClass"]);
+                //
+                // example:
+                //      Available in `dojo.NodeList` for multiple additions
+                //      |       dojo.query("ul > li").addClass("firstLevel");
+
+                node = byId(node);
+                classStr = str2array(classStr);
+                var cls = node[_className], oldLen;
+                cls = cls ? " " + cls + " " : " ";
+                oldLen = cls.length;
+                for(var i = 0, len = classStr.length, c; i < len; ++i){
+                        c = classStr[i];
+                        if(c && cls.indexOf(" " + c + " ") < 0){
+                                cls += c + " ";
+                        }
+                }
+                if(oldLen < cls.length){
+                        node[_className] = cls.substr(1, cls.length - 2);
+                }
+        };
+
+        dojo.removeClass = function(/*DomNode|String*/node, /*String|Array?*/classStr){
+                // summary:
+                //              Removes the specified classes from node. No `dojo.hasClass`
+                //              check is required.
+                //
+                // node:
+                //              String ID or DomNode reference to remove the class from.
+                //
+                // classStr:
+                //              An optional String class name to remove, or several space-separated
+                //              class names, or an array of class names. If omitted, all class names
+                //              will be deleted.
+                //
+                // example:
+                //      Remove a class from some node:
+                //      |       dojo.removeClass("someNode", "firstClass");
+                //
+                // example:
+                //      Remove two classes from some node:
+                //      |       dojo.removeClass("someNode", "firstClass secondClass");
+                //
+                // example:
+                //      Remove two classes from some node (using array):
+                //      |       dojo.removeClass("someNode", ["firstClass", "secondClass"]);
+                //
+                // example:
+                //      Remove all classes from some node:
+                //      |       dojo.removeClass("someNode");
+                //
+                // example:
+                //      Available in `dojo.NodeList()` for multiple removal
+                //      |       dojo.query(".foo").removeClass("foo");
+
+                node = byId(node);
+                var cls;
+                if(classStr !== undefined){
+                        classStr = str2array(classStr);
+                        cls = " " + node[_className] + " ";
+                        for(var i = 0, len = classStr.length; i < len; ++i){
+                                cls = cls.replace(" " + classStr[i] + " ", " ");
+                        }
+                        cls = d.trim(cls);
+                }else{
+                        cls = "";
+                }
+                if(node[_className] != cls){ node[_className] = cls; }
+        };
+
+        dojo.replaceClass = function(/*DomNode|String*/node, /*String|Array*/addClassStr, /*String|Array?*/removeClassStr){
+                // summary:
+                //              Replaces one or more classes on a node if not present.
+                //              Operates more quickly than calling dojo.removeClass and dojo.addClass
+                // node:
+                //              String ID or DomNode reference to remove the class from.
+                // addClassStr:
+                //              A String class name to add, or several space-separated class names,
+                //              or an array of class names.
+                // removeClassStr:
+                //              A String class name to remove, or several space-separated class names,
+                //              or an array of class names.
+                //
+                // example:
+                //      |       dojo.replaceClass("someNode", "add1 add2", "remove1 remove2");
+                //
+                // example:
+                //      Replace all classes with addMe
+                //      |       dojo.replaceClass("someNode", "addMe");
+                //
+                // example:
+                //      Available in `dojo.NodeList()` for multiple toggles
+                //      |       dojo.query(".findMe").replaceClass("addMe", "removeMe");
+
+        node = byId(node);
+                fakeNode.className = node.className;
+                dojo.removeClass(fakeNode, removeClassStr);
+                dojo.addClass(fakeNode, addClassStr);
+                if(node.className !== fakeNode.className){
+                        node.className = fakeNode.className;
+                }
+        };
+
+        dojo.toggleClass = function(/*DomNode|String*/node, /*String|Array*/classStr, /*Boolean?*/condition){
+                //      summary:
+                //              Adds a class to node if not present, or removes if present.
+                //              Pass a boolean condition if you want to explicitly add or remove.
+                //      condition:
+                //              If passed, true means to add the class, false means to remove.
+                //
+                // example:
+                //      |       dojo.toggleClass("someNode", "hovered");
+                //
+                // example:
+                //      Forcefully add a class
+                //      |       dojo.toggleClass("someNode", "hovered", true);
+                //
+                // example:
+                //      Available in `dojo.NodeList()` for multiple toggles
+                //      |       dojo.query(".toggleMe").toggleClass("toggleMe");
+
+                if(condition === undefined){
+                        condition = !d.hasClass(node, classStr);
+                }
+                d[condition ? "addClass" : "removeClass"](node, classStr);
+        };
+
+})();
+
+}
+
+if(!dojo._hasResource["dojo._base.NodeList"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dojo._base.NodeList"] = true;
+dojo.provide("dojo._base.NodeList");
+
+
+
+
+
+
+(function(){
+
+        var d = dojo;
+
+        var ap = Array.prototype, aps = ap.slice, apc = ap.concat;
+
+        var tnl = function(/*Array*/ a, /*dojo.NodeList?*/ parent, /*Function?*/ NodeListCtor){
+                // summary:
+                //              decorate an array to make it look like a `dojo.NodeList`.
+                // a:
+                //              Array of nodes to decorate.
+                // parent:
+                //              An optional parent NodeList that generated the current
+                //              list of nodes. Used to call _stash() so the parent NodeList
+                //              can be accessed via end() later.
+                // NodeListCtor:
+                //              An optional constructor function to use for any
+                //              new NodeList calls. This allows a certain chain of
+                //              NodeList calls to use a different object than dojo.NodeList.
+                if(!a.sort){
+                        // make sure it's a real array before we pass it on to be wrapped
+                        a = aps.call(a, 0);
+                }
+                var ctor = NodeListCtor || this._NodeListCtor || d._NodeListCtor;
+                a.constructor = ctor;
+                dojo._mixin(a, ctor.prototype);
+                a._NodeListCtor = ctor;
+                return parent ? a._stash(parent) : a;
+        };
+
+        var loopBody = function(f, a, o){
+                a = [0].concat(aps.call(a, 0));
+                o = o || d.global;
+                return function(node){
+                        a[0] = node;
+                        return f.apply(o, a);
+                };
+        };
+
+        // adapters
+
+        var adaptAsForEach = function(f, o){
+                //      summary:
+                //              adapts a single node function to be used in the forEach-type
+                //              actions. The initial object is returned from the specialized
+                //              function.
+                //      f: Function
+                //              a function to adapt
+                //      o: Object?
+                //              an optional context for f
+                return function(){
+                        this.forEach(loopBody(f, arguments, o));
+                        return this;    // Object
+                };
+        };
+
+        var adaptAsMap = function(f, o){
+                //      summary:
+                //              adapts a single node function to be used in the map-type
+                //              actions. The return is a new array of values, as via `dojo.map`
+                //      f: Function
+                //              a function to adapt
+                //      o: Object?
+                //              an optional context for f
+                return function(){
+                        return this.map(loopBody(f, arguments, o));
+                };
+        };
+
+        var adaptAsFilter = function(f, o){
+                //      summary:
+                //              adapts a single node function to be used in the filter-type actions
+                //      f: Function
+                //              a function to adapt
+                //      o: Object?
+                //              an optional context for f
+                return function(){
+                        return this.filter(loopBody(f, arguments, o));
+                };
+        };
+
+        var adaptWithCondition = function(f, g, o){
+                //      summary:
+                //              adapts a single node function to be used in the map-type
+                //              actions, behaves like forEach() or map() depending on arguments
+                //      f: Function
+                //              a function to adapt
+                //      g: Function
+                //              a condition function, if true runs as map(), otherwise runs as forEach()
+                //      o: Object?
+                //              an optional context for f and g
+                return function(){
+                        var a = arguments, body = loopBody(f, a, o);
+                        if(g.call(o || d.global, a)){
+                                return this.map(body);  // self
+                        }
+                        this.forEach(body);
+                        return this;    // self
+                };
+        };
+
+        var magicGuard = function(a){
+                //      summary:
+                //              the guard function for dojo.attr() and dojo.style()
+                return a.length == 1 && (typeof a[0] == "string"); // inline'd type check
+        };
+
+        var orphan = function(node){
+                //      summary:
+                //              function to orphan nodes
+                var p = node.parentNode;
+                if(p){
+                        p.removeChild(node);
+                }
+        };
+        // FIXME: should we move orphan() to dojo.html?
+
+        dojo.NodeList = function(){
+                //      summary:
+                //              dojo.NodeList is an of Array subclass which adds syntactic
+                //              sugar for chaining, common iteration operations, animation, and
+                //              node manipulation. NodeLists are most often returned as the
+                //              result of dojo.query() calls.
+                //      description:
+                //              dojo.NodeList instances provide many utilities that reflect
+                //              core Dojo APIs for Array iteration and manipulation, DOM
+                //              manipulation, and event handling. Instead of needing to dig up
+                //              functions in the dojo.* namespace, NodeLists generally make the
+                //              full power of Dojo available for DOM manipulation tasks in a
+                //              simple, chainable way.
+                //      example:
+                //              create a node list from a node
+                //              |       new dojo.NodeList(dojo.byId("foo"));
+                //      example:
+                //              get a NodeList from a CSS query and iterate on it
+                //              |       var l = dojo.query(".thinger");
+                //              |       l.forEach(function(node, index, nodeList){
+                //              |               console.log(index, node.innerHTML);
+                //              |       });
+                //      example:
+                //              use native and Dojo-provided array methods to manipulate a
+                //              NodeList without needing to use dojo.* functions explicitly:
+                //              |       var l = dojo.query(".thinger");
+                //              |       // since NodeLists are real arrays, they have a length
+                //              |       // property that is both readable and writable and
+                //              |       // push/pop/shift/unshift methods
+                //              |       console.log(l.length);
+                //              |       l.push(dojo.create("span"));
+                //              |
+                //              |       // dojo's normalized array methods work too:
+                //              |       console.log( l.indexOf(dojo.byId("foo")) );
+                //              |       // ...including the special "function as string" shorthand
+                //              |       console.log( l.every("item.nodeType == 1") );
+                //              |
+                //              |       // NodeLists can be [..] indexed, or you can use the at()
+                //              |       // function to get specific items wrapped in a new NodeList:
+                //              |       var node = l[3]; // the 4th element
+                //              |       var newList = l.at(1, 3); // the 2nd and 4th elements
+                //      example:
+                //              the style functions you expect are all there too:
+                //              |       // style() as a getter...
+                //              |       var borders = dojo.query(".thinger").style("border");
+                //              |       // ...and as a setter:
+                //              |       dojo.query(".thinger").style("border", "1px solid black");
+                //              |       // class manipulation
+                //              |       dojo.query("li:nth-child(even)").addClass("even");
+                //              |       // even getting the coordinates of all the items
+                //              |       var coords = dojo.query(".thinger").coords();
+                //      example:
+                //              DOM manipulation functions from the dojo.* namespace area also
+                //              available:
+                //              |       // remove all of the elements in the list from their
+                //              |       // parents (akin to "deleting" them from the document)
+                //              |       dojo.query(".thinger").orphan();
+                //              |       // place all elements in the list at the front of #foo
+                //              |       dojo.query(".thinger").place("foo", "first");
+                //      example:
+                //              Event handling couldn't be easier. `dojo.connect` is mapped in,
+                //              and shortcut handlers are provided for most DOM events:
+                //              |       // like dojo.connect(), but with implicit scope
+                //              |       dojo.query("li").connect("onclick", console, "log");
+                //              |
+                //              |       // many common event handlers are already available directly:
+                //              |       dojo.query("li").onclick(console, "log");
+                //              |       var toggleHovered = dojo.hitch(dojo, "toggleClass", "hovered");
+                //              |       dojo.query("p")
+                //              |               .onmouseenter(toggleHovered)
+                //              |               .onmouseleave(toggleHovered);
+                //      example:
+                //              chainability is a key advantage of NodeLists:
+                //              |       dojo.query(".thinger")
+                //              |               .onclick(function(e){ /* ... */ })
+                //              |               .at(1, 3, 8) // get a subset
+                //              |                       .style("padding", "5px")
+                //              |                       .forEach(console.log);
+
+                return tnl(Array.apply(null, arguments));
+        };
+
+        //Allow things that new up a NodeList to use a delegated or alternate NodeList implementation.
+        d._NodeListCtor = d.NodeList;
+
+        var nl = d.NodeList, nlp = nl.prototype;
+
+        // expose adapters and the wrapper as private functions
+
+        nl._wrap = nlp._wrap = tnl;
+        nl._adaptAsMap = adaptAsMap;
+        nl._adaptAsForEach = adaptAsForEach;
+        nl._adaptAsFilter  = adaptAsFilter;
+        nl._adaptWithCondition = adaptWithCondition;
+
+        // mass assignment
+
+        // add array redirectors
+        d.forEach(["slice", "splice"], function(name){
+                var f = ap[name];
+                //Use a copy of the this array via this.slice() to allow .end() to work right in the splice case.
+                // CANNOT apply ._stash()/end() to splice since it currently modifies
+                // the existing this array -- it would break backward compatibility if we copy the array before
+                // the splice so that we can use .end(). So only doing the stash option to this._wrap for slice.
+                nlp[name] = function(){ return this._wrap(f.apply(this, arguments), name == "slice" ? this : null); };
+        });
+        // concat should be here but some browsers with native NodeList have problems with it
+
+        // add array.js redirectors
+        d.forEach(["indexOf", "lastIndexOf", "every", "some"], function(name){
+                var f = d[name];
+                nlp[name] = function(){ return f.apply(d, [this].concat(aps.call(arguments, 0))); };
+        });
+
+        // add conditional methods
+        d.forEach(["attr", "style"], function(name){
+                nlp[name] = adaptWithCondition(d[name], magicGuard);
+        });
+
+        // add forEach actions
+        d.forEach(["connect", "addClass", "removeClass", "replaceClass", "toggleClass", "empty", "removeAttr"], function(name){
+                nlp[name] = adaptAsForEach(d[name]);
+        });
+
+        dojo.extend(dojo.NodeList, {
+                _normalize: function(/*String||Element||Object||NodeList*/content, /*DOMNode?*/refNode){
+                        // summary:
+                        //              normalizes data to an array of items to insert.
+                        // description:
+                        //              If content is an object, it can have special properties "template" and
+                        //              "parse". If "template" is defined, then the template value is run through
+                        //              dojo.string.substitute (if dojo.string.substitute has been dojo.required elsewhere),
+                        //              or if templateFunc is a function on the content, that function will be used to
+                        //              transform the template into a final string to be used for for passing to dojo._toDom.
+                        //              If content.parse is true, then it is remembered for later, for when the content
+                        //              nodes are inserted into the DOM. At that point, the nodes will be parsed for widgets
+                        //              (if dojo.parser has been dojo.required elsewhere).
+
+                        //Wanted to just use a DocumentFragment, but for the array/NodeList
+                        //case that meant  using cloneNode, but we may not want that.
+                        //Cloning should only happen if the node operations span
+                        //multiple refNodes. Also, need a real array, not a NodeList from the
+                        //DOM since the node movements could change those NodeLists.
+
+                        var parse = content.parse === true ? true : false;
+
+                        //Do we have an object that needs to be run through a template?
+                        if(typeof content.template == "string"){
+                                var templateFunc = content.templateFunc || (dojo.string && dojo.string.substitute);
+                                content = templateFunc ? templateFunc(content.template, content) : content;
+                        }
+
+                        var type = (typeof content);
+                        if(type == "string" || type == "number"){
+                                content = dojo._toDom(content, (refNode && refNode.ownerDocument));
+                                if(content.nodeType == 11){
+                                        //DocumentFragment. It cannot handle cloneNode calls, so pull out the children.
+                                        content = dojo._toArray(content.childNodes);
+                                }else{
+                                        content = [content];
+                                }
+                        }else if(!dojo.isArrayLike(content)){
+                                content = [content];
+                        }else if(!dojo.isArray(content)){
+                                //To get to this point, content is array-like, but
+                                //not an array, which likely means a DOM NodeList. Convert it now.
+                                content = dojo._toArray(content);
+                        }
+
+                        //Pass around the parse info
+                        if(parse){
+                                content._runParse = true;
+                        }
+                        return content; //Array
+                },
+
+                _cloneNode: function(/*DOMNode*/ node){
+                        // summary:
+                        //              private utility to clone a node. Not very interesting in the vanilla
+                        //              dojo.NodeList case, but delegates could do interesting things like
+                        //              clone event handlers if that is derivable from the node.
+                        return node.cloneNode(true);
+                },
+
+                _place: function(/*Array*/ary, /*DOMNode*/refNode, /*String*/position, /*Boolean*/useClone){
+                        // summary:
+                        //              private utility to handle placing an array of nodes relative to another node.
+                        // description:
+                        //              Allows for cloning the nodes in the array, and for
+                        //              optionally parsing widgets, if ary._runParse is true.
+
+                        //Avoid a disallowed operation if trying to do an innerHTML on a non-element node.
+                        if(refNode.nodeType != 1 && position == "only"){
+                                return;
+                        }
+                        var rNode = refNode, tempNode;
+
+                        //Always cycle backwards in case the array is really a
+                        //DOM NodeList and the DOM operations take it out of the live collection.
+                        var length = ary.length;
+                        for(var i = length - 1; i >= 0; i--){
+                                var node = (useClone ? this._cloneNode(ary[i]) : ary[i]);
+
+                                //If need widget parsing, use a temp node, instead of waiting after inserting into
+                                //real DOM because we need to start widget parsing at one node up from current node,
+                                //which could cause some already parsed widgets to be parsed again.
+                                if(ary._runParse && dojo.parser && dojo.parser.parse){
+                                        if(!tempNode){
+                                                tempNode = rNode.ownerDocument.createElement("div");
+                                        }
+                                        tempNode.appendChild(node);
+                                        dojo.parser.parse(tempNode);
+                                        node = tempNode.firstChild;
+                                        while(tempNode.firstChild){
+                                                tempNode.removeChild(tempNode.firstChild);
+                                        }
+                                }
+
+                                if(i == length - 1){
+                                        dojo.place(node, rNode, position);
+                                }else{
+                                        rNode.parentNode.insertBefore(node, rNode);
+                                }
+                                rNode = node;
+                        }
+                },
+
+                _stash: function(parent){
+                        // summary:
+                        //              private function to hold to a parent NodeList. end() to return the parent NodeList.
+                        //
+                        // example:
+                        // How to make a `dojo.NodeList` method that only returns the third node in
+                        // the dojo.NodeList but allows access to the original NodeList by using this._stash:
+                        //      |       dojo.extend(dojo.NodeList, {
+                        //      |               third: function(){
+                        //  |                   var newNodeList = dojo.NodeList(this[2]);
+                        //      |                       return newNodeList._stash(this);
+                        //      |               }
+                        //      |       });
+                        //      |       // then see how _stash applies a sub-list, to be .end()'ed out of
+                        //      |       dojo.query(".foo")
+                        //      |               .third()
+                        //      |                       .addClass("thirdFoo")
+                        //      |               .end()
+                        //      |               // access to the orig .foo list
+                        //      |               .removeClass("foo")
+                        //      |
+                        //
+                        this._parent = parent;
+                        return this; //dojo.NodeList
+                },
+
+                end: function(){
+                        // summary:
+                        //              Ends use of the current `dojo.NodeList` by returning the previous dojo.NodeList
+                        //              that generated the current dojo.NodeList.
+                        // description:
+                        //              Returns the `dojo.NodeList` that generated the current `dojo.NodeList`. If there
+                        //              is no parent dojo.NodeList, an empty dojo.NodeList is returned.
+                        // example:
+                        //      |       dojo.query("a")
+                        //      |               .filter(".disabled")
+                        //      |                       // operate on the anchors that only have a disabled class
+                        //      |                       .style("color", "grey")
+                        //      |               .end()
+                        //      |               // jump back to the list of anchors
+                        //      |               .style(...)
+                        //
+                        if(this._parent){
+                                return this._parent;
+                        }else{
+                                //Just return empty list.
+                                return new this._NodeListCtor();
+                        }
+                },
+
+                // http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Reference:Global_Objects:Array#Methods
+
+                // FIXME: handle return values for #3244
+                //              http://trac.dojotoolkit.org/ticket/3244
+
+                // FIXME:
+                //              need to wrap or implement:
+                //                      join (perhaps w/ innerHTML/outerHTML overload for toString() of items?)
+                //                      reduce
+                //                      reduceRight
+
+                /*=====
+                slice: function(begin, end){
+                        // summary:
+                        //              Returns a new NodeList, maintaining this one in place
+                        // description:
+                        //              This method behaves exactly like the Array.slice method
+                        //              with the caveat that it returns a dojo.NodeList and not a
+                        //              raw Array. For more details, see Mozilla's (slice
+                        //              documentation)[http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Reference:Global_Objects:Array:slice]
+                        // begin: Integer
+                        //              Can be a positive or negative integer, with positive
+                        //              integers noting the offset to begin at, and negative
+                        //              integers denoting an offset from the end (i.e., to the left
+                        //              of the end)
+                        // end: Integer?
+                        //              Optional parameter to describe what position relative to
+                        //              the NodeList's zero index to end the slice at. Like begin,
+                        //              can be positive or negative.
+                        return this._wrap(a.slice.apply(this, arguments));
+                },
+
+                splice: function(index, howmany, item){
+                        // summary:
+                        //              Returns a new NodeList, manipulating this NodeList based on
+                        //              the arguments passed, potentially splicing in new elements
+                        //              at an offset, optionally deleting elements
+                        // description:
+                        //              This method behaves exactly like the Array.splice method
+                        //              with the caveat that it returns a dojo.NodeList and not a
+                        //              raw Array. For more details, see Mozilla's (splice
+                        //              documentation)[http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Reference:Global_Objects:Array:splice]
+                        //              For backwards compatibility, calling .end() on the spliced NodeList
+                        //              does not return the original NodeList -- splice alters the NodeList in place.
+                        // index: Integer
+                        //              begin can be a positive or negative integer, with positive
+                        //              integers noting the offset to begin at, and negative
+                        //              integers denoting an offset from the end (i.e., to the left
+                        //              of the end)
+                        // howmany: Integer?
+                        //              Optional parameter to describe what position relative to
+                        //              the NodeList's zero index to end the slice at. Like begin,
+                        //              can be positive or negative.
+                        // item: Object...?
+                        //              Any number of optional parameters may be passed in to be
+                        //              spliced into the NodeList
+                        // returns:
+                        //              dojo.NodeList
+                        return this._wrap(a.splice.apply(this, arguments));
+                },
+
+                indexOf: function(value, fromIndex){
+                        //      summary:
+                        //              see dojo.indexOf(). The primary difference is that the acted-on
+                        //              array is implicitly this NodeList
+                        // value: Object:
+                        //              The value to search for.
+                        // fromIndex: Integer?:
+                        //              The location to start searching from. Optional. Defaults to 0.
+                        //      description:
+                        //              For more details on the behavior of indexOf, see Mozilla's
+                        //              (indexOf
+                        //              docs)[http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Reference:Global_Objects:Array:indexOf]
+                        //      returns:
+                        //              Positive Integer or 0 for a match, -1 of not found.
+                        return d.indexOf(this, value, fromIndex); // Integer
+                },
+
+                lastIndexOf: function(value, fromIndex){
+                        // summary:
+                        //              see dojo.lastIndexOf(). The primary difference is that the
+                        //              acted-on array is implicitly this NodeList
+                        //      description:
+                        //              For more details on the behavior of lastIndexOf, see
+                        //              Mozilla's (lastIndexOf
+                        //              docs)[http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Reference:Global_Objects:Array:lastIndexOf]
+                        // value: Object
+                        //              The value to search for.
+                        // fromIndex: Integer?
+                        //              The location to start searching from. Optional. Defaults to 0.
+                        // returns:
+                        //              Positive Integer or 0 for a match, -1 of not found.
+                        return d.lastIndexOf(this, value, fromIndex); // Integer
+                },
+
+                every: function(callback, thisObject){
+                        //      summary:
+                        //              see `dojo.every()` and the (Array.every
+                        //              docs)[http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Reference:Global_Objects:Array:every].
+                        //              Takes the same structure of arguments and returns as
+                        //              dojo.every() with the caveat that the passed array is
+                        //              implicitly this NodeList
+                        // callback: Function: the callback
+                        // thisObject: Object?: the context
+                        return d.every(this, callback, thisObject); // Boolean
+                },
+
+                some: function(callback, thisObject){
+                        //      summary:
+                        //              Takes the same structure of arguments and returns as
+                        //              `dojo.some()` with the caveat that the passed array is
+                        //              implicitly this NodeList.  See `dojo.some()` and Mozilla's
+                        //              (Array.some
+                        //              documentation)[http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Reference:Global_Objects:Array:some].
+                        // callback: Function: the callback
+                        // thisObject: Object?: the context
+                        return d.some(this, callback, thisObject); // Boolean
+                },
+                =====*/
+
+                concat: function(item){
+                        // summary:
+                        //              Returns a new NodeList comprised of items in this NodeList
+                        //              as well as items passed in as parameters
+                        // description:
+                        //              This method behaves exactly like the Array.concat method
+                        //              with the caveat that it returns a `dojo.NodeList` and not a
+                        //              raw Array. For more details, see the (Array.concat
+                        //              docs)[http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Reference:Global_Objects:Array:concat]
+                        // item: Object?
+                        //              Any number of optional parameters may be passed in to be
+                        //              spliced into the NodeList
+                        // returns:
+                        //              dojo.NodeList
+
+                        //return this._wrap(apc.apply(this, arguments));
+                        // the line above won't work for the native NodeList :-(
+
+                        // implementation notes:
+                        // 1) Native NodeList is not an array, and cannot be used directly
+                        // in concat() --- the latter doesn't recognize it as an array, and
+                        // does not inline it, but append as a single entity.
+                        // 2) On some browsers (e.g., Safari) the "constructor" property is
+                        // read-only and cannot be changed. So we have to test for both
+                        // native NodeList and dojo.NodeList in this property to recognize
+                        // the node list.
+
+                        var t = d.isArray(this) ? this : aps.call(this, 0),
+                                m = d.map(arguments, function(a){
+                                        return a && !d.isArray(a) &&
+                                                (typeof NodeList != "undefined" && a.constructor === NodeList || a.constructor === this._NodeListCtor) ?
+                                                        aps.call(a, 0) : a;
+                                });
+                        return this._wrap(apc.apply(t, m), this);       // dojo.NodeList
+                },
+
+                map: function(/*Function*/ func, /*Function?*/ obj){
+                        //      summary:
+                        //              see dojo.map(). The primary difference is that the acted-on
+                        //              array is implicitly this NodeList and the return is a
+                        //              dojo.NodeList (a subclass of Array)
+                        ///return d.map(this, func, obj, d.NodeList); // dojo.NodeList
+                        return this._wrap(d.map(this, func, obj), this); // dojo.NodeList
+                },
+
+                forEach: function(callback, thisObj){
+                        //      summary:
+                        //              see `dojo.forEach()`. The primary difference is that the acted-on
+                        //              array is implicitly this NodeList. If you want the option to break out
+                        //              of the forEach loop, use every() or some() instead.
+                        d.forEach(this, callback, thisObj);
+                        // non-standard return to allow easier chaining
+                        return this; // dojo.NodeList
+                },
+
+                /*=====
+                coords: function(){
+                        //      summary:
+                        //              Returns the box objects of all elements in a node list as
+                        //              an Array (*not* a NodeList). Acts like `dojo.coords`, though assumes
+                        //              the node passed is each node in this list.
+
+                        return d.map(this, d.coords); // Array
+                },
+
+                position: function(){
+                        //      summary:
+                        //              Returns border-box objects (x/y/w/h) of all elements in a node list
+                        //              as an Array (*not* a NodeList). Acts like `dojo.position`, though
+                        //              assumes the node passed is each node in this list.
+
+                        return d.map(this, d.position); // Array
+                },
+
+                attr: function(property, value){
+                        //      summary:
+                        //              gets or sets the DOM attribute for every element in the
+                        //              NodeList. See also `dojo.attr`
+                        //      property: String
+                        //              the attribute to get/set
+                        //      value: String?
+                        //              optional. The value to set the property to
+                        //      returns:
+                        //              if no value is passed, the result is an array of attribute values
+                        //              If a value is passed, the return is this NodeList
+                        //      example:
+                        //              Make all nodes with a particular class focusable:
+                        //      |       dojo.query(".focusable").attr("tabIndex", -1);
+                        //      example:
+                        //              Disable a group of buttons:
+                        //      |       dojo.query("button.group").attr("disabled", true);
+                        //      example:
+                        //              innerHTML can be assigned or retrieved as well:
+                        //      |       // get the innerHTML (as an array) for each list item
+                        //      |       var ih = dojo.query("li.replaceable").attr("innerHTML");
+                        return; // dojo.NodeList
+                        return; // Array
+                },
+
+                style: function(property, value){
+                        //      summary:
+                        //              gets or sets the CSS property for every element in the NodeList
+                        //      property: String
+                        //              the CSS property to get/set, in JavaScript notation
+                        //              ("lineHieght" instead of "line-height")
+                        //      value: String?
+                        //              optional. The value to set the property to
+                        //      returns:
+                        //              if no value is passed, the result is an array of strings.
+                        //              If a value is passed, the return is this NodeList
+                        return; // dojo.NodeList
+                        return; // Array
+                },
+
+                addClass: function(className){
+                        //      summary:
+                        //              adds the specified class to every node in the list
+                        //      className: String|Array
+                        //              A String class name to add, or several space-separated class names,
+                        //              or an array of class names.
+                        return; // dojo.NodeList
+                },
+
+                removeClass: function(className){
+                        //      summary:
+                        //              removes the specified class from every node in the list
+                        //      className: String|Array?
+                        //              An optional String class name to remove, or several space-separated
+                        //              class names, or an array of class names. If omitted, all class names
+                        //              will be deleted.
+                        //      returns:
+                        //              dojo.NodeList, this list
+                        return; // dojo.NodeList
+                },
+
+                toggleClass: function(className, condition){
+                        //      summary:
+                        //              Adds a class to node if not present, or removes if present.
+                        //              Pass a boolean condition if you want to explicitly add or remove.
+                        //      condition: Boolean?
+                        //              If passed, true means to add the class, false means to remove.
+                        //      className: String
+                        //              the CSS class to add
+                        return; // dojo.NodeList
+                },
+
+                connect: function(methodName, objOrFunc, funcName){
+                        //      summary:
+                        //              attach event handlers to every item of the NodeList. Uses dojo.connect()
+                        //              so event properties are normalized
+                        //      methodName: String
+                        //              the name of the method to attach to. For DOM events, this should be
+                        //              the lower-case name of the event
+                        //      objOrFunc: Object|Function|String
+                        //              if 2 arguments are passed (methodName, objOrFunc), objOrFunc should
+                        //              reference a function or be the name of the function in the global
+                        //              namespace to attach. If 3 arguments are provided
+                        //              (methodName, objOrFunc, funcName), objOrFunc must be the scope to
+                        //              locate the bound function in
+                        //      funcName: String?
+                        //              optional. A string naming the function in objOrFunc to bind to the
+                        //              event. May also be a function reference.
+                        //      example:
+                        //              add an onclick handler to every button on the page
+                        //              |       dojo.query("div:nth-child(odd)").connect("onclick", function(e){
+                        //              |               console.log("clicked!");
+                        //              |       });
+                        // example:
+                        //              attach foo.bar() to every odd div's onmouseover
+                        //              |       dojo.query("div:nth-child(odd)").connect("onmouseover", foo, "bar");
+                },
+
+                empty: function(){
+                        //      summary:
+                        //              clears all content from each node in the list. Effectively
+                        //              equivalent to removing all child nodes from every item in
+                        //              the list.
+                        return this.forEach("item.innerHTML='';"); // dojo.NodeList
+                        // FIXME: should we be checking for and/or disposing of widgets below these nodes?
+                },
+                =====*/
+
+                // useful html methods
+                coords: adaptAsMap(d.coords),
+                position: adaptAsMap(d.position),
+
+                // FIXME: connectPublisher()? connectRunOnce()?
+
+                /*
+                destroy: function(){
+                        //      summary:
+                        //              destroys every item in  the list.
+                        this.forEach(d.destroy);
+                        // FIXME: should we be checking for and/or disposing of widgets below these nodes?
+                },
+                */
+
+                place: function(/*String||Node*/ queryOrNode, /*String*/ position){
+                        //      summary:
+                        //              places elements of this node list relative to the first element matched
+                        //              by queryOrNode. Returns the original NodeList. See: `dojo.place`
+                        //      queryOrNode:
+                        //              may be a string representing any valid CSS3 selector or a DOM node.
+                        //              In the selector case, only the first matching element will be used
+                        //              for relative positioning.
+                        //      position:
+                        //              can be one of:
+                        //              |       "last" (default)
+                        //              |       "first"
+                        //              |       "before"
+                        //              |       "after"
+                        //              |       "only"
+                        //              |       "replace"
+                        //              or an offset in the childNodes property
+                        var item = d.query(queryOrNode)[0];
+                        return this.forEach(function(node){ d.place(node, item, position); }); // dojo.NodeList
+                },
+
+                orphan: function(/*String?*/ filter){
+                        //      summary:
+                        //              removes elements in this list that match the filter
+                        //              from their parents and returns them as a new NodeList.
+                        //      filter:
+                        //              CSS selector like ".foo" or "div > span"
+                        //      returns:
+                        //              `dojo.NodeList` containing the orphaned elements
+                        return (filter ? d._filterQueryResult(this, filter) : this).forEach(orphan); // dojo.NodeList
+                },
+
+                adopt: function(/*String||Array||DomNode*/ queryOrListOrNode, /*String?*/ position){
+                        //      summary:
+                        //              places any/all elements in queryOrListOrNode at a
+                        //              position relative to the first element in this list.
+                        //              Returns a dojo.NodeList of the adopted elements.
+                        //      queryOrListOrNode:
+                        //              a DOM node or a query string or a query result.
+                        //              Represents the nodes to be adopted relative to the
+                        //              first element of this NodeList.
+                        //      position:
+                        //              can be one of:
+                        //              |       "last" (default)
+                        //              |       "first"
+                        //              |       "before"
+                        //              |       "after"
+                        //              |       "only"
+                        //              |       "replace"
+                        //              or an offset in the childNodes property
+                        return d.query(queryOrListOrNode).place(this[0], position)._stash(this);        // dojo.NodeList
+                },
+
+                // FIXME: do we need this?
+                query: function(/*String*/ queryStr){
+                        //      summary:
+                        //              Returns a new list whose members match the passed query,
+                        //              assuming elements of the current NodeList as the root for
+                        //              each search.
+                        //      example:
+                        //              assume a DOM created by this markup:
+                        //      |       <div id="foo">
+                        //      |               <p>
+                        //      |                       bacon is tasty, <span>dontcha think?</span>
+                        //      |               </p>
+                        //      |       </div>
+                        //      |       <div id="bar">
+                        //      |               <p>great comedians may not be funny <span>in person</span></p>
+                        //      |       </div>
+                        //              If we are presented with the following definition for a NodeList:
+                        //      |       var l = new dojo.NodeList(dojo.byId("foo"), dojo.byId("bar"));
+                        //              it's possible to find all span elements under paragraphs
+                        //              contained by these elements with this sub-query:
+                        //      |       var spans = l.query("p span");
+
+                        // FIXME: probably slow
+                        if(!queryStr){ return this; }
+                        var ret = this.map(function(node){
+                                // FIXME: why would we ever get undefined here?
+                                return d.query(queryStr, node).filter(function(subNode){ return subNode !== undefined; });
+                        });
+                        return this._wrap(apc.apply([], ret), this);    // dojo.NodeList
+                },
+
+                filter: function(/*String|Function*/ filter){
+                        //      summary:
+                        //              "masks" the built-in javascript filter() method (supported
+                        //              in Dojo via `dojo.filter`) to support passing a simple
+                        //              string filter in addition to supporting filtering function
+                        //              objects.
+                        //      filter:
+                        //              If a string, a CSS rule like ".thinger" or "div > span".
+                        //      example:
+                        //              "regular" JS filter syntax as exposed in dojo.filter:
+                        //              |       dojo.query("*").filter(function(item){
+                        //              |               // highlight every paragraph
+                        //              |               return (item.nodeName == "p");
+                        //              |       }).style("backgroundColor", "yellow");
+                        // example:
+                        //              the same filtering using a CSS selector
+                        //              |       dojo.query("*").filter("p").styles("backgroundColor", "yellow");
+
+                        var a = arguments, items = this, start = 0;
+                        if(typeof filter == "string"){ // inline'd type check
+                                items = d._filterQueryResult(this, a[0]);
+                                if(a.length == 1){
+                                        // if we only got a string query, pass back the filtered results
+                                        return items._stash(this); // dojo.NodeList
+                                }
+                                // if we got a callback, run it over the filtered items
+                                start = 1;
+                        }
+                        return this._wrap(d.filter(items, a[start], a[start + 1]), this);       // dojo.NodeList
+                },
+
+                /*
+                // FIXME: should this be "copyTo" and include parenting info?
+                clone: function(){
+                        // summary:
+                        //              creates node clones of each element of this list
+                        //              and returns a new list containing the clones
+                },
+                */
+
+                addContent: function(/*String||DomNode||Object||dojo.NodeList*/ content, /*String||Integer?*/ position){
+                        //      summary:
+                        //              add a node, NodeList or some HTML as a string to every item in the
+                        //              list.  Returns the original list.
+                        //      description:
+                        //              a copy of the HTML content is added to each item in the
+                        //              list, with an optional position argument. If no position
+                        //              argument is provided, the content is appended to the end of
+                        //              each item.
+                        //      content:
+                        //              DOM node, HTML in string format, a NodeList or an Object. If a DOM node or
+                        //              NodeList, the content will be cloned if the current NodeList has more than one
+                        //              element. Only the DOM nodes are cloned, no event handlers. If it is an Object,
+                        //              it should be an object with at "template" String property that has the HTML string
+                        //              to insert. If dojo.string has already been dojo.required, then dojo.string.substitute
+                        //              will be used on the "template" to generate the final HTML string. Other allowed
+                        //              properties on the object are: "parse" if the HTML
+                        //              string should be parsed for widgets (dojo.require("dojo.parser") to get that
+                        //              option to work), and "templateFunc" if a template function besides dojo.string.substitute
+                        //              should be used to transform the "template".
+                        //      position:
+                        //              can be one of:
+                        //              |       "last"||"end" (default)
+                        //              |       "first||"start"
+                        //              |       "before"
+                        //              |       "after"
+                        //              |       "replace" (replaces nodes in this NodeList with new content)
+                        //              |       "only" (removes other children of the nodes so new content is the only child)
+                        //              or an offset in the childNodes property
+                        //      example:
+                        //              appends content to the end if the position is omitted
+                        //      |       dojo.query("h3 > p").addContent("hey there!");
+                        //      example:
+                        //              add something to the front of each element that has a
+                        //              "thinger" property:
+                        //      |       dojo.query("[thinger]").addContent("...", "first");
+                        //      example:
+                        //              adds a header before each element of the list
+                        //      |       dojo.query(".note").addContent("<h4>NOTE:</h4>", "before");
+                        //      example:
+                        //              add a clone of a DOM node to the end of every element in
+                        //              the list, removing it from its existing parent.
+                        //      |       dojo.query(".note").addContent(dojo.byId("foo"));
+                        //  example:
+                        //      Append nodes from a templatized string.
+                        //              dojo.require("dojo.string");
+                        //              dojo.query(".note").addContent({
+                        //              template: '<b>${id}: </b><span>${name}</span>',
+                        //                      id: "user332",
+                        //              name: "Mr. Anderson"
+                        //      });
+                        //  example:
+                        //      Append nodes from a templatized string that also has widgets parsed.
+                        //      dojo.require("dojo.string");
+                        //      dojo.require("dojo.parser");
+                        //      var notes = dojo.query(".note").addContent({
+                        //              template: '<button dojoType="dijit.form.Button">${text}</button>',
+                        //              parse: true,
+                        //              text: "Send"
+                        //      });
+                        content = this._normalize(content, this[0]);
+                        for(var i = 0, node; (node = this[i]); i++){
+                                this._place(content, node, position, i > 0);
+                        }
+                        return this; //dojo.NodeList
+                },
+
+                instantiate: function(/*String|Object*/ declaredClass, /*Object?*/ properties){
+                        //      summary:
+                        //              Create a new instance of a specified class, using the
+                        //              specified properties and each node in the nodeList as a
+                        //              srcNodeRef.
+                        //      example:
+                        //              Grabs all buttons in the page and converts them to diji.form.Buttons.
+                        //      |       var buttons = dojo.query("button").instantiate("dijit.form.Button", {showLabel: true});
+                        var c = d.isFunction(declaredClass) ? declaredClass : d.getObject(declaredClass);
+                        properties = properties || {};
+                        return this.forEach(function(node){
+                                new c(properties, node);
+                        });     // dojo.NodeList
+                },
+
+                at: function(/*===== index =====*/){
+                        //      summary:
+                        //              Returns a new NodeList comprised of items in this NodeList
+                        //              at the given index or indices.
+                        //
+                        //      index: Integer...
+                        //              One or more 0-based indices of items in the current
+                        //              NodeList. A negative index will start at the end of the
+                        //              list and go backwards.
+                        //
+                        //      example:
+                        //      Shorten the list to the first, second, and third elements
+                        //      |       dojo.query("a").at(0, 1, 2).forEach(fn);
+                        //
+                        //      example:
+                        //      Retrieve the first and last elements of a unordered list:
+                        //      |       dojo.query("ul > li").at(0, -1).forEach(cb);
+                        //
+                        //      example:
+                        //      Do something for the first element only, but end() out back to
+                        //      the original list and continue chaining:
+                        //      |       dojo.query("a").at(0).onclick(fn).end().forEach(function(n){
+                        //      |               console.log(n); // all anchors on the page.
+                        //      |       })
+                        //
+                        //      returns:
+                        //              dojo.NodeList
+                        var t = new this._NodeListCtor();
+                        d.forEach(arguments, function(i){
+                                if(i < 0){ i = this.length + i }
+                                if(this[i]){ t.push(this[i]); }
+                        }, this);
+                        return t._stash(this); // dojo.NodeList
+                }
+
+        });
+
+        nl.events = [
+                // summary:
+                //              list of all DOM events used in NodeList
+                "blur", "focus", "change", "click", "error", "keydown", "keypress",
+                "keyup", "load", "mousedown", "mouseenter", "mouseleave", "mousemove",
+                "mouseout", "mouseover", "mouseup", "submit"
+        ];
+        
+        // FIXME: pseudo-doc the above automatically generated on-event functions
+
+        // syntactic sugar for DOM events
+        d.forEach(nl.events, function(evt){
+                        var _oe = "on" + evt;
+                        nlp[_oe] = function(a, b){
+                                return this.connect(_oe, a, b);
+                        };
+                                // FIXME: should these events trigger publishes?
+                                /*
+                                return (a ? this.connect(_oe, a, b) :
+                                                        this.forEach(function(n){
+                                                                // FIXME:
+                                                                //              listeners get buried by
+                                                                //              addEventListener and can't be dug back
+                                                                //              out to be triggered externally.
+                                                                // see:
+                                                                //              http://developer.mozilla.org/en/docs/DOM:element
+
+                                                                console.log(n, evt, _oe);
+
+                                                                // FIXME: need synthetic event support!
+                                                                var _e = { target: n, faux: true, type: evt };
+                                                                // dojo._event_listener._synthesizeEvent({}, { target: n, faux: true, type: evt });
+                                                                try{ n[evt](_e); }catch(e){ console.log(e); }
+                                                                try{ n[_oe](_e); }catch(e){ console.log(e); }
+                                                        })
+                                );
+                                */
+                }
+        );
+
+})();
+
+}
+
+if(!dojo._hasResource["dojo._base.query"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dojo._base.query"] = true;
+(function(){
+
+/*
+        dojo.query() architectural overview:
+
+                dojo.query is a relatively full-featured CSS3 query library. It is
+                designed to take any valid CSS3 selector and return the nodes matching
+                the selector. To do this quickly, it processes queries in several
+                steps, applying caching where profitable.
+                
+                The steps (roughly in reverse order of the way they appear in the code):
+                        1.) check to see if we already have a "query dispatcher"
+                                - if so, use that with the given parameterization. Skip to step 4.
+                        2.) attempt to determine which branch to dispatch the query to:
+                                - JS (optimized DOM iteration)
+                                - native (FF3.1+, Safari 3.1+, IE 8+)
+                        3.) tokenize and convert to executable "query dispatcher"
+                                - this is where the lion's share of the complexity in the
+                                  system lies. In the DOM version, the query dispatcher is
+                                  assembled as a chain of "yes/no" test functions pertaining to
+                                  a section of a simple query statement (".blah:nth-child(odd)"
+                                  but not "div div", which is 2 simple statements). Individual
+                                  statement dispatchers are cached (to prevent re-definition)
+                                  as are entire dispatch chains (to make re-execution of the
+                                  same query fast)
+                        4.) the resulting query dispatcher is called in the passed scope
+                            (by default the top-level document)
+                                - for DOM queries, this results in a recursive, top-down
+                                  evaluation of nodes based on each simple query section
+                                - for native implementations, this may mean working around spec
+                                  bugs. So be it.
+                        5.) matched nodes are pruned to ensure they are unique (if necessary)
+*/
+
+var defineQuery= function(d){
+        // define everything in a closure for compressability reasons. "d" is an
+        // alias to "dojo" (or the toolkit alias object, e.g., "acme").
+
+        ////////////////////////////////////////////////////////////////////////
+        // Toolkit aliases
+        ////////////////////////////////////////////////////////////////////////
+
+        // if you are extracting dojo.query for use in your own system, you will
+        // need to provide these methods and properties. No other porting should be
+        // necessary, save for configuring the system to use a class other than
+        // dojo.NodeList as the return instance instantiator
+        var trim =                      d.trim;
+        var each =                      d.forEach;
+        //                                      d.isIE; // float
+        //                                      d.isSafari; // float
+        //                                      d.isOpera; // float
+        //                                      d.isWebKit; // float
+        //                                      d.doc ; // document element
+        var qlc = (d._NodeListCtor =            d.NodeList);
+
+        var getDoc = function(){ return d.doc; };
+        // NOTE(alex): the spec is idiotic. CSS queries should ALWAYS be case-sensitive, but nooooooo
+        var cssCaseBug = ((d.isWebKit||d.isMozilla) && ((getDoc().compatMode) == "BackCompat"));
+
+        ////////////////////////////////////////////////////////////////////////
+        // Global utilities
+        ////////////////////////////////////////////////////////////////////////
+
+
+        // on browsers that support the "children" collection we can avoid a lot of
+        // iteration on chaff (non-element) nodes.
+        // why.
+        var childNodesName = !!getDoc().firstChild["children"] ? "children" : "childNodes";
+
+        var specials = ">~+";
+
+        // global thunk to determine whether we should treat the current query as
+        // case sensitive or not. This switch is flipped by the query evaluator
+        // based on the document passed as the context to search.
+        var caseSensitive = false;
+
+        // how high?
+        var yesman = function(){ return true; };
+
+        ////////////////////////////////////////////////////////////////////////
+        // Tokenizer
+        ////////////////////////////////////////////////////////////////////////
+
+        var getQueryParts = function(query){
+                //      summary:
+                //              state machine for query tokenization
+                //      description:
+                //              instead of using a brittle and slow regex-based CSS parser,
+                //              dojo.query implements an AST-style query representation. This
+                //              representation is only generated once per query. For example,
+                //              the same query run multiple times or under different root nodes
+                //              does not re-parse the selector expression but instead uses the
+                //              cached data structure. The state machine implemented here
+                //              terminates on the last " " (space) character and returns an
+                //              ordered array of query component structures (or "parts"). Each
+                //              part represents an operator or a simple CSS filtering
+                //              expression. The structure for parts is documented in the code
+                //              below.
+
+
+                // NOTE:
+                //              this code is designed to run fast and compress well. Sacrifices
+                //              to readability and maintainability have been made.  Your best
+                //              bet when hacking the tokenizer is to put The Donnas on *really*
+                //              loud (may we recommend their "Spend The Night" release?) and
+                //              just assume you're gonna make mistakes. Keep the unit tests
+                //              open and run them frequently. Knowing is half the battle ;-)
+                if(specials.indexOf(query.slice(-1)) >= 0){
+                        // if we end with a ">", "+", or "~", that means we're implicitly
+                        // searching all children, so make it explicit
+                        query += " * "
+                }else{
+                        // if you have not provided a terminator, one will be provided for
+                        // you...
+                        query += " ";
+                }
+
+                var ts = function(/*Integer*/ s, /*Integer*/ e){
+                        // trim and slice.
+
+                        // take an index to start a string slice from and an end position
+                        // and return a trimmed copy of that sub-string
+                        return trim(query.slice(s, e));
+                }
+
+                // the overall data graph of the full query, as represented by queryPart objects
+                var queryParts = [];
+
+
+                // state keeping vars
+                var inBrackets = -1, inParens = -1, inMatchFor = -1,
+                        inPseudo = -1, inClass = -1, inId = -1, inTag = -1,
+                        lc = "", cc = "", pStart;
+
+                // iteration vars
+                var x = 0, // index in the query
+                        ql = query.length,
+                        currentPart = null, // data structure representing the entire clause
+                        _cp = null; // the current pseudo or attr matcher
+
+                // several temporary variables are assigned to this structure during a
+                // potential sub-expression match:
+                //              attr:
+                //                      a string representing the current full attribute match in a
+                //                      bracket expression
+                //              type:
+                //                      if there's an operator in a bracket expression, this is
+                //                      used to keep track of it
+                //              value:
+                //                      the internals of parenthetical expression for a pseudo. for
+                //                      :nth-child(2n+1), value might be "2n+1"
+
+                var endTag = function(){
+                        // called when the tokenizer hits the end of a particular tag name.
+                        // Re-sets state variables for tag matching and sets up the matcher
+                        // to handle the next type of token (tag or operator).
+                        if(inTag >= 0){
+                                var tv = (inTag == x) ? null : ts(inTag, x); // .toLowerCase();
+                                currentPart[ (specials.indexOf(tv) < 0) ? "tag" : "oper" ] = tv;
+                                inTag = -1;
+                        }
+                }
+
+                var endId = function(){
+                        // called when the tokenizer might be at the end of an ID portion of a match
+                        if(inId >= 0){
+                                currentPart.id = ts(inId, x).replace(/\\/g, "");
+                                inId = -1;
+                        }
+                }
+
+                var endClass = function(){
+                        // called when the tokenizer might be at the end of a class name
+                        // match. CSS allows for multiple classes, so we augment the
+                        // current item with another class in its list
+                        if(inClass >= 0){
+                                currentPart.classes.push(ts(inClass+1, x).replace(/\\/g, ""));
+                                inClass = -1;
+                        }
+                }
+
+                var endAll = function(){
+                        // at the end of a simple fragment, so wall off the matches
+                        endId(); endTag(); endClass();
+                }
+
+                var endPart = function(){
+                        endAll();
+                        if(inPseudo >= 0){
+                                currentPart.pseudos.push({ name: ts(inPseudo+1, x) });
+                        }
+                        // hint to the selector engine to tell it whether or not it
+                        // needs to do any iteration. Many simple selectors don't, and
+                        // we can avoid significant construction-time work by advising
+                        // the system to skip them
+                        currentPart.loops = (
+                                        currentPart.pseudos.length ||
+                                        currentPart.attrs.length ||
+                                        currentPart.classes.length      );
+
+                        currentPart.oquery = currentPart.query = ts(pStart, x); // save the full expression as a string
+
+
+                        // otag/tag are hints to suggest to the system whether or not
+                        // it's an operator or a tag. We save a copy of otag since the
+                        // tag name is cast to upper-case in regular HTML matches. The
+                        // system has a global switch to figure out if the current
+                        // expression needs to be case sensitive or not and it will use
+                        // otag or tag accordingly
+                        currentPart.otag = currentPart.tag = (currentPart["oper"]) ? null : (currentPart.tag || "*");
+
+                        if(currentPart.tag){
+                                // if we're in a case-insensitive HTML doc, we likely want
+                                // the toUpperCase when matching on element.tagName. If we
+                                // do it here, we can skip the string op per node
+                                // comparison
+                                currentPart.tag = currentPart.tag.toUpperCase();
+                        }
+
+                        // add the part to the list
+                        if(queryParts.length && (queryParts[queryParts.length-1].oper)){
+                                // operators are always infix, so we remove them from the
+                                // list and attach them to the next match. The evaluator is
+                                // responsible for sorting out how to handle them.
+                                currentPart.infixOper = queryParts.pop();
+                                currentPart.query = currentPart.infixOper.query + " " + currentPart.query;
+                                /*
+                                console.debug(  "swapping out the infix",
+                                                                currentPart.infixOper,
+                                                                "and attaching it to",
+                                                                currentPart);
+                                */
+                        }
+                        queryParts.push(currentPart);
+
+                        currentPart = null;
+                }
+
+                // iterate over the query, character by character, building up a
+                // list of query part objects
+                for(; lc=cc, cc=query.charAt(x), x < ql; x++){
+                        //              cc: the current character in the match
+                        //              lc: the last character (if any)
+
+                        // someone is trying to escape something, so don't try to match any
+                        // fragments. We assume we're inside a literal.
+                        if(lc == "\\"){ continue; }
+                        if(!currentPart){ // a part was just ended or none has yet been created
+                                // NOTE: I hate all this alloc, but it's shorter than writing tons of if's
+                                pStart = x;
+                                //      rules describe full CSS sub-expressions, like:
+                                //              #someId
+                                //              .className:first-child
+                                //      but not:
+                                //              thinger > div.howdy[type=thinger]
+                                //      the indidual components of the previous query would be
+                                //      split into 3 parts that would be represented a structure
+                                //      like:
+                                //              [
+                                //                      {
+                                //                              query: "thinger",
+                                //                              tag: "thinger",
+                                //                      },
+                                //                      {
+                                //                              query: "div.howdy[type=thinger]",
+                                //                              classes: ["howdy"],
+                                //                              infixOper: {
+                                //                                      query: ">",
+                                //                                      oper: ">",
+                                //                              }
+                                //                      },
+                                //              ]
+                                currentPart = {
+                                        query: null, // the full text of the part's rule
+                                        pseudos: [], // CSS supports multiple pseud-class matches in a single rule
+                                        attrs: [],      // CSS supports multi-attribute match, so we need an array
+                                        classes: [], // class matches may be additive, e.g.: .thinger.blah.howdy
+                                        tag: null,      // only one tag...
+                                        oper: null, // ...or operator per component. Note that these wind up being exclusive.
+                                        id: null,       // the id component of a rule
+                                        getTag: function(){
+                                                return (caseSensitive) ? this.otag : this.tag;
+                                        }
+                                };
+
+                                // if we don't have a part, we assume we're going to start at
+                                // the beginning of a match, which should be a tag name. This
+                                // might fault a little later on, but we detect that and this
+                                // iteration will still be fine.
+                                inTag = x;
+                        }
+
+                        if(inBrackets >= 0){
+                                // look for a the close first
+                                if(cc == "]"){ // if we're in a [...] clause and we end, do assignment
+                                        if(!_cp.attr){
+                                                // no attribute match was previously begun, so we
+                                                // assume this is an attribute existence match in the
+                                                // form of [someAttributeName]
+                                                _cp.attr = ts(inBrackets+1, x);
+                                        }else{
+                                                // we had an attribute already, so we know that we're
+                                                // matching some sort of value, as in [attrName=howdy]
+                                                _cp.matchFor = ts((inMatchFor||inBrackets+1), x);
+                                        }
+                                        var cmf = _cp.matchFor;
+                                        if(cmf){
+                                                // try to strip quotes from the matchFor value. We want
+                                                // [attrName=howdy] to match the same
+                                                //      as [attrName = 'howdy' ]
+                                                if(     (cmf.charAt(0) == '"') || (cmf.charAt(0)  == "'") ){
+                                                        _cp.matchFor = cmf.slice(1, -1);
+                                                }
+                                        }
+                                        // end the attribute by adding it to the list of attributes.
+                                        currentPart.attrs.push(_cp);
+                                        _cp = null; // necessary?
+                                        inBrackets = inMatchFor = -1;
+                                }else if(cc == "="){
+                                        // if the last char was an operator prefix, make sure we
+                                        // record it along with the "=" operator.
+                                        var addToCc = ("|~^$*".indexOf(lc) >=0 ) ? lc : "";
+                                        _cp.type = addToCc+cc;
+                                        _cp.attr = ts(inBrackets+1, x-addToCc.length);
+                                        inMatchFor = x+1;
+                                }
+                                // now look for other clause parts
+                        }else if(inParens >= 0){
+                                // if we're in a parenthetical expression, we need to figure
+                                // out if it's attached to a pseudo-selector rule like
+                                // :nth-child(1)
+                                if(cc == ")"){
+                                        if(inPseudo >= 0){
+                                                _cp.value = ts(inParens+1, x);
+                                        }
+                                        inPseudo = inParens = -1;
+                                }
+                        }else if(cc == "#"){
+                                // start of an ID match
+                                endAll();
+                                inId = x+1;
+                        }else if(cc == "."){
+                                // start of a class match
+                                endAll();
+                                inClass = x;
+                        }else if(cc == ":"){
+                                // start of a pseudo-selector match
+                                endAll();
+                                inPseudo = x;
+                        }else if(cc == "["){
+                                // start of an attribute match.
+                                endAll();
+                                inBrackets = x;
+                                // provide a new structure for the attribute match to fill-in
+                                _cp = {
+                                        /*=====
+                                        attr: null, type: null, matchFor: null
+                                        =====*/
+                                };
+                        }else if(cc == "("){
+                                // we really only care if we've entered a parenthetical
+                                // expression if we're already inside a pseudo-selector match
+                                if(inPseudo >= 0){
+                                        // provide a new structure for the pseudo match to fill-in
+                                        _cp = {
+                                                name: ts(inPseudo+1, x),
+                                                value: null
+                                        }
+                                        currentPart.pseudos.push(_cp);
+                                }
+                                inParens = x;
+                        }else if(
+                                (cc == " ") &&
+                                // if it's a space char and the last char is too, consume the
+                                // current one without doing more work
+                                (lc != cc)
+                        ){
+                                endPart();
+                        }
+                }
+                return queryParts;
+        };
+        
+
+        ////////////////////////////////////////////////////////////////////////
+        // DOM query infrastructure
+        ////////////////////////////////////////////////////////////////////////
+
+        var agree = function(first, second){
+                // the basic building block of the yes/no chaining system. agree(f1,
+                // f2) generates a new function which returns the boolean results of
+                // both of the passed functions to a single logical-anded result. If
+                // either are not passed, the other is used exclusively.
+                if(!first){ return second; }
+                if(!second){ return first; }
+
+                return function(){
+                        return first.apply(window, arguments) && second.apply(window, arguments);
+                }
+        };
+
+        var getArr = function(i, arr){
+                // helps us avoid array alloc when we don't need it
+                var r = arr||[]; // FIXME: should this be 'new d._NodeListCtor()' ?
+                if(i){ r.push(i); }
+                return r;
+        };
+
+        var _isElement = function(n){ return (1 == n.nodeType); };
+
+        // FIXME: need to coalesce _getAttr with defaultGetter
+        var blank = "";
+        var _getAttr = function(elem, attr){
+                if(!elem){ return blank; }
+                if(attr == "class"){
+                        return elem.className || blank;
+                }
+                if(attr == "for"){
+                        return elem.htmlFor || blank;
+                }
+                if(attr == "style"){
+                        return elem.style.cssText || blank;
+                }
+                return (caseSensitive ? elem.getAttribute(attr) : elem.getAttribute(attr, 2)) || blank;
+        };
+
+        var attrs = {
+                "*=": function(attr, value){
+                        return function(elem){
+                                // E[foo*="bar"]
+                                //              an E element whose "foo" attribute value contains
+                                //              the substring "bar"
+                                return (_getAttr(elem, attr).indexOf(value)>=0);
+                        }
+                },
+                "^=": function(attr, value){
+                        // E[foo^="bar"]
+                        //              an E element whose "foo" attribute value begins exactly
+                        //              with the string "bar"
+                        return function(elem){
+                                return (_getAttr(elem, attr).indexOf(value)==0);
+                        }
+                },
+                "$=": function(attr, value){
+                        // E[foo$="bar"]
+                        //              an E element whose "foo" attribute value ends exactly
+                        //              with the string "bar"
+                        var tval = " "+value;
+                        return function(elem){
+                                var ea = " "+_getAttr(elem, attr);
+                                return (ea.lastIndexOf(value)==(ea.length-value.length));
+                        }
+                },
+                "~=": function(attr, value){
+                        // E[foo~="bar"]
+                        //              an E element whose "foo" attribute value is a list of
+                        //              space-separated values, one of which is exactly equal
+                        //              to "bar"
+
+                        // return "[contains(concat(' ',@"+attr+",' '), ' "+ value +" ')]";
+                        var tval = " "+value+" ";
+                        return function(elem){
+                                var ea = " "+_getAttr(elem, attr)+" ";
+                                return (ea.indexOf(tval)>=0);
+                        }
+                },
+                "|=": function(attr, value){
+                        // E[hreflang|="en"]
+                        //              an E element whose "hreflang" attribute has a
+                        //              hyphen-separated list of values beginning (from the
+                        //              left) with "en"
+                        var valueDash = " "+value+"-";
+                        return function(elem){
+                                var ea = " "+_getAttr(elem, attr);
+                                return (
+                                        (ea == value) ||
+                                        (ea.indexOf(valueDash)==0)
+                                );
+                        }
+                },
+                "=": function(attr, value){
+                        return function(elem){
+                                return (_getAttr(elem, attr) == value);
+                        }
+                }
+        };
+
+        // avoid testing for node type if we can. Defining this in the negative
+        // here to avoid negation in the fast path.
+        var _noNES = (typeof getDoc().firstChild.nextElementSibling == "undefined");
+        var _ns = !_noNES ? "nextElementSibling" : "nextSibling";
+        var _ps = !_noNES ? "previousElementSibling" : "previousSibling";
+        var _simpleNodeTest = (_noNES ? _isElement : yesman);
+
+        var _lookLeft = function(node){
+                // look left
+                while(node = node[_ps]){
+                        if(_simpleNodeTest(node)){ return false; }
+                }
+                return true;
+        };
+
+        var _lookRight = function(node){
+                // look right
+                while(node = node[_ns]){
+                        if(_simpleNodeTest(node)){ return false; }
+                }
+                return true;
+        };
+
+        var getNodeIndex = function(node){
+                var root = node.parentNode;
+                var i = 0,
+                        tret = root[childNodesName],
+                        ci = (node["_i"]||-1),
+                        cl = (root["_l"]||-1);
+
+                if(!tret){ return -1; }
+                var l = tret.length;
+
+                // we calculate the parent length as a cheap way to invalidate the
+                // cache. It's not 100% accurate, but it's much more honest than what
+                // other libraries do
+                if( cl == l && ci >= 0 && cl >= 0 ){
+                        // if it's legit, tag and release
+                        return ci;
+                }
+
+                // else re-key things
+                root["_l"] = l;
+                ci = -1;
+                for(var te = root["firstElementChild"]||root["firstChild"]; te; te = te[_ns]){
+                        if(_simpleNodeTest(te)){
+                                te["_i"] = ++i;
+                                if(node === te){
+                                        // NOTE:
+                                        //      shortcutting the return at this step in indexing works
+                                        //      very well for benchmarking but we avoid it here since
+                                        //      it leads to potential O(n^2) behavior in sequential
+                                        //      getNodexIndex operations on a previously un-indexed
+                                        //      parent. We may revisit this at a later time, but for
+                                        //      now we just want to get the right answer more often
+                                        //      than not.
+                                        ci = i;
+                                }
+                        }
+                }
+                return ci;
+        };
+
+        var isEven = function(elem){
+                return !((getNodeIndex(elem)) % 2);
+        };
+
+        var isOdd = function(elem){
+                return ((getNodeIndex(elem)) % 2);
+        };
+
+        var pseudos = {
+                "checked": function(name, condition){
+                        return function(elem){
+                                return !!("checked" in elem ? elem.checked : elem.selected);
+                        }
+                },
+                "first-child": function(){ return _lookLeft; },
+                "last-child": function(){ return _lookRight; },
+                "only-child": function(name, condition){
+                        return function(node){
+                                if(!_lookLeft(node)){ return false; }
+                                if(!_lookRight(node)){ return false; }
+                                return true;
+                        };
+                },
+                "empty": function(name, condition){
+                        return function(elem){
+                                // DomQuery and jQuery get this wrong, oddly enough.
+                                // The CSS 3 selectors spec is pretty explicit about it, too.
+                                var cn = elem.childNodes;
+                                var cnl = elem.childNodes.length;
+                                // if(!cnl){ return true; }
+                                for(var x=cnl-1; x >= 0; x--){
+                                        var nt = cn[x].nodeType;
+                                        if((nt === 1)||(nt == 3)){ return false; }
+                                }
+                                return true;
+                        }
+                },
+                "contains": function(name, condition){
+                        var cz = condition.charAt(0);
+                        if( cz == '"' || cz == "'" ){ //remove quote
+                                condition = condition.slice(1, -1);
+                        }
+                        return function(elem){
+                                return (elem.innerHTML.indexOf(condition) >= 0);
+                        }
+                },
+                "not": function(name, condition){
+                        var p = getQueryParts(condition)[0];
+                        var ignores = { el: 1 };
+                        if(p.tag != "*"){
+                                ignores.tag = 1;
+                        }
+                        if(!p.classes.length){
+                                ignores.classes = 1;
+                        }
+                        var ntf = getSimpleFilterFunc(p, ignores);
+                        return function(elem){
+                                return (!ntf(elem));
+                        }
+                },
+                "nth-child": function(name, condition){
+                        var pi = parseInt;
+                        // avoid re-defining function objects if we can
+                        if(condition == "odd"){
+                                return isOdd;
+                        }else if(condition == "even"){
+                                return isEven;
+                        }
+                        // FIXME: can we shorten this?
+                        if(condition.indexOf("n") != -1){
+                                var tparts = condition.split("n", 2);
+                                var pred = tparts[0] ? ((tparts[0] == '-') ? -1 : pi(tparts[0])) : 1;
+                                var idx = tparts[1] ? pi(tparts[1]) : 0;
+                                var lb = 0, ub = -1;
+                                if(pred > 0){
+                                        if(idx < 0){
+                                                idx = (idx % pred) && (pred + (idx % pred));
+                                        }else if(idx>0){
+                                                if(idx >= pred){
+                                                        lb = idx - idx % pred;
+                                                }
+                                                idx = idx % pred;
+                                        }
+                                }else if(pred<0){
+                                        pred *= -1;
+                                        // idx has to be greater than 0 when pred is negative;
+                                        // shall we throw an error here?
+                                        if(idx > 0){
+                                                ub = idx;
+                                                idx = idx % pred;
+                                        }
+                                }
+                                if(pred > 0){
+                                        return function(elem){
+                                                var i = getNodeIndex(elem);
+                                                return (i>=lb) && (ub<0 || i<=ub) && ((i % pred) == idx);
+                                        }
+                                }else{
+                                        condition = idx;
+                                }
+                        }
+                        var ncount = pi(condition);
+                        return function(elem){
+                                return (getNodeIndex(elem) == ncount);
+                        }
+                }
+        };
+
+        var defaultGetter = (d.isIE < 9 || (dojo.isIE && dojo.isQuirks)) ? function(cond){
+                var clc = cond.toLowerCase();
+                if(clc == "class"){ cond = "className"; }
+                return function(elem){
+                        return (caseSensitive ? elem.getAttribute(cond) : elem[cond]||elem[clc]);
+                }
+        } : function(cond){
+                return function(elem){
+                        return (elem && elem.getAttribute && elem.hasAttribute(cond));
+                }
+        };
+
+        var getSimpleFilterFunc = function(query, ignores){
+                // generates a node tester function based on the passed query part. The
+                // query part is one of the structures generated by the query parser
+                // when it creates the query AST. The "ignores" object specifies which
+                // (if any) tests to skip, allowing the system to avoid duplicating
+                // work where it may have already been taken into account by other
+                // factors such as how the nodes to test were fetched in the first
+                // place
+                if(!query){ return yesman; }
+                ignores = ignores||{};
+
+                var ff = null;
+
+                if(!("el" in ignores)){
+                        ff = agree(ff, _isElement);
+                }
+
+                if(!("tag" in ignores)){
+                        if(query.tag != "*"){
+                                ff = agree(ff, function(elem){
+                                        return (elem && (elem.tagName == query.getTag()));
+                                });
+                        }
+                }
+
+                if(!("classes" in ignores)){
+                        each(query.classes, function(cname, idx, arr){
+                                // get the class name
+                                /*
+                                var isWildcard = cname.charAt(cname.length-1) == "*";
+                                if(isWildcard){
+                                        cname = cname.substr(0, cname.length-1);
+                                }
+                                // I dislike the regex thing, even if memoized in a cache, but it's VERY short
+                                var re = new RegExp("(?:^|\\s)" + cname + (isWildcard ? ".*" : "") + "(?:\\s|$)");
+                                */
+                                var re = new RegExp("(?:^|\\s)" + cname + "(?:\\s|$)");
+                                ff = agree(ff, function(elem){
+                                        return re.test(elem.className);
+                                });
+                                ff.count = idx;
+                        });
+                }
+
+                if(!("pseudos" in ignores)){
+                        each(query.pseudos, function(pseudo){
+                                var pn = pseudo.name;
+                                if(pseudos[pn]){
+                                        ff = agree(ff, pseudos[pn](pn, pseudo.value));
+                                }
+                        });
+                }
+
+                if(!("attrs" in ignores)){
+                        each(query.attrs, function(attr){
+                                var matcher;
+                                var a = attr.attr;
+                                // type, attr, matchFor
+                                if(attr.type && attrs[attr.type]){
+                                        matcher = attrs[attr.type](a, attr.matchFor);
+                                }else if(a.length){
+                                        matcher = defaultGetter(a);
+                                }
+                                if(matcher){
+                                        ff = agree(ff, matcher);
+                                }
+                        });
+                }
+
+                if(!("id" in ignores)){
+                        if(query.id){
+                                ff = agree(ff, function(elem){
+                                        return (!!elem && (elem.id == query.id));
+                                });
+                        }
+                }
+
+                if(!ff){
+                        if(!("default" in ignores)){
+                                ff = yesman;
+                        }
+                }
+                return ff;
+        };
+
+        var _nextSibling = function(filterFunc){
+                return function(node, ret, bag){
+                        while(node = node[_ns]){
+                                if(_noNES && (!_isElement(node))){ continue; }
+                                if(
+                                        (!bag || _isUnique(node, bag)) &&
+                                        filterFunc(node)
+                                ){
+                                        ret.push(node);
+                                }
+                                break;
+                        }
+                        return ret;
+                }
+        };
+
+        var _nextSiblings = function(filterFunc){
+                return function(root, ret, bag){
+                        var te = root[_ns];
+                        while(te){
+                                if(_simpleNodeTest(te)){
+                                        if(bag && !_isUnique(te, bag)){
+                                                break;
+                                        }
+                                        if(filterFunc(te)){
+                                                ret.push(te);
+                                        }
+                                }
+                                te = te[_ns];
+                        }
+                        return ret;
+                }
+        };
+
+        // get an array of child *elements*, skipping text and comment nodes
+        var _childElements = function(filterFunc){
+                filterFunc = filterFunc||yesman;
+                return function(root, ret, bag){
+                        // get an array of child elements, skipping text and comment nodes
+                        var te, x = 0, tret = root[childNodesName];
+                        while(te = tret[x++]){
+                                if(
+                                        _simpleNodeTest(te) &&
+                                        (!bag || _isUnique(te, bag)) &&
+                                        (filterFunc(te, x))
+                                ){
+                                        ret.push(te);
+                                }
+                        }
+                        return ret;
+                };
+        };
+        
+        /*
+        // thanks, Dean!
+        var itemIsAfterRoot = d.isIE ? function(item, root){
+                return (item.sourceIndex > root.sourceIndex);
+        } : function(item, root){
+                return (item.compareDocumentPosition(root) == 2);
+        };
+        */
+
+        // test to see if node is below root
+        var _isDescendant = function(node, root){
+                var pn = node.parentNode;
+                while(pn){
+                        if(pn == root){
+                                break;
+                        }
+                        pn = pn.parentNode;
+                }
+                return !!pn;
+        };
+
+        var _getElementsFuncCache = {};
+
+        var getElementsFunc = function(query){
+                var retFunc = _getElementsFuncCache[query.query];
+                // if we've got a cached dispatcher, just use that
+                if(retFunc){ return retFunc; }
+                // else, generate a new on
+
+                // NOTE:
+                //              this function returns a function that searches for nodes and
+                //              filters them.  The search may be specialized by infix operators
+                //              (">", "~", or "+") else it will default to searching all
+                //              descendants (the " " selector). Once a group of children is
+                //              found, a test function is applied to weed out the ones we
+                //              don't want. Many common cases can be fast-pathed. We spend a
+                //              lot of cycles to create a dispatcher that doesn't do more work
+                //              than necessary at any point since, unlike this function, the
+                //              dispatchers will be called every time. The logic of generating
+                //              efficient dispatchers looks like this in pseudo code:
+                //
+                //              # if it's a purely descendant query (no ">", "+", or "~" modifiers)
+                //              if infixOperator == " ":
+                //                      if only(id):
+                //                              return def(root):
+                //                                      return d.byId(id, root);
+                //
+                //                      elif id:
+                //                              return def(root):
+                //                                      return filter(d.byId(id, root));
+                //
+                //                      elif cssClass && getElementsByClassName:
+                //                              return def(root):
+                //                                      return filter(root.getElementsByClassName(cssClass));
+                //
+                //                      elif only(tag):
+                //                              return def(root):
+                //                                      return root.getElementsByTagName(tagName);
+                //
+                //                      else:
+                //                              # search by tag name, then filter
+                //                              return def(root):
+                //                                      return filter(root.getElementsByTagName(tagName||"*"));
+                //
+                //              elif infixOperator == ">":
+                //                      # search direct children
+                //                      return def(root):
+                //                              return filter(root.children);
+                //
+                //              elif infixOperator == "+":
+                //                      # search next sibling
+                //                      return def(root):
+                //                              return filter(root.nextElementSibling);
+                //
+                //              elif infixOperator == "~":
+                //                      # search rightward siblings
+                //                      return def(root):
+                //                              return filter(nextSiblings(root));
+
+                var io = query.infixOper;
+                var oper = (io ? io.oper : "");
+                // the default filter func which tests for all conditions in the query
+                // part. This is potentially inefficient, so some optimized paths may
+                // re-define it to test fewer things.
+                var filterFunc = getSimpleFilterFunc(query, { el: 1 });
+                var qt = query.tag;
+                var wildcardTag = ("*" == qt);
+                var ecs = getDoc()["getElementsByClassName"];
+
+                if(!oper){
+                        // if there's no infix operator, then it's a descendant query. ID
+                        // and "elements by class name" variants can be accelerated so we
+                        // call them out explicitly:
+                        if(query.id){
+                                // testing shows that the overhead of yesman() is acceptable
+                                // and can save us some bytes vs. re-defining the function
+                                // everywhere.
+                                filterFunc = (!query.loops && wildcardTag) ?
+                                        yesman :
+                                        getSimpleFilterFunc(query, { el: 1, id: 1 });
+
+                                retFunc = function(root, arr){
+                                        var te = d.byId(query.id, (root.ownerDocument||root));
+                                        if(!te || !filterFunc(te)){ return; }
+                                        if(9 == root.nodeType){ // if root's a doc, we just return directly
+                                                return getArr(te, arr);
+                                        }else{ // otherwise check ancestry
+                                                if(_isDescendant(te, root)){
+                                                        return getArr(te, arr);
+                                                }
+                                        }
+                                }
+                        }else if(
+                                ecs &&
+                                // isAlien check. Workaround for Prototype.js being totally evil/dumb.
+                                /\{\s*\[native code\]\s*\}/.test(String(ecs)) &&
+                                query.classes.length &&
+                                !cssCaseBug
+                        ){
+                                // it's a class-based query and we've got a fast way to run it.
+
+                                // ignore class and ID filters since we will have handled both
+                                filterFunc = getSimpleFilterFunc(query, { el: 1, classes: 1, id: 1 });
+                                var classesString = query.classes.join(" ");
+                                retFunc = function(root, arr, bag){
+                                        var ret = getArr(0, arr), te, x=0;
+                                        var tret = root.getElementsByClassName(classesString);
+                                        while((te = tret[x++])){
+                                                if(filterFunc(te, root) && _isUnique(te, bag)){
+                                                        ret.push(te);
+                                                }
+                                        }
+                                        return ret;
+                                };
+
+                        }else if(!wildcardTag && !query.loops){
+                                // it's tag only. Fast-path it.
+                                retFunc = function(root, arr, bag){
+                                        var ret = getArr(0, arr), te, x=0;
+                                        var tret = root.getElementsByTagName(query.getTag());
+                                        while((te = tret[x++])){
+                                                if(_isUnique(te, bag)){
+                                                        ret.push(te);
+                                                }
+                                        }
+                                        return ret;
+                                };
+                        }else{
+                                // the common case:
+                                //              a descendant selector without a fast path. By now it's got
+                                //              to have a tag selector, even if it's just "*" so we query
+                                //              by that and filter
+                                filterFunc = getSimpleFilterFunc(query, { el: 1, tag: 1, id: 1 });
+                                retFunc = function(root, arr, bag){
+                                        var ret = getArr(0, arr), te, x=0;
+                                        // we use getTag() to avoid case sensitivity issues
+                                        var tret = root.getElementsByTagName(query.getTag());
+                                        while((te = tret[x++])){
+                                                if(filterFunc(te, root) && _isUnique(te, bag)){
+                                                        ret.push(te);
+                                                }
+                                        }
+                                        return ret;
+                                };
+                        }
+                }else{
+                        // the query is scoped in some way. Instead of querying by tag we
+                        // use some other collection to find candidate nodes
+                        var skipFilters = { el: 1 };
+                        if(wildcardTag){
+                                skipFilters.tag = 1;
+                        }
+                        filterFunc = getSimpleFilterFunc(query, skipFilters);
+                        if("+" == oper){
+                                retFunc = _nextSibling(filterFunc);
+                        }else if("~" == oper){
+                                retFunc = _nextSiblings(filterFunc);
+                        }else if(">" == oper){
+                                retFunc = _childElements(filterFunc);
+                        }
+                }
+                // cache it and return
+                return _getElementsFuncCache[query.query] = retFunc;
+        };
+
+        var filterDown = function(root, queryParts){
+                // NOTE:
+                //              this is the guts of the DOM query system. It takes a list of
+                //              parsed query parts and a root and finds children which match
+                //              the selector represented by the parts
+                var candidates = getArr(root), qp, x, te, qpl = queryParts.length, bag, ret;
+
+                for(var i = 0; i < qpl; i++){
+                        ret = [];
+                        qp = queryParts[i];
+                        x = candidates.length - 1;
+                        if(x > 0){
+                                // if we have more than one root at this level, provide a new
+                                // hash to use for checking group membership but tell the
+                                // system not to post-filter us since we will already have been
+                                // gauranteed to be unique
+                                bag = {};
+                                ret.nozip = true;
+                        }
+                        var gef = getElementsFunc(qp);
+                        for(var j = 0; (te = candidates[j]); j++){
+                                // for every root, get the elements that match the descendant
+                                // selector, adding them to the "ret" array and filtering them
+                                // via membership in this level's bag. If there are more query
+                                // parts, then this level's return will be used as the next
+                                // level's candidates
+                                gef(te, ret, bag);
+                        }
+                        if(!ret.length){ break; }
+                        candidates = ret;
+                }
+                return ret;
+        };
+
+        ////////////////////////////////////////////////////////////////////////
+        // the query runner
+        ////////////////////////////////////////////////////////////////////////
+
+        // these are the primary caches for full-query results. The query
+        // dispatcher functions are generated then stored here for hash lookup in
+        // the future
+        var _queryFuncCacheDOM = {},
+                _queryFuncCacheQSA = {};
+
+        // this is the second level of spliting, from full-length queries (e.g.,
+        // "div.foo .bar") into simple query expressions (e.g., ["div.foo",
+        // ".bar"])
+        var getStepQueryFunc = function(query){
+                var qparts = getQueryParts(trim(query));
+
+                // if it's trivial, avoid iteration and zipping costs
+                if(qparts.length == 1){
+                        // we optimize this case here to prevent dispatch further down the
+                        // chain, potentially slowing things down. We could more elegantly
+                        // handle this in filterDown(), but it's slower for simple things
+                        // that need to be fast (e.g., "#someId").
+                        var tef = getElementsFunc(qparts[0]);
+                        return function(root){
+                                var r = tef(root, new qlc());
+                                if(r){ r.nozip = true; }
+                                return r;
+                        }
+                }
+
+                // otherwise, break it up and return a runner that iterates over the parts recursively
+                return function(root){
+                        return filterDown(root, qparts);
+                }
+        };
+
+        // NOTES:
+        //      * we can't trust QSA for anything but document-rooted queries, so
+        //        caching is split into DOM query evaluators and QSA query evaluators
+        //      * caching query results is dirty and leak-prone (or, at a minimum,
+        //        prone to unbounded growth). Other toolkits may go this route, but
+        //        they totally destroy their own ability to manage their memory
+        //        footprint. If we implement it, it should only ever be with a fixed
+        //        total element reference # limit and an LRU-style algorithm since JS
+        //        has no weakref support. Caching compiled query evaluators is also
+        //        potentially problematic, but even on large documents the size of the
+        //        query evaluators is often < 100 function objects per evaluator (and
+        //        LRU can be applied if it's ever shown to be an issue).
+        //      * since IE's QSA support is currently only for HTML documents and even
+        //        then only in IE 8's "standards mode", we have to detect our dispatch
+        //        route at query time and keep 2 separate caches. Ugg.
+
+        // we need to determine if we think we can run a given query via
+        // querySelectorAll or if we'll need to fall back on DOM queries to get
+        // there. We need a lot of information about the environment and the query
+        // to make the determiniation (e.g. does it support QSA, does the query in
+        // question work in the native QSA impl, etc.).
+        var nua = navigator.userAgent;
+        // some versions of Safari provided QSA, but it was buggy and crash-prone.
+        // We need te detect the right "internal" webkit version to make this work.
+        var wk = "WebKit/";
+        var is525 = (
+                d.isWebKit &&
+                (nua.indexOf(wk) > 0) &&
+                (parseFloat(nua.split(wk)[1]) > 528)
+        );
+
+        // IE QSA queries may incorrectly include comment nodes, so we throw the
+        // zipping function into "remove" comments mode instead of the normal "skip
+        // it" which every other QSA-clued browser enjoys
+        var noZip = d.isIE ? "commentStrip" : "nozip";
+
+        var qsa = "querySelectorAll";
+        var qsaAvail = (
+                !!getDoc()[qsa] &&
+                // see #5832
+                (!d.isSafari || (d.isSafari > 3.1) || is525 )
+        );
+
+        //Don't bother with n+3 type of matches, IE complains if we modify those.
+        var infixSpaceRe = /n\+\d|([^ ])?([>~+])([^ =])?/g;
+        var infixSpaceFunc = function(match, pre, ch, post) {
+                return ch ? (pre ? pre + " " : "") + ch + (post ? " " + post : "") : /*n+3*/ match;
+        };
+
+        var getQueryFunc = function(query, forceDOM){
+                //Normalize query. The CSS3 selectors spec allows for omitting spaces around
+                //infix operators, >, ~ and +
+                //Do the work here since detection for spaces is used as a simple "not use QSA"
+                //test below.
+                query = query.replace(infixSpaceRe, infixSpaceFunc);
+
+                if(qsaAvail){
+                        // if we've got a cached variant and we think we can do it, run it!
+                        var qsaCached = _queryFuncCacheQSA[query];
+                        if(qsaCached && !forceDOM){ return qsaCached; }
+                }
+
+                // else if we've got a DOM cached variant, assume that we already know
+                // all we need to and use it
+                var domCached = _queryFuncCacheDOM[query];
+                if(domCached){ return domCached; }
+
+                // TODO:
+                //              today we're caching DOM and QSA branches separately so we
+                //              recalc useQSA every time. If we had a way to tag root+query
+                //              efficiently, we'd be in good shape to do a global cache.
+
+                var qcz = query.charAt(0);
+                var nospace = (-1 == query.indexOf(" "));
+
+                // byId searches are wicked fast compared to QSA, even when filtering
+                // is required
+                if( (query.indexOf("#") >= 0) && (nospace) ){
+                        forceDOM = true;
+                }
+
+                var useQSA = (
+                        qsaAvail && (!forceDOM) &&
+                        // as per CSS 3, we can't currently start w/ combinator:
+                        //              http://www.w3.org/TR/css3-selectors/#w3cselgrammar
+                        (specials.indexOf(qcz) == -1) &&
+                        // IE's QSA impl sucks on pseudos
+                        (!d.isIE || (query.indexOf(":") == -1)) &&
+
+                        (!(cssCaseBug && (query.indexOf(".") >= 0))) &&
+
+                        // FIXME:
+                        //              need to tighten up browser rules on ":contains" and "|=" to
+                        //              figure out which aren't good
+                        //              Latest webkit (around 531.21.8) does not seem to do well with :checked on option
+                        //              elements, even though according to spec, selected options should
+                        //              match :checked. So go nonQSA for it:
+                        //              http://bugs.dojotoolkit.org/ticket/5179
+                        (query.indexOf(":contains") == -1) && (query.indexOf(":checked") == -1) &&
+                        (query.indexOf("|=") == -1) // some browsers don't grok it
+                );
+
+                // TODO:
+                //              if we've got a descendant query (e.g., "> .thinger" instead of
+                //              just ".thinger") in a QSA-able doc, but are passed a child as a
+                //              root, it should be possible to give the item a synthetic ID and
+                //              trivially rewrite the query to the form "#synid > .thinger" to
+                //              use the QSA branch
+
+
+                if(useQSA){
+                        var tq = (specials.indexOf(query.charAt(query.length-1)) >= 0) ?
+                                                (query + " *") : query;
+                        return _queryFuncCacheQSA[query] = function(root){
+                                try{
+                                        // the QSA system contains an egregious spec bug which
+                                        // limits us, effectively, to only running QSA queries over
+                                        // entire documents.  See:
+                                        //              http://ejohn.org/blog/thoughts-on-queryselectorall/
+                                        //      despite this, we can also handle QSA runs on simple
+                                        //      selectors, but we don't want detection to be expensive
+                                        //      so we're just checking for the presence of a space char
+                                        //      right now. Not elegant, but it's cheaper than running
+                                        //      the query parser when we might not need to
+                                        if(!((9 == root.nodeType) || nospace)){ throw ""; }
+                                        var r = root[qsa](tq);
+                                        // skip expensive duplication checks and just wrap in a NodeList
+                                        r[noZip] = true;
+                                        return r;
+                                }catch(e){
+                                        // else run the DOM branch on this query, ensuring that we
+                                        // default that way in the future
+                                        return getQueryFunc(query, true)(root);
+                                }
+                        }
+                }else{
+                        // DOM branch
+                        var parts = query.split(/\s*,\s*/);
+                        return _queryFuncCacheDOM[query] = ((parts.length < 2) ?
+                                // if not a compound query (e.g., ".foo, .bar"), cache and return a dispatcher
+                                getStepQueryFunc(query) :
+                                // if it *is* a complex query, break it up into its
+                                // constituent parts and return a dispatcher that will
+                                // merge the parts when run
+                                function(root){
+                                        var pindex = 0, // avoid array alloc for every invocation
+                                                ret = [],
+                                                tp;
+                                        while((tp = parts[pindex++])){
+                                                ret = ret.concat(getStepQueryFunc(tp)(root));
+                                        }
+                                        return ret;
+                                }
+                        );
+                }
+        };
+
+        var _zipIdx = 0;
+
+        // NOTE:
+        //              this function is Moo inspired, but our own impl to deal correctly
+        //              with XML in IE
+        var _nodeUID = d.isIE ? function(node){
+                if(caseSensitive){
+                        // XML docs don't have uniqueID on their nodes
+                        return (node.getAttribute("_uid") || node.setAttribute("_uid", ++_zipIdx) || _zipIdx);
+
+                }else{
+                        return node.uniqueID;
+                }
+        } :
+        function(node){
+                return (node._uid || (node._uid = ++_zipIdx));
+        };
+
+        // determine if a node in is unique in a "bag". In this case we don't want
+        // to flatten a list of unique items, but rather just tell if the item in
+        // question is already in the bag. Normally we'd just use hash lookup to do
+        // this for us but IE's DOM is busted so we can't really count on that. On
+        // the upside, it gives us a built in unique ID function.
+        var _isUnique = function(node, bag){
+                if(!bag){ return 1; }
+                var id = _nodeUID(node);
+                if(!bag[id]){ return bag[id] = 1; }
+                return 0;
+        };
+
+        // attempt to efficiently determine if an item in a list is a dupe,
+        // returning a list of "uniques", hopefully in doucment order
+        var _zipIdxName = "_zipIdx";
+        var _zip = function(arr){
+                if(arr && arr.nozip){
+                        return (qlc._wrap) ? qlc._wrap(arr) : arr;
+                }
+                // var ret = new d._NodeListCtor();
+                var ret = new qlc();
+                if(!arr || !arr.length){ return ret; }
+                if(arr[0]){
+                        ret.push(arr[0]);
+                }
+                if(arr.length < 2){ return ret; }
+
+                _zipIdx++;
+                
+                // we have to fork here for IE and XML docs because we can't set
+                // expandos on their nodes (apparently). *sigh*
+                if(d.isIE && caseSensitive){
+                        var szidx = _zipIdx+"";
+                        arr[0].setAttribute(_zipIdxName, szidx);
+                        for(var x = 1, te; te = arr[x]; x++){
+                                if(arr[x].getAttribute(_zipIdxName) != szidx){
+                                        ret.push(te);
+                                }
+                                te.setAttribute(_zipIdxName, szidx);
+                        }
+                }else if(d.isIE && arr.commentStrip){
+                        try{
+                                for(var x = 1, te; te = arr[x]; x++){
+                                        if(_isElement(te)){
+                                                ret.push(te);
+                                        }
+                                }
+                        }catch(e){ /* squelch */ }
+                }else{
+                        if(arr[0]){ arr[0][_zipIdxName] = _zipIdx; }
+                        for(var x = 1, te; te = arr[x]; x++){
+                                if(arr[x][_zipIdxName] != _zipIdx){
+                                        ret.push(te);
+                                }
+                                te[_zipIdxName] = _zipIdx;
+                        }
+                }
+                return ret;
+        };
+
+        // the main executor
+        d.query = function(/*String*/ query, /*String|DOMNode?*/ root){
+                //      summary:
+                //              Returns nodes which match the given CSS3 selector, searching the
+                //              entire document by default but optionally taking a node to scope
+                //              the search by. Returns an instance of dojo.NodeList.
+                //      description:
+                //              dojo.query() is the swiss army knife of DOM node manipulation in
+                //              Dojo. Much like Prototype's "$$" (bling-bling) function or JQuery's
+                //              "$" function, dojo.query provides robust, high-performance
+                //              CSS-based node selector support with the option of scoping searches
+                //              to a particular sub-tree of a document.
+                //
+                //              Supported Selectors:
+                //              --------------------
+                //
+                //              dojo.query() supports a rich set of CSS3 selectors, including:
+                //
+                //                      * class selectors (e.g., `.foo`)
+                //                      * node type selectors like `span`
+                //                      * ` ` descendant selectors
+                //                      * `>` child element selectors
+                //                      * `#foo` style ID selectors
+                //                      * `*` universal selector
+                //                      * `~`, the preceded-by sibling selector
+                //                      * `+`, the immediately preceded-by sibling selector
+                //                      * attribute queries:
+                //                      |       * `[foo]` attribute presence selector
+                //                      |       * `[foo='bar']` attribute value exact match
+                //                      |       * `[foo~='bar']` attribute value list item match
+                //                      |       * `[foo^='bar']` attribute start match
+                //                      |       * `[foo$='bar']` attribute end match
+                //                      |       * `[foo*='bar']` attribute substring match
+                //                      * `:first-child`, `:last-child`, and `:only-child` positional selectors
+                //                      * `:empty` content emtpy selector
+                //                      * `:checked` pseudo selector
+                //                      * `:nth-child(n)`, `:nth-child(2n+1)` style positional calculations
+                //                      * `:nth-child(even)`, `:nth-child(odd)` positional selectors
+                //                      * `:not(...)` negation pseudo selectors
+                //
+                //              Any legal combination of these selectors will work with
+                //              `dojo.query()`, including compound selectors ("," delimited).
+                //              Very complex and useful searches can be constructed with this
+                //              palette of selectors and when combined with functions for
+                //              manipulation presented by dojo.NodeList, many types of DOM
+                //              manipulation operations become very straightforward.
+                //
+                //              Unsupported Selectors:
+                //              ----------------------
+                //
+                //              While dojo.query handles many CSS3 selectors, some fall outside of
+                //              what's reasonable for a programmatic node querying engine to
+                //              handle. Currently unsupported selectors include:
+                //
+                //                      * namespace-differentiated selectors of any form
+                //                      * all `::` pseduo-element selectors
+                //                      * certain pseduo-selectors which don't get a lot of day-to-day use:
+                //                      |       * `:root`, `:lang()`, `:target`, `:focus`
+                //                      * all visual and state selectors:
+                //                      |       * `:root`, `:active`, `:hover`, `:visisted`, `:link`,
+                //                                `:enabled`, `:disabled`
+                //                      * `:*-of-type` pseudo selectors
+                //
+                //              dojo.query and XML Documents:
+                //              -----------------------------
+                //
+                //              `dojo.query` (as of dojo 1.2) supports searching XML documents
+                //              in a case-sensitive manner. If an HTML document is served with
+                //              a doctype that forces case-sensitivity (e.g., XHTML 1.1
+                //              Strict), dojo.query() will detect this and "do the right
+                //              thing". Case sensitivity is dependent upon the document being
+                //              searched and not the query used. It is therefore possible to
+                //              use case-sensitive queries on strict sub-documents (iframes,
+                //              etc.) or XML documents while still assuming case-insensitivity
+                //              for a host/root document.
+                //
+                //              Non-selector Queries:
+                //              ---------------------
+                //
+                //              If something other than a String is passed for the query,
+                //              `dojo.query` will return a new `dojo.NodeList` instance
+                //              constructed from that parameter alone and all further
+                //              processing will stop. This means that if you have a reference
+                //              to a node or NodeList, you can quickly construct a new NodeList
+                //              from the original by calling `dojo.query(node)` or
+                //              `dojo.query(list)`.
+                //
+                //      query:
+                //              The CSS3 expression to match against. For details on the syntax of
+                //              CSS3 selectors, see <http://www.w3.org/TR/css3-selectors/#selectors>
+                //      root:
+                //              A DOMNode (or node id) to scope the search from. Optional.
+                //      returns: dojo.NodeList
+                //              An instance of `dojo.NodeList`. Many methods are available on
+                //              NodeLists for searching, iterating, manipulating, and handling
+                //              events on the matched nodes in the returned list.
+                //      example:
+                //              search the entire document for elements with the class "foo":
+                //      |       dojo.query(".foo");
+                //              these elements will match:
+                //      |       <span class="foo"></span>
+                //      |       <span class="foo bar"></span>
+                //      |       <p class="thud foo"></p>
+                //      example:
+                //              search the entire document for elements with the classes "foo" *and* "bar":
+                //      |       dojo.query(".foo.bar");
+                //              these elements will match:
+                //      |       <span class="foo bar"></span>
+                //              while these will not:
+                //      |       <span class="foo"></span>
+                //      |       <p class="thud foo"></p>
+                //      example:
+                //              find `<span>` elements which are descendants of paragraphs and
+                //              which have a "highlighted" class:
+                //      |       dojo.query("p span.highlighted");
+                //              the innermost span in this fragment matches:
+                //      |       <p class="foo">
+                //      |               <span>...
+                //      |                       <span class="highlighted foo bar">...</span>
+                //      |               </span>
+                //      |       </p>
+                //      example:
+                //              set an "odd" class on all odd table rows inside of the table
+                //              `#tabular_data`, using the `>` (direct child) selector to avoid
+                //              affecting any nested tables:
+                //      |       dojo.query("#tabular_data > tbody > tr:nth-child(odd)").addClass("odd");
+                //      example:
+                //              remove all elements with the class "error" from the document
+                //              and store them in a list:
+                //      |       var errors = dojo.query(".error").orphan();
+                //      example:
+                //              add an onclick handler to every submit button in the document
+                //              which causes the form to be sent via Ajax instead:
+                //      |       dojo.query("input[type='submit']").onclick(function(e){
+                //      |               dojo.stopEvent(e); // prevent sending the form
+                //      |               var btn = e.target;
+                //      |               dojo.xhrPost({
+                //      |                       form: btn.form,
+                //      |                       load: function(data){
+                //      |                               // replace the form with the response
+                //      |                               var div = dojo.doc.createElement("div");
+                //      |                               dojo.place(div, btn.form, "after");
+                //      |                               div.innerHTML = data;
+                //      |                               dojo.style(btn.form, "display", "none");
+                //      |                       }
+                //      |               });
+                //      |       });
+
+                //Set list constructor to desired value. This can change
+                //between calls, so always re-assign here.
+                qlc = d._NodeListCtor;
+
+                if(!query){
+                        return new qlc();
+                }
+
+                if(query.constructor == qlc){
+                        return query;
+                }
+                if(typeof query != "string"){ // inline'd type check
+                        return new qlc(query); // dojo.NodeList
+                }
+                if(typeof root == "string"){ // inline'd type check
+                        root = d.byId(root);
+                        if(!root){ return new qlc(); }
+                }
+
+                root = root||getDoc();
+                var od = root.ownerDocument||root.documentElement;
+
+                // throw the big case sensitivity switch
+
+                // NOTE:
+                //              Opera in XHTML mode doesn't detect case-sensitivity correctly
+                //              and it's not clear that there's any way to test for it
+                caseSensitive = (root.contentType && root.contentType=="application/xml") ||
+                                                (d.isOpera && (root.doctype || od.toString() == "[object XMLDocument]")) ||
+                                                (!!od) &&
+                                                (d.isIE ? od.xml : (root.xmlVersion||od.xmlVersion));
+
+                // NOTE:
+                //              adding "true" as the 2nd argument to getQueryFunc is useful for
+                //              testing the DOM branch without worrying about the
+                //              behavior/performance of the QSA branch.
+                var r = getQueryFunc(query)(root);
+
+                // FIXME:
+                //              need to investigate this branch WRT #8074 and #8075
+                if(r && r.nozip && !qlc._wrap){
+                        return r;
+                }
+                return _zip(r); // dojo.NodeList
+        }
+
+        // FIXME: need to add infrastructure for post-filtering pseudos, ala :last
+        d.query.pseudos = pseudos;
+
+        // function for filtering a NodeList based on a selector, optimized for simple selectors
+        d._filterQueryResult = function(/*NodeList*/ nodeList, /*String*/ filter, /*String|DOMNode?*/ root){
+                var tmpNodeList = new d._NodeListCtor(),
+                        parts = getQueryParts(filter),
+                        filterFunc =
+                                (parts.length == 1 && !/[^\w#\.]/.test(filter)) ?
+                                getSimpleFilterFunc(parts[0]) :
+                                function(node) {
+                                        return dojo.query(filter, root).indexOf(node) != -1;
+                                };
+                for(var x = 0, te; te = nodeList[x]; x++){
+                        if(filterFunc(te)){ tmpNodeList.push(te); }
+                }
+                return tmpNodeList;
+        }
+};//end defineQuery
+
+var defineAcme= function(){
+        // a self-sufficient query impl
+        acme = {
+                trim: function(/*String*/ str){
+                        // summary:
+                        //              trims whitespaces from both sides of the string
+                        str = str.replace(/^\s+/, '');
+                        for(var i = str.length - 1; i >= 0; i--){
+                                if(/\S/.test(str.charAt(i))){
+                                        str = str.substring(0, i + 1);
+                                        break;
+                                }
+                        }
+                        return str;     // String
+                },
+                forEach: function(/*String*/ arr, /*Function*/ callback, /*Object?*/ thisObject){
+                        //      summary:
+                        //              an iterator function that passes items, indexes,
+                        //              and the array to a callback
+                        if(!arr || !arr.length){ return; }
+                        for(var i=0,l=arr.length; i<l; ++i){
+                                callback.call(thisObject||window, arr[i], i, arr);
+                        }
+                },
+                byId: function(id, doc){
+                        //      summary:
+                        //              a function that return an element by ID, but also
+                        //              accepts nodes safely
+                        if(typeof id == "string"){
+                                return (doc||document).getElementById(id); // DomNode
+                        }else{
+                                return id; // DomNode
+                        }
+                },
+                // the default document to search
+                doc: document,
+                // the constructor for node list objects returned from query()
+                NodeList: Array
+        };
+
+        // define acme.isIE, acme.isSafari, acme.isOpera, etc.
+        var n = navigator;
+        var dua = n.userAgent;
+        var dav = n.appVersion;
+        var tv = parseFloat(dav);
+        acme.isOpera = (dua.indexOf("Opera") >= 0) ? tv: undefined;
+        acme.isKhtml = (dav.indexOf("Konqueror") >= 0) ? tv : undefined;
+        acme.isWebKit = parseFloat(dua.split("WebKit/")[1]) || undefined;
+        acme.isChrome = parseFloat(dua.split("Chrome/")[1]) || undefined;
+        var index = Math.max(dav.indexOf("WebKit"), dav.indexOf("Safari"), 0);
+        if(index && !acme.isChrome){
+                acme.isSafari = parseFloat(dav.split("Version/")[1]);
+                if(!acme.isSafari || parseFloat(dav.substr(index + 7)) <= 419.3){
+                        acme.isSafari = 2;
+                }
+        }
+        if(document.all && !acme.isOpera){
+                acme.isIE = parseFloat(dav.split("MSIE ")[1]) || undefined;
+        }
+
+        Array._wrap = function(arr){ return arr; };
+  return acme;
+};
+
+        //prefers queryPortability, then acme, then dojo
+        if(this["dojo"]){
+                dojo.provide("dojo._base.query");
+                
+                
+                defineQuery(this["queryPortability"]||this["acme"]||dojo);
+        }else{
+                defineQuery(this["queryPortability"]||this["acme"]||defineAcme());
+        }
+
+})();
+
+/*
+*/
+
+}
+
+if(!dojo._hasResource["dojo._base.xhr"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dojo._base.xhr"] = true;
+dojo.provide("dojo._base.xhr");
+
+
+
+
+
+
+(function(){
+        var _d = dojo, cfg = _d.config;
+
+        function setValue(/*Object*/obj, /*String*/name, /*String*/value){
+                //summary:
+                //              For the named property in object, set the value. If a value
+                //              already exists and it is a string, convert the value to be an
+                //              array of values.
+
+                //Skip it if there is no value
+                if(value === null){
+                        return;
+                }
+
+                var val = obj[name];
+                if(typeof val == "string"){ // inline'd type check
+                        obj[name] = [val, value];
+                }else if(_d.isArray(val)){
+                        val.push(value);
+                }else{
+                        obj[name] = value;
+                }
+        }
+        
+        dojo.fieldToObject = function(/*DOMNode||String*/ inputNode){
+                // summary:
+                //              Serialize a form field to a JavaScript object.
+                //
+                // description:
+                //              Returns the value encoded in a form field as
+                //              as a string or an array of strings. Disabled form elements
+                //              and unchecked radio and checkboxes are skipped. Multi-select
+                //              elements are returned as an array of string values.
+                var ret = null;
+                var item = _d.byId(inputNode);
+                if(item){
+                        var _in = item.name;
+                        var type = (item.type||"").toLowerCase();
+                        if(_in && type && !item.disabled){
+                                if(type == "radio" || type == "checkbox"){
+                                        if(item.checked){ ret = item.value; }
+                                }else if(item.multiple){
+                                        ret = [];
+                                        _d.query("option", item).forEach(function(opt){
+                                                if(opt.selected){
+                                                        ret.push(opt.value);
+                                                }
+                                        });
+                                }else{
+                                        ret = item.value;
+                                }
+                        }
+                }
+                return ret; // Object
+        };
+
+        dojo.formToObject = function(/*DOMNode||String*/ formNode){
+                // summary:
+                //              Serialize a form node to a JavaScript object.
+                // description:
+                //              Returns the values encoded in an HTML form as
+                //              string properties in an object which it then returns. Disabled form
+                //              elements, buttons, and other non-value form elements are skipped.
+                //              Multi-select elements are returned as an array of string values.
+                //
+                // example:
+                //              This form:
+                //              |       <form id="test_form">
+                //              |               <input type="text" name="blah" value="blah">
+                //              |               <input type="text" name="no_value" value="blah" disabled>
+                //              |               <input type="button" name="no_value2" value="blah">
+                //              |               <select type="select" multiple name="multi" size="5">
+                //              |                       <option value="blah">blah</option>
+                //              |                       <option value="thud" selected>thud</option>
+                //              |                       <option value="thonk" selected>thonk</option>
+                //              |               </select>
+                //              |       </form>
+                //
+                //              yields this object structure as the result of a call to
+                //              formToObject():
+                //
+                //              |       {
+                //              |               blah: "blah",
+                //              |               multi: [
+                //              |                       "thud",
+                //              |                       "thonk"
+                //              |               ]
+                //              |       };
+
+                var ret = {};
+                var exclude = "file|submit|image|reset|button|";
+                _d.forEach(dojo.byId(formNode).elements, function(item){
+                        var _in = item.name;
+                        var type = (item.type||"").toLowerCase();
+                        if(_in && type && exclude.indexOf(type) == -1 && !item.disabled){
+                                setValue(ret, _in, _d.fieldToObject(item));
+                                if(type == "image"){
+                                        ret[_in+".x"] = ret[_in+".y"] = ret[_in].x = ret[_in].y = 0;
+                                }
+                        }
+                });
+                return ret; // Object
+        };
+
+        dojo.objectToQuery = function(/*Object*/ map){
+                //      summary:
+                //              takes a name/value mapping object and returns a string representing
+                //              a URL-encoded version of that object.
+                //      example:
+                //              this object:
+                //
+                //              |       {
+                //              |               blah: "blah",
+                //              |               multi: [
+                //              |                       "thud",
+                //              |                       "thonk"
+                //              |               ]
+                //              |       };
+                //
+                //      yields the following query string:
+                //
+                //      |       "blah=blah&multi=thud&multi=thonk"
+
+                // FIXME: need to implement encodeAscii!!
+                var enc = encodeURIComponent;
+                var pairs = [];
+                var backstop = {};
+                for(var name in map){
+                        var value = map[name];
+                        if(value != backstop[name]){
+                                var assign = enc(name) + "=";
+                                if(_d.isArray(value)){
+                                        for(var i=0; i < value.length; i++){
+                                                pairs.push(assign + enc(value[i]));
+                                        }
+                                }else{
+                                        pairs.push(assign + enc(value));
+                                }
+                        }
+                }
+                return pairs.join("&"); // String
+        };
+
+        dojo.formToQuery = function(/*DOMNode||String*/ formNode){
+                // summary:
+                //              Returns a URL-encoded string representing the form passed as either a
+                //              node or string ID identifying the form to serialize
+                return _d.objectToQuery(_d.formToObject(formNode)); // String
+        };
+
+        dojo.formToJson = function(/*DOMNode||String*/ formNode, /*Boolean?*/prettyPrint){
+                // summary:
+                //              Create a serialized JSON string from a form node or string
+                //              ID identifying the form to serialize
+                return _d.toJson(_d.formToObject(formNode), prettyPrint); // String
+        };
+
+        dojo.queryToObject = function(/*String*/ str){
+                // summary:
+                //              Create an object representing a de-serialized query section of a
+                //              URL. Query keys with multiple values are returned in an array.
+                //
+                // example:
+                //              This string:
+                //
+                //      |               "foo=bar&foo=baz&thinger=%20spaces%20=blah&zonk=blarg&"
+                //
+                //              results in this object structure:
+                //
+                //      |               {
+                //      |                       foo: [ "bar", "baz" ],
+                //      |                       thinger: " spaces =blah",
+                //      |                       zonk: "blarg"
+                //      |               }
+                //
+                //              Note that spaces and other urlencoded entities are correctly
+                //              handled.
+
+                // FIXME: should we grab the URL string if we're not passed one?
+                var ret = {};
+                var qp = str.split("&");
+                var dec = decodeURIComponent;
+                _d.forEach(qp, function(item){
+                        if(item.length){
+                                var parts = item.split("=");
+                                var name = dec(parts.shift());
+                                var val = dec(parts.join("="));
+                                if(typeof ret[name] == "string"){ // inline'd type check
+                                        ret[name] = [ret[name]];
+                                }
+
+                                if(_d.isArray(ret[name])){
+                                        ret[name].push(val);
+                                }else{
+                                        ret[name] = val;
+                                }
+                        }
+                });
+                return ret; // Object
+        };
+
+        // need to block async callbacks from snatching this thread as the result
+        // of an async callback might call another sync XHR, this hangs khtml forever
+        // must checked by watchInFlight()
+
+        dojo._blockAsync = false;
+
+        // MOW: remove dojo._contentHandlers alias in 2.0
+        var handlers = _d._contentHandlers = dojo.contentHandlers = {
+                // summary:
+                //              A map of availble XHR transport handle types. Name matches the
+                //              `handleAs` attribute passed to XHR calls.
+                //
+                // description:
+                //              A map of availble XHR transport handle types. Name matches the
+                //              `handleAs` attribute passed to XHR calls. Each contentHandler is
+                //              called, passing the xhr object for manipulation. The return value
+                //              from the contentHandler will be passed to the `load` or `handle`
+                //              functions defined in the original xhr call.
+                //
+                // example:
+                //              Creating a custom content-handler:
+                //      |       dojo.contentHandlers.makeCaps = function(xhr){
+                //      |               return xhr.responseText.toUpperCase();
+                //      |       }
+                //      |       // and later:
+                //      |       dojo.xhrGet({
+                //      |               url:"foo.txt",
+                //      |               handleAs:"makeCaps",
+                //      |               load: function(data){ /* data is a toUpper version of foo.txt */ }
+                //      |       });
+
+                text: function(xhr){
+                        // summary: A contentHandler which simply returns the plaintext response data
+                        return xhr.responseText;
+                },
+                json: function(xhr){
+                        // summary: A contentHandler which returns a JavaScript object created from the response data
+                        return _d.fromJson(xhr.responseText || null);
+                },
+                "json-comment-filtered": function(xhr){
+                        // summary: A contentHandler which expects comment-filtered JSON.
+                        // description:
+                        //              A contentHandler which expects comment-filtered JSON.
+                        //              the json-comment-filtered option was implemented to prevent
+                        //              "JavaScript Hijacking", but it is less secure than standard JSON. Use
+                        //              standard JSON instead. JSON prefixing can be used to subvert hijacking.
+                        //
+                        //              Will throw a notice suggesting to use application/json mimetype, as
+                        //              json-commenting can introduce security issues. To decrease the chances of hijacking,
+                        //              use the standard `json` contentHandler, and prefix your "JSON" with: {}&&
+                        //
+                        //              use djConfig.useCommentedJson = true to turn off the notice
+                        if(!dojo.config.useCommentedJson){
+                                console.warn("Consider using the standard mimetype:application/json."
+                                        + " json-commenting can introduce security issues. To"
+                                        + " decrease the chances of hijacking, use the standard the 'json' handler and"
+                                        + " prefix your json with: {}&&\n"
+                                        + "Use djConfig.useCommentedJson=true to turn off this message.");
+                        }
+
+                        var value = xhr.responseText;
+                        var cStartIdx = value.indexOf("\/*");
+                        var cEndIdx = value.lastIndexOf("*\/");
+                        if(cStartIdx == -1 || cEndIdx == -1){
+                                throw new Error("JSON was not comment filtered");
+                        }
+                        return _d.fromJson(value.substring(cStartIdx+2, cEndIdx));
+                },
+                javascript: function(xhr){
+                        // summary: A contentHandler which evaluates the response data, expecting it to be valid JavaScript
+
+                        // FIXME: try Moz and IE specific eval variants?
+                        return _d.eval(xhr.responseText);
+                },
+                xml: function(xhr){
+                        // summary: A contentHandler returning an XML Document parsed from the response data
+                        var result = xhr.responseXML;
+                                                if(_d.isIE && (!result || !result.documentElement)){
+                                //WARNING: this branch used by the xml handling in dojo.io.iframe,
+                                //so be sure to test dojo.io.iframe if making changes below.
+                                var ms = function(n){ return "MSXML" + n + ".DOMDocument"; };
+                                var dp = ["Microsoft.XMLDOM", ms(6), ms(4), ms(3), ms(2)];
+                                _d.some(dp, function(p){
+                                        try{
+                                                var dom = new ActiveXObject(p);
+                                                dom.async = false;
+                                                dom.loadXML(xhr.responseText);
+                                                result = dom;
+                                        }catch(e){ return false; }
+                                        return true;
+                                });
+                        }
+                                                return result; // DOMDocument
+                },
+                "json-comment-optional": function(xhr){
+                        // summary: A contentHandler which checks the presence of comment-filtered JSON and
+                        //              alternates between the `json` and `json-comment-filtered` contentHandlers.
+                        if(xhr.responseText && /^[^{\[]*\/\*/.test(xhr.responseText)){
+                                return handlers["json-comment-filtered"](xhr);
+                        }else{
+                                return handlers["json"](xhr);
+                        }
+                }
+        };
+
+        /*=====
+        dojo.__IoArgs = function(){
+                //      url: String
+                //              URL to server endpoint.
+                //      content: Object?
+                //              Contains properties with string values. These
+                //              properties will be serialized as name1=value2 and
+                //              passed in the request.
+                //      timeout: Integer?
+                //              Milliseconds to wait for the response. If this time
+                //              passes, the then error callbacks are called.
+                //      form: DOMNode?
+                //              DOM node for a form. Used to extract the form values
+                //              and send to the server.
+                //      preventCache: Boolean?
+                //              Default is false. If true, then a
+                //              "dojo.preventCache" parameter is sent in the request
+                //              with a value that changes with each request
+                //              (timestamp). Useful only with GET-type requests.
+                //      handleAs: String?
+                //              Acceptable values depend on the type of IO
+                //              transport (see specific IO calls for more information).
+                //      rawBody: String?
+                //              Sets the raw body for an HTTP request. If this is used, then the content
+                //              property is ignored. This is mostly useful for HTTP methods that have
+                //              a body to their requests, like PUT or POST. This property can be used instead
+                //              of postData and putData for dojo.rawXhrPost and dojo.rawXhrPut respectively.
+                //      ioPublish: Boolean?
+                //              Set this explicitly to false to prevent publishing of topics related to
+                //              IO operations. Otherwise, if djConfig.ioPublish is set to true, topics
+                //              will be published via dojo.publish for different phases of an IO operation.
+                //              See dojo.__IoPublish for a list of topics that are published.
+                //      load: Function?
+                //              This function will be
+                //              called on a successful HTTP response code.
+                //      error: Function?
+                //              This function will
+                //              be called when the request fails due to a network or server error, the url
+                //              is invalid, etc. It will also be called if the load or handle callback throws an
+                //              exception, unless djConfig.debugAtAllCosts is true.  This allows deployed applications
+                //              to continue to run even when a logic error happens in the callback, while making
+                //              it easier to troubleshoot while in debug mode.
+                //      handle: Function?
+                //              This function will
+                //              be called at the end of every request, whether or not an error occurs.
+                this.url = url;
+                this.content = content;
+                this.timeout = timeout;
+                this.form = form;
+                this.preventCache = preventCache;
+                this.handleAs = handleAs;
+                this.ioPublish = ioPublish;
+                this.load = function(response, ioArgs){
+                        // ioArgs: dojo.__IoCallbackArgs
+                        //              Provides additional information about the request.
+                        // response: Object
+                        //              The response in the format as defined with handleAs.
+                }
+                this.error = function(response, ioArgs){
+                        // ioArgs: dojo.__IoCallbackArgs
+                        //              Provides additional information about the request.
+                        // response: Object
+                        //              The response in the format as defined with handleAs.
+                }
+                this.handle = function(loadOrError, response, ioArgs){
+                        // loadOrError: String
+                        //              Provides a string that tells you whether this function
+                        //              was called because of success (load) or failure (error).
+                        // response: Object
+                        //              The response in the format as defined with handleAs.
+                        // ioArgs: dojo.__IoCallbackArgs
+                        //              Provides additional information about the request.
+                }
+        }
+        =====*/
+
+        /*=====
+        dojo.__IoCallbackArgs = function(args, xhr, url, query, handleAs, id, canDelete, json){
+                //      args: Object
+                //              the original object argument to the IO call.
+                //      xhr: XMLHttpRequest
+                //              For XMLHttpRequest calls only, the
+                //              XMLHttpRequest object that was used for the
+                //              request.
+                //      url: String
+                //              The final URL used for the call. Many times it
+                //              will be different than the original args.url
+                //              value.
+                //      query: String
+                //              For non-GET requests, the
+                //              name1=value1&name2=value2 parameters sent up in
+                //              the request.
+                //      handleAs: String
+                //              The final indicator on how the response will be
+                //              handled.
+                //      id: String
+                //              For dojo.io.script calls only, the internal
+                //              script ID used for the request.
+                //      canDelete: Boolean
+                //              For dojo.io.script calls only, indicates
+                //              whether the script tag that represents the
+                //              request can be deleted after callbacks have
+                //              been called. Used internally to know when
+                //              cleanup can happen on JSONP-type requests.
+                //      json: Object
+                //              For dojo.io.script calls only: holds the JSON
+                //              response for JSONP-type requests. Used
+                //              internally to hold on to the JSON responses.
+                //              You should not need to access it directly --
+                //              the same object should be passed to the success
+                //              callbacks directly.
+                this.args = args;
+                this.xhr = xhr;
+                this.url = url;
+                this.query = query;
+                this.handleAs = handleAs;
+                this.id = id;
+                this.canDelete = canDelete;
+                this.json = json;
+        }
+        =====*/
+
+
+        /*=====
+        dojo.__IoPublish = function(){
+                //      summary:
+                //              This is a list of IO topics that can be published
+                //              if djConfig.ioPublish is set to true. IO topics can be
+                //              published for any Input/Output, network operation. So,
+                //              dojo.xhr, dojo.io.script and dojo.io.iframe can all
+                //              trigger these topics to be published.
+                //      start: String
+                //              "/dojo/io/start" is sent when there are no outstanding IO
+                //              requests, and a new IO request is started. No arguments
+                //              are passed with this topic.
+                //      send: String
+                //              "/dojo/io/send" is sent whenever a new IO request is started.
+                //              It passes the dojo.Deferred for the request with the topic.
+                //      load: String
+                //              "/dojo/io/load" is sent whenever an IO request has loaded
+                //              successfully. It passes the response and the dojo.Deferred
+                //              for the request with the topic.
+                //      error: String
+                //              "/dojo/io/error" is sent whenever an IO request has errored.
+                //              It passes the error and the dojo.Deferred
+                //              for the request with the topic.
+                //      done: String
+                //              "/dojo/io/done" is sent whenever an IO request has completed,
+                //              either by loading or by erroring. It passes the error and
+                //              the dojo.Deferred for the request with the topic.
+                //      stop: String
+                //              "/dojo/io/stop" is sent when all outstanding IO requests have
+                //              finished. No arguments are passed with this topic.
+                this.start = "/dojo/io/start";
+                this.send = "/dojo/io/send";
+                this.load = "/dojo/io/load";
+                this.error = "/dojo/io/error";
+                this.done = "/dojo/io/done";
+                this.stop = "/dojo/io/stop";
+        }
+        =====*/
+
+
+        dojo._ioSetArgs = function(/*dojo.__IoArgs*/args,
+                        /*Function*/canceller,
+                        /*Function*/okHandler,
+                        /*Function*/errHandler){
+                //      summary:
+                //              sets up the Deferred and ioArgs property on the Deferred so it
+                //              can be used in an io call.
+                //      args:
+                //              The args object passed into the public io call. Recognized properties on
+                //              the args object are:
+                //      canceller:
+                //              The canceller function used for the Deferred object. The function
+                //              will receive one argument, the Deferred object that is related to the
+                //              canceller.
+                //      okHandler:
+                //              The first OK callback to be registered with Deferred. It has the opportunity
+                //              to transform the OK response. It will receive one argument -- the Deferred
+                //              object returned from this function.
+                //      errHandler:
+                //              The first error callback to be registered with Deferred. It has the opportunity
+                //              to do cleanup on an error. It will receive two arguments: error (the
+                //              Error object) and dfd, the Deferred object returned from this function.
+
+                var ioArgs = {args: args, url: args.url};
+
+                //Get values from form if requestd.
+                var formObject = null;
+                if(args.form){
+                        var form = _d.byId(args.form);
+                        //IE requires going through getAttributeNode instead of just getAttribute in some form cases,
+                        //so use it for all.  See #2844
+                        var actnNode = form.getAttributeNode("action");
+                        ioArgs.url = ioArgs.url || (actnNode ? actnNode.value : null);
+                        formObject = _d.formToObject(form);
+                }
+
+                // set up the query params
+                var miArgs = [{}];
+        
+                if(formObject){
+                        // potentially over-ride url-provided params w/ form values
+                        miArgs.push(formObject);
+                }
+                if(args.content){
+                        // stuff in content over-rides what's set by form
+                        miArgs.push(args.content);
+                }
+                if(args.preventCache){
+                        miArgs.push({"dojo.preventCache": new Date().valueOf()});
+                }
+                ioArgs.query = _d.objectToQuery(_d.mixin.apply(null, miArgs));
+        
+                // .. and the real work of getting the deferred in order, etc.
+                ioArgs.handleAs = args.handleAs || "text";
+                var d = new _d.Deferred(canceller);
+                d.addCallbacks(okHandler, function(error){
+                        return errHandler(error, d);
+                });
+
+                //Support specifying load, error and handle callback functions from the args.
+                //For those callbacks, the "this" object will be the args object.
+                //The callbacks will get the deferred result value as the
+                //first argument and the ioArgs object as the second argument.
+                var ld = args.load;
+                if(ld && _d.isFunction(ld)){
+                        d.addCallback(function(value){
+                                return ld.call(args, value, ioArgs);
+                        });
+                }
+                var err = args.error;
+                if(err && _d.isFunction(err)){
+                        d.addErrback(function(value){
+                                return err.call(args, value, ioArgs);
+                        });
+                }
+                var handle = args.handle;
+                if(handle && _d.isFunction(handle)){
+                        d.addBoth(function(value){
+                                return handle.call(args, value, ioArgs);
+                        });
+                }
+
+                //Plug in topic publishing, if dojo.publish is loaded.
+                if(cfg.ioPublish && _d.publish && ioArgs.args.ioPublish !== false){
+                        d.addCallbacks(
+                                function(res){
+                                        _d.publish("/dojo/io/load", [d, res]);
+                                        return res;
+                                },
+                                function(res){
+                                        _d.publish("/dojo/io/error", [d, res]);
+                                        return res;
+                                }
+                        );
+                        d.addBoth(function(res){
+                                _d.publish("/dojo/io/done", [d, res]);
+                                return res;
+                        });
+                }
+
+                d.ioArgs = ioArgs;
+        
+                // FIXME: need to wire up the xhr object's abort method to something
+                // analagous in the Deferred
+                return d;
+        };
+
+        var _deferredCancel = function(/*Deferred*/dfd){
+                // summary: canceller function for dojo._ioSetArgs call.
+                
+                dfd.canceled = true;
+                var xhr = dfd.ioArgs.xhr;
+                var _at = typeof xhr.abort;
+                if(_at == "function" || _at == "object" || _at == "unknown"){
+                        xhr.abort();
+                }
+                var err = dfd.ioArgs.error;
+                if(!err){
+                        err = new Error("xhr cancelled");
+                        err.dojoType="cancel";
+                }
+                return err;
+        };
+        var _deferredOk = function(/*Deferred*/dfd){
+                // summary: okHandler function for dojo._ioSetArgs call.
+
+                var ret = handlers[dfd.ioArgs.handleAs](dfd.ioArgs.xhr);
+                return ret === undefined ? null : ret;
+        };
+        var _deferError = function(/*Error*/error, /*Deferred*/dfd){
+                // summary: errHandler function for dojo._ioSetArgs call.
+
+                if(!dfd.ioArgs.args.failOk){
+                        console.error(error);
+                }
+                return error;
+        };
+
+        // avoid setting a timer per request. It degrades performance on IE
+        // something fierece if we don't use unified loops.
+        var _inFlightIntvl = null;
+        var _inFlight = [];
+        
+        
+        //Use a separate count for knowing if we are starting/stopping io calls.
+        //Cannot use _inFlight.length since it can change at a different time than
+        //when we want to do this kind of test. We only want to decrement the count
+        //after a callback/errback has finished, since the callback/errback should be
+        //considered as part of finishing a request.
+        var _pubCount = 0;
+        var _checkPubCount = function(dfd){
+                if(_pubCount <= 0){
+                        _pubCount = 0;
+                        if(cfg.ioPublish && _d.publish && (!dfd || dfd && dfd.ioArgs.args.ioPublish !== false)){
+                                _d.publish("/dojo/io/stop");
+                        }
+                }
+        };
+
+        var _watchInFlight = function(){
+                //summary:
+                //              internal method that checks each inflight XMLHttpRequest to see
+                //              if it has completed or if the timeout situation applies.
+                
+                var now = (new Date()).getTime();
+                // make sure sync calls stay thread safe, if this callback is called
+                // during a sync call and this results in another sync call before the
+                // first sync call ends the browser hangs
+                if(!_d._blockAsync){
+                        // we need manual loop because we often modify _inFlight (and therefore 'i') while iterating
+                        // note: the second clause is an assigment on purpose, lint may complain
+                        for(var i = 0, tif; i < _inFlight.length && (tif = _inFlight[i]); i++){
+                                var dfd = tif.dfd;
+                                var func = function(){
+                                        if(!dfd || dfd.canceled || !tif.validCheck(dfd)){
+                                                _inFlight.splice(i--, 1);
+                                                _pubCount -= 1;
+                                        }else if(tif.ioCheck(dfd)){
+                                                _inFlight.splice(i--, 1);
+                                                tif.resHandle(dfd);
+                                                _pubCount -= 1;
+                                        }else if(dfd.startTime){
+                                                //did we timeout?
+                                                if(dfd.startTime + (dfd.ioArgs.args.timeout || 0) < now){
+                                                        _inFlight.splice(i--, 1);
+                                                        var err = new Error("timeout exceeded");
+                                                        err.dojoType = "timeout";
+                                                        dfd.errback(err);
+                                                        //Cancel the request so the io module can do appropriate cleanup.
+                                                        dfd.cancel();
+                                                        _pubCount -= 1;
+                                                }
+                                        }
+                                };
+                                if(dojo.config.debugAtAllCosts){
+                                        func.call(this);
+                                }else{
+                                        try{
+                                                func.call(this);
+                                        }catch(e){
+                                                dfd.errback(e);
+                                        }
+                                }
+                        }
+                }
+
+                _checkPubCount(dfd);
+
+                if(!_inFlight.length){
+                        clearInterval(_inFlightIntvl);
+                        _inFlightIntvl = null;
+                        return;
+                }
+        };
+
+        dojo._ioCancelAll = function(){
+                //summary: Cancels all pending IO requests, regardless of IO type
+                //(xhr, script, iframe).
+                try{
+                        _d.forEach(_inFlight, function(i){
+                                try{
+                                        i.dfd.cancel();
+                                }catch(e){/*squelch*/}
+                        });
+                }catch(e){/*squelch*/}
+        };
+
+        //Automatically call cancel all io calls on unload
+        //in IE for trac issue #2357.
+                if(_d.isIE){
+                _d.addOnWindowUnload(_d._ioCancelAll);
+        }
+        
+        _d._ioNotifyStart = function(/*Deferred*/dfd){
+                // summary:
+                //              If dojo.publish is available, publish topics
+                //              about the start of a request queue and/or the
+                //              the beginning of request.
+                // description:
+                //              Used by IO transports. An IO transport should
+                //              call this method before making the network connection.
+                if(cfg.ioPublish && _d.publish && dfd.ioArgs.args.ioPublish !== false){
+                        if(!_pubCount){
+                                _d.publish("/dojo/io/start");
+                        }
+                        _pubCount += 1;
+                        _d.publish("/dojo/io/send", [dfd]);
+                }
+        };
+
+        _d._ioWatch = function(dfd, validCheck, ioCheck, resHandle){
+                // summary:
+                //              Watches the io request represented by dfd to see if it completes.
+                // dfd: Deferred
+                //              The Deferred object to watch.
+                // validCheck: Function
+                //              Function used to check if the IO request is still valid. Gets the dfd
+                //              object as its only argument.
+                // ioCheck: Function
+                //              Function used to check if basic IO call worked. Gets the dfd
+                //              object as its only argument.
+                // resHandle: Function
+                //              Function used to process response. Gets the dfd
+                //              object as its only argument.
+                var args = dfd.ioArgs.args;
+                if(args.timeout){
+                        dfd.startTime = (new Date()).getTime();
+                }
+                
+                _inFlight.push({dfd: dfd, validCheck: validCheck, ioCheck: ioCheck, resHandle: resHandle});
+                if(!_inFlightIntvl){
+                        _inFlightIntvl = setInterval(_watchInFlight, 50);
+                }
+                // handle sync requests
+                //A weakness: async calls in flight
+                //could have their handlers called as part of the
+                //_watchInFlight call, before the sync's callbacks
+                // are called.
+                if(args.sync){
+                        _watchInFlight();
+                }
+        };
+
+        var _defaultContentType = "application/x-www-form-urlencoded";
+
+        var _validCheck = function(/*Deferred*/dfd){
+                return dfd.ioArgs.xhr.readyState; //boolean
+        };
+        var _ioCheck = function(/*Deferred*/dfd){
+                return 4 == dfd.ioArgs.xhr.readyState; //boolean
+        };
+        var _resHandle = function(/*Deferred*/dfd){
+                var xhr = dfd.ioArgs.xhr;
+                if(_d._isDocumentOk(xhr)){
+                        dfd.callback(dfd);
+                }else{
+                        var err = new Error("Unable to load " + dfd.ioArgs.url + " status:" + xhr.status);
+                        err.status = xhr.status;
+                        err.responseText = xhr.responseText;
+                        dfd.errback(err);
+                }
+        };
+
+        dojo._ioAddQueryToUrl = function(/*dojo.__IoCallbackArgs*/ioArgs){
+                //summary: Adds query params discovered by the io deferred construction to the URL.
+                //Only use this for operations which are fundamentally GET-type operations.
+                if(ioArgs.query.length){
+                        ioArgs.url += (ioArgs.url.indexOf("?") == -1 ? "?" : "&") + ioArgs.query;
+                        ioArgs.query = null;
+                }
+        };
+
+        /*=====
+        dojo.declare("dojo.__XhrArgs", dojo.__IoArgs, {
+                constructor: function(){
+                        //      summary:
+                        //              In addition to the properties listed for the dojo._IoArgs type,
+                        //              the following properties are allowed for dojo.xhr* methods.
+                        //      handleAs: String?
+                        //              Acceptable values are: text (default), json, json-comment-optional,
+                        //              json-comment-filtered, javascript, xml. See `dojo.contentHandlers`
+                        //      sync: Boolean?
+                        //              false is default. Indicates whether the request should
+                        //              be a synchronous (blocking) request.
+                        //      headers: Object?
+                        //              Additional HTTP headers to send in the request.
+                        //      failOk: Boolean?
+                        //              false is default. Indicates whether a request should be
+                        //              allowed to fail (and therefore no console error message in
+                        //              the event of a failure)
+                        this.handleAs = handleAs;
+                        this.sync = sync;
+                        this.headers = headers;
+                        this.failOk = failOk;
+                }
+        });
+        =====*/
+
+        dojo.xhr = function(/*String*/ method, /*dojo.__XhrArgs*/ args, /*Boolean?*/ hasBody){
+                //      summary:
+                //              Sends an HTTP request with the given method.
+                //      description:
+                //              Sends an HTTP request with the given method.
+                //              See also dojo.xhrGet(), xhrPost(), xhrPut() and dojo.xhrDelete() for shortcuts
+                //              for those HTTP methods. There are also methods for "raw" PUT and POST methods
+                //              via dojo.rawXhrPut() and dojo.rawXhrPost() respectively.
+                //      method:
+                //              HTTP method to be used, such as GET, POST, PUT, DELETE.  Should be uppercase.
+                //      hasBody:
+                //              If the request has an HTTP body, then pass true for hasBody.
+
+                //Make the Deferred object for this xhr request.
+                var dfd = _d._ioSetArgs(args, _deferredCancel, _deferredOk, _deferError);
+                var ioArgs = dfd.ioArgs;
+
+                //Pass the args to _xhrObj, to allow alternate XHR calls based specific calls, like
+                //the one used for iframe proxies.
+                var xhr = ioArgs.xhr = _d._xhrObj(ioArgs.args);
+                //If XHR factory fails, cancel the deferred.
+                if(!xhr){
+                        dfd.cancel();
+                        return dfd;
+                }
+
+                //Allow for specifying the HTTP body completely.
+                if("postData" in args){
+                        ioArgs.query = args.postData;
+                }else if("putData" in args){
+                        ioArgs.query = args.putData;
+                }else if("rawBody" in args){
+                        ioArgs.query = args.rawBody;
+                }else if((arguments.length > 2 && !hasBody) || "POST|PUT".indexOf(method.toUpperCase()) == -1){
+                        //Check for hasBody being passed. If no hasBody,
+                        //then only append query string if not a POST or PUT request.
+                        _d._ioAddQueryToUrl(ioArgs);
+                }
+
+                // IE 6 is a steaming pile. It won't let you call apply() on the native function (xhr.open).
+                // workaround for IE6's apply() "issues"
+                xhr.open(method, ioArgs.url, args.sync !== true, args.user || undefined, args.password || undefined);
+                if(args.headers){
+                        for(var hdr in args.headers){
+                                if(hdr.toLowerCase() === "content-type" && !args.contentType){
+                                        args.contentType = args.headers[hdr];
+                                }else if(args.headers[hdr]){
+                                        //Only add header if it has a value. This allows for instnace, skipping
+                                        //insertion of X-Requested-With by specifying empty value.
+                                        xhr.setRequestHeader(hdr, args.headers[hdr]);
+                                }
+                        }
+                }
+                // FIXME: is this appropriate for all content types?
+                xhr.setRequestHeader("Content-Type", args.contentType || _defaultContentType);
+                if(!args.headers || !("X-Requested-With" in args.headers)){
+                        xhr.setRequestHeader("X-Requested-With", "XMLHttpRequest");
+                }
+                // FIXME: set other headers here!
+                _d._ioNotifyStart(dfd);
+                if(dojo.config.debugAtAllCosts){
+                        xhr.send(ioArgs.query);
+                }else{
+                        try{
+                                xhr.send(ioArgs.query);
+                        }catch(e){
+                                ioArgs.error = e;
+                                dfd.cancel();
+                        }
+                }
+                _d._ioWatch(dfd, _validCheck, _ioCheck, _resHandle);
+                xhr = null;
+                return dfd; // dojo.Deferred
+        };
+
+        dojo.xhrGet = function(/*dojo.__XhrArgs*/ args){
+                //      summary:
+                //              Sends an HTTP GET request to the server.
+                return _d.xhr("GET", args); // dojo.Deferred
+        };
+
+        dojo.rawXhrPost = dojo.xhrPost = function(/*dojo.__XhrArgs*/ args){
+                //      summary:
+                //              Sends an HTTP POST request to the server. In addtion to the properties
+                //              listed for the dojo.__XhrArgs type, the following property is allowed:
+                //      postData:
+                //              String. Send raw data in the body of the POST request.
+                return _d.xhr("POST", args, true); // dojo.Deferred
+        };
+
+        dojo.rawXhrPut = dojo.xhrPut = function(/*dojo.__XhrArgs*/ args){
+                //      summary:
+                //              Sends an HTTP PUT request to the server. In addtion to the properties
+                //              listed for the dojo.__XhrArgs type, the following property is allowed:
+                //      putData:
+                //              String. Send raw data in the body of the PUT request.
+                return _d.xhr("PUT", args, true); // dojo.Deferred
+        };
+
+        dojo.xhrDelete = function(/*dojo.__XhrArgs*/ args){
+                //      summary:
+                //              Sends an HTTP DELETE request to the server.
+                return _d.xhr("DELETE", args); //dojo.Deferred
+        };
+
+        /*
+        dojo.wrapForm = function(formNode){
+                //summary:
+                //              A replacement for FormBind, but not implemented yet.
+
+                // FIXME: need to think harder about what extensions to this we might
+                // want. What should we allow folks to do w/ this? What events to
+                // set/send?
+                throw new Error("dojo.wrapForm not yet implemented");
+        }
+        */
+})();
+
+}
+
+if(!dojo._hasResource["dojo._base.fx"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dojo._base.fx"] = true;
+dojo.provide("dojo._base.fx");
+
+
+
+
+
+
+/*
+        Animation loosely package based on Dan Pupius' work, contributed under CLA:
+                http://pupius.co.uk/js/Toolkit.Drawing.js
+*/
+(function(){
+        var d = dojo;
+        var _mixin = d._mixin;
+
+        dojo._Line = function(/*int*/ start, /*int*/ end){
+                //      summary:
+                //              dojo._Line is the object used to generate values from a start value
+                //              to an end value
+                //      start: int
+                //              Beginning value for range
+                //      end: int
+                //              Ending value for range
+                this.start = start;
+                this.end = end;
+        };
+
+        dojo._Line.prototype.getValue = function(/*float*/ n){
+                //      summary: Returns the point on the line
+                //      n: a floating point number greater than 0 and less than 1
+                return ((this.end - this.start) * n) + this.start; // Decimal
+        };
+
+        dojo.Animation = function(args){
+                //      summary:
+                //              A generic animation class that fires callbacks into its handlers
+                //              object at various states.
+                //      description:
+                //              A generic animation class that fires callbacks into its handlers
+                //              object at various states. Nearly all dojo animation functions
+                //              return an instance of this method, usually without calling the
+                //              .play() method beforehand. Therefore, you will likely need to
+                //              call .play() on instances of `dojo.Animation` when one is
+                //              returned.
+                // args: Object
+                //              The 'magic argument', mixing all the properties into this
+                //              animation instance.
+
+                _mixin(this, args);
+                if(d.isArray(this.curve)){
+                        this.curve = new d._Line(this.curve[0], this.curve[1]);
+                }
+
+        };
+
+        // Alias to drop come 2.0:
+        d._Animation = d.Animation;
+
+        d.extend(dojo.Animation, {
+                // duration: Integer
+                //              The time in milliseonds the animation will take to run
+                duration: 350,
+
+        /*=====
+                // curve: dojo._Line|Array
+                //              A two element array of start and end values, or a `dojo._Line` instance to be
+                //              used in the Animation.
+                curve: null,
+
+                // easing: Function?
+                //              A Function to adjust the acceleration (or deceleration) of the progress
+                //              across a dojo._Line
+                easing: null,
+        =====*/
+
+                // repeat: Integer?
+                //              The number of times to loop the animation
+                repeat: 0,
+
+                // rate: Integer?
+                //              the time in milliseconds to wait before advancing to next frame
+                //              (used as a fps timer: 1000/rate = fps)
+                rate: 20 /* 50 fps */,
+
+        /*=====
+                // delay: Integer?
+                //              The time in milliseconds to wait before starting animation after it
+                //              has been .play()'ed
+                delay: null,
+
+                // beforeBegin: Event?
+                //              Synthetic event fired before a dojo.Animation begins playing (synchronous)
+                beforeBegin: null,
+
+                // onBegin: Event?
+                //              Synthetic event fired as a dojo.Animation begins playing (useful?)
+                onBegin: null,
+
+                // onAnimate: Event?
+                //              Synthetic event fired at each interval of a `dojo.Animation`
+                onAnimate: null,
+
+                // onEnd: Event?
+                //              Synthetic event fired after the final frame of a `dojo.Animation`
+                onEnd: null,
+
+                // onPlay: Event?
+                //              Synthetic event fired any time a `dojo.Animation` is play()'ed
+                onPlay: null,
+
+                // onPause: Event?
+                //              Synthetic event fired when a `dojo.Animation` is paused
+                onPause: null,
+
+                // onStop: Event
+                //              Synthetic event fires when a `dojo.Animation` is stopped
+                onStop: null,
+
+        =====*/
+
+                _percent: 0,
+                _startRepeatCount: 0,
+
+                _getStep: function(){
+                        var _p = this._percent,
+                                _e = this.easing
+                        ;
+                        return _e ? _e(_p) : _p;
+                },
+                _fire: function(/*Event*/ evt, /*Array?*/ args){
+                        //      summary:
+                        //              Convenience function.  Fire event "evt" and pass it the
+                        //              arguments specified in "args".
+                        //      description:
+                        //              Convenience function.  Fire event "evt" and pass it the
+                        //              arguments specified in "args".
+                        //              Fires the callback in the scope of the `dojo.Animation`
+                        //              instance.
+                        //      evt:
+                        //              The event to fire.
+                        //      args:
+                        //              The arguments to pass to the event.
+                        var a = args||[];
+                        if(this[evt]){
+                                if(d.config.debugAtAllCosts){
+                                        this[evt].apply(this, a);
+                                }else{
+                                        try{
+                                                this[evt].apply(this, a);
+                                        }catch(e){
+                                                // squelch and log because we shouldn't allow exceptions in
+                                                // synthetic event handlers to cause the internal timer to run
+                                                // amuck, potentially pegging the CPU. I'm not a fan of this
+                                                // squelch, but hopefully logging will make it clear what's
+                                                // going on
+                                                console.error("exception in animation handler for:", evt);
+                                                console.error(e);
+                                        }
+                                }
+                        }
+                        return this; // dojo.Animation
+                },
+
+                play: function(/*int?*/ delay, /*Boolean?*/ gotoStart){
+                        // summary:
+                        //              Start the animation.
+                        // delay:
+                        //              How many milliseconds to delay before starting.
+                        // gotoStart:
+                        //              If true, starts the animation from the beginning; otherwise,
+                        //              starts it from its current position.
+                        // returns: dojo.Animation
+                        //              The instance to allow chaining.
+
+                        var _t = this;
+                        if(_t._delayTimer){ _t._clearTimer(); }
+                        if(gotoStart){
+                                _t._stopTimer();
+                                _t._active = _t._paused = false;
+                                _t._percent = 0;
+                        }else if(_t._active && !_t._paused){
+                                return _t;
+                        }
+
+                        _t._fire("beforeBegin", [_t.node]);
+
+                        var de = delay || _t.delay,
+                                _p = dojo.hitch(_t, "_play", gotoStart);
+
+                        if(de > 0){
+                                _t._delayTimer = setTimeout(_p, de);
+                                return _t;
+                        }
+                        _p();
+                        return _t;
+                },
+
+                _play: function(gotoStart){
+                        var _t = this;
+                        if(_t._delayTimer){ _t._clearTimer(); }
+                        _t._startTime = new Date().valueOf();
+                        if(_t._paused){
+                                _t._startTime -= _t.duration * _t._percent;
+                        }
+
+                        _t._active = true;
+                        _t._paused = false;
+                        var value = _t.curve.getValue(_t._getStep());
+                        if(!_t._percent){
+                                if(!_t._startRepeatCount){
+                                        _t._startRepeatCount = _t.repeat;
+                                }
+                                _t._fire("onBegin", [value]);
+                        }
+
+                        _t._fire("onPlay", [value]);
+
+                        _t._cycle();
+                        return _t; // dojo.Animation
+                },
+
+                pause: function(){
+                        // summary: Pauses a running animation.
+                        var _t = this;
+                        if(_t._delayTimer){ _t._clearTimer(); }
+                        _t._stopTimer();
+                        if(!_t._active){ return _t; /*dojo.Animation*/ }
+                        _t._paused = true;
+                        _t._fire("onPause", [_t.curve.getValue(_t._getStep())]);
+                        return _t; // dojo.Animation
+                },
+
+                gotoPercent: function(/*Decimal*/ percent, /*Boolean?*/ andPlay){
+                        //      summary:
+                        //              Sets the progress of the animation.
+                        //      percent:
+                        //              A percentage in decimal notation (between and including 0.0 and 1.0).
+                        //      andPlay:
+                        //              If true, play the animation after setting the progress.
+                        var _t = this;
+                        _t._stopTimer();
+                        _t._active = _t._paused = true;
+                        _t._percent = percent;
+                        if(andPlay){ _t.play(); }
+                        return _t; // dojo.Animation
+                },
+
+                stop: function(/*boolean?*/ gotoEnd){
+                        // summary: Stops a running animation.
+                        // gotoEnd: If true, the animation will end.
+                        var _t = this;
+                        if(_t._delayTimer){ _t._clearTimer(); }
+                        if(!_t._timer){ return _t; /* dojo.Animation */ }
+                        _t._stopTimer();
+                        if(gotoEnd){
+                                _t._percent = 1;
+                        }
+                        _t._fire("onStop", [_t.curve.getValue(_t._getStep())]);
+                        _t._active = _t._paused = false;
+                        return _t; // dojo.Animation
+                },
+
+                status: function(){
+                        // summary:
+                        //              Returns a string token representation of the status of
+                        //              the animation, one of: "paused", "playing", "stopped"
+                        if(this._active){
+                                return this._paused ? "paused" : "playing"; // String
+                        }
+                        return "stopped"; // String
+                },
+
+                _cycle: function(){
+                        var _t = this;
+                        if(_t._active){
+                                var curr = new Date().valueOf();
+                                var step = (curr - _t._startTime) / (_t.duration);
+
+                                if(step >= 1){
+                                        step = 1;
+                                }
+                                _t._percent = step;
+
+                                // Perform easing
+                                if(_t.easing){
+                                        step = _t.easing(step);
+                                }
+
+                                _t._fire("onAnimate", [_t.curve.getValue(step)]);
+
+                                if(_t._percent < 1){
+                                        _t._startTimer();
+                                }else{
+                                        _t._active = false;
+
+                                        if(_t.repeat > 0){
+                                                _t.repeat--;
+                                                _t.play(null, true);
+                                        }else if(_t.repeat == -1){
+                                                _t.play(null, true);
+                                        }else{
+                                                if(_t._startRepeatCount){
+                                                        _t.repeat = _t._startRepeatCount;
+                                                        _t._startRepeatCount = 0;
+                                                }
+                                        }
+                                        _t._percent = 0;
+                                        _t._fire("onEnd", [_t.node]);
+                                        !_t.repeat && _t._stopTimer();
+                                }
+                        }
+                        return _t; // dojo.Animation
+                },
+
+                _clearTimer: function(){
+                        // summary: Clear the play delay timer
+                        clearTimeout(this._delayTimer);
+                        delete this._delayTimer;
+                }
+
+        });
+
+        // the local timer, stubbed into all Animation instances
+        var ctr = 0,
+                timer = null,
+                runner = {
+                        run: function(){}
+                };
+
+        d.extend(d.Animation, {
+
+                _startTimer: function(){
+                        if(!this._timer){
+                                this._timer = d.connect(runner, "run", this, "_cycle");
+                                ctr++;
+                        }
+                        if(!timer){
+                                timer = setInterval(d.hitch(runner, "run"), this.rate);
+                        }
+                },
+
+                _stopTimer: function(){
+                        if(this._timer){
+                                d.disconnect(this._timer);
+                                this._timer = null;
+                                ctr--;
+                        }
+                        if(ctr <= 0){
+                                clearInterval(timer);
+                                timer = null;
+                                ctr = 0;
+                        }
+                }
+
+        });
+
+        var _makeFadeable =
+                                d.isIE ? function(node){
+                        // only set the zoom if the "tickle" value would be the same as the
+                        // default
+                        var ns = node.style;
+                        // don't set the width to auto if it didn't already cascade that way.
+                        // We don't want to f anyones designs
+                        if(!ns.width.length && d.style(node, "width") == "auto"){
+                                ns.width = "auto";
+                        }
+                } :
+                                function(){};
+
+        dojo._fade = function(/*Object*/ args){
+                //      summary:
+                //              Returns an animation that will fade the node defined by
+                //              args.node from the start to end values passed (args.start
+                //              args.end) (end is mandatory, start is optional)
+
+                args.node = d.byId(args.node);
+                var fArgs = _mixin({ properties: {} }, args),
+                        props = (fArgs.properties.opacity = {});
+
+                props.start = !("start" in fArgs) ?
+                        function(){
+                                return +d.style(fArgs.node, "opacity")||0;
+                        } : fArgs.start;
+                props.end = fArgs.end;
+
+                var anim = d.animateProperty(fArgs);
+                d.connect(anim, "beforeBegin", d.partial(_makeFadeable, fArgs.node));
+
+                return anim; // dojo.Animation
+        };
+
+        /*=====
+        dojo.__FadeArgs = function(node, duration, easing){
+                //      node: DOMNode|String
+                //              The node referenced in the animation
+                //      duration: Integer?
+                //              Duration of the animation in milliseconds.
+                //      easing: Function?
+                //              An easing function.
+                this.node = node;
+                this.duration = duration;
+                this.easing = easing;
+        }
+        =====*/
+
+        dojo.fadeIn = function(/*dojo.__FadeArgs*/ args){
+                // summary:
+                //              Returns an animation that will fade node defined in 'args' from
+                //              its current opacity to fully opaque.
+                return d._fade(_mixin({ end: 1 }, args)); // dojo.Animation
+        };
+
+        dojo.fadeOut = function(/*dojo.__FadeArgs*/  args){
+                // summary:
+                //              Returns an animation that will fade node defined in 'args'
+                //              from its current opacity to fully transparent.
+                return d._fade(_mixin({ end: 0 }, args)); // dojo.Animation
+        };
+
+        dojo._defaultEasing = function(/*Decimal?*/ n){
+                // summary: The default easing function for dojo.Animation(s)
+                return 0.5 + ((Math.sin((n + 1.5) * Math.PI)) / 2);
+        };
+
+        var PropLine = function(properties){
+                // PropLine is an internal class which is used to model the values of
+                // an a group of CSS properties across an animation lifecycle. In
+                // particular, the "getValue" function handles getting interpolated
+                // values between start and end for a particular CSS value.
+                this._properties = properties;
+                for(var p in properties){
+                        var prop = properties[p];
+                        if(prop.start instanceof d.Color){
+                                // create a reusable temp color object to keep intermediate results
+                                prop.tempColor = new d.Color();
+                        }
+                }
+        };
+
+        PropLine.prototype.getValue = function(r){
+                var ret = {};
+                for(var p in this._properties){
+                        var prop = this._properties[p],
+                                start = prop.start;
+                        if(start instanceof d.Color){
+                                ret[p] = d.blendColors(start, prop.end, r, prop.tempColor).toCss();
+                        }else if(!d.isArray(start)){
+                                ret[p] = ((prop.end - start) * r) + start + (p != "opacity" ? prop.units || "px" : 0);
+                        }
+                }
+                return ret;
+        };
+
+        /*=====
+        dojo.declare("dojo.__AnimArgs", [dojo.__FadeArgs], {
+                // Properties: Object?
+                //      A hash map of style properties to Objects describing the transition,
+                //      such as the properties of dojo._Line with an additional 'units' property
+                properties: {}
+
+                //TODOC: add event callbacks
+        });
+        =====*/
+
+        dojo.animateProperty = function(/*dojo.__AnimArgs*/ args){
+                // summary:
+                //              Returns an animation that will transition the properties of
+                //              node defined in `args` depending how they are defined in
+                //              `args.properties`
+                //
+                // description:
+                //              `dojo.animateProperty` is the foundation of most `dojo.fx`
+                //              animations. It takes an object of "properties" corresponding to
+                //              style properties, and animates them in parallel over a set
+                //              duration.
+                //
+                // example:
+                //              A simple animation that changes the width of the specified node.
+                //      |       dojo.animateProperty({
+                //      |               node: "nodeId",
+                //      |               properties: { width: 400 },
+                //      |       }).play();
+                //              Dojo figures out the start value for the width and converts the
+                //              integer specified for the width to the more expressive but
+                //              verbose form `{ width: { end: '400', units: 'px' } }` which you
+                //              can also specify directly. Defaults to 'px' if ommitted.
+                //
+                // example:
+                //              Animate width, height, and padding over 2 seconds... the
+                //              pedantic way:
+                //      |       dojo.animateProperty({ node: node, duration:2000,
+                //      |               properties: {
+                //      |                       width: { start: '200', end: '400', units:"px" },
+                //      |                       height: { start:'200', end: '400', units:"px" },
+                //      |                       paddingTop: { start:'5', end:'50', units:"px" }
+                //      |               }
+                //      |       }).play();
+                //              Note 'paddingTop' is used over 'padding-top'. Multi-name CSS properties
+                //              are written using "mixed case", as the hyphen is illegal as an object key.
+                //
+                // example:
+                //              Plug in a different easing function and register a callback for
+                //              when the animation ends. Easing functions accept values between
+                //              zero and one and return a value on that basis. In this case, an
+                //              exponential-in curve.
+                //      |       dojo.animateProperty({
+                //      |               node: "nodeId",
+                //      |               // dojo figures out the start value
+                //      |               properties: { width: { end: 400 } },
+                //      |               easing: function(n){
+                //      |                       return (n==0) ? 0 : Math.pow(2, 10 * (n - 1));
+                //      |               },
+                //      |               onEnd: function(node){
+                //      |                       // called when the animation finishes. The animation
+                //      |                       // target is passed to this function
+                //      |               }
+                //      |       }).play(500); // delay playing half a second
+                //
+                // example:
+                //              Like all `dojo.Animation`s, animateProperty returns a handle to the
+                //              Animation instance, which fires the events common to Dojo FX. Use `dojo.connect`
+                //              to access these events outside of the Animation definiton:
+                //      |       var anim = dojo.animateProperty({
+                //      |               node:"someId",
+                //      |               properties:{
+                //      |                       width:400, height:500
+                //      |               }
+                //      |       });
+                //      |       dojo.connect(anim,"onEnd", function(){
+                //      |               console.log("animation ended");
+                //      |       });
+                //      |       // play the animation now:
+                //      |       anim.play();
+                //
+                // example:
+                //              Each property can be a function whose return value is substituted along.
+                //              Additionally, each measurement (eg: start, end) can be a function. The node
+                //              reference is passed direcly to callbacks.
+                //      |       dojo.animateProperty({
+                //      |               node:"mine",
+                //      |               properties:{
+                //      |                       height:function(node){
+                //      |                               // shrink this node by 50%
+                //      |                               return dojo.position(node).h / 2
+                //      |                       },
+                //      |                       width:{
+                //      |                               start:function(node){ return 100; },
+                //      |                               end:function(node){ return 200; }
+                //      |                       }
+                //      |               }
+                //      |       }).play();
+                //
+
+                var n = args.node = d.byId(args.node);
+                if(!args.easing){ args.easing = d._defaultEasing; }
+
+                var anim = new d.Animation(args);
+                d.connect(anim, "beforeBegin", anim, function(){
+                        var pm = {};
+                        for(var p in this.properties){
+                                // Make shallow copy of properties into pm because we overwrite
+                                // some values below. In particular if start/end are functions
+                                // we don't want to overwrite them or the functions won't be
+                                // called if the animation is reused.
+                                if(p == "width" || p == "height"){
+                                        this.node.display = "block";
+                                }
+                                var prop = this.properties[p];
+                                if(d.isFunction(prop)){
+                                        prop = prop(n);
+                                }
+                                prop = pm[p] = _mixin({}, (d.isObject(prop) ? prop: { end: prop }));
+
+                                if(d.isFunction(prop.start)){
+                                        prop.start = prop.start(n);
+                                }
+                                if(d.isFunction(prop.end)){
+                                        prop.end = prop.end(n);
+                                }
+                                var isColor = (p.toLowerCase().indexOf("color") >= 0);
+                                function getStyle(node, p){
+                                        // dojo.style(node, "height") can return "auto" or "" on IE; this is more reliable:
+                                        var v = { height: node.offsetHeight, width: node.offsetWidth }[p];
+                                        if(v !== undefined){ return v; }
+                                        v = d.style(node, p);
+                                        return (p == "opacity") ? +v : (isColor ? v : parseFloat(v));
+                                }
+                                if(!("end" in prop)){
+                                        prop.end = getStyle(n, p);
+                                }else if(!("start" in prop)){
+                                        prop.start = getStyle(n, p);
+                                }
+
+                                if(isColor){
+                                        prop.start = new d.Color(prop.start);
+                                        prop.end = new d.Color(prop.end);
+                                }else{
+                                        prop.start = (p == "opacity") ? +prop.start : parseFloat(prop.start);
+                                }
+                        }
+                        this.curve = new PropLine(pm);
+                });
+                d.connect(anim, "onAnimate", d.hitch(d, "style", anim.node));
+                return anim; // dojo.Animation
+        };
+
+        dojo.anim = function(   /*DOMNode|String*/      node,
+                                                        /*Object*/                      properties,
+                                                        /*Integer?*/            duration,
+                                                        /*Function?*/           easing,
+                                                        /*Function?*/           onEnd,
+                                                        /*Integer?*/            delay){
+                //      summary:
+                //              A simpler interface to `dojo.animateProperty()`, also returns
+                //              an instance of `dojo.Animation` but begins the animation
+                //              immediately, unlike nearly every other Dojo animation API.
+                //      description:
+                //              `dojo.anim` is a simpler (but somewhat less powerful) version
+                //              of `dojo.animateProperty`.  It uses defaults for many basic properties
+                //              and allows for positional parameters to be used in place of the
+                //              packed "property bag" which is used for other Dojo animation
+                //              methods.
+                //
+                //              The `dojo.Animation` object returned from `dojo.anim` will be
+                //              already playing when it is returned from this function, so
+                //              calling play() on it again is (usually) a no-op.
+                //      node:
+                //              a DOM node or the id of a node to animate CSS properties on
+                //      duration:
+                //              The number of milliseconds over which the animation
+                //              should run. Defaults to the global animation default duration
+                //              (350ms).
+                //      easing:
+                //              An easing function over which to calculate acceleration
+                //              and deceleration of the animation through its duration.
+                //              A default easing algorithm is provided, but you may
+                //              plug in any you wish. A large selection of easing algorithms
+                //              are available in `dojo.fx.easing`.
+                //      onEnd:
+                //              A function to be called when the animation finishes
+                //              running.
+                //      delay:
+                //              The number of milliseconds to delay beginning the
+                //              animation by. The default is 0.
+                //      example:
+                //              Fade out a node
+                //      |       dojo.anim("id", { opacity: 0 });
+                //      example:
+                //              Fade out a node over a full second
+                //      |       dojo.anim("id", { opacity: 0 }, 1000);
+                return d.animateProperty({ // dojo.Animation
+                        node: node,
+                        duration: duration || d.Animation.prototype.duration,
+                        properties: properties,
+                        easing: easing,
+                        onEnd: onEnd
+                }).play(delay || 0);
+        };
+})();
+
+}
+
+if(!dojo._hasResource["dojo._base.browser"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dojo._base.browser"] = true;
+dojo.provide("dojo._base.browser");
+
+
+
+
+
+
+
+
+
+        //Need this to be the last code segment in base, so do not place any
+        //dojo/requireIf calls in this file/ Otherwise, due to how the build system
+        //puts all requireIf dependencies after the current file, the require calls
+        //could be called before all of base is defined/
+        dojo.forEach(dojo.config.require, function(i){
+                dojo["require"](i);
+        });
+
+}
+
+if(!dojo._hasResource["dojo._base"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dojo._base"] = true;
+dojo.provide("dojo._base");
+
+
+
+
+
+
+
+
+
+
+
+}
+
+        //INSERT dojo.i18n._preloadLocalizations HERE
+
+        //Check if document already complete, and if so, just trigger page load
+        //listeners. NOTE: does not work with Firefox before 3.6. To support
+        //those browsers, set djConfig.afterOnLoad = true when you know Dojo is added
+        //after page load. Using a timeout so the rest of this
+        //script gets evaluated properly. This work needs to happen after the
+        //dojo.config.require work done in dojo._base.
+        if(dojo.isBrowser && (document.readyState === "complete" || dojo.config.afterOnLoad)){
+                window.setTimeout(dojo._loadInit, 100);
+        }
+})();
+
diff --git a/PerformanceTests/Dromaeo/resources/dromaeo/web/lib/dojo.js b/PerformanceTests/Dromaeo/resources/dromaeo/web/lib/dojo.js
deleted file mode 100644 (file)
index b721f40..0000000
+++ /dev/null
@@ -1,8458 +0,0 @@
-/*
-        Copyright (c) 2004-2008, The Dojo Foundation All Rights Reserved.
-        Available via Academic Free License >= 2.1 OR the modified BSD license.
-        see: http://dojotoolkit.org/license for details
-*/
-
-/*
-        This is a compiled version of Dojo, built for deployment and not for
-        development. To get an editable version, please visit:
-
-                http://dojotoolkit.org
-
-        for documentation and information on getting the source.
-*/
-
-;(function(){
-
-        /*
-        dojo, dijit, and dojox must always be the first three, and in that order.
-        djConfig.scopeMap = [
-                ["dojo", "fojo"],
-                ["dijit", "fijit"],
-                ["dojox", "fojox"]
-        
-        ]
-        */
-
-        /**Build will replace this comment with a scoped djConfig **/
-
-        //The null below can be relaced by a build-time value used instead of djConfig.scopeMap.
-        var sMap = null;
-
-        //See if new scopes need to be defined.
-        if((sMap || (typeof djConfig != "undefined" && djConfig.scopeMap)) && (typeof window != "undefined")){
-                var scopeDef = "", scopePrefix = "", scopeSuffix = "", scopeMap = {}, scopeMapRev = {};
-                sMap = sMap || djConfig.scopeMap;
-                for(var i = 0; i < sMap.length; i++){
-                        //Make local variables, then global variables that use the locals.
-                        var newScope = sMap[i];
-                        scopeDef += "var " + newScope[0] + " = {}; " + newScope[1] + " = " + newScope[0] + ";" + newScope[1] + "._scopeName = '" + newScope[1] + "';";
-                        scopePrefix += (i == 0 ? "" : ",") + newScope[0];
-                        scopeSuffix += (i == 0 ? "" : ",") + newScope[1];
-                        scopeMap[newScope[0]] = newScope[1];
-                        scopeMapRev[newScope[1]] = newScope[0];
-                }
-
-                eval(scopeDef + "dojo._scopeArgs = [" + scopeSuffix + "];");
-
-                dojo._scopePrefixArgs = scopePrefix;
-                dojo._scopePrefix = "(function(" + scopePrefix + "){";
-                dojo._scopeSuffix = "})(" + scopeSuffix + ")";
-                dojo._scopeMap = scopeMap;
-                dojo._scopeMapRev = scopeMapRev;
-        }
-
-/*=====
-// note:
-//              'djConfig' does not exist under 'dojo.*' so that it can be set before the
-//              'dojo' variable exists.
-// note:
-//              Setting any of these variables *after* the library has loaded does
-//              nothing at all.
-
-djConfig = {
-        // summary:
-        //              Application code can set the global 'djConfig' prior to loading
-        //              the library to override certain global settings for how dojo works.
-        //
-        // isDebug: Boolean
-        //              Defaults to `false`. If set to `true`, ensures that Dojo provides
-        //              extended debugging feedback via Firebug. If Firebug is not available
-        //              on your platform, setting `isDebug` to `true` will force Dojo to
-        //              pull in (and display) the version of Firebug Lite which is
-        //              integrated into the Dojo distribution, thereby always providing a
-        //              debugging/logging console when `isDebug` is enabled. Note that
-        //              Firebug's `console.*` methods are ALWAYS defined by Dojo. If
-        //              `isDebug` is false and you are on a platform without Firebug, these
-        //              methods will be defined as no-ops.
-        isDebug: false,
-        // debugAtAllCosts: Boolean
-        //              Defaults to `false`. If set to `true`, this triggers an alternate
-        //              mode of the package system in which dependencies are detected and
-        //              only then are resources evaluated in dependency order via
-        //              `<script>` tag inclusion. This may double-request resources and
-        //              cause problems with scripts which expect `dojo.require()` to
-        //              preform synchronously. `debugAtAllCosts` can be an invaluable
-        //              debugging aid, but when using it, ensure that all code which
-        //              depends on Dojo modules is wrapped in `dojo.addOnLoad()` handlers.
-        //              Due to the somewhat unpredictable side-effects of using
-        //              `debugAtAllCosts`, it is strongly recommended that you enable this
-        //              flag as a last resort. `debugAtAllCosts` has no effect when loading
-        //              resources across domains. For usage information, see the
-        //              [Dojo Book](http://dojotoolkit.org/book/book-dojo/part-4-meta-dojo-making-your-dojo-code-run-faster-and-better/debugging-facilities/deb)
-        debugAtAllCosts: false,
-        // locale: String
-        //              The locale to assume for loading localized resources in this page,
-        //              specified according to [RFC 3066](http://www.ietf.org/rfc/rfc3066.txt).
-        //              Must be specified entirely in lowercase, e.g. `en-us` and `zh-cn`.
-        //              See the documentation for `dojo.i18n` and `dojo.requireLocalization`
-        //              for details on loading localized resources. If no locale is specified,
-        //              Dojo assumes the locale of the user agent, according to `navigator.userLanguage`
-        //              or `navigator.language` properties.
-        locale: undefined,
-        // extraLocale: Array
-        //              No default value. Specifies additional locales whose
-        //              resources should also be loaded alongside the default locale when
-        //              calls to `dojo.requireLocalization()` are processed.
-        extraLocale: undefined,
-        // baseUrl: String
-        //              The directory in which `dojo.js` is located. Under normal
-        //              conditions, Dojo auto-detects the correct location from which it
-        //              was loaded. You may need to manually configure `baseUrl` in cases
-        //              where you have renamed `dojo.js` or in which `<base>` tags confuse
-        //              some browsers (e.g. IE 6). The variable `dojo.baseUrl` is assigned
-        //              either the value of `djConfig.baseUrl` if one is provided or the
-        //              auto-detected root if not. Other modules are located relative to
-        //              this path.
-        baseUrl: undefined,
-        // modulePaths: Object
-        //              A map of module names to paths relative to `dojo.baseUrl`. The
-        //              key/value pairs correspond directly to the arguments which
-        //              `dojo.registerModulePath` accepts. Specifiying
-        //              `djConfig.modulePaths = { "foo": "../../bar" }` is the equivalent
-        //              of calling `dojo.registerModulePath("foo", "../../bar");`. Multiple
-        //              modules may be configured via `djConfig.modulePaths`.
-        modulePaths: {},
-        // afterOnLoad: Boolean 
-        //              Indicates Dojo was added to the page after the page load. In this case
-        //              Dojo will not wait for the page DOMContentLoad/load events and fire
-        //              its dojo.addOnLoad callbacks after making sure all outstanding
-        //              dojo.required modules have loaded.
-        afterOnLoad: false,
-        // addOnLoad: Function or Array
-        //              Adds a callback via dojo.addOnLoad. Useful when Dojo is added after
-        //              the page loads and djConfig.afterOnLoad is true. Supports the same
-        //              arguments as dojo.addOnLoad. When using a function reference, use
-        //              `djConfig.addOnLoad = function(){};`. For object with function name use
-        //              `djConfig.addOnLoad = [myObject, "functionName"];` and for object with
-        //              function reference use
-        //              `djConfig.addOnLoad = [myObject, function(){}];`
-        addOnLoad: null,
-        // require: Array
-        //              An array of module names to be loaded immediately after dojo.js has been included
-        //              in a page. 
-        require: []
-}
-=====*/
-
-(function(){
-        // firebug stubs
-
-        // if((!this["console"])||(!console["firebug"])){
-
-        if(!this["console"]){
-                this.console = {
-                };
-        }
-
-        //      Be careful to leave 'log' always at the end
-        var cn = [
-                "assert", "count", "debug", "dir", "dirxml", "error", "group",
-                "groupEnd", "info", "profile", "profileEnd", "time", "timeEnd",
-                "trace", "warn", "log" 
-        ];
-        var i=0, tn;
-        while((tn=cn[i++])){
-                if(!console[tn]){
-                        (function(){
-                                var tcn = tn+"";
-                                console[tcn] = ('log' in console) ? function(){ 
-                                        var a = Array.apply({}, arguments);
-                                        a.unshift(tcn+":");
-                                        console["log"](a.join(" "));
-                                } : function(){}
-                        })();
-                }
-        }
-
-        //TODOC:  HOW TO DOC THIS?
-        // dojo is the root variable of (almost all) our public symbols -- make sure it is defined.
-        if(typeof dojo == "undefined"){
-                this.dojo = {
-                        _scopeName: "dojo",
-                        _scopePrefix: "",
-                        _scopePrefixArgs: "",
-                        _scopeSuffix: "",
-                        _scopeMap: {},
-                        _scopeMapRev: {}
-                };
-        }
-
-        var d = dojo;
-
-        //Need placeholders for dijit and dojox for scoping code.
-        if(typeof dijit == "undefined"){
-                this.dijit = {_scopeName: "dijit"};
-        }
-        if(typeof dojox == "undefined"){
-                this.dojox = {_scopeName: "dojox"};
-        }
-        
-        if(!d._scopeArgs){
-                d._scopeArgs = [dojo, dijit, dojox];
-        }
-
-/*=====
-dojo.global = {
-        //      summary:
-        //              Alias for the global scope
-        //              (e.g. the window object in a browser).
-        //      description:
-        //              Refer to 'dojo.global' rather than referring to window to ensure your
-        //              code runs correctly in contexts other than web browsers (e.g. Rhino on a server).
-}
-=====*/
-        d.global = this;
-
-        d.config =/*===== djConfig = =====*/{
-                isDebug: false,
-                debugAtAllCosts: false
-        };
-
-        if(typeof djConfig != "undefined"){
-                for(var opt in djConfig){
-                        d.config[opt] = djConfig[opt];
-                }
-        }
-
-        var _platforms = ["Browser", "Rhino", "Spidermonkey", "Mobile"];
-        var t;
-        while((t=_platforms.shift())){
-                d["is"+t] = false;
-        }
-
-/*=====
-        // Override locale setting, if specified
-        dojo.locale = {
-                // summary: the locale as defined by Dojo (read-only)
-        };
-=====*/
-        dojo.locale = d.config.locale;
-        
-        var rev = "$Rev: 15729 $".match(/\d+/);
-
-        dojo.version = {
-                // summary: 
-                //              version number of dojo
-                //      major: Integer
-                //              Major version. If total version is "1.2.0beta1", will be 1
-                //      minor: Integer
-                //              Minor version. If total version is "1.2.0beta1", will be 2
-                //      patch: Integer
-                //              Patch version. If total version is "1.2.0beta1", will be 0
-                //      flag: String
-                //              Descriptor flag. If total version is "1.2.0beta1", will be "beta1"
-                //      revision: Number
-                //              The SVN rev from which dojo was pulled
-                major: 1, minor: 2, patch: 2, flag: "",
-                revision: rev ? +rev[0] : 999999, //FIXME: use NaN?
-                toString: function(){
-                        with(d.version){
-                                return major + "." + minor + "." + patch + flag + " (" + revision + ")";        // String
-                        }
-                }
-        }
-
-        // Register with the OpenAjax hub
-        if(typeof OpenAjax != "undefined"){
-                OpenAjax.hub.registerLibrary(dojo._scopeName, "http://dojotoolkit.org", d.version.toString());
-        }
-
-        dojo._mixin = function(/*Object*/ obj, /*Object*/ props){
-                // summary:
-                //              Adds all properties and methods of props to obj. This addition
-                //              is "prototype extension safe", so that instances of objects
-                //              will not pass along prototype defaults.
-                var tobj = {};
-                for(var x in props){
-                        // the "tobj" condition avoid copying properties in "props"
-                        // inherited from Object.prototype.  For example, if obj has a custom
-                        // toString() method, don't overwrite it with the toString() method
-                        // that props inherited from Object.prototype
-                        if(tobj[x] === undefined || tobj[x] != props[x]){
-                                obj[x] = props[x];
-                        }
-                }
-                // IE doesn't recognize custom toStrings in for..in
-                if(d["isIE"] && props){
-                        var p = props.toString;
-                        if(typeof p == "function" && p != obj.toString && p != tobj.toString &&
-                                p != "\nfunction toString() {\n    [native code]\n}\n"){
-                                        obj.toString = props.toString;
-                        }
-                }
-                return obj; // Object
-        }
-
-        dojo.mixin = function(/*Object*/obj, /*Object...*/props){
-                // summary:     
-                //              Adds all properties and methods of props to obj and returns the
-                //              (now modified) obj.
-                //      description:
-                //              `dojo.mixin` can mix multiple source objects into a
-                //              destionation object which is then returned. Unlike regular
-                //              `for...in` iteration, `dojo.mixin` is also smart about avoiding
-                //              extensions which other toolkits may unwisely add to the root
-                //              object prototype
-                //      obj:
-                //              The object to mix properties into. Also the return value.
-                //      props:
-                //              One or more objects whose values are successively copied into
-                //              obj. If more than one of these objects contain the same value,
-                //              the one specified last in the function call will "win".
-                //      example:
-                //              make a shallow copy of an object
-                //      |       var copy = dojo.mixin({}, source);
-                //      example:
-                //              many class constructors often take an object which specifies
-                //              values to be configured on the object. In this case, it is
-                //              often simplest to call `dojo.mixin` on the `this` object:
-                //      |       dojo.declare("acme.Base", null, {
-                //      |               constructor: function(properties){
-                //      |                       // property configuration:
-                //      |                       dojo.mixin(this, properties);
-                //      |       
-                //      |                       
-                //      |                       //  ...
-                //      |               },
-                //      |               quip: "I wasn't born yesterday, you know - I've seen movies.",
-                //      |               // ...
-                //      |       });
-                //      |
-                //      |       // create an instance of the class and configure it
-                //      |       var b = new acme.Base({quip: "That's what it does!" });
-                //      example:
-                //              copy in properties from multiple objects
-                //      |       var flattened = dojo.mixin(
-                //      |               {
-                //      |                       name: "Frylock",
-                //      |                       braces: true
-                //      |               },
-                //      |               {
-                //      |                       name: "Carl Brutanananadilewski"
-                //      |               }
-                //      |       );
-                //      |       
-                //      |       // will print "Carl Brutanananadilewski"
-                //      |       
-                //      |       // will print "true"
-                //      |       
-                for(var i=1, l=arguments.length; i<l; i++){
-                        d._mixin(obj, arguments[i]);
-                }
-                return obj; // Object
-        }
-
-        dojo._getProp = function(/*Array*/parts, /*Boolean*/create, /*Object*/context){
-                var obj=context || d.global;
-                for(var i=0, p; obj && (p=parts[i]); i++){
-                        if(i == 0 && this._scopeMap[p]){
-                                p = this._scopeMap[p];
-                        }
-                        obj = (p in obj ? obj[p] : (create ? obj[p]={} : undefined));
-                }
-                return obj; // mixed
-        }
-
-        dojo.setObject = function(/*String*/name, /*Object*/value, /*Object?*/context){
-                // summary: 
-                //              Set a property from a dot-separated string, such as "A.B.C"
-                //      description: 
-                //              Useful for longer api chains where you have to test each object in
-                //              the chain, or when you have an object reference in string format.
-                //              Objects are created as needed along `path`. Returns the passed
-                //              value if setting is successful or `undefined` if not.
-                //      name:   
-                //              Path to a property, in the form "A.B.C".
-                //      context:
-                //              Optional. Object to use as root of path. Defaults to
-                //              `dojo.global`.
-                //      example:
-                //              set the value of `foo.bar.baz`, regardless of whether
-                //              intermediate objects already exist:
-                //      |       dojo.setObject("foo.bar.baz", value);
-                //      example:
-                //              without `dojo.setObject`, we often see code like this:
-                //      |       // ensure that intermediate objects are available
-                //      |       if(!obj["parent"]){ obj.parent = {}; }
-                //      |       if(!obj.parent["child"]){ obj.parent.child= {}; }
-                //      |       // now we can safely set the property
-                //      |       obj.parent.child.prop = "some value";
-                //              wheras with `dojo.setObject`, we can shorten that to:
-                //      |       dojo.setObject("parent.child.prop", "some value", obj);
-                var parts=name.split("."), p=parts.pop(), obj=d._getProp(parts, true, context);
-                return obj && p ? (obj[p]=value) : undefined; // Object
-        }
-
-        dojo.getObject = function(/*String*/name, /*Boolean*/create, /*Object*/context){
-                // summary: 
-                //              Get a property from a dot-separated string, such as "A.B.C"
-                //      description: 
-                //              Useful for longer api chains where you have to test each object in
-                //              the chain, or when you have an object reference in string format.
-                //      name:   
-                //              Path to an property, in the form "A.B.C".
-                //      context:
-                //              Optional. Object to use as root of path. Defaults to
-                //              'dojo.global'. Null may be passed.
-                //      create: 
-                //              Optional. Defaults to `false`. If `true`, Objects will be
-                //              created at any point along the 'path' that is undefined.
-                return d._getProp(name.split("."), create, context); // Object
-        }
-
-        dojo.exists = function(/*String*/name, /*Object?*/obj){
-                //      summary: 
-                //              determine if an object supports a given method
-                //      description: 
-                //              useful for longer api chains where you have to test each object in
-                //              the chain
-                //      name:   
-                //              Path to an object, in the form "A.B.C".
-                //      obj:
-                //              Object to use as root of path. Defaults to
-                //              'dojo.global'. Null may be passed.
-                //      example:
-                //      |       // define an object
-                //      |       var foo = {
-                //      |               bar: { }
-                //      |       };
-                //      |
-                //      |       // search the global scope
-                //      |       dojo.exists("foo.bar"); // true
-                //      |       dojo.exists("foo.bar.baz"); // false
-                //      |
-                //      |       // search from a particular scope
-                //      |       dojo.exists("bar", foo); // true
-                //      |       dojo.exists("bar.baz", foo); // false
-                return !!d.getObject(name, false, obj); // Boolean
-        }
-
-
-        dojo["eval"] = function(/*String*/ scriptFragment){
-                //      summary: 
-                //              Perform an evaluation in the global scope. Use this rather than
-                //              calling 'eval()' directly.
-                //      description: 
-                //              Placed in a separate function to minimize size of trapped
-                //              exceptions. Calling eval() directly from some other scope may
-                //              complicate tracebacks on some platforms.
-                //      returns:
-                //              The result of the evaluation. Often `undefined`
-
-
-                // note:
-                //       - JSC eval() takes an optional second argument which can be 'unsafe'.
-                //       - Mozilla/SpiderMonkey eval() takes an optional second argument which is the
-                //       scope object for new symbols.
-
-                // FIXME: investigate Joseph Smarr's technique for IE:
-                //              http://josephsmarr.com/2007/01/31/fixing-eval-to-use-global-scope-in-ie/
-                //      see also:
-                //              http://trac.dojotoolkit.org/ticket/744
-                return d.global.eval ? d.global.eval(scriptFragment) : eval(scriptFragment);    // Object
-        }
-
-        /*=====
-                dojo.deprecated = function(behaviour, extra, removal){
-                        //      summary: 
-                        //              Log a debug message to indicate that a behavior has been
-                        //              deprecated.
-                        //      behaviour: String
-                        //              The API or behavior being deprecated. Usually in the form
-                        //              of "myApp.someFunction()".
-                        //      extra: String?
-                        //              Text to append to the message. Often provides advice on a
-                        //              new function or facility to achieve the same goal during
-                        //              the deprecation period.
-                        //      removal: String?
-                        //              Text to indicate when in the future the behavior will be
-                        //              removed. Usually a version number.
-                        //      example:
-                        //      |       dojo.deprecated("myApp.getTemp()", "use myApp.getLocaleTemp() instead", "1.0");
-                }
-
-                dojo.experimental = function(moduleName, extra){
-                        //      summary: Marks code as experimental.
-                        //      description: 
-                        //              This can be used to mark a function, file, or module as
-                        //              experimental.  Experimental code is not ready to be used, and the
-                        //              APIs are subject to change without notice.  Experimental code may be
-                        //              completed deleted without going through the normal deprecation
-                        //              process.
-                        //      moduleName: String
-                        //              The name of a module, or the name of a module file or a specific
-                        //              function
-                        //      extra: String?
-                        //              some additional message for the user
-                        //      example:
-                        //      |       dojo.experimental("dojo.data.Result");
-                        //      example:
-                        //      |       dojo.experimental("dojo.weather.toKelvin()", "PENDING approval from NOAA");
-                }
-        =====*/
-
-        //Real functions declared in dojo._firebug.firebug.
-        d.deprecated = d.experimental = function(){};
-
-})();
-// vim:ai:ts=4:noet
-
-/*
- * loader.js - A bootstrap module.  Runs before the hostenv_*.js file. Contains
- * all of the package loading methods.
- */
-
-(function(){
-        var d = dojo;
-
-        d.mixin(d, {
-                _loadedModules: {},
-                _inFlightCount: 0,
-                _hasResource: {},
-
-                _modulePrefixes: {
-                        dojo:   {       name: "dojo", value: "." },
-                        // dojox:       {       name: "dojox", value: "../dojox" },
-                        // dijit:       {       name: "dijit", value: "../dijit" },
-                        doh:    {       name: "doh", value: "../util/doh" },
-                        tests:  {       name: "tests", value: "tests" }
-                },
-
-                _moduleHasPrefix: function(/*String*/module){
-                        // summary: checks to see if module has been established
-                        var mp = this._modulePrefixes;
-                        return !!(mp[module] && mp[module].value); // Boolean
-                },
-
-                _getModulePrefix: function(/*String*/module){
-                        // summary: gets the prefix associated with module
-                        var mp = this._modulePrefixes;
-                        if(this._moduleHasPrefix(module)){
-                                return mp[module].value; // String
-                        }
-                        return module; // String
-                },
-
-                _loadedUrls: [],
-
-                //WARNING: 
-                //              This variable is referenced by packages outside of bootstrap:
-                //              FloatingPane.js and undo/browser.js
-                _postLoad: false,
-                
-                //Egad! Lots of test files push on this directly instead of using dojo.addOnLoad.
-                _loaders: [],
-                _unloaders: [],
-                _loadNotifying: false
-        });
-
-
-                dojo._loadPath = function(/*String*/relpath, /*String?*/module, /*Function?*/cb){
-                //      summary:
-                //              Load a Javascript module given a relative path
-                //
-                //      description:
-                //              Loads and interprets the script located at relpath, which is
-                //              relative to the script root directory.  If the script is found but
-                //              its interpretation causes a runtime exception, that exception is
-                //              not caught by us, so the caller will see it.  We return a true
-                //              value if and only if the script is found.
-                //
-                // relpath: 
-                //              A relative path to a script (no leading '/', and typically ending
-                //              in '.js').
-                // module: 
-                //              A module whose existance to check for after loading a path.  Can be
-                //              used to determine success or failure of the load.
-                // cb: 
-                //              a callback function to pass the result of evaluating the script
-
-                var uri = ((relpath.charAt(0) == '/' || relpath.match(/^\w+:/)) ? "" : this.baseUrl) + relpath;
-                try{
-                        return !module ? this._loadUri(uri, cb) : this._loadUriAndCheck(uri, module, cb); // Boolean
-                }catch(e){
-                        console.error(e);
-                        return false; // Boolean
-                }
-        }
-
-        dojo._loadUri = function(/*String*/uri, /*Function?*/cb){
-                //      summary:
-                //              Loads JavaScript from a URI
-                //      description:
-                //              Reads the contents of the URI, and evaluates the contents.  This is
-                //              used to load modules as well as resource bundles. Returns true if
-                //              it succeeded. Returns false if the URI reading failed.  Throws if
-                //              the evaluation throws.
-                //      uri: a uri which points at the script to be loaded
-                //      cb: 
-                //              a callback function to process the result of evaluating the script
-                //              as an expression, typically used by the resource bundle loader to
-                //              load JSON-style resources
-
-                if(this._loadedUrls[uri]){
-                        return true; // Boolean
-                }
-                var contents = this._getText(uri, true);
-                if(!contents){ return false; } // Boolean
-                this._loadedUrls[uri] = true;
-                this._loadedUrls.push(uri);
-                if(cb){
-                        contents = '('+contents+')';
-                }else{
-                        //Only do the scoping if no callback. If a callback is specified,
-                        //it is most likely the i18n bundle stuff.
-                        contents = this._scopePrefix + contents + this._scopeSuffix;
-                }
-                if(d.isMoz){ contents += "\r\n//@ sourceURL=" + uri; } // debugging assist for Firebug
-                var value = d["eval"](contents);
-                if(cb){ cb(value); }
-                return true; // Boolean
-        }
-        
-        // FIXME: probably need to add logging to this method
-        dojo._loadUriAndCheck = function(/*String*/uri, /*String*/moduleName, /*Function?*/cb){
-                // summary: calls loadUri then findModule and returns true if both succeed
-                var ok = false;
-                try{
-                        ok = this._loadUri(uri, cb);
-                }catch(e){
-                        console.error("failed loading " + uri + " with error: " + e);
-                }
-                return !!(ok && this._loadedModules[moduleName]); // Boolean
-        }
-
-        dojo.loaded = function(){
-                // summary:
-                //              signal fired when initial environment and package loading is
-                //              complete. You may use dojo.addOnLoad() or dojo.connect() to
-                //              this method in order to handle initialization tasks that
-                //              require the environment to be initialized. In a browser host,
-                //              declarative widgets will be constructed when this function
-                //              finishes runing.
-                this._loadNotifying = true;
-                this._postLoad = true;
-                var mll = d._loaders;
-
-                //Clear listeners so new ones can be added
-                //For other xdomain package loads after the initial load.
-                this._loaders = [];
-
-                for(var x = 0; x < mll.length; x++){
-                        mll[x]();
-                }
-
-                this._loadNotifying = false;
-                
-                //Make sure nothing else got added to the onload queue
-                //after this first run. If something did, and we are not waiting for any
-                //more inflight resources, run again.
-                if(d._postLoad && d._inFlightCount == 0 && mll.length){
-                        d._callLoaded();
-                }
-        }
-
-        dojo.unloaded = function(){
-                // summary:
-                //              signal fired by impending environment destruction. You may use
-                //              dojo.addOnUnload() or dojo.connect() to this method to perform
-                //              page/application cleanup methods. See dojo.addOnUnload for more info.
-                var mll = this._unloaders;
-                while(mll.length){
-                        (mll.pop())();
-                }
-        }
-
-        d._onto = function(arr, obj, fn){
-                if(!fn){
-                        arr.push(obj);
-                }else if(fn){
-                        var func = (typeof fn == "string") ? obj[fn] : fn;
-                        arr.push(function(){ func.call(obj); });
-                }
-        }
-
-        dojo.addOnLoad = function(/*Object?*/obj, /*String|Function*/functionName){
-                // summary:
-                //              Registers a function to be triggered after the DOM has finished
-                //              loading and widgets declared in markup have been instantiated.
-                //              Images and CSS files may or may not have finished downloading when
-                //              the specified function is called.  (Note that widgets' CSS and HTML
-                //              code is guaranteed to be downloaded before said widgets are
-                //              instantiated.)
-                // example:
-                //      |       dojo.addOnLoad(functionPointer);
-                //      |       dojo.addOnLoad(object, "functionName");
-                //      |       dojo.addOnLoad(object, function(){ /* ... */});
-
-                d._onto(d._loaders, obj, functionName);
-
-                //Added for xdomain loading. dojo.addOnLoad is used to
-                //indicate callbacks after doing some dojo.require() statements.
-                //In the xdomain case, if all the requires are loaded (after initial
-                //page load), then immediately call any listeners.
-                if(d._postLoad && d._inFlightCount == 0 && !d._loadNotifying){
-                        d._callLoaded();
-                }
-        }
-
-        //Support calling dojo.addOnLoad via djConfig.addOnLoad. Support all the
-        //call permutations of dojo.addOnLoad. Mainly useful when dojo is added
-        //to the page after the page has loaded.
-        var dca = d.config.addOnLoad;
-        if(dca){
-                d.addOnLoad[(dca instanceof Array ? "apply" : "call")](d, dca);
-        }
-
-        dojo.addOnUnload = function(/*Object?*/obj, /*String|Function?*/functionName){
-                // summary:
-                //              registers a function to be triggered when the page unloads. In a browser
-                //              enviroment, the functions will be triggered during the window.onbeforeunload
-                //              event. Be careful doing work during window.onbeforeunload. onbeforeunload
-                //              can be triggered if a link to download a file is clicked, or if the link is a
-                //              javascript: link. In these cases, the onbeforeunload event fires, but the
-                //              document is not actually destroyed. So be careful about doing destructive
-                //              operations in a dojo.addOnUnload callback.
-                // example:
-                //      |       dojo.addOnUnload(functionPointer)
-                //      |       dojo.addOnUnload(object, "functionName")
-                //      |       dojo.addOnUnload(object, function(){ /* ... */});
-
-                d._onto(d._unloaders, obj, functionName);
-        }
-
-        dojo._modulesLoaded = function(){
-                if(d._postLoad){ return; }
-                if(d._inFlightCount > 0){ 
-                        console.warn("files still in flight!");
-                        return;
-                }
-                d._callLoaded();
-        }
-
-        dojo._callLoaded = function(){
-
-                // The "object" check is for IE, and the other opera check fixes an
-                // issue in Opera where it could not find the body element in some
-                // widget test cases.  For 0.9, maybe route all browsers through the
-                // setTimeout (need protection still for non-browser environments
-                // though). This might also help the issue with FF 2.0 and freezing
-                // issues where we try to do sync xhr while background css images are
-                // being loaded (trac #2572)? Consider for 0.9.
-                if(typeof setTimeout == "object" || (dojo.config.useXDomain && d.isOpera)){
-                        if(dojo.isAIR){
-                                setTimeout(function(){dojo.loaded();}, 0);
-                        }else{
-                                setTimeout(dojo._scopeName + ".loaded();", 0);
-                        }
-                }else{
-                        d.loaded();
-                }
-        }
-
-        dojo._getModuleSymbols = function(/*String*/modulename){
-                // summary:
-                //              Converts a module name in dotted JS notation to an array
-                //              representing the path in the source tree
-                var syms = modulename.split(".");
-                for(var i = syms.length; i>0; i--){
-                        var parentModule = syms.slice(0, i).join(".");
-                        if((i==1) && !this._moduleHasPrefix(parentModule)){             
-                                // Support default module directory (sibling of dojo) for top-level modules 
-                                syms[0] = "../" + syms[0];
-                        }else{
-                                var parentModulePath = this._getModulePrefix(parentModule);
-                                if(parentModulePath != parentModule){
-                                        syms.splice(0, i, parentModulePath);
-                                        break;
-                                }
-                        }
-                }
-                // 
-                return syms; // Array
-        }
-
-        dojo._global_omit_module_check = false;
-
-        dojo.loadInit = function(/*Function*/init){
-                //      summary:
-                //              Executes a function that needs to be executed for the loader's dojo.requireIf
-                //              resolutions to work. This is needed mostly for the xdomain loader case where
-                //              a function needs to be executed to set up the possible values for a dojo.requireIf
-                //              call.
-                //      init:
-                //              a function reference. Executed immediately.
-                //      description: This function is mainly a marker for the xdomain loader to know parts of
-                //              code that needs be executed outside the function wrappper that is placed around modules.
-                //              The init function could be executed more than once, and it should make no assumptions
-                //              on what is loaded, or what modules are available. Only the functionality in Dojo Base
-                //              is allowed to be used. Avoid using this method. For a valid use case,
-                //              see the source for dojox.gfx.
-                init();
-        }
-
-        dojo._loadModule = dojo.require = function(/*String*/moduleName, /*Boolean?*/omitModuleCheck){
-                //      summary:
-                //              loads a Javascript module from the appropriate URI
-                //      moduleName:
-                //              module name to load, using periods for separators,
-                //               e.g. "dojo.date.locale".  Module paths are de-referenced by dojo's
-                //              internal mapping of locations to names and are disambiguated by
-                //              longest prefix. See `dojo.registerModulePath()` for details on
-                //              registering new modules.
-                //      omitModuleCheck:
-                //              if `true`, omitModuleCheck skips the step of ensuring that the
-                //              loaded file actually defines the symbol it is referenced by.
-                //              For example if it called as `dojo.require("a.b.c")` and the
-                //              file located at `a/b/c.js` does not define an object `a.b.c`,
-                //              and exception will be throws whereas no exception is raised
-                //              when called as `dojo.require("a.b.c", true)`
-                //      description:
-                //              `dojo.require("A.B")` first checks to see if symbol A.B is
-                //              defined. If it is, it is simply returned (nothing to do).
-                //      
-                //              If it is not defined, it will look for `A/B.js` in the script root
-                //              directory.
-                //      
-                //              `dojo.require` throws an excpetion if it cannot find a file
-                //              to load, or if the symbol `A.B` is not defined after loading.
-                //      
-                //              It returns the object `A.B`.
-                //      
-                //              `dojo.require()` does nothing about importing symbols into
-                //              the current namespace.  It is presumed that the caller will
-                //              take care of that. For example, to import all symbols into a
-                //              local block, you might write:
-                //      
-                //              |       with (dojo.require("A.B")) {
-                //              |               ...
-                //              |       }
-                //      
-                //              And to import just the leaf symbol to a local variable:
-                //      
-                //              |       var B = dojo.require("A.B");
-                //              |       ...
-                //      returns: the required namespace object
-                omitModuleCheck = this._global_omit_module_check || omitModuleCheck;
-
-                //Check if it is already loaded.
-                var module = this._loadedModules[moduleName];
-                if(module){
-                        return module;
-                }
-
-                // convert periods to slashes
-                var relpath = this._getModuleSymbols(moduleName).join("/") + '.js';
-
-                var modArg = (!omitModuleCheck) ? moduleName : null;
-                var ok = this._loadPath(relpath, modArg);
-
-                if(!ok && !omitModuleCheck){
-                        throw new Error("Could not load '" + moduleName + "'; last tried '" + relpath + "'");
-                }
-
-                // check that the symbol was defined
-                // Don't bother if we're doing xdomain (asynchronous) loading.
-                if(!omitModuleCheck && !this._isXDomain){
-                        // pass in false so we can give better error
-                        module = this._loadedModules[moduleName];
-                        if(!module){
-                                throw new Error("symbol '" + moduleName + "' is not defined after loading '" + relpath + "'"); 
-                        }
-                }
-
-                return module;
-        }
-
-        dojo.provide = function(/*String*/ resourceName){
-                //      summary:
-                //              Each javascript source file must have at least one
-                //              `dojo.provide()` call at the top of the file, corresponding to
-                //              the file name.  For example, `js/dojo/foo.js` must have
-                //              `dojo.provide("dojo.foo");` before any calls to
-                //              `dojo.require()` are made.
-                //      description:
-                //              Each javascript source file is called a resource.  When a
-                //              resource is loaded by the browser, `dojo.provide()` registers
-                //              that it has been loaded.
-                //      
-                //              For backwards compatibility reasons, in addition to registering
-                //              the resource, `dojo.provide()` also ensures that the javascript
-                //              object for the module exists.  For example,
-                //              `dojo.provide("dojox.data.FlickrStore")`, in addition to
-                //              registering that `FlickrStore.js` is a resource for the
-                //              `dojox.data` module, will ensure that the `dojox.data`
-                //              javascript object exists, so that calls like 
-                //              `dojo.data.foo = function(){ ... }` don't fail.
-                //
-                //              In the case of a build where multiple javascript source files
-                //              are combined into one bigger file (similar to a .lib or .jar
-                //              file), that file may contain multiple dojo.provide() calls, to
-                //              note that it includes multiple resources.
-
-                //Make sure we have a string.
-                resourceName = resourceName + "";
-                return (d._loadedModules[resourceName] = d.getObject(resourceName, true)); // Object
-        }
-
-        //Start of old bootstrap2:
-
-        dojo.platformRequire = function(/*Object*/modMap){
-                //      summary:
-                //              require one or more modules based on which host environment
-                //              Dojo is currently operating in
-                //      description:
-                //              This method takes a "map" of arrays which one can use to
-                //              optionally load dojo modules. The map is indexed by the
-                //              possible dojo.name_ values, with two additional values:
-                //              "default" and "common". The items in the "default" array will
-                //              be loaded if none of the other items have been choosen based on
-                //              dojo.name_, set by your host environment. The items in the
-                //              "common" array will *always* be loaded, regardless of which
-                //              list is chosen.
-                //      example:
-                //              |       dojo.platformRequire({
-                //              |               browser: [
-                //              |                       "foo.sample", // simple module
-                //              |                       "foo.test",
-                //              |                       ["foo.bar.baz", true] // skip object check in _loadModule (dojo.require)
-                //              |               ],
-                //              |               default: [ "foo.sample._base" ],
-                //              |               common: [ "important.module.common" ]
-                //              |       });
-
-                var common = modMap.common || [];
-                var result = common.concat(modMap[d._name] || modMap["default"] || []);
-
-                for(var x=0; x<result.length; x++){
-                        var curr = result[x];
-                        if(curr.constructor == Array){
-                                d._loadModule.apply(d, curr);
-                        }else{
-                                d._loadModule(curr);
-                        }
-                }
-        }
-
-        dojo.requireIf = function(/*Boolean*/ condition, /*String*/ resourceName){
-                // summary:
-                //              If the condition is true then call dojo.require() for the specified
-                //              resource
-                if(condition === true){
-                        // FIXME: why do we support chained require()'s here? does the build system?
-                        var args = [];
-                        for(var i = 1; i < arguments.length; i++){ 
-                                args.push(arguments[i]);
-                        }
-                        d.require.apply(d, args);
-                }
-        }
-
-        dojo.requireAfterIf = d.requireIf;
-
-        dojo.registerModulePath = function(/*String*/module, /*String*/prefix){
-                //      summary: 
-                //              maps a module name to a path
-                //      description: 
-                //              An unregistered module is given the default path of ../[module],
-                //              relative to Dojo root. For example, module acme is mapped to
-                //              ../acme.  If you want to use a different module name, use
-                //              dojo.registerModulePath. 
-                //      example:
-                //              If your dojo.js is located at this location in the web root:
-                //      |       /myapp/js/dojo/dojo/dojo.js
-                //              and your modules are located at:
-                //      |       /myapp/js/foo/bar.js
-                //      |       /myapp/js/foo/baz.js
-                //      |       /myapp/js/foo/thud/xyzzy.js
-                //              Your application can tell Dojo to locate the "foo" namespace by calling:
-                //      |       dojo.registerModulePath("foo", "../../foo");
-                //              At which point you can then use dojo.require() to load the
-                //              modules (assuming they provide() the same things which are
-                //              required). The full code might be:
-                //      |       <script type="text/javascript" 
-                //      |               src="/myapp/js/dojo/dojo/dojo.js"></script>
-                //      |       <script type="text/javascript">
-                //      |               dojo.registerModulePath("foo", "../../foo");
-                //      |               dojo.require("foo.bar");
-                //      |               dojo.require("foo.baz");
-                //      |               dojo.require("foo.thud.xyzzy");
-                //      |       </script>
-                d._modulePrefixes[module] = { name: module, value: prefix };
-        }
-
-        dojo.requireLocalization = function(/*String*/moduleName, /*String*/bundleName, /*String?*/locale, /*String?*/availableFlatLocales){
-                // summary:
-                //              Declares translated resources and loads them if necessary, in the
-                //              same style as dojo.require.  Contents of the resource bundle are
-                //              typically strings, but may be any name/value pair, represented in
-                //              JSON format.  See also `dojo.i18n.getLocalization`.
-                //
-                // description:
-                //              Load translated resource bundles provided underneath the "nls"
-                //              directory within a package.  Translated resources may be located in
-                //              different packages throughout the source tree.  
-                //
-                //              Each directory is named for a locale as specified by RFC 3066,
-                //              (http://www.ietf.org/rfc/rfc3066.txt), normalized in lowercase.
-                //              Note that the two bundles in the example do not define all the
-                //              same variants.  For a given locale, bundles will be loaded for
-                //              that locale and all more general locales above it, including a
-                //              fallback at the root directory.  For example, a declaration for
-                //              the "de-at" locale will first load `nls/de-at/bundleone.js`,
-                //              then `nls/de/bundleone.js` and finally `nls/bundleone.js`.  The
-                //              data will be flattened into a single Object so that lookups
-                //              will follow this cascading pattern.  An optional build step can
-                //              preload the bundles to avoid data redundancy and the multiple
-                //              network hits normally required to load these resources.
-                //
-                // moduleName: 
-                //              name of the package containing the "nls" directory in which the
-                //              bundle is found
-                //
-                // bundleName: 
-                //              bundle name, i.e. the filename without the '.js' suffix
-                //
-                // locale: 
-                //              the locale to load (optional)  By default, the browser's user
-                //              locale as defined by dojo.locale
-                //
-                // availableFlatLocales: 
-                //              A comma-separated list of the available, flattened locales for this
-                //              bundle. This argument should only be set by the build process.
-                //
-                //      example:
-                //              A particular widget may define one or more resource bundles,
-                //              structured in a program as follows, where moduleName is
-                //              mycode.mywidget and bundleNames available include bundleone and
-                //              bundletwo:
-                //      |               ...
-                //      |       mycode/
-                //      |               mywidget/
-                //      |                       nls/
-                //      |                               bundleone.js (the fallback translation, English in this example)
-                //      |                               bundletwo.js (also a fallback translation)
-                //      |                               de/
-                //      |                                       bundleone.js
-                //      |                                       bundletwo.js
-                //      |                               de-at/
-                //      |                                       bundleone.js
-                //      |                               en/
-                //      |                                       (empty; use the fallback translation)
-                //      |                               en-us/
-                //      |                                       bundleone.js
-                //      |                               en-gb/
-                //      |                                       bundleone.js
-                //      |                               es/
-                //      |                                       bundleone.js
-                //      |                                       bundletwo.js
-                //      |                                 ...etc
-                //      |                               ...
-                //
-
-                d.require("dojo.i18n");
-                d.i18n._requireLocalization.apply(d.hostenv, arguments);
-        };
-
-
-        var ore = new RegExp("^(([^:/?#]+):)?(//([^/?#]*))?([^?#]*)(\\?([^#]*))?(#(.*))?$");
-        var ire = new RegExp("^((([^\\[:]+):)?([^@]+)@)?(\\[([^\\]]+)\\]|([^\\[:]*))(:([0-9]+))?$");
-
-        dojo._Url = function(/*dojo._Url||String...*/){
-                // summary: 
-                //              Constructor to create an object representing a URL.
-                //              It is marked as private, since we might consider removing
-                //              or simplifying it.
-                // description: 
-                //              Each argument is evaluated in order relative to the next until
-                //              a canonical uri is produced. To get an absolute Uri relative to
-                //              the current document use:
-                //              new dojo._Url(document.baseURI, url)
-
-                var n = null;
-
-                var _a = arguments;
-                var uri = [_a[0]];
-                // resolve uri components relative to each other
-                for(var i = 1; i<_a.length; i++){
-                        if(!_a[i]){ continue; }
-
-                        // Safari doesn't support this.constructor so we have to be explicit
-                        // FIXME: Tracked (and fixed) in Webkit bug 3537.
-                        //              http://bugs.webkit.org/show_bug.cgi?id=3537
-                        var relobj = new d._Url(_a[i]+"");
-                        var uriobj = new d._Url(uri[0]+"");
-
-                        if(
-                                relobj.path == "" &&
-                                !relobj.scheme &&
-                                !relobj.authority &&
-                                !relobj.query
-                        ){
-                                if(relobj.fragment != n){
-                                        uriobj.fragment = relobj.fragment;
-                                }
-                                relobj = uriobj;
-                        }else if(!relobj.scheme){
-                                relobj.scheme = uriobj.scheme;
-
-                                if(!relobj.authority){
-                                        relobj.authority = uriobj.authority;
-
-                                        if(relobj.path.charAt(0) != "/"){
-                                                var path = uriobj.path.substring(0,
-                                                        uriobj.path.lastIndexOf("/") + 1) + relobj.path;
-
-                                                var segs = path.split("/");
-                                                for(var j = 0; j < segs.length; j++){
-                                                        if(segs[j] == "."){
-                                                                // flatten "./" references
-                                                                if(j == segs.length - 1){
-                                                                        segs[j] = "";
-                                                                }else{
-                                                                        segs.splice(j, 1);
-                                                                        j--;
-                                                                }
-                                                        }else if(j > 0 && !(j == 1 && segs[0] == "") &&
-                                                                segs[j] == ".." && segs[j-1] != ".."){
-                                                                // flatten "../" references
-                                                                if(j == (segs.length - 1)){
-                                                                        segs.splice(j, 1);
-                                                                        segs[j - 1] = "";
-                                                                }else{
-                                                                        segs.splice(j - 1, 2);
-                                                                        j -= 2;
-                                                                }
-                                                        }
-                                                }
-                                                relobj.path = segs.join("/");
-                                        }
-                                }
-                        }
-
-                        uri = [];
-                        if(relobj.scheme){ 
-                                uri.push(relobj.scheme, ":");
-                        }
-                        if(relobj.authority){
-                                uri.push("//", relobj.authority);
-                        }
-                        uri.push(relobj.path);
-                        if(relobj.query){
-                                uri.push("?", relobj.query);
-                        }
-                        if(relobj.fragment){
-                                uri.push("#", relobj.fragment);
-                        }
-                }
-
-                this.uri = uri.join("");
-
-                // break the uri into its main components
-                var r = this.uri.match(ore);
-
-                this.scheme = r[2] || (r[1] ? "" : n);
-                this.authority = r[4] || (r[3] ? "" : n);
-                this.path = r[5]; // can never be undefined
-                this.query = r[7] || (r[6] ? "" : n);
-                this.fragment  = r[9] || (r[8] ? "" : n);
-
-                if(this.authority != n){
-                        // server based naming authority
-                        r = this.authority.match(ire);
-
-                        this.user = r[3] || n;
-                        this.password = r[4] || n;
-                        this.host = r[6] || r[7]; // ipv6 || ipv4
-                        this.port = r[9] || n;
-                }
-        }
-
-        dojo._Url.prototype.toString = function(){ return this.uri; };
-
-        dojo.moduleUrl = function(/*String*/module, /*dojo._Url||String*/url){
-                //      summary: 
-                //              Returns a `dojo._Url` object relative to a module.
-                //      example:
-                //      |       var pngPath = dojo.moduleUrl("acme","images/small.png");
-                //      |        // list the object properties
-                //      |       // create an image and set it's source to pngPath's value:
-                //      |       var img = document.createElement("img");
-                //      |       // NOTE: we assign the string representation of the url object
-                //      |       img.src = pngPath.toString(); 
-                //      |       // add our image to the document
-                //      |       dojo.body().appendChild(img);
-                //      example: 
-                //              you may de-reference as far as you like down the package
-                //              hierarchy.  This is sometimes handy to avoid lenghty relative
-                //              urls or for building portable sub-packages. In this example,
-                //              the `acme.widget` and `acme.util` directories may be located
-                //              under different roots (see `dojo.registerModulePath`) but the
-                //              the modules which reference them can be unaware of their
-                //              relative locations on the filesystem:
-                //      |       // somewhere in a configuration block
-                //      |       dojo.registerModulePath("acme.widget", "../../acme/widget");
-                //      |       dojo.registerModulePath("acme.util", "../../util");
-                //      |       
-                //      |       // ...
-                //      |       
-                //      |       // code in a module using acme resources
-                //      |       var tmpltPath = dojo.moduleUrl("acme.widget","templates/template.html");
-                //      |       var dataPath = dojo.moduleUrl("acme.util","resources/data.json");
-
-                var loc = d._getModuleSymbols(module).join('/');
-                if(!loc){ return null; }
-                if(loc.lastIndexOf("/") != loc.length-1){
-                        loc += "/";
-                }
-                
-                //If the path is an absolute path (starts with a / or is on another
-                //domain/xdomain) then don't add the baseUrl.
-                var colonIndex = loc.indexOf(":");
-                if(loc.charAt(0) != "/" && (colonIndex == -1 || colonIndex > loc.indexOf("/"))){
-                        loc = d.baseUrl + loc;
-                }
-
-                return new d._Url(loc, url); // String
-        }
-})();
-
-/*=====
-dojo.isBrowser = {
-        //      example:
-        //      |       if(dojo.isBrowser){ ... }
-};
-
-dojo.isFF = {
-        //      example:
-        //      |       if(dojo.isFF > 1){ ... }
-};
-
-dojo.isIE = {
-        // example:
-        //      |       if(dojo.isIE > 6){
-        //      |               // we are IE7
-        //      |       }
-};
-
-dojo.isSafari = {
-        //      example:
-        //      |       if(dojo.isSafari){ ... }
-        //      example: 
-        //              Detect iPhone:
-        //      |       if(dojo.isSafari && navigator.userAgent.indexOf("iPhone") != -1){ 
-        //      |               // we are iPhone. Note, iPod touch reports "iPod" above and fails this test.
-        //      |       }
-};
-
-dojo = {
-        // isBrowser: Boolean
-        //              True if the client is a web-browser
-        isBrowser: true,
-        //      isFF: Number | undefined
-        //              Version as a Number if client is FireFox. undefined otherwise. Corresponds to
-        //              major detected FireFox version (1.5, 2, 3, etc.)
-        isFF: 2,
-        //      isIE: Number | undefined
-        //              Version as a Number if client is MSIE(PC). undefined otherwise. Corresponds to
-        //              major detected IE version (6, 7, 8, etc.)
-        isIE: 6,
-        //      isKhtml: Number | undefined
-        //              Version as a Number if client is a KTHML-derived browser (Konqueror,
-        //              Safari, etc.). undefined otherwise. Corresponds to major detected version.
-        isKhtml: 0,
-        //      isMozilla: Number | undefined
-        //              Version as a Number if client is a Mozilla-based browser (Firefox,
-        //              SeaMonkey). undefined otherwise. Corresponds to major detected version.
-        isMozilla: 0,
-        //      isOpera: Number | undefined
-        //              Version as a Number if client is Opera. undefined otherwise. Corresponds to
-        //              major detected version.
-        isOpera: 0,
-        //      isSafari: Number | undefined
-        //              Version as a Number if client is Safari or iPhone. undefined otherwise.
-        isSafari: 0
-}
-=====*/
-
-if(typeof window != 'undefined'){
-        dojo.isBrowser = true;
-        dojo._name = "browser";
-
-
-        // attempt to figure out the path to dojo if it isn't set in the config
-        (function(){
-                var d = dojo;
-                // this is a scope protection closure. We set browser versions and grab
-                // the URL we were loaded from here.
-
-                // grab the node we were loaded from
-                if(document && document.getElementsByTagName){
-                        var scripts = document.getElementsByTagName("script");
-                        var rePkg = /dojo(\.xd)?\.js(\W|$)/i;
-                        for(var i = 0; i < scripts.length; i++){
-                                var src = scripts[i].getAttribute("src");
-                                if(!src){ continue; }
-                                var m = src.match(rePkg);
-                                if(m){
-                                        // find out where we came from
-                                        if(!d.config.baseUrl){
-                                                d.config.baseUrl = src.substring(0, m.index);
-                                        }
-                                        // and find out if we need to modify our behavior
-                                        var cfg = scripts[i].getAttribute("djConfig");
-                                        if(cfg){
-                                                var cfgo = eval("({ "+cfg+" })");
-                                                for(var x in cfgo){
-                                                        dojo.config[x] = cfgo[x];
-                                                }
-                                        }
-                                        break; // "first Dojo wins"
-                                }
-                        }
-                }
-                d.baseUrl = d.config.baseUrl;
-
-                // fill in the rendering support information in dojo.render.*
-                var n = navigator;
-                var dua = n.userAgent;
-                var dav = n.appVersion;
-                var tv = parseFloat(dav);
-
-                if(dua.indexOf("Opera") >= 0){ d.isOpera = tv; }
-                // safari detection derived from:
-                //              http://developer.apple.com/internet/safari/faq.html#anchor2
-                //              http://developer.apple.com/internet/safari/uamatrix.html
-                var index = Math.max(dav.indexOf("WebKit"), dav.indexOf("Safari"), 0);
-                if(index){
-                        // try to grab the explicit Safari version first. If we don't get
-                        // one, look for 419.3+ as the indication that we're on something
-                        // "Safari 3-ish". Lastly, default to "Safari 2" handling.
-                        d.isSafari = parseFloat(dav.split("Version/")[1]) ||
-                                (parseFloat(dav.substr(index + 7)) > 419.3) ? 3 : 2;
-                }
-                if(dua.indexOf("AdobeAIR") >= 0){ d.isAIR = 1; }
-                if(dav.indexOf("Konqueror") >= 0 || d.isSafari){ d.isKhtml =  tv; }
-                if(dua.indexOf("Gecko") >= 0 && !d.isKhtml){ d.isMozilla = d.isMoz = tv; }
-                if(d.isMoz){
-                        d.isFF = parseFloat(dua.split("Firefox/")[1]) || undefined;
-                }
-                if(document.all && !d.isOpera){
-                        d.isIE = parseFloat(dav.split("MSIE ")[1]) || undefined;
-                }
-
-                //Workaround to get local file loads of dojo to work on IE 7
-                //by forcing to not use native xhr.
-                if(dojo.isIE && window.location.protocol === "file:"){
-                        dojo.config.ieForceActiveXXhr=true;
-                }
-
-                var cm = document.compatMode;
-                d.isQuirks = cm == "BackCompat" || cm == "QuirksMode" || d.isIE < 6;
-
-                // TODO: is the HTML LANG attribute relevant?
-                d.locale = dojo.config.locale || (d.isIE ? n.userLanguage : n.language).toLowerCase();
-
-                // These are in order of decreasing likelihood; this will change in time.
-                d._XMLHTTP_PROGIDS = ['Msxml2.XMLHTTP', 'Microsoft.XMLHTTP', 'Msxml2.XMLHTTP.4.0'];
-
-                d._xhrObj = function(){
-                        // summary: 
-                        //              does the work of portably generating a new XMLHTTPRequest
-                        //              object.
-                        var http = null;
-                        var last_e = null;
-                        if(!dojo.isIE || !dojo.config.ieForceActiveXXhr){
-                                try{ http = new XMLHttpRequest(); }catch(e){}
-                        }
-                        if(!http){
-                                for(var i=0; i<3; ++i){
-                                        var progid = d._XMLHTTP_PROGIDS[i];
-                                        try{
-                                                http = new ActiveXObject(progid);
-                                        }catch(e){
-                                                last_e = e;
-                                        }
-
-                                        if(http){
-                                                d._XMLHTTP_PROGIDS = [progid];  // so faster next time
-                                                break;
-                                        }
-                                }
-                        }
-
-                        if(!http){
-                                throw new Error("XMLHTTP not available: "+last_e);
-                        }
-
-                        return http; // XMLHTTPRequest instance
-                }
-
-                d._isDocumentOk = function(http){
-                        var stat = http.status || 0;
-                        return (stat >= 200 && stat < 300) ||   // Boolean
-                                stat == 304 ||                                          // allow any 2XX response code
-                                stat == 1223 ||                                                 // get it out of the cache
-                                (!stat && (location.protocol=="file:" || location.protocol=="chrome:") ); // Internet Explorer mangled the status code
-                }
-
-                //See if base tag is in use.
-                //This is to fix http://trac.dojotoolkit.org/ticket/3973,
-                //but really, we need to find out how to get rid of the dojo._Url reference
-                //below and still have DOH work with the dojo.i18n test following some other
-                //test that uses the test frame to load a document (trac #2757).
-                //Opera still has problems, but perhaps a larger issue of base tag support
-                //with XHR requests (hasBase is true, but the request is still made to document
-                //path, not base path).
-                var owloc = window.location+"";
-                var base = document.getElementsByTagName("base");
-                var hasBase = (base && base.length > 0);
-
-                d._getText = function(/*URI*/ uri, /*Boolean*/ fail_ok){
-                        // summary: Read the contents of the specified uri and return those contents.
-                        // uri:
-                        //              A relative or absolute uri. If absolute, it still must be in
-                        //              the same "domain" as we are.
-                        // fail_ok:
-                        //              Default false. If fail_ok and loading fails, return null
-                        //              instead of throwing.
-                        // returns: The response text. null is returned when there is a
-                        //              failure and failure is okay (an exception otherwise)
-
-                        // alert("_getText: " + uri);
-
-                        // NOTE: must be declared before scope switches ie. this._xhrObj()
-                        var http = this._xhrObj();
-
-                        if(!hasBase && dojo._Url){
-                                uri = (new dojo._Url(owloc, uri)).toString();
-                        }
-                        /*
-                        
-                        
-                        alert(uri);
-                        */
-
-                        if(d.config.cacheBust){
-                                //Make sure we have a string before string methods are used on uri
-                                uri += "";
-                                uri += (uri.indexOf("?") == -1 ? "?" : "&") + String(d.config.cacheBust).replace(/\W+/g,"");
-                        }
-
-                        http.open('GET', uri, false);
-                        try{
-                                http.send(null);
-                                // alert(http);
-                                if(!d._isDocumentOk(http)){
-                                        var err = Error("Unable to load "+uri+" status:"+ http.status);
-                                        err.status = http.status;
-                                        err.responseText = http.responseText;
-                                        throw err;
-                                }
-                        }catch(e){
-                                if(fail_ok){ return null; } // null
-                                // rethrow the exception
-                                throw e;
-                        }
-                        return http.responseText; // String
-                }
-                
-                d._windowUnloaders = [];
-                
-                d.windowUnloaded = function(){
-                        // summary:
-                        //              signal fired by impending window destruction. You may use
-                        //              dojo.addOnWIndowUnload() or dojo.connect() to this method to perform
-                        //              page/application cleanup methods. See dojo.addOnWindowUnload for more info.
-                        var mll = this._windowUnloaders;
-                        while(mll.length){
-                                (mll.pop())();
-                        }
-                }
-
-                d.addOnWindowUnload = function(/*Object?*/obj, /*String|Function?*/functionName){
-                        // summary:
-                        //              registers a function to be triggered when window.onunload fires.
-                        //              Be careful trying to modify the DOM or access JavaScript properties
-                        //              during this phase of page unloading: they may not always be available.
-                        //              Consider dojo.addOnUnload() if you need to modify the DOM or do heavy
-                        //              JavaScript work.
-                        // example:
-                        //      |       dojo.addOnWindowUnload(functionPointer)
-                        //      |       dojo.addOnWindowUnload(object, "functionName")
-                        //      |       dojo.addOnWindowUnload(object, function(){ /* ... */});
-        
-                        d._onto(d._windowUnloaders, obj, functionName);
-                }
-        })();
-
-        dojo._initFired = false;
-        //      BEGIN DOMContentLoaded, from Dean Edwards (http://dean.edwards.name/weblog/2006/06/again/)
-        dojo._loadInit = function(e){
-                dojo._initFired = true;
-                // allow multiple calls, only first one will take effect
-                // A bug in khtml calls events callbacks for document for event which isnt supported
-                // for example a created contextmenu event calls DOMContentLoaded, workaround
-                var type = (e && e.type) ? e.type.toLowerCase() : "load";
-                if(arguments.callee.initialized || (type != "domcontentloaded" && type != "load")){ return; }
-                arguments.callee.initialized = true;
-                if("_khtmlTimer" in dojo){
-                        clearInterval(dojo._khtmlTimer);
-                        delete dojo._khtmlTimer;
-                }
-
-                if(dojo._inFlightCount == 0){
-                        dojo._modulesLoaded();
-                }
-        }
-
-        dojo._fakeLoadInit = function(){
-                dojo._loadInit({type: "load"});
-        }
-
-        if(!dojo.config.afterOnLoad){
-                //      START DOMContentLoaded
-                // Mozilla and Opera 9 expose the event we could use
-                if(document.addEventListener){
-                        // NOTE: 
-                        //              due to a threading issue in Firefox 2.0, we can't enable
-                        //              DOMContentLoaded on that platform. For more information, see:
-                        //              http://trac.dojotoolkit.org/ticket/1704
-                        if(dojo.isOpera || dojo.isFF >= 3 || (dojo.isMoz && dojo.config.enableMozDomContentLoaded === true)){
-                                document.addEventListener("DOMContentLoaded", dojo._loadInit, null);
-                        }
-        
-                        //      mainly for Opera 8.5, won't be fired if DOMContentLoaded fired already.
-                        //  also used for Mozilla because of trac #1640
-                        window.addEventListener("load", dojo._loadInit, null);
-                }
-        
-                if(dojo.isAIR){
-                        window.addEventListener("load", dojo._loadInit, null);
-                }else if(/(WebKit|khtml)/i.test(navigator.userAgent)){ // sniff
-                        dojo._khtmlTimer = setInterval(function(){
-                                if(/loaded|complete/.test(document.readyState)){
-                                        dojo._loadInit(); // call the onload handler
-                                }
-                        }, 10);
-                }
-                //      END DOMContentLoaded
-        }
-
-        (function(){
-                var _w = window;
-                var _handleNodeEvent = function(/*String*/evtName, /*Function*/fp){
-                        // summary:
-                        //              non-destructively adds the specified function to the node's
-                        //              evtName handler.
-                        // evtName: should be in the form "onclick" for "onclick" handlers.
-                        // Make sure you pass in the "on" part.
-                        var oldHandler = _w[evtName] || function(){};
-                        _w[evtName] = function(){
-                                fp.apply(_w, arguments);
-                                oldHandler.apply(_w, arguments);
-                        };
-                };
-
-                if(dojo.isIE){
-                        //      for Internet Explorer. readyState will not be achieved on init
-                        //      call, but dojo doesn't need it however, we'll include it
-                        //      because we don't know if there are other functions added that
-                        //      might.  Note that this has changed because the build process
-                        //      strips all comments -- including conditional ones.
-                        if(!dojo.config.afterOnLoad){
-                                document.write('<scr'+'ipt defer src="//:" '
-                                        + 'onreadystatechange="if(this.readyState==\'complete\'){' + dojo._scopeName + '._loadInit();}">'
-                                        + '</scr'+'ipt>'
-                                );
-                        }
-
-                        try{
-                                document.namespaces.add("v","urn:schemas-microsoft-com:vml");
-                                document.createStyleSheet().addRule("v\\:*", "behavior:url(#default#VML)");
-                        }catch(e){}
-                }
-
-                // FIXME: dojo.unloaded requires dojo scope, so using anon function wrapper.
-                _handleNodeEvent("onbeforeunload", function() { dojo.unloaded(); });
-                _handleNodeEvent("onunload", function() { dojo.windowUnloaded(); });
-        })();
-
-        /*
-        OpenAjax.subscribe("OpenAjax", "onload", function(){
-                if(dojo._inFlightCount == 0){
-                        dojo._modulesLoaded();
-                }
-        });
-
-        OpenAjax.subscribe("OpenAjax", "onunload", function(){
-                dojo.unloaded();
-        });
-        */
-} //if (typeof window != 'undefined')
-
-//Register any module paths set up in djConfig. Need to do this
-//in the hostenvs since hostenv_browser can read djConfig from a
-//script tag's attribute.
-(function(){
-        var mp = dojo.config["modulePaths"];
-        if(mp){
-                for(var param in mp){
-                        dojo.registerModulePath(param, mp[param]);
-                }
-        }
-})();
-
-//Load debug code if necessary.
-if(dojo.config.isDebug){
-        dojo.require("dojo._firebug.firebug");
-}
-
-if(dojo.config.debugAtAllCosts){
-        dojo.config.useXDomain = true;
-        dojo.require("dojo._base._loader.loader_xd");
-        dojo.require("dojo._base._loader.loader_debug");
-        dojo.require("dojo.i18n");
-}
-
-if(!dojo._hasResource["dojo._base.lang"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
-dojo._hasResource["dojo._base.lang"] = true;
-dojo.provide("dojo._base.lang");
-
-// Crockford (ish) functions
-
-dojo.isString = function(/*anything*/ it){
-        //      summary:
-        //              Return true if it is a String
-        return !!arguments.length && it != null && (typeof it == "string" || it instanceof String); // Boolean
-}
-
-dojo.isArray = function(/*anything*/ it){
-        //      summary:
-        //              Return true if it is an Array
-        return it && (it instanceof Array || typeof it == "array"); // Boolean
-}
-
-/*=====
-dojo.isFunction = function(it){
-        // summary: Return true if it is a Function
-        // it: anything
-        return; // Boolean
-}
-=====*/
-
-dojo.isFunction = (function(){
-        var _isFunction = function(/*anything*/ it){
-                return it && (typeof it == "function" || it instanceof Function); // Boolean
-        };
-
-        return dojo.isSafari ?
-                // only slow this down w/ gratuitious casting in Safari since it's what's b0rken
-                function(/*anything*/ it){
-                        if(typeof it == "function" && it == "[object NodeList]"){ return false; }
-                        return _isFunction(it); // Boolean
-                } : _isFunction;
-})();
-
-dojo.isObject = function(/*anything*/ it){
-        // summary: 
-        //              Returns true if it is a JavaScript object (or an Array, a Function
-        //              or null)
-        return it !== undefined &&
-                (it === null || typeof it == "object" || dojo.isArray(it) || dojo.isFunction(it)); // Boolean
-}
-
-dojo.isArrayLike = function(/*anything*/ it){
-        //      summary:
-        //              similar to dojo.isArray() but more permissive
-        //      description:
-        //              Doesn't strongly test for "arrayness".  Instead, settles for "isn't
-        //              a string or number and has a length property". Arguments objects
-        //              and DOM collections will return true when passed to
-        //              dojo.isArrayLike(), but will return false when passed to
-        //              dojo.isArray().
-        //      returns:
-        //              If it walks like a duck and quicks like a duck, return `true`
-        var d = dojo;
-        return it && it !== undefined && // Boolean
-                // keep out built-in constructors (Number, String, ...) which have length
-                // properties
-                !d.isString(it) && !d.isFunction(it) &&
-                !(it.tagName && it.tagName.toLowerCase() == 'form') &&
-                (d.isArray(it) || isFinite(it.length));
-}
-
-dojo.isAlien = function(/*anything*/ it){
-        // summary: 
-        //              Returns true if it is a built-in function or some other kind of
-        //              oddball that *should* report as a function but doesn't
-        return it && !dojo.isFunction(it) && /\{\s*\[native code\]\s*\}/.test(String(it)); // Boolean
-}
-
-dojo.extend = function(/*Object*/ constructor, /*Object...*/ props){
-        // summary:
-        //              Adds all properties and methods of props to constructor's
-        //              prototype, making them available to all instances created with
-        //              constructor.
-        for(var i=1, l=arguments.length; i<l; i++){
-                dojo._mixin(constructor.prototype, arguments[i]);
-        }
-        return constructor; // Object
-}
-
-dojo._hitchArgs = function(scope, method /*,...*/){
-        var pre = dojo._toArray(arguments, 2);
-        var named = dojo.isString(method);
-        return function(){
-                // arrayify arguments
-                var args = dojo._toArray(arguments);
-                // locate our method
-                var f = named ? (scope||dojo.global)[method] : method;
-                // invoke with collected args
-                return f && f.apply(scope || this, pre.concat(args)); // mixed
-        } // Function
-}
-
-dojo.hitch = function(/*Object*/scope, /*Function|String*/method /*,...*/){
-        //      summary: 
-        //              Returns a function that will only ever execute in the a given scope. 
-        //              This allows for easy use of object member functions
-        //              in callbacks and other places in which the "this" keyword may
-        //              otherwise not reference the expected scope. 
-        //              Any number of default positional arguments may be passed as parameters 
-        //              beyond "method".
-        //              Each of these values will be used to "placehold" (similar to curry)
-        //              for the hitched function. 
-        //      scope: 
-        //              The scope to use when method executes. If method is a string, 
-        //              scope is also the object containing method.
-        //      method:
-        //              A function to be hitched to scope, or the name of the method in
-        //              scope to be hitched.
-        //      example:
-        //      |       dojo.hitch(foo, "bar")(); 
-        //              runs foo.bar() in the scope of foo
-        //      example:
-        //      |       dojo.hitch(foo, myFunction);
-        //              returns a function that runs myFunction in the scope of foo
-        if(arguments.length > 2){
-                return dojo._hitchArgs.apply(dojo, arguments); // Function
-        }
-        if(!method){
-                method = scope;
-                scope = null;
-        }
-        if(dojo.isString(method)){
-                scope = scope || dojo.global;
-                if(!scope[method]){ throw(['dojo.hitch: scope["', method, '"] is null (scope="', scope, '")'].join('')); }
-                return function(){ return scope[method].apply(scope, arguments || []); }; // Function
-        }
-        return !scope ? method : function(){ return method.apply(scope, arguments || []); }; // Function
-}
-
-/*=====
-dojo.delegate = function(obj, props){
-        //      summary:
-        //              returns a new object which "looks" to obj for properties which it
-        //              does not have a value for. Optionally takes a bag of properties to
-        //              seed the returned object with initially. 
-        //      description:
-        //              This is a small implementaton of the Boodman/Crockford delegation
-        //              pattern in JavaScript. An intermediate object constructor mediates
-        //              the prototype chain for the returned object, using it to delegate
-        //              down to obj for property lookup when object-local lookup fails.
-        //              This can be thought of similarly to ES4's "wrap", save that it does
-        //              not act on types but rather on pure objects.
-        //      obj:
-        //              The object to delegate to for properties not found directly on the
-        //              return object or in props.
-        //      props:
-        //              an object containing properties to assign to the returned object
-        //      returns:
-        //              an Object of anonymous type
-        //      example:
-        //      |       var foo = { bar: "baz" };
-        //      |       var thinger = dojo.delegate(foo, { thud: "xyzzy"});
-        //      |       thinger.bar == "baz"; // delegated to foo
-        //      |       foo.thud == undefined; // by definition
-        //      |       thinger.thud == "xyzzy"; // mixed in from props
-        //      |       foo.bar = "thonk";
-        //      |       thinger.bar == "thonk"; // still delegated to foo's bar
-}
-=====*/
-
-dojo.delegate = dojo._delegate = (function(){
-        // boodman/crockford delegation w/ cornford optimization
-        function TMP(){};
-        return function(obj, props){
-                TMP.prototype = obj;
-                var tmp = new TMP();
-                if(props){
-                        dojo._mixin(tmp, props);
-                }
-                return tmp; // Object
-        }
-})();
-
-/*=====
-dojo._toArray = function(obj, offset, startWith){
-        //      summary:
-        //              Converts an array-like object (i.e. arguments, DOMCollection) to an
-        //              array. Returns a new Array with the elements of obj.
-        //      obj: Object
-        //              the object to "arrayify". We expect the object to have, at a
-        //              minimum, a length property which corresponds to integer-indexed
-        //              properties.
-        //      offset: Number?
-        //              the location in obj to start iterating from. Defaults to 0.
-        //              Optional.
-        //      startWith: Array?
-        //              An array to pack with the properties of obj. If provided,
-        //              properties in obj are appended at the end of startWith and
-        //              startWith is the returned array.
-}
-=====*/
-
-(function(){
-        var efficient = function(obj, offset, startWith){
-                return (startWith||[]).concat(Array.prototype.slice.call(obj, offset||0));
-        };
-
-        var slow = function(obj, offset, startWith){
-                var arr = startWith||[]; 
-                for(var x = offset || 0; x < obj.length; x++){ 
-                        arr.push(obj[x]); 
-                } 
-                return arr;
-        };
-
-        dojo._toArray = (!dojo.isIE) ? efficient : function(obj){
-                return ((obj.item) ? slow : efficient).apply(this, arguments);
-        };
-
-})();
-
-dojo.partial = function(/*Function|String*/method /*, ...*/){
-        //      summary:
-        //              similar to hitch() except that the scope object is left to be
-        //              whatever the execution context eventually becomes.
-        //      description:
-        //              Calling dojo.partial is the functional equivalent of calling:
-        //              |       dojo.hitch(null, funcName, ...);
-        var arr = [ null ];
-        return dojo.hitch.apply(dojo, arr.concat(dojo._toArray(arguments))); // Function
-}
-
-dojo.clone = function(/*anything*/ o){
-        // summary:
-        //              Clones objects (including DOM nodes) and all children.
-        //              Warning: do not clone cyclic structures.
-        if(!o){ return o; }
-        if(dojo.isArray(o)){
-                var r = [];
-                for(var i = 0; i < o.length; ++i){
-                        r.push(dojo.clone(o[i]));
-                }
-                return r; // Array
-        }
-        if(!dojo.isObject(o)){
-                return o;       /*anything*/
-        }
-        if(o.nodeType && o.cloneNode){ // isNode
-                return o.cloneNode(true); // Node
-        }
-        if(o instanceof Date){
-                return new Date(o.getTime());   // Date
-        }
-        // Generic objects
-        var r = new o.constructor(); // specific to dojo.declare()'d classes!
-        for(var i in o){
-                if(!(i in r) || r[i] != o[i]){
-                        r[i] = dojo.clone(o[i]);
-                }
-        }
-        return r; // Object
-}
-
-dojo.trim = function(/*String*/ str){
-        // summary: 
-        //              trims whitespaces from both sides of the string
-        // description:
-        //              This version of trim() was selected for inclusion into the base due
-        //              to its compact size and relatively good performance (see Steven
-        //              Levithan's blog:
-        //              http://blog.stevenlevithan.com/archives/faster-trim-javascript).
-        //              The fastest but longest version of this function is located at
-        //              dojo.string.trim()
-        return str.replace(/^\s\s*/, '').replace(/\s\s*$/, ''); // String
-}
-
-}
-
-if(!dojo._hasResource["dojo._base.declare"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
-dojo._hasResource["dojo._base.declare"] = true;
-dojo.provide("dojo._base.declare");
-
-
-// this file courtesy of the TurboAjax Group, licensed under a Dojo CLA
-
-dojo.declare = function(/*String*/ className, /*Function|Function[]*/ superclass, /*Object*/ props){
-        //      summary: 
-        //              Create a feature-rich constructor from compact notation
-        //      className:
-        //              The name of the constructor (loosely, a "class")
-        //              stored in the "declaredClass" property in the created prototype
-        //      superclass:
-        //              May be null, a Function, or an Array of Functions. If an array, 
-        //              the first element is used as the prototypical ancestor and
-        //              any following Functions become mixin ancestors.
-        //      props:
-        //              An object whose properties are copied to the
-        //              created prototype.
-        //              Add an instance-initialization function by making it a property 
-        //              named "constructor".
-        //      description:
-        //              Create a constructor using a compact notation for inheritance and
-        //              prototype extension. 
-        //
-        //              All superclasses (including mixins) must be Functions (not simple Objects).
-        //
-        //              Mixin ancestors provide a type of multiple inheritance. Prototypes of mixin 
-        //              ancestors are copied to the new class: changes to mixin prototypes will
-        //              not affect classes to which they have been mixed in.
-        //
-        //              "className" is cached in "declaredClass" property of the new class.
-        //
-        //      example:
-        //      |       dojo.declare("my.classes.bar", my.classes.foo, {
-        //      |               // properties to be added to the class prototype
-        //      |               someValue: 2,
-        //      |               // initialization function
-        //      |               constructor: function(){
-        //      |                       this.myComplicatedObject = new ReallyComplicatedObject(); 
-        //      |               },
-        //      |               // other functions
-        //      |               someMethod: function(){ 
-        //      |                       doStuff(); 
-        //      |               }
-        //      |       );
-
-        // process superclass argument
-        var dd = arguments.callee, mixins;
-        if(dojo.isArray(superclass)){
-                mixins = superclass;
-                superclass = mixins.shift();
-        }
-        // construct intermediate classes for mixins
-        if(mixins){
-                dojo.forEach(mixins, function(m){
-                        if(!m){ throw(className + ": mixin #" + i + " is null"); } // It's likely a required module is not loaded
-                        superclass = dd._delegate(superclass, m);
-                });
-        }
-        // create constructor
-        var ctor = dd._delegate(superclass);
-        // extend with "props"
-        props = props || {};
-        ctor.extend(props);
-        // more prototype decoration
-        dojo.extend(ctor, {declaredClass: className, _constructor: props.constructor/*, preamble: null*/});
-        // special help for IE
-        ctor.prototype.constructor = ctor;
-        // create named reference
-        return dojo.setObject(className, ctor); // Function
-};
-
-dojo.mixin(dojo.declare, {
-        _delegate: function(base, mixin){
-                var bp = (base||0).prototype, mp = (mixin||0).prototype, dd=dojo.declare;
-                // fresh constructor, fresh prototype
-                var ctor = dd._makeCtor();
-                // cache ancestry
-                dojo.mixin(ctor, {superclass: bp, mixin: mp, extend: dd._extend});
-                // chain prototypes
-                if(base){ctor.prototype = dojo._delegate(bp);}
-                // add mixin and core
-                dojo.extend(ctor, dd._core, mp||0, {_constructor: null, preamble: null});
-                // special help for IE
-                ctor.prototype.constructor = ctor;
-                // name this class for debugging
-                ctor.prototype.declaredClass = (bp||0).declaredClass + '_' + (mp||0).declaredClass;
-                return ctor;
-        },
-        _extend: function(props){
-                var i, fn;
-                for(i in props){ if(dojo.isFunction(fn=props[i]) && !0[i]){fn.nom=i;fn.ctor=this;} }
-                dojo.extend(this, props);
-        },
-        _makeCtor: function(){
-                // we have to make a function, but don't want to close over anything
-                return function(){ this._construct(arguments); };
-        },
-        _core: { 
-                _construct: function(args){
-                        var c=args.callee, s=c.superclass, ct=s&&s.constructor, m=c.mixin, mct=m&&m.constructor, a=args, ii, fn;
-                        // side-effect of = used on purpose here, lint may complain, don't try this at home
-                        if(a[0]){ 
-                                // FIXME: preambles for each mixin should be allowed
-                                // FIXME: 
-                                //              should we allow the preamble here NOT to modify the
-                                //              default args, but instead to act on each mixin
-                                //              independently of the class instance being constructed
-                                //              (for impedence matching)?
-
-                                // allow any first argument w/ a "preamble" property to act as a
-                                // class preamble (not exclusive of the prototype preamble)
-                                if(/*dojo.isFunction*/((fn = a[0].preamble))){ 
-                                        a = fn.apply(this, a) || a; 
-                                }
-                        } 
-                        // prototype preamble
-                        if((fn = c.prototype.preamble)){a = fn.apply(this, a) || a;}
-                        // FIXME: 
-                        //              need to provide an optional prototype-settable
-                        //              "_explicitSuper" property which disables this
-                        // initialize superclass
-                        if(ct&&ct.apply){ct.apply(this, a);}
-                        // initialize mixin
-                        if(mct&&mct.apply){mct.apply(this, a);}
-                        // initialize self
-                        if((ii=c.prototype._constructor)){ii.apply(this, args);}
-                        // post construction
-                        if(this.constructor.prototype==c.prototype && (ct=this.postscript)){ ct.apply(this, args); }
-                },
-                _findMixin: function(mixin){
-                        var c = this.constructor, p, m;
-                        while(c){
-                                p = c.superclass;
-                                m = c.mixin;
-                                if(m==mixin || (m instanceof mixin.constructor)){return p;}
-                                if(m && m._findMixin && (m=m._findMixin(mixin))){return m;}
-                                c = p && p.constructor;
-                        }
-                },
-                _findMethod: function(name, method, ptype, has){
-                        // consciously trading readability for bytes and speed in this low-level method
-                        var p=ptype, c, m, f;
-                        do{
-                                c = p.constructor;
-                                m = c.mixin;
-                                // find method by name in our mixin ancestor
-                                if(m && (m=this._findMethod(name, method, m, has))){return m;}
-                                // if we found a named method that either exactly-is or exactly-is-not 'method'
-                                if((f=p[name])&&(has==(f==method))){return p;}
-                                // ascend chain
-                                p = c.superclass;
-                        }while(p);
-                        // if we couldn't find an ancestor in our primary chain, try a mixin chain
-                        return !has && (p=this._findMixin(ptype)) && this._findMethod(name, method, p, has);
-                },
-                inherited: function(name, args, newArgs){
-                        // optionalize name argument
-                        var a = arguments;
-                        if(!dojo.isString(a[0])){newArgs=args; args=name; name=args.callee.nom;}
-                        a = newArgs||args;
-                        var c = args.callee, p = this.constructor.prototype, fn, mp;
-                        // if not an instance override
-                        if(this[name] != c || p[name] == c){
-                                // start from memoized prototype, or
-                                // find a prototype that has property 'name' == 'c'
-                                mp = (c.ctor||0).superclass || this._findMethod(name, c, p, true);
-                                if(!mp){throw(this.declaredClass + ': inherited method "' + name + '" mismatch');}
-                                // find a prototype that has property 'name' != 'c'
-                                p = this._findMethod(name, c, mp, false);
-                        }
-                        // we expect 'name' to be in prototype 'p'
-                        fn = p && p[name];
-                        if(!fn){throw(mp.declaredClass + ': inherited method "' + name + '" not found');}
-                        // if the function exists, invoke it in our scope
-                        return fn.apply(this, a);
-                }
-        }
-});
-
-}
-
-if(!dojo._hasResource["dojo._base.connect"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
-dojo._hasResource["dojo._base.connect"] = true;
-dojo.provide("dojo._base.connect");
-
-
-// this file courtesy of the TurboAjax Group, licensed under a Dojo CLA
-
-// low-level delegation machinery
-dojo._listener = {
-        // create a dispatcher function
-        getDispatcher: function(){
-                // following comments pulled out-of-line to prevent cloning them 
-                // in the returned function.
-                // - indices (i) that are really in the array of listeners (ls) will 
-                //   not be in Array.prototype. This is the 'sparse array' trick
-                //   that keeps us safe from libs that take liberties with built-in 
-                //   objects
-                // - listener is invoked with current scope (this)
-                return function(){
-                        var ap=Array.prototype, c=arguments.callee, ls=c._listeners, t=c.target;
-                        // return value comes from original target function
-                        var r = t && t.apply(this, arguments);
-                        // make local copy of listener array so it is immutable during processing
-                        var lls;
-                                                                                        lls = [].concat(ls);
-                                                        
-                        // invoke listeners after target function
-                        for(var i in lls){
-                                if(!(i in ap)){
-                                        lls[i].apply(this, arguments);
-                                }
-                        }
-                        // return value comes from original target function
-                        return r;
-                }
-        },
-        // add a listener to an object
-        add: function(/*Object*/ source, /*String*/ method, /*Function*/ listener){
-                // Whenever 'method' is invoked, 'listener' will have the same scope.
-                // Trying to supporting a context object for the listener led to 
-                // complexity. 
-                // Non trivial to provide 'once' functionality here
-                // because listener could be the result of a dojo.hitch call,
-                // in which case two references to the same hitch target would not
-                // be equivalent. 
-                source = source || dojo.global;
-                // The source method is either null, a dispatcher, or some other function
-                var f = source[method];
-                // Ensure a dispatcher
-                if(!f||!f._listeners){
-                        var d = dojo._listener.getDispatcher();
-                        // original target function is special
-                        d.target = f;
-                        // dispatcher holds a list of listeners
-                        d._listeners = []; 
-                        // redirect source to dispatcher
-                        f = source[method] = d;
-                }
-                // The contract is that a handle is returned that can 
-                // identify this listener for disconnect. 
-                //
-                // The type of the handle is private. Here is it implemented as Integer. 
-                // DOM event code has this same contract but handle is Function 
-                // in non-IE browsers.
-                //
-                // We could have separate lists of before and after listeners.
-                return f._listeners.push(listener) ; /*Handle*/
-        },
-        // remove a listener from an object
-        remove: function(/*Object*/ source, /*String*/ method, /*Handle*/ handle){
-                var f = (source||dojo.global)[method];
-                // remember that handle is the index+1 (0 is not a valid handle)
-                if(f && f._listeners && handle--){
-                        delete f._listeners[handle];
-                }
-        }
-};
-
-// Multiple delegation for arbitrary methods.
-
-// This unit knows nothing about DOM, 
-// but we include DOM aware 
-// documentation and dontFix
-// argument here to help the autodocs.
-// Actual DOM aware code is in event.js.
-
-dojo.connect = function(/*Object|null*/ obj, 
-                                                /*String*/ event, 
-                                                /*Object|null*/ context, 
-                                                /*String|Function*/ method,
-                                                /*Boolean*/ dontFix){
-        // summary:
-        //              Create a link that calls one function when another executes. 
-        //
-        // description:
-        //              Connects method to event, so that after event fires, method
-        //              does too. All connected functions are passed the same arguments as
-        //              the event function was initially called with. You may connect as
-        //              many methods to event as needed.
-        //
-        //              event must be a string. If obj is null, dojo.global is used.
-        //
-        //              null arguments may simply be omitted.
-        //
-        //              obj[event] can resolve to a function or undefined (null). 
-        //              If obj[event] is null, it is assigned a function.
-        //
-        //              The return value is a handle that is needed to 
-        //              remove this connection with dojo.disconnect.
-        //
-        // obj: 
-        //              The source object for the event function. 
-        //              Defaults to dojo.global if null.
-        //              If obj is a DOM node, the connection is delegated 
-        //              to the DOM event manager (unless dontFix is true).
-        //
-        // event:
-        //              String name of the event function in obj. 
-        //              I.e. identifies a property obj[event].
-        //
-        // context: 
-        //              The object that method will receive as "this".
-        //
-        //              If context is null and method is a function, then method
-        //              inherits the context of event.
-        //      
-        //              If method is a string then context must be the source 
-        //              object object for method (context[method]). If context is null,
-        //              dojo.global is used.
-        //
-        // method:
-        //              A function reference, or name of a function in context. 
-        //              The function identified by method fires after event does. 
-        //              method receives the same arguments as the event.
-        //              See context argument comments for information on method's scope.
-        //
-        // dontFix:
-        //              If obj is a DOM node, set dontFix to true to prevent delegation 
-        //              of this connection to the DOM event manager. 
-        //
-        // example:
-        //              When obj.onchange(), do ui.update():
-        //      |       dojo.connect(obj, "onchange", ui, "update");
-        //      |       dojo.connect(obj, "onchange", ui, ui.update); // same
-        //
-        // example:
-        //              Using return value for disconnect:
-        //      |       var link = dojo.connect(obj, "onchange", ui, "update");
-        //      |       ...
-        //      |       dojo.disconnect(link);
-        //
-        // example:
-        //              When onglobalevent executes, watcher.handler is invoked:
-        //      |       dojo.connect(null, "onglobalevent", watcher, "handler");
-        //
-        // example:
-        //              When ob.onCustomEvent executes, customEventHandler is invoked:
-        //      |       dojo.connect(ob, "onCustomEvent", null, "customEventHandler");
-        //      |       dojo.connect(ob, "onCustomEvent", "customEventHandler"); // same
-        //
-        // example:
-        //              When ob.onCustomEvent executes, customEventHandler is invoked
-        //              with the same scope (this):
-        //      |       dojo.connect(ob, "onCustomEvent", null, customEventHandler);
-        //      |       dojo.connect(ob, "onCustomEvent", customEventHandler); // same
-        //
-        // example:
-        //              When globalEvent executes, globalHandler is invoked
-        //              with the same scope (this):
-        //      |       dojo.connect(null, "globalEvent", null, globalHandler);
-        //      |       dojo.connect("globalEvent", globalHandler); // same
-
-        // normalize arguments
-        var a=arguments, args=[], i=0;
-        // if a[0] is a String, obj was ommited
-        args.push(dojo.isString(a[0]) ? null : a[i++], a[i++]);
-        // if the arg-after-next is a String or Function, context was NOT omitted
-        var a1 = a[i+1];
-        args.push(dojo.isString(a1)||dojo.isFunction(a1) ? a[i++] : null, a[i++]);
-        // absorb any additional arguments
-        for(var l=a.length; i<l; i++){  args.push(a[i]); }
-        // do the actual work
-        return dojo._connect.apply(this, args); /*Handle*/
-}
-
-// used by non-browser hostenvs. always overriden by event.js
-dojo._connect = function(obj, event, context, method){
-        var l=dojo._listener, h=l.add(obj, event, dojo.hitch(context, method)); 
-        return [obj, event, h, l]; // Handle
-}
-
-dojo.disconnect = function(/*Handle*/ handle){
-        // summary:
-        //              Remove a link created by dojo.connect.
-        // description:
-        //              Removes the connection between event and the method referenced by handle.
-        // handle:
-        //              the return value of the dojo.connect call that created the connection.
-        if(handle && handle[0] !== undefined){
-                dojo._disconnect.apply(this, handle);
-                // let's not keep this reference
-                delete handle[0];
-        }
-}
-
-dojo._disconnect = function(obj, event, handle, listener){
-        listener.remove(obj, event, handle);
-}
-
-// topic publish/subscribe
-
-dojo._topics = {};
-
-dojo.subscribe = function(/*String*/ topic, /*Object|null*/ context, /*String|Function*/ method){
-        //      summary:
-        //              Attach a listener to a named topic. The listener function is invoked whenever the
-        //              named topic is published (see: dojo.publish).
-        //              Returns a handle which is needed to unsubscribe this listener.
-        //      context:
-        //              Scope in which method will be invoked, or null for default scope.
-        //      method:
-        //              The name of a function in context, or a function reference. This is the function that
-        //              is invoked when topic is published.
-        //      example:
-        //      |       dojo.subscribe("alerts", null, function(caption, message){ alert(caption + "\n" + message); };
-        //      |       dojo.publish("alerts", [ "read this", "hello world" ]);                                                                                                                                 
-
-        // support for 2 argument invocation (omitting context) depends on hitch
-        return [topic, dojo._listener.add(dojo._topics, topic, dojo.hitch(context, method))]; /*Handle*/
-}
-
-dojo.unsubscribe = function(/*Handle*/ handle){
-        //      summary:
-        //              Remove a topic listener. 
-        //      handle:
-        //              The handle returned from a call to subscribe.
-        //      example:
-        //      |       var alerter = dojo.subscribe("alerts", null, function(caption, message){ alert(caption + "\n" + message); };
-        //      |       ...
-        //      |       dojo.unsubscribe(alerter);
-        if(handle){
-                dojo._listener.remove(dojo._topics, handle[0], handle[1]);
-        }
-}
-
-dojo.publish = function(/*String*/ topic, /*Array*/ args){
-        //      summary:
-        //              Invoke all listener method subscribed to topic.
-        //      topic:
-        //              The name of the topic to publish.
-        //      args:
-        //              An array of arguments. The arguments will be applied 
-        //              to each topic subscriber (as first class parameters, via apply).
-        //      example:
-        //      |       dojo.subscribe("alerts", null, function(caption, message){ alert(caption + "\n" + message); };
-        //      |       dojo.publish("alerts", [ "read this", "hello world" ]); 
-
-        // Note that args is an array, which is more efficient vs variable length
-        // argument list.  Ideally, var args would be implemented via Array
-        // throughout the APIs.
-        var f = dojo._topics[topic];
-        if(f){
-                f.apply(this, args||[]);
-        }
-}
-
-dojo.connectPublisher = function(       /*String*/ topic, 
-                                                                        /*Object|null*/ obj, 
-                                                                        /*String*/ event){
-        //      summary:
-        //              Ensure that everytime obj.event() is called, a message is published
-        //              on the topic. Returns a handle which can be passed to
-        //              dojo.disconnect() to disable subsequent automatic publication on
-        //              the topic.
-        //      topic:
-        //              The name of the topic to publish.
-        //      obj: 
-        //              The source object for the event function. Defaults to dojo.global
-        //              if null.
-        //      event:
-        //              The name of the event function in obj. 
-        //              I.e. identifies a property obj[event].
-        //      example:
-        //      |       dojo.connectPublisher("/ajax/start", dojo, "xhrGet");
-        var pf = function(){ dojo.publish(topic, arguments); }
-        return (event) ? dojo.connect(obj, event, pf) : dojo.connect(obj, pf); //Handle
-};
-
-}
-
-if(!dojo._hasResource["dojo._base.Deferred"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
-dojo._hasResource["dojo._base.Deferred"] = true;
-dojo.provide("dojo._base.Deferred");
-
-
-dojo.Deferred = function(/*Function?*/ canceller){
-        // summary:
-        //              Encapsulates a sequence of callbacks in response to a value that
-        //              may not yet be available.  This is modeled after the Deferred class
-        //              from Twisted <http://twistedmatrix.com>.
-        // description:
-        //              JavaScript has no threads, and even if it did, threads are hard.
-        //              Deferreds are a way of abstracting non-blocking events, such as the
-        //              final response to an XMLHttpRequest. Deferreds create a promise to
-        //              return a response a some point in the future and an easy way to
-        //              register your interest in receiving that response.
-        //
-        //              The most important methods for Deffered users are:
-        //
-        //                      * addCallback(handler)
-        //                      * addErrback(handler)
-        //                      * callback(result)
-        //                      * errback(result)
-        //
-        //              In general, when a function returns a Deferred, users then "fill
-        //              in" the second half of the contract by registering callbacks and
-        //              error handlers. You may register as many callback and errback
-        //              handlers as you like and they will be executed in the order
-        //              registered when a result is provided. Usually this result is
-        //              provided as the result of an asynchronous operation. The code
-        //              "managing" the Deferred (the code that made the promise to provide
-        //              an answer later) will use the callback() and errback() methods to
-        //              communicate with registered listeners about the result of the
-        //              operation. At this time, all registered result handlers are called
-        //              *with the most recent result value*.
-        //
-        //              Deferred callback handlers are treated as a chain, and each item in
-        //              the chain is required to return a value that will be fed into
-        //              successive handlers. The most minimal callback may be registered
-        //              like this:
-        //
-        //              |       var d = new dojo.Deferred();
-        //              |       d.addCallback(function(result){ return result; });
-        //
-        //              Perhaps the most common mistake when first using Deferreds is to
-        //              forget to return a value (in most cases, the value you were
-        //              passed).
-        //
-        //              The sequence of callbacks is internally represented as a list of
-        //              2-tuples containing the callback/errback pair.  For example, the
-        //              following call sequence:
-        //              
-        //              |       var d = new dojo.Deferred();
-        //              |       d.addCallback(myCallback);
-        //              |       d.addErrback(myErrback);
-        //              |       d.addBoth(myBoth);
-        //              |       d.addCallbacks(myCallback, myErrback);
-        //
-        //              is translated into a Deferred with the following internal
-        //              representation:
-        //
-        //              |       [
-        //              |               [myCallback, null],
-        //              |               [null, myErrback],
-        //              |               [myBoth, myBoth],
-        //              |               [myCallback, myErrback]
-        //              |       ]
-        //
-        //              The Deferred also keeps track of its current status (fired).  Its
-        //              status may be one of three things:
-        //
-        //                      * -1: no value yet (initial condition)
-        //                      * 0: success
-        //                      * 1: error
-        //      
-        //              A Deferred will be in the error state if one of the following three
-        //              conditions are met:
-        //
-        //                      1. The result given to callback or errback is "instanceof" Error
-        //                      2. The previous callback or errback raised an exception while
-        //                         executing
-        //                      3. The previous callback or errback returned a value
-        //                         "instanceof" Error
-        //
-        //              Otherwise, the Deferred will be in the success state. The state of
-        //              the Deferred determines the next element in the callback sequence
-        //              to run.
-        //
-        //              When a callback or errback occurs with the example deferred chain,
-        //              something equivalent to the following will happen (imagine
-        //              that exceptions are caught and returned):
-        //
-        //              |       // d.callback(result) or d.errback(result)
-        //              |       if(!(result instanceof Error)){
-        //              |               result = myCallback(result);
-        //              |       }
-        //              |       if(result instanceof Error){
-        //              |               result = myErrback(result);
-        //              |       }
-        //              |       result = myBoth(result);
-        //              |       if(result instanceof Error){
-        //              |               result = myErrback(result);
-        //              |       }else{
-        //              |               result = myCallback(result);
-        //              |       }
-        //
-        //              The result is then stored away in case another step is added to the
-        //              callback sequence.      Since the Deferred already has a value
-        //              available, any new callbacks added will be called immediately.
-        //
-        //              There are two other "advanced" details about this implementation
-        //              that are useful:
-        //
-        //              Callbacks are allowed to return Deferred instances themselves, so
-        //              you can build complicated sequences of events with ease.
-        //
-        //              The creator of the Deferred may specify a canceller.  The canceller
-        //              is a function that will be called if Deferred.cancel is called
-        //              before the Deferred fires. You can use this to implement clean
-        //              aborting of an XMLHttpRequest, etc. Note that cancel will fire the
-        //              deferred with a CancelledError (unless your canceller returns
-        //              another kind of error), so the errbacks should be prepared to
-        //              handle that error for cancellable Deferreds.
-        // example:
-        //      |       var deferred = new dojo.Deferred();
-        //      |       setTimeout(function(){ deferred.callback({success: true}); }, 1000);
-        //      |       return deferred;
-        // example:
-        //              Deferred objects are often used when making code asynchronous. It
-        //              may be easiest to write functions in a synchronous manner and then
-        //              split code using a deferred to trigger a response to a long-lived
-        //              operation. For example, instead of register a callback function to
-        //              denote when a rendering operation completes, the function can
-        //              simply return a deferred:
-        //
-        //              |       // callback style:
-        //              |       function renderLotsOfData(data, callback){
-        //              |               var success = false
-        //              |               try{
-        //              |                       for(var x in data){
-        //              |                               renderDataitem(data[x]);
-        //              |                       }
-        //              |                       success = true;
-        //              |               }catch(e){ }
-        //              |               if(callback){
-        //              |                       callback(success);
-        //              |               }
-        //              |       }
-        //
-        //              |       // using callback style
-        //              |       renderLotsOfData(someDataObj, function(success){
-        //              |               // handles success or failure
-        //              |               if(!success){
-        //              |                       promptUserToRecover();
-        //              |               }
-        //              |       });
-        //              |       // NOTE: no way to add another callback here!!
-        // example:
-        //              Using a Deferred doesn't simplify the sending code any, but it
-        //              provides a standard interface for callers and senders alike,
-        //              providing both with a simple way to service multiple callbacks for
-        //              an operation and freeing both sides from worrying about details
-        //              such as "did this get called already?". With Deferreds, new
-        //              callbacks can be added at any time.
-        //
-        //              |       // Deferred style:
-        //              |       function renderLotsOfData(data){
-        //              |               var d = new dojo.Deferred();
-        //              |               try{
-        //              |                       for(var x in data){
-        //              |                               renderDataitem(data[x]);
-        //              |                       }
-        //              |                       d.callback(true);
-        //              |               }catch(e){ 
-        //              |                       d.errback(new Error("rendering failed"));
-        //              |               }
-        //              |               return d;
-        //              |       }
-        //
-        //              |       // using Deferred style
-        //              |       renderLotsOfData(someDataObj).addErrback(function(){
-        //              |               promptUserToRecover();
-        //              |       });
-        //              |       // NOTE: addErrback and addCallback both return the Deferred
-        //              |       // again, so we could chain adding callbacks or save the
-        //              |       // deferred for later should we need to be notified again.
-        // example:
-        //              In this example, renderLotsOfData is syncrhonous and so both
-        //              versions are pretty artificial. Putting the data display on a
-        //              timeout helps show why Deferreds rock:
-        //
-        //              |       // Deferred style and async func
-        //              |       function renderLotsOfData(data){
-        //              |               var d = new dojo.Deferred();
-        //              |               setTimeout(function(){
-        //              |                       try{
-        //              |                               for(var x in data){
-        //              |                                       renderDataitem(data[x]);
-        //              |                               }
-        //              |                               d.callback(true);
-        //              |                       }catch(e){ 
-        //              |                               d.errback(new Error("rendering failed"));
-        //              |                       }
-        //              |               }, 100);
-        //              |               return d;
-        //              |       }
-        //
-        //              |       // using Deferred style
-        //              |       renderLotsOfData(someDataObj).addErrback(function(){
-        //              |               promptUserToRecover();
-        //              |       });
-        //
-        //              Note that the caller doesn't have to change his code at all to
-        //              handle the asynchronous case.
-
-        this.chain = [];
-        this.id = this._nextId();
-        this.fired = -1;
-        this.paused = 0;
-        this.results = [null, null];
-        this.canceller = canceller;
-        this.silentlyCancelled = false;
-};
-
-dojo.extend(dojo.Deferred, {
-        /*
-        makeCalled: function(){
-                // summary:
-                //              returns a new, empty deferred, which is already in the called
-                //              state. Calling callback() or errback() on this deferred will
-                //              yeild an error and adding new handlers to it will result in
-                //              them being called immediately.
-                var deferred = new dojo.Deferred();
-                deferred.callback();
-                return deferred;
-        },
-
-        toString: function(){
-                var state;
-                if(this.fired == -1){
-                        state = 'unfired';
-                }else{
-                        state = this.fired ? 'success' : 'error';
-                }
-                return 'Deferred(' + this.id + ', ' + state + ')';
-        },
-        */
-
-        _nextId: (function(){
-                var n = 1;
-                return function(){ return n++; };
-        })(),
-
-        cancel: function(){
-                // summary:     
-                //              Cancels a Deferred that has not yet received a value, or is
-                //              waiting on another Deferred as its value.
-                // description:
-                //              If a canceller is defined, the canceller is called. If the
-                //              canceller did not return an error, or there was no canceller,
-                //              then the errback chain is started.
-                var err;
-                if(this.fired == -1){
-                        if(this.canceller){
-                                err = this.canceller(this);
-                        }else{
-                                this.silentlyCancelled = true;
-                        }
-                        if(this.fired == -1){
-                                if(!(err instanceof Error)){
-                                        var res = err;
-                                        err = new Error("Deferred Cancelled");
-                                        err.dojoType = "cancel";
-                                        err.cancelResult = res;
-                                }
-                                this.errback(err);
-                        }
-                }else if(       (this.fired == 0) &&
-                                        (this.results[0] instanceof dojo.Deferred)
-                ){
-                        this.results[0].cancel();
-                }
-        },
-                        
-
-        _resback: function(res){
-                // summary:
-                //              The private primitive that means either callback or errback
-                this.fired = ((res instanceof Error) ? 1 : 0);
-                this.results[this.fired] = res;
-                this._fire();
-        },
-
-        _check: function(){
-                if(this.fired != -1){
-                        if(!this.silentlyCancelled){
-                                throw new Error("already called!");
-                        }
-                        this.silentlyCancelled = false;
-                        return;
-                }
-        },
-
-        callback: function(res){
-                //      summary:        
-                //              Begin the callback sequence with a non-error value.
-                
-                /*
-                callback or errback should only be called once on a given
-                Deferred.
-                */
-                this._check();
-                this._resback(res);
-        },
-
-        errback: function(/*Error*/res){
-                //      summary: 
-                //              Begin the callback sequence with an error result.
-                this._check();
-                if(!(res instanceof Error)){
-                        res = new Error(res);
-                }
-                this._resback(res);
-        },
-
-        addBoth: function(/*Function|Object*/cb, /*String?*/cbfn){
-                //      summary:
-                //              Add the same function as both a callback and an errback as the
-                //              next element on the callback sequence.This is useful for code
-                //              that you want to guarantee to run, e.g. a finalizer.
-                var enclosed = dojo.hitch.apply(dojo, arguments);
-                return this.addCallbacks(enclosed, enclosed); // dojo.Deferred
-        },
-
-        addCallback: function(/*Function|Object*/cb, /*String?*/cbfn /*...*/){
-                //      summary: 
-                //              Add a single callback to the end of the callback sequence.
-                return this.addCallbacks(dojo.hitch.apply(dojo, arguments)); // dojo.Deferred
-        },
-
-        addErrback: function(cb, cbfn){
-                //      summary: 
-                //              Add a single callback to the end of the callback sequence.
-                return this.addCallbacks(null, dojo.hitch.apply(dojo, arguments)); // dojo.Deferred
-        },
-
-        addCallbacks: function(cb, eb){
-                // summary: 
-                //              Add separate callback and errback to the end of the callback
-                //              sequence.
-                this.chain.push([cb, eb])
-                if(this.fired >= 0){
-                        this._fire();
-                }
-                return this; // dojo.Deferred
-        },
-
-        _fire: function(){
-                // summary: 
-                //              Used internally to exhaust the callback sequence when a result
-                //              is available.
-                var chain = this.chain;
-                var fired = this.fired;
-                var res = this.results[fired];
-                var self = this;
-                var cb = null;
-                while(
-                        (chain.length > 0) &&
-                        (this.paused == 0)
-                ){
-                        // Array
-                        var f = chain.shift()[fired];
-                        if(!f){ continue; }
-                        var func = function(){
-                                var ret = f(res);
-                                //If no response, then use previous response.
-                                if(typeof ret != "undefined"){
-                                        res = ret;
-                                }
-                                fired = ((res instanceof Error) ? 1 : 0);
-                                if(res instanceof dojo.Deferred){
-                                        cb = function(res){
-                                                self._resback(res);
-                                                // inlined from _pause()
-                                                self.paused--;
-                                                if(
-                                                        (self.paused == 0) && 
-                                                        (self.fired >= 0)
-                                                ){
-                                                        self._fire();
-                                                }
-                                        }
-                                        // inlined from _unpause
-                                        this.paused++;
-                                }
-                        };
-                        if(dojo.config.isDebug){
-                                func.call(this);
-                        }else{
-                                try{
-                                        func.call(this);
-                                }catch(err){
-                                        fired = 1;
-                                        res = err;
-                                }
-                        }
-                }
-                this.fired = fired;
-                this.results[fired] = res;
-                if((cb)&&(this.paused)){
-                        // this is for "tail recursion" in case the dependent
-                        // deferred is already fired
-                        res.addBoth(cb);
-                }
-        }
-});
-
-}
-
-if(!dojo._hasResource["dojo._base.json"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
-dojo._hasResource["dojo._base.json"] = true;
-dojo.provide("dojo._base.json");
-
-dojo.fromJson = function(/*String*/ json){
-        // summary:
-        //              Parses a [JSON](http://json.org) string to return a JavaScript object.  Throws for invalid JSON strings.
-        // json: 
-        //              a string literal of a JSON item, for instance:
-        //                      `'{ "foo": [ "bar", 1, { "baz": "thud" } ] }'`
-
-        return eval("(" + json + ")"); // Object
-}
-
-dojo._escapeString = function(/*String*/str){
-        //summary:
-        //              Adds escape sequences for non-visual characters, double quote and
-        //              backslash and surrounds with double quotes to form a valid string
-        //              literal.
-        return ('"' + str.replace(/(["\\])/g, '\\$1') + '"').
-                replace(/[\f]/g, "\\f").replace(/[\b]/g, "\\b").replace(/[\n]/g, "\\n").
-                replace(/[\t]/g, "\\t").replace(/[\r]/g, "\\r"); // string
-}
-
-dojo.toJsonIndentStr = "\t";
-dojo.toJson = function(/*Object*/ it, /*Boolean?*/ prettyPrint, /*String?*/ _indentStr){
-        // summary:
-        //              Returns a [JSON](http://json.org) serialization of an object.
-        //
-        // description:
-        //              Returns a [JSON](http://json.org) serialization of an object.
-        //              Note that this doesn't check for infinite recursion, so don't do that!
-        //
-        // it:
-        //              an object to be serialized. Objects may define their own
-        //              serialization via a special "__json__" or "json" function
-        //              property. If a specialized serializer has been defined, it will
-        //              be used as a fallback.
-        //
-        // prettyPrint:
-        //              if true, we indent objects and arrays to make the output prettier.
-        //              The variable dojo.toJsonIndentStr is used as the indent string 
-        //              -- to use something other than the default (tab), 
-        //              change that variable before calling dojo.toJson().
-        //
-        // _indentStr:
-        //              private variable for recursive calls when pretty printing, do not use.
-
-        if(it === undefined){
-                return "undefined";
-        }
-        var objtype = typeof it;
-        if(objtype == "number" || objtype == "boolean"){
-                return it + "";
-        }
-        if(it === null){
-                return "null";
-        }
-        if(dojo.isString(it)){ 
-                return dojo._escapeString(it); 
-        }
-        // recurse
-        var recurse = arguments.callee;
-        // short-circuit for objects that support "json" serialization
-        // if they return "self" then just pass-through...
-        var newObj;
-        _indentStr = _indentStr || "";
-        var nextIndent = prettyPrint ? _indentStr + dojo.toJsonIndentStr : "";
-        var tf = it.__json__||it.json;
-        if(dojo.isFunction(tf)){
-                newObj = tf.call(it);
-                if(it !== newObj){
-                        return recurse(newObj, prettyPrint, nextIndent);
-                }
-        }
-        if(it.nodeType && it.cloneNode){ // isNode
-                // we can't seriailize DOM nodes as regular objects because they have cycles
-                // DOM nodes could be serialized with something like outerHTML, but
-                // that can be provided by users in the form of .json or .__json__ function.
-                throw new Error("Can't serialize DOM nodes");
-        }
-
-        var sep = prettyPrint ? " " : "";
-        var newLine = prettyPrint ? "\n" : "";
-
-        // array
-        if(dojo.isArray(it)){
-                var res = dojo.map(it, function(obj){
-                        var val = recurse(obj, prettyPrint, nextIndent);
-                        if(typeof val != "string"){
-                                val = "undefined";
-                        }
-                        return newLine + nextIndent + val;
-                });
-                return "[" + res.join("," + sep) + newLine + _indentStr + "]";
-        }
-        /*
-        // look in the registry
-        try {
-                window.o = it;
-                newObj = dojo.json.jsonRegistry.match(it);
-                return recurse(newObj, prettyPrint, nextIndent);
-        }catch(e){
-                // 
-        }
-        // it's a function with no adapter, skip it
-        */
-        if(objtype == "function"){
-                return null; // null
-        }
-        // generic object code path
-        var output = [], key;
-        for(key in it){
-                var keyStr, val;
-                if(typeof key == "number"){
-                        keyStr = '"' + key + '"';
-                }else if(typeof key == "string"){
-                        keyStr = dojo._escapeString(key);
-                }else{
-                        // skip non-string or number keys
-                        continue;
-                }
-                val = recurse(it[key], prettyPrint, nextIndent);
-                if(typeof val != "string"){
-                        // skip non-serializable values
-                        continue;
-                }
-                // FIXME: use += on Moz!!
-                //       MOW NOTE: using += is a pain because you have to account for the dangling comma...
-                output.push(newLine + nextIndent + keyStr + ":" + sep + val);
-        }
-        return "{" + output.join("," + sep) + newLine + _indentStr + "}"; // String
-}
-
-}
-
-if(!dojo._hasResource["dojo._base.array"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
-dojo._hasResource["dojo._base.array"] = true;
-
-dojo.provide("dojo._base.array");
-
-(function(){
-        var _getParts = function(arr, obj, cb){
-                return [ 
-                        dojo.isString(arr) ? arr.split("") : arr, 
-                        obj || dojo.global,
-                        // FIXME: cache the anonymous functions we create here?
-                        dojo.isString(cb) ? new Function("item", "index", "array", cb) : cb
-                ];
-        };
-
-        dojo.mixin(dojo, {
-                indexOf: function(      /*Array*/               array, 
-                                                        /*Object*/              value,
-                                                        /*Integer?*/    fromIndex,
-                                                        /*Boolean?*/    findLast){
-                        // summary:
-                        //              locates the first index of the provided value in the
-                        //              passed array. If the value is not found, -1 is returned.
-                        // description:
-                        //              For details on this method, see:
-                        //                      http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Reference:Global_Objects:Array:indexOf
-
-                        var step = 1, end = array.length || 0, i = 0;
-                        if(findLast){
-                                i = end - 1;
-                                step = end = -1;
-                        }
-                        if(fromIndex != undefined){ i = fromIndex; }
-                        if((findLast && i > end) || i < end){
-                                for(; i != end; i += step){
-                                        if(array[i] == value){ return i; }
-                                }
-                        }
-                        return -1;      // Number
-                },
-
-                lastIndexOf: function(/*Array*/array, /*Object*/value, /*Integer?*/fromIndex){
-                        // summary:
-                        //              locates the last index of the provided value in the passed
-                        //              array. If the value is not found, -1 is returned.
-                        // description:
-                        //              For details on this method, see:
-                        //                      http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Reference:Global_Objects:Array:lastIndexOf
-                        return dojo.indexOf(array, value, fromIndex, true); // Number
-                },
-
-                forEach: function(/*Array|String*/arr, /*Function|String*/callback, /*Object?*/thisObject){
-                        //      summary:
-                        //              for every item in arr, callback is invoked. Return values are ignored.
-                        //      arr:
-                        //              the array to iterate over. If a string, operates on individual characters.
-                        //      callback:
-                        //              a function is invoked with three arguments: item, index, and array
-                        //      thisObject:
-                        //              may be used to scope the call to callback
-                        //      description:
-                        //              This function corresponds to the JavaScript 1.6
-                        //              Array.forEach() method. For more details, see:
-                        //                      http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Reference:Global_Objects:Array:forEach
-                        //      example:
-                        //      |       // log out all members of the array:
-                        //      |       dojo.forEach(
-                        //      |               [ "thinger", "blah", "howdy", 10 ],
-                        //      |               function(item){
-                        //      |                       
-                        //      |               }
-                        //      |       );
-                        //      example:
-                        //      |       // log out the members and their indexes
-                        //      |       dojo.forEach(
-                        //      |               [ "thinger", "blah", "howdy", 10 ],
-                        //      |               function(item, idx, arr){
-                        //      |                       
-                        //      |               }
-                        //      |       );
-                        //      example:
-                        //      |       // use a scoped object member as the callback
-                        //      |       
-                        //      |       var obj = {
-                        //      |               prefix: "logged via obj.callback:", 
-                        //      |               callback: function(item){
-                        //      |                       
-                        //      |               }
-                        //      |       };
-                        //      |       
-                        //      |       // specifying the scope function executes the callback in that scope
-                        //      |       dojo.forEach(
-                        //      |               [ "thinger", "blah", "howdy", 10 ],
-                        //      |               obj.callback,
-                        //      |               obj
-                        //      |       );
-                        //      |       
-                        //      |       // alternately, we can accomplish the same thing with dojo.hitch()
-                        //      |       dojo.forEach(
-                        //      |               [ "thinger", "blah", "howdy", 10 ],
-                        //      |               dojo.hitch(obj, "callback")
-                        //      |       );
-
-                        // match the behavior of the built-in forEach WRT empty arrs
-                        if(!arr || !arr.length){ return; }
-
-                        // FIXME: there are several ways of handilng thisObject. Is
-                        // dojo.global always the default context?
-                        var _p = _getParts(arr, thisObject, callback); arr = _p[0];
-                        for(var i=0,l=arr.length; i<l; ++i){ 
-                                _p[2].call(_p[1], arr[i], i, arr);
-                        }
-                },
-
-                _everyOrSome: function(/*Boolean*/every, /*Array|String*/arr, /*Function|String*/callback, /*Object?*/thisObject){
-                        var _p = _getParts(arr, thisObject, callback); arr = _p[0];
-                        for(var i=0,l=arr.length; i<l; ++i){
-                                var result = !!_p[2].call(_p[1], arr[i], i, arr);
-                                if(every ^ result){
-                                        return result; // Boolean
-                                }
-                        }
-                        return every; // Boolean
-                },
-
-                every: function(/*Array|String*/arr, /*Function|String*/callback, /*Object?*/thisObject){
-                        // summary:
-                        //              Determines whether or not every item in arr satisfies the
-                        //              condition implemented by callback.
-                        // arr:
-                        //              the array to iterate on. If a string, operates on individual characters.
-                        // callback:
-                        //              a function is invoked with three arguments: item, index,
-                        //              and array and returns true if the condition is met.
-                        // thisObject:
-                        //              may be used to scope the call to callback
-                        // description:
-                        //              This function corresponds to the JavaScript 1.6
-                        //              Array.every() method. For more details, see:
-                        //                      http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Reference:Global_Objects:Array:every
-                        // example:
-                        //      |       // returns false
-                        //      |       dojo.every([1, 2, 3, 4], function(item){ return item>1; });
-                        // example:
-                        //      |       // returns true 
-                        //      |       dojo.every([1, 2, 3, 4], function(item){ return item>0; });
-                        return this._everyOrSome(true, arr, callback, thisObject); // Boolean
-                },
-
-                some: function(/*Array|String*/arr, /*Function|String*/callback, /*Object?*/thisObject){
-                        // summary:
-                        //              Determines whether or not any item in arr satisfies the
-                        //              condition implemented by callback.
-                        // arr:
-                        //              the array to iterate over. If a string, operates on individual characters.
-                        // callback:
-                        //              a function is invoked with three arguments: item, index,
-                        //              and array and returns true if the condition is met.
-                        // thisObject:
-                        //              may be used to scope the call to callback
-                        // description:
-                        //              This function corresponds to the JavaScript 1.6
-                        //              Array.some() method. For more details, see:
-                        //                      http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Reference:Global_Objects:Array:some
-                        // example:
-                        //      |       // is true
-                        //      |       dojo.some([1, 2, 3, 4], function(item){ return item>1; });
-                        // example:
-                        //      |       // is false
-                        //      |       dojo.some([1, 2, 3, 4], function(item){ return item<1; });
-                        return this._everyOrSome(false, arr, callback, thisObject); // Boolean
-                },
-
-                map: function(/*Array|String*/arr, /*Function|String*/callback, /*Function?*/thisObject){
-                        // summary:
-                        //              applies callback to each element of arr and returns
-                        //              an Array with the results
-                        // arr:
-                        //              the array to iterate on. If a string, operates on
-                        //              individual characters.
-                        // callback:
-                        //              a function is invoked with three arguments, (item, index,
-                        //              array),  and returns a value
-                        // thisObject:
-                        //              may be used to scope the call to callback
-                        // description:
-                        //              This function corresponds to the JavaScript 1.6 Array.map()
-                        //              method. For more details, see:
-                        //                      http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Reference:Global_Objects:Array:map
-                        // example:
-                        //      |       // returns [2, 3, 4, 5]
-                        //      |       dojo.map([1, 2, 3, 4], function(item){ return item+1 });
-
-                        var _p = _getParts(arr, thisObject, callback); arr = _p[0];
-                        var outArr = (arguments[3] ? (new arguments[3]()) : []);
-                        for(var i=0,l=arr.length; i<l; ++i){
-                                outArr.push(_p[2].call(_p[1], arr[i], i, arr));
-                        }
-                        return outArr; // Array
-                },
-
-                filter: function(/*Array*/arr, /*Function|String*/callback, /*Object?*/thisObject){
-                        // summary:
-                        //              Returns a new Array with those items from arr that match the
-                        //              condition implemented by callback.
-                        // arr:
-                        //              the array to iterate over.
-                        // callback:
-                        //              a function that is invoked with three arguments (item,
-                        //              index, array). The return of this function is expected to
-                        //              be a boolean which determines whether the passed-in item
-                        //              will be included in the returned array.
-                        // thisObject:
-                        //              may be used to scope the call to callback
-                        // description:
-                        //              This function corresponds to the JavaScript 1.6
-                        //              Array.filter() method. For more details, see:
-                        //                      http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Reference:Global_Objects:Array:filter
-                        // example:
-                        //      |       // returns [2, 3, 4]
-                        //      |       dojo.filter([1, 2, 3, 4], function(item){ return item>1; });
-
-                        var _p = _getParts(arr, thisObject, callback); arr = _p[0];
-                        var outArr = [];
-                        for(var i=0,l=arr.length; i<l; ++i){
-                                if(_p[2].call(_p[1], arr[i], i, arr)){
-                                        outArr.push(arr[i]);
-                                }
-                        }
-                        return outArr; // Array
-                }
-        });
-})();
-
-}
-
-if(!dojo._hasResource["dojo._base.Color"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
-dojo._hasResource["dojo._base.Color"] = true;
-dojo.provide("dojo._base.Color");
-
-
-
-dojo.Color = function(/*Array|String|Object*/ color){
-        // summary:
-        //              takes a named string, hex string, array of rgb or rgba values,
-        //              an object with r, g, b, and a properties, or another dojo.Color object
-        if(color){ this.setColor(color); }
-};
-
-// FIXME: there's got to be a more space-efficient way to encode or discover these!!  Use hex?
-dojo.Color.named = {
-        black:      [0,0,0],
-        silver:     [192,192,192],
-        gray:       [128,128,128],
-        white:      [255,255,255],
-        maroon:         [128,0,0],
-        red:        [255,0,0],
-        purple:         [128,0,128],
-        fuchsia:        [255,0,255],
-        green:      [0,128,0],
-        lime:       [0,255,0],
-        olive:          [128,128,0],
-        yellow:         [255,255,0],
-        navy:       [0,0,128],
-        blue:       [0,0,255],
-        teal:           [0,128,128],
-        aqua:           [0,255,255]
-};
-
-
-dojo.extend(dojo.Color, {
-        r: 255, g: 255, b: 255, a: 1,
-        _set: function(r, g, b, a){
-                var t = this; t.r = r; t.g = g; t.b = b; t.a = a;
-        },
-        setColor: function(/*Array|String|Object*/ color){
-                // summary:
-                //              takes a named string, hex string, array of rgb or rgba values,
-                //              an object with r, g, b, and a properties, or another dojo.Color object
-                var d = dojo;
-                if(d.isString(color)){
-                        d.colorFromString(color, this);
-                }else if(d.isArray(color)){
-                        d.colorFromArray(color, this);
-                }else{
-                        this._set(color.r, color.g, color.b, color.a);
-                        if(!(color instanceof d.Color)){ this.sanitize(); }
-                }
-                return this;    // dojo.Color
-        },
-        sanitize: function(){
-                // summary:
-                //              makes sure that the object has correct attributes
-                // description: 
-                //              the default implementation does nothing, include dojo.colors to
-                //              augment it to real checks
-                return this;    // dojo.Color
-        },
-        toRgb: function(){
-                // summary: returns 3 component array of rgb values
-                var t = this;
-                return [t.r, t.g, t.b]; // Array
-        },
-        toRgba: function(){
-                // summary: returns a 4 component array of rgba values
-                var t = this;
-                return [t.r, t.g, t.b, t.a];    // Array
-        },
-        toHex: function(){
-                // summary: returns a css color string in hexadecimal representation
-                var arr = dojo.map(["r", "g", "b"], function(x){
-                        var s = this[x].toString(16);
-                        return s.length < 2 ? "0" + s : s;
-                }, this);
-                return "#" + arr.join("");      // String
-        },
-        toCss: function(/*Boolean?*/ includeAlpha){
-                // summary: returns a css color string in rgb(a) representation
-                var t = this, rgb = t.r + ", " + t.g + ", " + t.b;
-                return (includeAlpha ? "rgba(" + rgb + ", " + t.a : "rgb(" + rgb) + ")";        // String
-        },
-        toString: function(){
-                // summary: returns a visual representation of the color
-                return this.toCss(true); // String
-        }
-});
-
-dojo.blendColors = function(
-        /*dojo.Color*/ start, 
-        /*dojo.Color*/ end, 
-        /*Number*/ weight,
-        /*dojo.Color?*/ obj
-){
-        // summary: 
-        //              blend colors end and start with weight from 0 to 1, 0.5 being a 50/50 blend,
-        //              can reuse a previously allocated dojo.Color object for the result
-        var d = dojo, t = obj || new dojo.Color();
-        d.forEach(["r", "g", "b", "a"], function(x){
-                t[x] = start[x] + (end[x] - start[x]) * weight;
-                if(x != "a"){ t[x] = Math.round(t[x]); }
-        });
-        return t.sanitize();    // dojo.Color
-};
-
-dojo.colorFromRgb = function(/*String*/ color, /*dojo.Color?*/ obj){
-        // summary: get rgb(a) array from css-style color declarations
-        var m = color.toLowerCase().match(/^rgba?\(([\s\.,0-9]+)\)/);
-        return m && dojo.colorFromArray(m[1].split(/\s*,\s*/), obj);    // dojo.Color
-};
-
-dojo.colorFromHex = function(/*String*/ color, /*dojo.Color?*/ obj){
-        // summary: converts a hex string with a '#' prefix to a color object.
-        //      Supports 12-bit #rgb shorthand.
-        var d = dojo, t = obj || new d.Color(),
-                bits = (color.length == 4) ? 4 : 8,
-                mask = (1 << bits) - 1;
-        color = Number("0x" + color.substr(1));
-        if(isNaN(color)){
-                return null; // dojo.Color
-        }
-        d.forEach(["b", "g", "r"], function(x){
-                var c = color & mask;
-                color >>= bits;
-                t[x] = bits == 4 ? 17 * c : c;
-        });
-        t.a = 1;
-        return t;       // dojo.Color
-};
-
-dojo.colorFromArray = function(/*Array*/ a, /*dojo.Color?*/ obj){
-        // summary: builds a color from 1, 2, 3, or 4 element array
-        var t = obj || new dojo.Color();
-        t._set(Number(a[0]), Number(a[1]), Number(a[2]), Number(a[3]));
-        if(isNaN(t.a)){ t.a = 1; }
-        return t.sanitize();    // dojo.Color
-};
-
-dojo.colorFromString = function(/*String*/ str, /*dojo.Color?*/ obj){
-        //      summary:
-        //              parses str for a color value.
-        //      description:
-        //              Acceptable input values for str may include arrays of any form
-        //              accepted by dojo.colorFromArray, hex strings such as "#aaaaaa", or
-        //              rgb or rgba strings such as "rgb(133, 200, 16)" or "rgba(10, 10,
-        //              10, 50)"
-        //      returns:
-        //              a dojo.Color object. If obj is passed, it will be the return value.
-        var a = dojo.Color.named[str];
-        return a && dojo.colorFromArray(a, obj) || dojo.colorFromRgb(str, obj) || dojo.colorFromHex(str, obj);
-};
-
-}
-
-if(!dojo._hasResource["dojo._base"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
-dojo._hasResource["dojo._base"] = true;
-dojo.provide("dojo._base");
-
-
-
-
-
-
-
-
-
-}
-
-if(!dojo._hasResource["dojo._base.window"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
-dojo._hasResource["dojo._base.window"] = true;
-dojo.provide("dojo._base.window");
-
-/*=====
-dojo.doc = {
-        // summary:
-        //              Alias for the current document. 'dojo.doc' can be modified
-        //              for temporary context shifting. Also see dojo.withDoc().
-        // description:
-        //    Refer to dojo.doc rather
-        //    than referring to 'window.document' to ensure your code runs
-        //    correctly in managed contexts.
-        // example:
-        //      |       n.appendChild(dojo.doc.createElement('div'));
-}
-=====*/
-dojo.doc = window["document"] || null;
-
-dojo.body = function(){
-        // summary:
-        //              Return the body element of the document
-        //              return the body object associated with dojo.doc
-        // example:
-        //      |       dojo.body().appendChild(dojo.doc.createElement('div'));
-
-        // Note: document.body is not defined for a strict xhtml document
-        // Would like to memoize this, but dojo.doc can change vi dojo.withDoc().
-        return dojo.doc.body || dojo.doc.getElementsByTagName("body")[0]; // Node
-}
-
-dojo.setContext = function(/*Object*/globalObject, /*DocumentElement*/globalDocument){
-        // summary:
-        //              changes the behavior of many core Dojo functions that deal with
-        //              namespace and DOM lookup, changing them to work in a new global
-        //              context (e.g., an iframe). The varibles dojo.global and dojo.doc
-        //              are modified as a result of calling this function and the result of
-        //              `dojo.body()` likewise differs.
-        dojo.global = globalObject;
-        dojo.doc = globalDocument;
-};
-
-dojo._fireCallback = function(callback, context, cbArguments){
-        if(context && dojo.isString(callback)){
-                callback = context[callback];
-        }
-        return callback.apply(context, cbArguments || [ ]);
-}
-
-dojo.withGlobal = function(     /*Object*/globalObject, 
-                                                        /*Function*/callback, 
-                                                        /*Object?*/thisObject, 
-                                                        /*Array?*/cbArguments){
-        // summary:
-        //              Call callback with globalObject as dojo.global and
-        //              globalObject.document as dojo.doc. If provided, globalObject
-        //              will be executed in the context of object thisObject
-        // description:
-        //              When callback() returns or throws an error, the dojo.global
-        //              and dojo.doc will be restored to its previous state.
-        var rval;
-        var oldGlob = dojo.global;
-        var oldDoc = dojo.doc;
-        try{
-                dojo.setContext(globalObject, globalObject.document);
-                rval = dojo._fireCallback(callback, thisObject, cbArguments);
-        }finally{
-                dojo.setContext(oldGlob, oldDoc);
-        }
-        return rval;
-}
-
-dojo.withDoc = function(        /*Object*/documentObject, 
-                                                        /*Function*/callback, 
-                                                        /*Object?*/thisObject, 
-                                                        /*Array?*/cbArguments){
-        // summary:
-        //              Call callback with documentObject as dojo.doc. If provided,
-        //              callback will be executed in the context of object thisObject
-        // description:
-        //              When callback() returns or throws an error, the dojo.doc will
-        //              be restored to its previous state.
-        var rval;
-        var oldDoc = dojo.doc;
-        try{
-                dojo.doc = documentObject;
-                rval = dojo._fireCallback(callback, thisObject, cbArguments);
-        }finally{
-                dojo.doc = oldDoc;
-        }
-        return rval;
-};
-
-}
-
-if(!dojo._hasResource["dojo._base.event"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
-dojo._hasResource["dojo._base.event"] = true;
-dojo.provide("dojo._base.event");
-
-
-// this file courtesy of the TurboAjax Group, licensed under a Dojo CLA
-
-(function(){
-        // DOM event listener machinery
-        var del = (dojo._event_listener = {
-                add: function(/*DOMNode*/node, /*String*/name, /*Function*/fp){
-                        if(!node){return;} 
-                        name = del._normalizeEventName(name);
-                        fp = del._fixCallback(name, fp);
-                        var oname = name;
-                        if(!dojo.isIE && (name == "mouseenter" || name == "mouseleave")){
-                                var ofp = fp;
-                                //oname = name;
-                                name = (name == "mouseenter") ? "mouseover" : "mouseout";
-                                fp = function(e){
-                                        // check tagName to fix a FF2 bug with invalid nodes (hidden child DIV of INPUT)
-                                        // which causes isDecendant to return false which causes
-                                        // spurious, and more importantly, incorrect mouse events to fire.
-                                        // TODO: remove tagName check when Firefox 2 is no longer supported
-                                        try{ e.relatedTarget.tagName; } catch(e2){ return; }
-                                        if(!dojo.isDescendant(e.relatedTarget, node)){
-                                                // e.type = oname; // FIXME: doesn't take? SJM: event.type is generally immutable.
-                                                return ofp.call(this, e); 
-                                        }
-                                }
-                        }
-                        node.addEventListener(name, fp, false);
-                        return fp; /*Handle*/
-                },
-                remove: function(/*DOMNode*/node, /*String*/event, /*Handle*/handle){
-                        // summary:
-                        //              clobbers the listener from the node
-                        // node:
-                        //              DOM node to attach the event to
-                        // event:
-                        //              the name of the handler to remove the function from
-                        // handle:
-                        //              the handle returned from add
-                        if (node){
-                                event = del._normalizeEventName(event);
-                                if(!dojo.isIE && (event == "mouseenter" || event == "mouseleave")){
-                                        event = (event == "mouseenter") ? "mouseover" : "mouseout";
-                                }
-
-                                node.removeEventListener(event, handle, false);
-                        }
-                },
-                _normalizeEventName: function(/*String*/name){
-                        // Generally, name should be lower case, unless it is special
-                        // somehow (e.g. a Mozilla DOM event).
-                        // Remove 'on'.
-                        return name.slice(0,2) =="on" ? name.slice(2) : name;
-                },
-                _fixCallback: function(/*String*/name, fp){
-                        // By default, we only invoke _fixEvent for 'keypress'
-                        // If code is added to _fixEvent for other events, we have
-                        // to revisit this optimization.
-                        // This also applies to _fixEvent overrides for Safari and Opera
-                        // below.
-                        return name != "keypress" ? fp : function(e){ return fp.call(this, del._fixEvent(e, this)); };
-                },
-                _fixEvent: function(evt, sender){
-                        // _fixCallback only attaches us to keypress.
-                        // Switch on evt.type anyway because we might 
-                        // be called directly from dojo.fixEvent.
-                        switch(evt.type){
-                                case "keypress":
-                                        del._setKeyChar(evt);
-                                        break;
-                        }
-                        return evt;
-                },
-                _setKeyChar: function(evt){
-                        evt.keyChar = evt.charCode ? String.fromCharCode(evt.charCode) : '';
-                        evt.charOrCode = evt.keyChar || evt.keyCode;
-                },
-                // For IE and Safari: some ctrl-key combinations (mostly w/punctuation) do not emit a char code in IE
-                // we map those virtual key codes to ascii here
-                // not valid for all (non-US) keyboards, so maybe we shouldn't bother
-                _punctMap: { 
-                        106:42, 
-                        111:47, 
-                        186:59, 
-                        187:43, 
-                        188:44, 
-                        189:45, 
-                        190:46, 
-                        191:47, 
-                        192:96, 
-                        219:91, 
-                        220:92, 
-                        221:93, 
-                        222:39 
-                }
-        });
-
-        // DOM events
-        
-        dojo.fixEvent = function(/*Event*/evt, /*DOMNode*/sender){
-                // summary:
-                //              normalizes properties on the event object including event
-                //              bubbling methods, keystroke normalization, and x/y positions
-                // evt: Event
-                //              native event object
-                // sender: DOMNode
-                //              node to treat as "currentTarget"
-                return del._fixEvent(evt, sender);
-        }
-
-        dojo.stopEvent = function(/*Event*/evt){
-                // summary:
-                //              prevents propagation and clobbers the default action of the
-                //              passed event
-                // evt: Event
-                //              The event object. If omitted, window.event is used on IE.
-                evt.preventDefault();
-                evt.stopPropagation();
-                // NOTE: below, this method is overridden for IE
-        }
-
-        // the default listener to use on dontFix nodes, overriden for IE
-        var node_listener = dojo._listener;
-        
-        // Unify connect and event listeners
-        dojo._connect = function(obj, event, context, method, dontFix){
-                // FIXME: need a more strict test
-                var isNode = obj && (obj.nodeType||obj.attachEvent||obj.addEventListener);
-                // choose one of three listener options: raw (connect.js), DOM event on a Node, custom event on a Node
-                // we need the third option to provide leak prevention on broken browsers (IE)
-                var lid = !isNode ? 0 : (!dontFix ? 1 : 2), l = [dojo._listener, del, node_listener][lid];
-                // create a listener
-                var h = l.add(obj, event, dojo.hitch(context, method));
-                // formerly, the disconnect package contained "l" directly, but if client code
-                // leaks the disconnect package (by connecting it to a node), referencing "l" 
-                // compounds the problem.
-                // instead we return a listener id, which requires custom _disconnect below.
-                // return disconnect package
-                return [ obj, event, h, lid ];
-        }
-
-        dojo._disconnect = function(obj, event, handle, listener){
-                ([dojo._listener, del, node_listener][listener]).remove(obj, event, handle);
-        }
-
-        // Constants
-
-        // Public: client code should test
-        // keyCode against these named constants, as the
-        // actual codes can vary by browser.
-        dojo.keys = {
-                // summary: definitions for common key values
-                BACKSPACE: 8,
-                TAB: 9,
-                CLEAR: 12,
-                ENTER: 13,
-                SHIFT: 16,
-                CTRL: 17,
-                ALT: 18,
-                PAUSE: 19,
-                CAPS_LOCK: 20,
-                ESCAPE: 27,
-                SPACE: 32,
-                PAGE_UP: 33,
-                PAGE_DOWN: 34,
-                END: 35,
-                HOME: 36,
-                LEFT_ARROW: 37,
-                UP_ARROW: 38,
-                RIGHT_ARROW: 39,
-                DOWN_ARROW: 40,
-                INSERT: 45,
-                DELETE: 46,
-                HELP: 47,
-                LEFT_WINDOW: 91,
-                RIGHT_WINDOW: 92,
-                SELECT: 93,
-                NUMPAD_0: 96,
-                NUMPAD_1: 97,
-                NUMPAD_2: 98,
-                NUMPAD_3: 99,
-                NUMPAD_4: 100,
-                NUMPAD_5: 101,
-                NUMPAD_6: 102,
-                NUMPAD_7: 103,
-                NUMPAD_8: 104,
-                NUMPAD_9: 105,
-                NUMPAD_MULTIPLY: 106,
-                NUMPAD_PLUS: 107,
-                NUMPAD_ENTER: 108,
-                NUMPAD_MINUS: 109,
-                NUMPAD_PERIOD: 110,
-                NUMPAD_DIVIDE: 111,
-                F1: 112,
-                F2: 113,
-                F3: 114,
-                F4: 115,
-                F5: 116,
-                F6: 117,
-                F7: 118,
-                F8: 119,
-                F9: 120,
-                F10: 121,
-                F11: 122,
-                F12: 123,
-                F13: 124,
-                F14: 125,
-                F15: 126,
-                NUM_LOCK: 144,
-                SCROLL_LOCK: 145
-        };
-        
-        // IE event normalization
-        if(dojo.isIE){ 
-                var _trySetKeyCode = function(e, code){
-                        try{
-                                // squelch errors when keyCode is read-only
-                                // (e.g. if keyCode is ctrl or shift)
-                                return (e.keyCode = code);
-                        }catch(e){
-                                return 0;
-                        }
-                }
-
-                // by default, use the standard listener
-                var iel = dojo._listener;
-                var listenersName = dojo._ieListenersName = "_" + dojo._scopeName + "_listeners";
-                // dispatcher tracking property
-                if(!dojo.config._allow_leaks){
-                        // custom listener that handles leak protection for DOM events
-                        node_listener = iel = dojo._ie_listener = {
-                                // support handler indirection: event handler functions are 
-                                // referenced here. Event dispatchers hold only indices.
-                                handlers: [],
-                                // add a listener to an object
-                                add: function(/*Object*/ source, /*String*/ method, /*Function*/ listener){
-                                        source = source || dojo.global;
-                                        var f = source[method];
-                                        if(!f||!f[listenersName]){
-                                                var d = dojo._getIeDispatcher();
-                                                // original target function is special
-                                                d.target = f && (ieh.push(f) - 1);
-                                                // dispatcher holds a list of indices into handlers table
-                                                d[listenersName] = [];
-                                                // redirect source to dispatcher
-                                                f = source[method] = d;
-                                        }
-                                        return f[listenersName].push(ieh.push(listener) - 1) ; /*Handle*/
-                                },
-                                // remove a listener from an object
-                                remove: function(/*Object*/ source, /*String*/ method, /*Handle*/ handle){
-                                        var f = (source||dojo.global)[method], l = f && f[listenersName];
-                                        if(f && l && handle--){
-                                                delete ieh[l[handle]];
-                                                delete l[handle];
-                                        }
-                                }
-                        };
-                        // alias used above
-                        var ieh = iel.handlers;
-                }
-
-                dojo.mixin(del, {
-                        add: function(/*DOMNode*/node, /*String*/event, /*Function*/fp){
-                                if(!node){return;} // undefined
-                                event = del._normalizeEventName(event);
-                                if(event=="onkeypress"){
-                                        // we need to listen to onkeydown to synthesize
-                                        // keypress events that otherwise won't fire
-                                        // on IE
-                                        var kd = node.onkeydown;
-                                        if(!kd || !kd[listenersName] || !kd._stealthKeydownHandle){
-                                                var h = del.add(node, "onkeydown", del._stealthKeyDown);
-                                                kd = node.onkeydown;
-                                                kd._stealthKeydownHandle = h;
-                                                kd._stealthKeydownRefs = 1;
-                                        }else{
-                                                kd._stealthKeydownRefs++;
-                                        }
-                                }
-                                return iel.add(node, event, del._fixCallback(fp));
-                        },
-                        remove: function(/*DOMNode*/node, /*String*/event, /*Handle*/handle){
-                                event = del._normalizeEventName(event);
-                                iel.remove(node, event, handle); 
-                                if(event=="onkeypress"){
-                                        var kd = node.onkeydown;
-                                        if(--kd._stealthKeydownRefs <= 0){
-                                                iel.remove(node, "onkeydown", kd._stealthKeydownHandle);
-                                                delete kd._stealthKeydownHandle;
-                                        }
-                                }
-                        },
-                        _normalizeEventName: function(/*String*/eventName){
-                                // Generally, eventName should be lower case, unless it is
-                                // special somehow (e.g. a Mozilla event)
-                                // ensure 'on'
-                                return eventName.slice(0,2) != "on" ? "on" + eventName : eventName;
-                        },
-                        _nop: function(){},
-                        _fixEvent: function(/*Event*/evt, /*DOMNode*/sender){
-                                // summary:
-                                //              normalizes properties on the event object including event
-                                //              bubbling methods, keystroke normalization, and x/y positions
-                                // evt: native event object
-                                // sender: node to treat as "currentTarget"
-                                if(!evt){
-                                        var w = sender && (sender.ownerDocument || sender.document || sender).parentWindow || window;
-                                        evt = w.event; 
-                                }
-                                if(!evt){return(evt);}
-                                evt.target = evt.srcElement; 
-                                evt.currentTarget = (sender || evt.srcElement); 
-                                evt.layerX = evt.offsetX;
-                                evt.layerY = evt.offsetY;
-                                // FIXME: scroll position query is duped from dojo.html to
-                                // avoid dependency on that entire module. Now that HTML is in
-                                // Base, we should convert back to something similar there.
-                                var se = evt.srcElement, doc = (se && se.ownerDocument) || document;
-                                // DO NOT replace the following to use dojo.body(), in IE, document.documentElement should be used
-                                // here rather than document.body
-                                var docBody = ((dojo.isIE < 6) || (doc["compatMode"] == "BackCompat")) ? doc.body : doc.documentElement;
-                                var offset = dojo._getIeDocumentElementOffset();
-                                evt.pageX = evt.clientX + dojo._fixIeBiDiScrollLeft(docBody.scrollLeft || 0) - offset.x;
-                                evt.pageY = evt.clientY + (docBody.scrollTop || 0) - offset.y;
-                                if(evt.type == "mouseover"){ 
-                                        evt.relatedTarget = evt.fromElement;
-                                }
-                                if(evt.type == "mouseout"){ 
-                                        evt.relatedTarget = evt.toElement;
-                                }
-                                evt.stopPropagation = del._stopPropagation;
-                                evt.preventDefault = del._preventDefault;
-                                return del._fixKeys(evt);
-                        },
-                        _fixKeys: function(evt){
-                                switch(evt.type){
-                                        case "keypress":
-                                                var c = ("charCode" in evt ? evt.charCode : evt.keyCode);
-                                                if (c==10){
-                                                        // CTRL-ENTER is CTRL-ASCII(10) on IE, but CTRL-ENTER on Mozilla
-                                                        c=0;
-                                                        evt.keyCode = 13;
-                                                }else if(c==13||c==27){
-                                                        c=0; // Mozilla considers ENTER and ESC non-printable
-                                                }else if(c==3){
-                                                        c=99; // Mozilla maps CTRL-BREAK to CTRL-c
-                                                }
-                                                // Mozilla sets keyCode to 0 when there is a charCode
-                                                // but that stops the event on IE.
-                                                evt.charCode = c;
-                                                del._setKeyChar(evt);
-                                                break;
-                                }
-                                return evt;
-                        },
-                        _stealthKeyDown: function(evt){
-                                // IE doesn't fire keypress for most non-printable characters.
-                                // other browsers do, we simulate it here.
-                                var kp = evt.currentTarget.onkeypress;
-                                // only works if kp exists and is a dispatcher
-                                if(!kp || !kp[listenersName]){ return; }
-                                // munge key/charCode
-                                var k=evt.keyCode;
-                                // These are Windows Virtual Key Codes
-                                // http://msdn.microsoft.com/library/default.asp?url=/library/en-us/winui/WinUI/WindowsUserInterface/UserInput/VirtualKeyCodes.asp
-                                var unprintable = (k!=13)&&(k!=32)&&(k!=27)&&(k<48||k>90)&&(k<96||k>111)&&(k<186||k>192)&&(k<219||k>222);
-                                // synthesize keypress for most unprintables and CTRL-keys
-                                if(unprintable||evt.ctrlKey){
-                                        var c = unprintable ? 0 : k;
-                                        if(evt.ctrlKey){
-                                                if(k==3 || k==13){
-                                                        return; // IE will post CTRL-BREAK, CTRL-ENTER as keypress natively 
-                                                }else if(c>95 && c<106){ 
-                                                        c -= 48; // map CTRL-[numpad 0-9] to ASCII
-                                                }else if((!evt.shiftKey)&&(c>=65&&c<=90)){ 
-                                                        c += 32; // map CTRL-[A-Z] to lowercase
-                                                }else{ 
-                                                        c = del._punctMap[c] || c; // map other problematic CTRL combinations to ASCII
-                                                }
-                                        }
-                                        // simulate a keypress event
-                                        var faux = del._synthesizeEvent(evt, {type: 'keypress', faux: true, charCode: c});
-                                        kp.call(evt.currentTarget, faux);
-                                        evt.cancelBubble = faux.cancelBubble;
-                                        evt.returnValue = faux.returnValue;
-                                        _trySetKeyCode(evt, faux.keyCode);
-                                }
-                        },
-                        // Called in Event scope
-                        _stopPropagation: function(){
-                                this.cancelBubble = true; 
-                        },
-                        _preventDefault: function(){
-                                // Setting keyCode to 0 is the only way to prevent certain keypresses (namely
-                                // ctrl-combinations that correspond to menu accelerator keys).
-                                // Otoh, it prevents upstream listeners from getting this information
-                                // Try to split the difference here by clobbering keyCode only for ctrl 
-                                // combinations. If you still need to access the key upstream, bubbledKeyCode is
-                                // provided as a workaround.
-                                this.bubbledKeyCode = this.keyCode;
-                                if(this.ctrlKey){_trySetKeyCode(this, 0);}
-                                this.returnValue = false;
-                        }
-                });
-                                
-                // override stopEvent for IE
-                dojo.stopEvent = function(evt){
-                        evt = evt || window.event;
-                        del._stopPropagation.call(evt);
-                        del._preventDefault.call(evt);
-                }
-        }
-
-        del._synthesizeEvent = function(evt, props){
-                        var faux = dojo.mixin({}, evt, props);
-                        del._setKeyChar(faux);
-                        // FIXME: would prefer to use dojo.hitch: dojo.hitch(evt, evt.preventDefault); 
-                        // but it throws an error when preventDefault is invoked on Safari
-                        // does Event.preventDefault not support "apply" on Safari?
-                        faux.preventDefault = function(){ evt.preventDefault(); }; 
-                        faux.stopPropagation = function(){ evt.stopPropagation(); }; 
-                        return faux;
-        }
-        
-        // Opera event normalization
-        if(dojo.isOpera){
-                dojo.mixin(del, {
-                        _fixEvent: function(evt, sender){
-                                switch(evt.type){
-                                        case "keypress":
-                                                var c = evt.which;
-                                                if(c==3){
-                                                        c=99; // Mozilla maps CTRL-BREAK to CTRL-c
-                                                }
-                                                // can't trap some keys at all, like INSERT and DELETE
-                                                // there is no differentiating info between DELETE and ".", or INSERT and "-"
-                                                c = ((c<41)&&(!evt.shiftKey) ? 0 : c);
-                                                if((evt.ctrlKey)&&(!evt.shiftKey)&&(c>=65)&&(c<=90)){
-                                                        // lowercase CTRL-[A-Z] keys
-                                                        c += 32;
-                                                }
-                                                return del._synthesizeEvent(evt, { charCode: c });
-                                }
-                                return evt;
-                        }
-                });
-        }
-
-        // Safari event normalization
-        if(dojo.isSafari){
-                del._add = del.add;
-                del._remove = del.remove;
-
-                dojo.mixin(del, {
-                        add: function(/*DOMNode*/node, /*String*/event, /*Function*/fp){
-                                if(!node){return;} // undefined
-                                var handle = del._add(node, event, fp);
-                                if(del._normalizeEventName(event) == "keypress"){
-                                        // we need to listen to onkeydown to synthesize
-                                        // keypress events that otherwise won't fire
-                                        // in Safari 3.1+: https://lists.webkit.org/pipermail/webkit-dev/2007-December/002992.html
-                                        handle._stealthKeyDownHandle = del._add(node, "keydown", function(evt){
-                                                //A variation on the IE _stealthKeydown function
-                                                //Synthesize an onkeypress event, but only for unprintable characters.
-                                                var k=evt.keyCode;
-                                                // These are Windows Virtual Key Codes
-                                                // http://msdn.microsoft.com/library/default.asp?url=/library/en-us/winui/WinUI/WindowsUserInterface/UserInput/VirtualKeyCodes.asp
-                                                var unprintable = (k!=13)&&(k!=32)&&(k!=27)&&(k<48||k>90)&&(k<96||k>111)&&(k<186||k>192)&&(k<219||k>222);
-                                                // synthesize keypress for most unprintables and CTRL-keys
-                                                if(unprintable||evt.ctrlKey){
-                                                        var c = unprintable ? 0 : k;
-                                                        if(evt.ctrlKey){
-                                                                if(k==3 || k==13){
-                                                                        return; // IE will post CTRL-BREAK, CTRL-ENTER as keypress natively 
-                                                                }else if(c>95 && c<106){ 
-                                                                        c -= 48; // map CTRL-[numpad 0-9] to ASCII
-                                                                }else if((!evt.shiftKey)&&(c>=65&&c<=90)){ 
-                                                                        c += 32; // map CTRL-[A-Z] to lowercase
-                                                                }else{ 
-                                                                        c = del._punctMap[c] || c; // map other problematic CTRL combinations to ASCII
-                                                                }
-                                                        }
-                                                        // simulate a keypress event
-                                                        var faux = del._synthesizeEvent(evt, {type: 'keypress', faux: true, charCode: c});
-                                                        fp.call(evt.currentTarget, faux);
-                                                }
-                                        });
-                                }
-                                return handle; /*Handle*/
-                        },
-
-                        remove: function(/*DOMNode*/node, /*String*/event, /*Handle*/handle){
-                                if(node){
-                                        if(handle._stealthKeyDownHandle){
-                                                del._remove(node, "keydown", handle._stealthKeyDownHandle);
-                                        }
-                                        del._remove(node, event, handle);
-                                }
-                        },
-                        _fixEvent: function(evt, sender){
-                                switch(evt.type){
-                                        case "keypress":
-                                                if(evt.faux){ return evt; }
-                                                var c = evt.charCode;
-                                                c = c>=32? c : 0;
-                                                return del._synthesizeEvent(evt, {charCode: c, faux: true});
-                                }
-                                return evt;
-                        }
-                });
-        }
-})();
-
-if(dojo.isIE){
-        // keep this out of the closure
-        // closing over 'iel' or 'ieh' b0rks leak prevention
-        // ls[i] is an index into the master handler array
-        dojo._ieDispatcher = function(args, sender){
-                var ap=Array.prototype, h=dojo._ie_listener.handlers, c=args.callee, ls=c[dojo._ieListenersName], t=h[c.target];
-                // return value comes from original target function
-                var r = t && t.apply(sender, args);
-                // make local copy of listener array so it's immutable during processing
-                var lls = [].concat(ls);
-                // invoke listeners after target function
-                for(var i in lls){
-                        if(!(i in ap)){
-                                h[lls[i]].apply(sender, args);
-                        }
-                }
-                return r;
-        }
-        dojo._getIeDispatcher = function(){
-                // ensure the returned function closes over nothing ("new Function" apparently doesn't close)
-                return new Function(dojo._scopeName + "._ieDispatcher(arguments, this)"); // function
-        }
-        // keep this out of the closure to reduce RAM allocation
-        dojo._event_listener._fixCallback = function(fp){
-                var f = dojo._event_listener._fixEvent;
-                return function(e){ return fp.call(this, f(e, this)); };
-        }
-}
-
-}
-
-if(!dojo._hasResource["dojo._base.html"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
-dojo._hasResource["dojo._base.html"] = true;
-
-dojo.provide("dojo._base.html");
-
-// FIXME: need to add unit tests for all the semi-public methods
-
-try{
-        document.execCommand("BackgroundImageCache", false, true);
-}catch(e){
-        // sane browsers don't have cache "issues"
-}
-
-// =============================
-// DOM Functions
-// =============================
-
-/*=====
-dojo.byId = function(id, doc){
-        //      summary:
-        //              Returns DOM node with matching `id` attribute or `null` 
-        //              if not found, similar to "$" function in another library.
-        //              If `id` is a DomNode, this function is a no-op.
-        //
-        //      id: String|DOMNode
-        //              A string to match an HTML id attribute or a reference to a DOM Node
-        //
-        //      doc: Document?
-        //              Document to work in. Defaults to the current value of
-        //              dojo.doc.  Can be used to retrieve
-        //              node references from other documents.
-=====*/
-if(dojo.isIE || dojo.isOpera){
-        dojo.byId = function(id, doc){
-                if(dojo.isString(id)){
-                        var _d = doc || dojo.doc;
-                        var te = _d.getElementById(id);
-                        // attributes.id.value is better than just id in case the 
-                        // user has a name=id inside a form
-                        if(te && te.attributes.id.value == id){
-                                return te;
-                        }else{
-                                var eles = _d.all[id];
-                                if(!eles || !eles.length){ return eles; }
-                                // if more than 1, choose first with the correct id
-                                var i=0;
-                                while((te=eles[i++])){
-                                        if(te.attributes.id.value == id){ return te; }
-                                }
-                        }
-                }else{
-                        return id; // DomNode
-                }
-        }
-}else{
-        dojo.byId = function(id, doc){
-                return dojo.isString(id) ? (doc || dojo.doc).getElementById(id) : id; // DomNode
-        }
-}
-/*=====
-}
-=====*/
-
-(function(){
-        var d = dojo;
-
-        var _destroyContainer = null;
-        dojo.addOnWindowUnload(function(){
-                _destroyContainer=null; //prevent IE leak
-        });
-
-        dojo._destroyElement = function(/*String||DomNode*/node){
-                // summary:
-                //              removes node from its parent, clobbers it and all of its
-                //              children.
-                //      node:
-                //              the element to be destroyed, either as an ID or a reference
-
-                node = d.byId(node);
-                try{
-                        if(!_destroyContainer || _destroyContainer.ownerDocument != node.ownerDocument){
-                                _destroyContainer = node.ownerDocument.createElement("div");
-                        }
-                        _destroyContainer.appendChild(node.parentNode ? node.parentNode.removeChild(node) : node);
-                        // NOTE: see http://trac.dojotoolkit.org/ticket/2931. This may be a bug and not a feature
-                        _destroyContainer.innerHTML = ""; 
-                }catch(e){
-                        /* squelch */
-                }
-        };
-
-        dojo.isDescendant = function(/*DomNode|String*/node, /*DomNode|String*/ancestor){
-                //      summary:
-                //              Returns true if node is a descendant of ancestor
-                //      node: id or node reference to test
-                //      ancestor: id or node reference of potential parent to test against
-                try{
-                        node = d.byId(node);
-                        ancestor = d.byId(ancestor);
-                        while(node){
-                                if(node === ancestor){
-                                        return true; // Boolean
-                                }
-                                node = node.parentNode;
-                        }
-                }catch(e){ /* squelch, return false */ }
-                return false; // Boolean
-        };
-
-        dojo.setSelectable = function(/*DomNode|String*/node, /*Boolean*/selectable){
-                //      summary: enable or disable selection on a node
-                //      node:
-                //              id or reference to node
-                //      selectable:
-                node = d.byId(node);
-                if(d.isMozilla){
-                        node.style.MozUserSelect = selectable ? "" : "none";
-                }else if(d.isKhtml){
-                        node.style.KhtmlUserSelect = selectable ? "auto" : "none";
-                }else if(d.isIE){
-                        var v = (node.unselectable = selectable ? "" : "on");
-                        d.query("*", node).forEach("item.unselectable = '"+v+"'");
-                }
-                //FIXME: else?  Opera?
-        };
-
-        var _insertBefore = function(/*Node*/node, /*Node*/ref){
-                ref.parentNode.insertBefore(node, ref);
-                return true;    //      boolean
-        }
-
-        var _insertAfter = function(/*Node*/node, /*Node*/ref){
-                //      summary:
-                //              Try to insert node after ref
-                var pn = ref.parentNode;
-                if(ref == pn.lastChild){
-                        pn.appendChild(node);
-                }else{
-                        return _insertBefore(node, ref.nextSibling);    //      boolean
-                }
-                return true;    //      boolean
-        }
-
-        dojo.place = function(/*String|DomNode*/node, /*String|DomNode*/refNode, /*String?|Number?*/position){
-                //      summary:
-                //              Attempt to insert node into the DOM, choosing from various positioning options.
-                //              Returns true if successful, false otherwise.
-                //      node: 
-                //              id or node reference to place relative to refNode
-                //      refNode: 
-                //              id or node reference to use as basis for placement
-                //      position:
-                //              string noting the position of node relative to refNode or a
-                //              number indicating the location in the childNodes collection of refNode. 
-                //              Accepted string values are:
-                //              * before
-                //              * after
-                //              * first
-                //              * last
-                //
-                //              "first" and "last" indicate positions as children of refNode.  position defaults
-                //              to "last" if not specified
-
-                // FIXME: need to write tests for this!!!!
-                if(!node || !refNode){
-                        return false;   //      boolean 
-                }
-                node = d.byId(node);
-                refNode = d.byId(refNode);
-                if(typeof position == "number"){
-                        var cn = refNode.childNodes;
-                        if(!cn.length || cn.length <= position){
-                                refNode.appendChild(node);
-                                return true;
-                        }
-                        return _insertBefore(node, position <= 0 ? refNode.firstChild : cn[position]);
-                }
-                switch(position){
-                        case "before":
-                                return _insertBefore(node, refNode);    //      boolean
-                        case "after":
-                                return _insertAfter(node, refNode);             //      boolean
-                        case "first":
-                                if(refNode.firstChild){
-                                        return _insertBefore(node, refNode.firstChild); //      boolean
-                                }
-                                // else fallthrough...
-                        default: // aka: last
-                                refNode.appendChild(node);
-                                return true;    //      boolean
-                }
-        }
-
-        // Box functions will assume this model.
-        // On IE/Opera, BORDER_BOX will be set if the primary document is in quirks mode.
-        // Can be set to change behavior of box setters.
-        
-        // can be either:
-        //      "border-box"
-        //      "content-box" (default)
-        dojo.boxModel = "content-box";
-        
-        // We punt per-node box mode testing completely.
-        // If anybody cares, we can provide an additional (optional) unit 
-        // that overrides existing code to include per-node box sensitivity.
-
-        // Opera documentation claims that Opera 9 uses border-box in BackCompat mode.
-        // but experiments (Opera 9.10.8679 on Windows Vista) indicate that it actually continues to use content-box.
-        // IIRC, earlier versions of Opera did in fact use border-box.
-        // Opera guys, this is really confusing. Opera being broken in quirks mode is not our fault.
-
-        if(d.isIE /*|| dojo.isOpera*/){
-                var _dcm = document.compatMode;
-                // client code may have to adjust if compatMode varies across iframes
-                d.boxModel = _dcm == "BackCompat" || _dcm == "QuirksMode" || d.isIE<6 ? "border-box" : "content-box"; // FIXME: remove IE < 6 support?
-        }
-
-        // =============================
-        // Style Functions
-        // =============================
-        
-        // getComputedStyle drives most of the style code.
-        // Wherever possible, reuse the returned object.
-        //
-        // API functions below that need to access computed styles accept an 
-        // optional computedStyle parameter.
-        // If this parameter is omitted, the functions will call getComputedStyle themselves.
-        // This way, calling code can access computedStyle once, and then pass the reference to 
-        // multiple API functions. 
-
-/*=====
-        dojo.getComputedStyle = function(node){
-                //      summary:
-                //              Returns a "computed style" object.
-                //
-                //      description:
-                //              Gets a "computed style" object which can be used to gather
-                //              information about the current state of the rendered node. 
-                //
-                //              Note that this may behave differently on different browsers.
-                //              Values may have different formats and value encodings across
-                //              browsers.
-                //
-                //              Note also that this method is expensive.  Wherever possible,
-                //              reuse the returned object.
-                //
-                //              Use the dojo.style() method for more consistent (pixelized)
-                //              return values.
-                //
-                //      node: DOMNode
-                //              A reference to a DOM node. Does NOT support taking an
-                //              ID string for speed reasons.
-                //      example:
-                //      |       dojo.getComputedStyle(dojo.byId('foo')).borderWidth;
-                return; // CSS2Properties
-        }
-=====*/
-
-        // Although we normally eschew argument validation at this
-        // level, here we test argument 'node' for (duck)type.
-        // Argument node must also implement Element.  (Note: we check
-        // against HTMLElement rather than Element for interop with prototype.js)
-        // Because 'document' is the 'parentNode' of 'body'
-        // it is frequently sent to this function even 
-        // though it is not Element.
-        var gcs;
-        if(d.isSafari){
-                gcs = function(/*DomNode*/node){
-                        var s;
-                        if(node instanceof HTMLElement){
-                                var dv = node.ownerDocument.defaultView;
-                                s = dv.getComputedStyle(node, null);
-                                if(!s && node.style){ 
-                                        node.style.display = ""; 
-                                        s = dv.getComputedStyle(node, null);
-                                }
-                        }
-                        return s || {};
-                }; 
-        }else if(d.isIE){
-                gcs = function(node){
-                        // IE (as of 7) doesn't expose Element like sane browsers
-                        return node.nodeType == 1 /* ELEMENT_NODE*/ ? node.currentStyle : {};
-                };
-        }else{
-                gcs = function(node){
-                        return node instanceof HTMLElement ? 
-                                node.ownerDocument.defaultView.getComputedStyle(node, null) : {};
-                };
-        }
-        dojo.getComputedStyle = gcs;
-
-        if(!d.isIE){
-                dojo._toPixelValue = function(element, value){
-                        // style values can be floats, client code may want
-                        // to round for integer pixels.
-                        return parseFloat(value) || 0; 
-                };
-        }else{
-                dojo._toPixelValue = function(element, avalue){
-                        if(!avalue){ return 0; }
-                        // on IE7, medium is usually 4 pixels
-                        if(avalue=="medium"){ return 4; }
-                        // style values can be floats, client code may
-                        // want to round this value for integer pixels.
-                        if(avalue.slice && (avalue.slice(-2)=='px')){ return parseFloat(avalue); }
-                        with(element){
-                                var sLeft = style.left;
-                                var rsLeft = runtimeStyle.left;
-                                runtimeStyle.left = currentStyle.left;
-                                try{
-                                        // 'avalue' may be incompatible with style.left, which can cause IE to throw
-                                        // this has been observed for border widths using "thin", "medium", "thick" constants
-                                        // those particular constants could be trapped by a lookup
-                                        // but perhaps there are more
-                                        style.left = avalue;
-                                        avalue = style.pixelLeft;
-                                }catch(e){
-                                        avalue = 0;
-                                }
-                                style.left = sLeft;
-                                runtimeStyle.left = rsLeft;
-                        }
-                        return avalue;
-                }
-        }
-        var px = d._toPixelValue;
-
-        // FIXME: there opacity quirks on FF that we haven't ported over. Hrm.
-        /*=====
-        dojo._getOpacity = function(node){
-                        //      summary:
-                        //              Returns the current opacity of the passed node as a
-                        //              floating-point value between 0 and 1.
-                        //      node: DomNode
-                        //              a reference to a DOM node. Does NOT support taking an
-                        //              ID string for speed reasons.
-                        //      returns: Number between 0 and 1
-                        return; // Number
-        }
-        =====*/
-
-        var astr = "DXImageTransform.Microsoft.Alpha";
-        var af = function(n, f){ 
-                try{
-                        return n.filters.item(astr);
-                }catch(e){
-                        return f ? {} : null;
-                }
-        }
-
-        dojo._getOpacity = d.isIE ? function(node){
-                try{
-                        return af(node).Opacity / 100; // Number
-                }catch(e){
-                        return 1; // Number
-                }
-        } : function(node){
-                return gcs(node).opacity;
-        };
-
-        /*=====
-        dojo._setOpacity = function(node, opacity){
-                        //      summary:
-                        //              set the opacity of the passed node portably. Returns the
-                        //              new opacity of the node.
-                        //      node: DOMNode
-                        //              a reference to a DOM node. Does NOT support taking an
-                        //              ID string for performance reasons.
-                        //      opacity: Number
-                        //              A Number between 0 and 1. 0 specifies transparent.
-                        //      returns: Number between 0 and 1
-                        return; // Number
-        }
-        =====*/
-
-        dojo._setOpacity = d.isIE ? function(/*DomNode*/node, /*Number*/opacity){
-                var ov = opacity * 100;
-                node.style.zoom = 1.0;
-
-                // on IE7 Alpha(Filter opacity=100) makes text look fuzzy so disable it altogether (bug #2661),
-                //but still update the opacity value so we can get a correct reading if it is read later.
-                af(node, 1).Enabled = (opacity == 1 ? false : true);
-
-                if(!af(node)){
-                        node.style.filter += " progid:"+astr+"(Opacity="+ov+")";
-                }else{
-                        af(node, 1).Opacity = ov;
-                }
-
-                if(node.nodeName.toLowerCase() == "tr"){
-                        d.query("> td", node).forEach(function(i){
-                                d._setOpacity(i, opacity);
-                        });
-                }
-                return opacity;
-        } : function(node, opacity){
-                return node.style.opacity = opacity;
-        };
-
-        var _pixelNamesCache = {
-                left: true, top: true
-        };
-        var _pixelRegExp = /margin|padding|width|height|max|min|offset/;  // |border
-        var _toStyleValue = function(node, type, value){
-                type = type.toLowerCase(); // FIXME: should we really be doing string case conversion here? Should we cache it? Need to profile!
-                if(d.isIE){
-                        if(value == "auto"){
-                                if(type == "height"){ return node.offsetHeight; }
-                                if(type == "width"){ return node.offsetWidth; }
-                        }
-                        if(type == "fontweight"){
-                                switch(value){
-                                        case 700: return "bold";
-                                        case 400:
-                                        default: return "normal";
-                                }
-                        }
-                }
-                if(!(type in _pixelNamesCache)){
-                        _pixelNamesCache[type] = _pixelRegExp.test(type);
-                }
-                return _pixelNamesCache[type] ? px(node, value) : value;
-        }
-
-        var _floatStyle = d.isIE ? "styleFloat" : "cssFloat";
-        var _floatAliases = { "cssFloat": _floatStyle, "styleFloat": _floatStyle, "float": _floatStyle };
-        
-        // public API
-        
-        dojo.style = function(  /*DomNode|String*/ node, 
-                                                        /*String?|Object?*/ style, 
-                                                        /*String?*/ value){
-                //      summary:
-                //              Accesses styles on a node. If 2 arguments are
-                //              passed, acts as a getter. If 3 arguments are passed, acts
-                //              as a setter.
-                //      node:
-                //              id or reference to node to get/set style for
-                //      style:
-                //              the style property to set in DOM-accessor format
-                //              ("borderWidth", not "border-width") or an object with key/value
-                //              pairs suitable for setting each property.
-                //      value:
-                //              If passed, sets value on the node for style, handling
-                //              cross-browser concerns.
-                //      example:
-                //              Passing only an ID or node returns the computed style object of
-                //              the node:
-                //      |       dojo.style("thinger");
-                //      example:
-                //              Passing a node and a style property returns the current
-                //              normalized, computed value for that property:
-                //      |       dojo.style("thinger", "opacity"); // 1 by default
-                //
-                //      example:
-                //              Passing a node, a style property, and a value changes the
-                //              current display of the node and returns the new computed value
-                //      |       dojo.style("thinger", "opacity", 0.5); // == 0.5
-                //
-                //      example:
-                //              Passing a node, an object-style style property sets each of the values in turn and returns the computed style object of the node:
-                //      |       dojo.style("thinger", {
-                //      |               "opacity": 0.5,
-                //      |               "border": "3px solid black",
-                //      |               "height": 300
-                //      |       });
-                //
-                //      example:
-                //              When the CSS style property is hyphenated, the JavaScript property is camelCased.
-                //              font-size becomes fontSize, and so on.
-                //      |       dojo.style("thinger",{
-                //      |               fontSize:"14pt",
-                //      |               letterSpacing:"1.2em"
-                //      |       });
-                //
-                //      example:
-                //              dojo.NodeList implements .style() using the same syntax, omitting the "node" parameter, calling
-                //              dojo.style() on every element of the list. See: dojo.query and dojo.NodeList
-                //      |       dojo.query(".someClassName").style("visibility","hidden");
-                //      |       // or
-                //      |       dojo.query("#baz > div").style({
-                //      |               opacity:0.75,
-                //      |               fontSize:"13pt"
-                //      |       });
-
-                var n = d.byId(node), args = arguments.length, op = (style=="opacity");
-                style = _floatAliases[style] || style;
-                if(args == 3){
-                        return op ? d._setOpacity(n, value) : n.style[style] = value; /*Number*/
-                }
-                if(args == 2 && op){
-                        return d._getOpacity(n);
-                }
-                var s = gcs(n);
-                if(args == 2 && !d.isString(style)){
-                        for(var x in style){
-                                d.style(node, x, style[x]);
-                        }
-                        return s;
-                }
-                return (args == 1) ? s : _toStyleValue(n, style, s[style]||n.style[style]); /* CSS2Properties||String||Number */
-        }
-
-        // =============================
-        // Box Functions
-        // =============================
-
-        dojo._getPadExtents = function(/*DomNode*/n, /*Object*/computedStyle){
-                //      summary:
-                //              Returns object with special values specifically useful for node
-                //              fitting.
-                //
-                //              * l/t = left/top padding (respectively)
-                //              * w = the total of the left and right padding 
-                //              * h = the total of the top and bottom padding
-                //
-                //              If 'node' has position, l/t forms the origin for child nodes. 
-                //              The w/h are used for calculating boxes.
-                //              Normally application code will not need to invoke this
-                //              directly, and will use the ...box... functions instead.
-                var 
-                        s = computedStyle||gcs(n), 
-                        l = px(n, s.paddingLeft), 
-                        t = px(n, s.paddingTop);
-                return { 
-                        l: l,
-                        t: t,
-                        w: l+px(n, s.paddingRight),
-                        h: t+px(n, s.paddingBottom)
-                };
-        }
-
-        dojo._getBorderExtents = function(/*DomNode*/n, /*Object*/computedStyle){
-                //      summary:
-                //              returns an object with properties useful for noting the border
-                //              dimensions.
-                //
-                //              * l/t = the sum of left/top border (respectively)
-                //              * w = the sum of the left and right border
-                //              * h = the sum of the top and bottom border
-                //
-                //              The w/h are used for calculating boxes.
-                //              Normally application code will not need to invoke this
-                //              directly, and will use the ...box... functions instead.
-                var 
-                        ne = "none",
-                        s = computedStyle||gcs(n), 
-                        bl = (s.borderLeftStyle != ne ? px(n, s.borderLeftWidth) : 0),
-                        bt = (s.borderTopStyle != ne ? px(n, s.borderTopWidth) : 0);
-                return { 
-                        l: bl,
-                        t: bt,
-                        w: bl + (s.borderRightStyle!=ne ? px(n, s.borderRightWidth) : 0),
-                        h: bt + (s.borderBottomStyle!=ne ? px(n, s.borderBottomWidth) : 0)
-                };
-        }
-
-        dojo._getPadBorderExtents = function(/*DomNode*/n, /*Object*/computedStyle){
-                //      summary:
-                //              returns object with properties useful for box fitting with
-                //              regards to padding.
-                //
-                //              * l/t = the sum of left/top padding and left/top border (respectively)
-                //              * w = the sum of the left and right padding and border
-                //              * h = the sum of the top and bottom padding and border
-                //
-                //              The w/h are used for calculating boxes.
-                //              Normally application code will not need to invoke this
-                //              directly, and will use the ...box... functions instead.
-                var 
-                        s = computedStyle||gcs(n), 
-                        p = d._getPadExtents(n, s),
-                        b = d._getBorderExtents(n, s);
-                return { 
-                        l: p.l + b.l,
-                        t: p.t + b.t,
-                        w: p.w + b.w,
-                        h: p.h + b.h
-                };
-        }
-
-        dojo._getMarginExtents = function(n, computedStyle){
-                //      summary:
-                //              returns object with properties useful for box fitting with
-                //              regards to box margins (i.e., the outer-box).
-                //
-                //              * l/t = marginLeft, marginTop, respectively
-                //              * w = total width, margin inclusive
-                //              * h = total height, margin inclusive
-                //
-                //              The w/h are used for calculating boxes.
-                //              Normally application code will not need to invoke this
-                //              directly, and will use the ...box... functions instead.
-                var 
-                        s = computedStyle||gcs(n), 
-                        l = px(n, s.marginLeft),
-                        t = px(n, s.marginTop),
-                        r = px(n, s.marginRight),
-                        b = px(n, s.marginBottom);
-                if(d.isSafari && (s.position != "absolute")){
-                        // FIXME: Safari's version of the computed right margin
-                        // is the space between our right edge and the right edge 
-                        // of our offsetParent. 
-                        // What we are looking for is the actual margin value as 
-                        // determined by CSS.
-                        // Hack solution is to assume left/right margins are the same.
-                        r = l;
-                }
-                return { 
-                        l: l,
-                        t: t,
-                        w: l+r,
-                        h: t+b
-                };
-        }
-
-        // Box getters work in any box context because offsetWidth/clientWidth
-        // are invariant wrt box context
-        //
-        // They do *not* work for display: inline objects that have padding styles
-        // because the user agent ignores padding (it's bogus styling in any case)
-        //
-        // Be careful with IMGs because they are inline or block depending on 
-        // browser and browser mode.
-
-        // Although it would be easier to read, there are not separate versions of 
-        // _getMarginBox for each browser because:
-        // 1. the branching is not expensive
-        // 2. factoring the shared code wastes cycles (function call overhead)
-        // 3. duplicating the shared code wastes bytes
-        
-        dojo._getMarginBox = function(/*DomNode*/node, /*Object*/computedStyle){
-                // summary:
-                //              returns an object that encodes the width, height, left and top
-                //              positions of the node's margin box.
-                var s = computedStyle||gcs(node), me = d._getMarginExtents(node, s);
-                var l = node.offsetLeft - me.l, t = node.offsetTop - me.t, p = node.parentNode;
-                if(d.isMoz){
-                        // Mozilla:
-                        // If offsetParent has a computed overflow != visible, the offsetLeft is decreased
-                        // by the parent's border.
-                        // We don't want to compute the parent's style, so instead we examine node's
-                        // computed left/top which is more stable.
-                        var sl = parseFloat(s.left), st = parseFloat(s.top);
-                        if(!isNaN(sl) && !isNaN(st)){
-                                l = sl, t = st;
-                        }else{
-                                // If child's computed left/top are not parseable as a number (e.g. "auto"), we
-                                // have no choice but to examine the parent's computed style.
-                                if(p && p.style){
-                                        var pcs = gcs(p);
-                                        if(pcs.overflow != "visible"){
-                                                var be = d._getBorderExtents(p, pcs);
-                                                l += be.l, t += be.t;
-                                        }
-                                }
-                        }
-                }else if(d.isOpera){
-                        // On Opera, offsetLeft includes the parent's border
-                        if(p){
-                                var be = d._getBorderExtents(p);
-                                l -= be.l;
-                                t -= be.t;
-                        }
-                }
-                return { 
-                        l: l, 
-                        t: t, 
-                        w: node.offsetWidth + me.w, 
-                        h: node.offsetHeight + me.h 
-                };
-        }
-        
-        dojo._getContentBox = function(node, computedStyle){
-                // summary:
-                //              Returns an object that encodes the width, height, left and top
-                //              positions of the node's content box, irrespective of the
-                //              current box model.
-
-                // clientWidth/Height are important since the automatically account for scrollbars
-                // fallback to offsetWidth/Height for special cases (see #3378)
-                var s=computedStyle||gcs(node), pe=d._getPadExtents(node, s), be=d._getBorderExtents(node, s), w=node.clientWidth, h;
-                if(!w){
-                        w=node.offsetWidth, h=node.offsetHeight;
-                }else{
-                        h=node.clientHeight, be.w = be.h = 0; 
-                }
-                // On Opera, offsetLeft includes the parent's border
-                if(d.isOpera){ pe.l += be.l; pe.t += be.t; };
-                return { 
-                        l: pe.l, 
-                        t: pe.t, 
-                        w: w - pe.w - be.w, 
-                        h: h - pe.h - be.h
-                };
-        }
-
-        dojo._getBorderBox = function(node, computedStyle){
-                var s=computedStyle||gcs(node), pe=d._getPadExtents(node, s), cb=d._getContentBox(node, s);
-                return { 
-                        l: cb.l - pe.l, 
-                        t: cb.t - pe.t, 
-                        w: cb.w + pe.w, 
-                        h: cb.h + pe.h
-                };
-        }
-
-        // Box setters depend on box context because interpretation of width/height styles
-        // vary wrt box context.
-        //
-        // The value of dojo.boxModel is used to determine box context.
-        // dojo.boxModel can be set directly to change behavior.
-        //
-        // Beware of display: inline objects that have padding styles
-        // because the user agent ignores padding (it's a bogus setup anyway)
-        //
-        // Be careful with IMGs because they are inline or block depending on 
-        // browser and browser mode.
-        // 
-        // Elements other than DIV may have special quirks, like built-in
-        // margins or padding, or values not detectable via computedStyle.
-        // In particular, margins on TABLE do not seems to appear 
-        // at all in computedStyle on Mozilla.
-        
-        dojo._setBox = function(/*DomNode*/node, /*Number?*/l, /*Number?*/t, /*Number?*/w, /*Number?*/h, /*String?*/u){
-                //      summary:
-                //              sets width/height/left/top in the current (native) box-model
-                //              dimentions. Uses the unit passed in u.
-                //      node: DOM Node reference. Id string not supported for performance reasons.
-                //      l: optional. left offset from parent.
-                //      t: optional. top offset from parent.
-                //      w: optional. width in current box model.
-                //      h: optional. width in current box model.
-                //      u: optional. unit measure to use for other measures. Defaults to "px".
-                u = u || "px";
-                var s = node.style;
-                if(!isNaN(l)){ s.left = l+u; }
-                if(!isNaN(t)){ s.top = t+u; }
-                if(w>=0){ s.width = w+u; }
-                if(h>=0){ s.height = h+u; }
-        }
-
-        dojo._isButtonTag = function(/*DomNode*/node) {
-                // summary:
-                //              True if the node is BUTTON or INPUT.type="button".
-                return node.tagName == "BUTTON" 
-                        || node.tagName=="INPUT" && node.getAttribute("type").toUpperCase() == "BUTTON"; // boolean
-        }
-        
-        dojo._usesBorderBox = function(/*DomNode*/node){
-                //      summary: 
-                //              True if the node uses border-box layout.
-
-                // We could test the computed style of node to see if a particular box
-                // has been specified, but there are details and we choose not to bother.
-                
-                // TABLE and BUTTON (and INPUT type=button) are always border-box by default.
-                // If you have assigned a different box to either one via CSS then
-                // box functions will break.
-                
-                var n = node.tagName;
-                return d.boxModel=="border-box" || n=="TABLE" || dojo._isButtonTag(node); // boolean
-        }
-
-        dojo._setContentSize = function(/*DomNode*/node, /*Number*/widthPx, /*Number*/heightPx, /*Object*/computedStyle){
-                //      summary:
-                //              Sets the size of the node's contents, irrespective of margins,
-                //              padding, or borders.
-                if(d._usesBorderBox(node)){
-                        var pb = d._getPadBorderExtents(node, computedStyle);
-                        if(widthPx >= 0){ widthPx += pb.w; }
-                        if(heightPx >= 0){ heightPx += pb.h; }
-                }
-                d._setBox(node, NaN, NaN, widthPx, heightPx);
-        }
-
-        dojo._setMarginBox = function(/*DomNode*/node,  /*Number?*/leftPx, /*Number?*/topPx, 
-                                                                                                        /*Number?*/widthPx, /*Number?*/heightPx, 
-                                                                                                        /*Object*/computedStyle){
-                //      summary:
-                //              sets the size of the node's margin box and placement
-                //              (left/top), irrespective of box model. Think of it as a
-                //              passthrough to dojo._setBox that handles box-model vagaries for
-                //              you.
-
-                var s = computedStyle||gcs(node);
-                // Some elements have special padding, margin, and box-model settings. 
-                // To use box functions you may need to set padding, margin explicitly.
-                // Controlling box-model is harder, in a pinch you might set dojo.boxModel.
-                var bb=d._usesBorderBox(node),
-                                pb=bb ? _nilExtents : d._getPadBorderExtents(node, s);
-                if (dojo.isSafari) {
-                        // on Safari (3.1.2), button nodes with no explicit size have a default margin
-                        // setting an explicit size eliminates the margin.
-                        // We have to swizzle the width to get correct margin reading.
-                        if (dojo._isButtonTag(node)){
-                                var ns = node.style;
-                                if (widthPx>=0 && !ns.width) { ns.width = "4px"; }
-                                if (heightPx>=0 && !ns.height) { ns.height = "4px"; }
-                        }
-                }
-                var mb=d._getMarginExtents(node, s);
-                if(widthPx>=0){ widthPx = Math.max(widthPx - pb.w - mb.w, 0); }
-                if(heightPx>=0){ heightPx = Math.max(heightPx - pb.h - mb.h, 0); }
-                d._setBox(node, leftPx, topPx, widthPx, heightPx);
-        }
-        
-        var _nilExtents = { l:0, t:0, w:0, h:0 };
-
-        // public API
-        
-        dojo.marginBox = function(/*DomNode|String*/node, /*Object?*/box){
-                //      summary:
-                //              Getter/setter for the margin-box of node.
-                //      description: 
-                //              Returns an object in the expected format of box (regardless
-                //              if box is passed). The object might look like:
-                //                      `{ l: 50, t: 200, w: 300: h: 150 }`
-                //              for a node offset from its parent 50px to the left, 200px from
-                //              the top with a margin width of 300px and a margin-height of
-                //              150px.
-                //      node:
-                //              id or reference to DOM Node to get/set box for
-                //      box:
-                //              If passed, denotes that dojo.marginBox() should
-                //              update/set the margin box for node. Box is an object in the
-                //              above format. All properties are optional if passed.
-                var n=d.byId(node), s=gcs(n), b=box;
-                return !b ? d._getMarginBox(n, s) : d._setMarginBox(n, b.l, b.t, b.w, b.h, s); // Object
-        }
-
-        dojo.contentBox = function(/*DomNode|String*/node, /*Object?*/box){
-                //      summary:
-                //              Getter/setter for the content-box of node.
-                //      description:
-                //              Returns an object in the expected format of box (regardless if box is passed).
-                //              The object might look like:
-                //                      `{ l: 50, t: 200, w: 300: h: 150 }`
-                //              for a node offset from its parent 50px to the left, 200px from
-                //              the top with a content width of 300px and a content-height of
-                //              150px. Note that the content box may have a much larger border
-                //              or margin box, depending on the box model currently in use and
-                //              CSS values set/inherited for node.
-                //      node:
-                //              id or reference to DOM Node to get/set box for
-                //      box:
-                //              If passed, denotes that dojo.contentBox() should
-                //              update/set the content box for node. Box is an object in the
-                //              above format. All properties are optional if passed.
-                var n=d.byId(node), s=gcs(n), b=box;
-                return !b ? d._getContentBox(n, s) : d._setContentSize(n, b.w, b.h, s); // Object
-        }
-        
-        // =============================
-        // Positioning 
-        // =============================
-        
-        var _sumAncestorProperties = function(node, prop){
-                if(!(node = (node||0).parentNode)){return 0};
-                var val, retVal = 0, _b = d.body();
-                while(node && node.style){
-                        if(gcs(node).position == "fixed"){
-                                return 0;
-                        }
-                        val = node[prop];
-                        if(val){
-                                retVal += val - 0;
-                                // opera and khtml #body & #html has the same values, we only
-                                // need one value
-                                if(node == _b){ break; }
-                        }
-                        node = node.parentNode;
-                }
-                return retVal;  //      integer
-        }
-
-        dojo._docScroll = function(){
-                var 
-                        _b = d.body(),
-                        _w = d.global,
-                        de = d.doc.documentElement;
-                return {
-                        y: (_w.pageYOffset || de.scrollTop || _b.scrollTop || 0),
-                        x: (_w.pageXOffset || d._fixIeBiDiScrollLeft(de.scrollLeft) || _b.scrollLeft || 0)
-                };
-        };
-        
-        dojo._isBodyLtr = function(){
-                //FIXME: could check html and body tags directly instead of computed style?  need to ignore case, accept empty values
-                return !("_bodyLtr" in d) ? 
-                        d._bodyLtr = gcs(d.body()).direction == "ltr" :
-                        d._bodyLtr; // Boolean 
-        }
-        
-        dojo._getIeDocumentElementOffset = function(){
-                // summary
-                // The following values in IE contain an offset:
-                //     event.clientX 
-                //     event.clientY 
-                //     node.getBoundingClientRect().left
-                //     node.getBoundingClientRect().top
-                // But other position related values do not contain this offset, such as
-                // node.offsetLeft, node.offsetTop, node.style.left and node.style.top.
-                // The offset is always (2, 2) in LTR direction. When the body is in RTL
-                // direction, the offset counts the width of left scroll bar's width.
-                // This function computes the actual offset.
-
-                //NOTE: assumes we're being called in an IE browser
-
-                var de = d.doc.documentElement;
-                //FIXME: use this instead?                      var de = d.compatMode == "BackCompat" ? d.body : d.documentElement;
-
-                return (d.isIE >= 7) ?
-                        {x: de.getBoundingClientRect().left, y: de.getBoundingClientRect().top}
-                :
-                        // IE 6.0
-                        {x: d._isBodyLtr() || window.parent == window ?
-                                de.clientLeft : de.offsetWidth - de.clientWidth - de.clientLeft, 
-                                y: de.clientTop}; // Object
-        };
-        
-        dojo._fixIeBiDiScrollLeft = function(/*Integer*/ scrollLeft){
-                // In RTL direction, scrollLeft should be a negative value, but IE 
-                // returns a positive one. All codes using documentElement.scrollLeft
-                // must call this function to fix this error, otherwise the position
-                // will offset to right when there is a horizontal scrollbar.
-                var dd = d.doc;
-                if(d.isIE && !dojo._isBodyLtr()){
-                        var de = dd.compatMode == "BackCompat" ? dd.body : dd.documentElement;
-                        return scrollLeft + de.clientWidth - de.scrollWidth; // Integer
-                }
-                return scrollLeft; // Integer
-        }
-
-        dojo._abs = function(/*DomNode*/node, /*Boolean?*/includeScroll){
-                //      summary:
-                //              Gets the position of the passed element relative to
-                //              the viewport (if includeScroll==false), or relative to the
-                //              document root (if includeScroll==true).
-                //
-                //              Returns an object of the form:
-                //                      { x: 100, y: 300 }
-                //              if includeScroll is passed, the x and y values will include any
-                //              document offsets that may affect the position relative to the
-                //              viewport.
-
-                // FIXME: need to decide in the brave-new-world if we're going to be
-                // margin-box or border-box.
-                var ownerDocument = node.ownerDocument;
-                var ret = {
-                        x: 0,
-                        y: 0
-                };
-
-                // targetBoxType == "border-box"
-                var db = d.body();
-                if(d.isIE || (d.isFF >= 3)){
-                        var client = node.getBoundingClientRect();
-                        var cs;
-                        if(d.isFF){
-                                // in FF3 you have to subract the document element margins
-                                var dv = node.ownerDocument.defaultView;
-                                cs=dv.getComputedStyle(db.parentNode, null);
-                        }
-                        var offset = (d.isIE) ? d._getIeDocumentElementOffset() : { x: px(db.parentNode,cs.marginLeft), y: px(db.parentNode,cs.marginTop)};
-                        ret.x = client.left - offset.x;
-                        ret.y = client.top - offset.y;
-                }else{
-                        if(node["offsetParent"]){
-                                var endNode;
-                                // in Safari, if the node is an absolutely positioned child of
-                                // the body and the body has a margin the offset of the child
-                                // and the body contain the body's margins, so we need to end
-                                // at the body
-                                // FIXME: getting contrary results to the above in latest WebKit.
-                                if(d.isSafari &&
-                                        //(node.style.getPropertyValue("position") == "absolute") &&
-                                        (gcs(node).position == "absolute") &&
-                                        (node.parentNode == db)){
-                                        endNode = db;
-                                }else{
-                                        endNode = db.parentNode;
-                                }
-                                // Opera seems to be double counting for some elements
-                                var cs=gcs(node);
-                                var n=node;
-                                if(d.isOpera&&cs.position!="absolute"){
-                                        n=n.offsetParent;
-                                }
-                                ret.x -= _sumAncestorProperties(n, "scrollLeft");
-                                ret.y -= _sumAncestorProperties(n, "scrollTop");
-
-                                var curnode = node;
-                                do{
-                                        var n = curnode.offsetLeft;
-                                        //FIXME: ugly hack to workaround the submenu in 
-                                        //popupmenu2 does not shown up correctly in opera. 
-                                        //Someone have a better workaround?
-                                        if(!d.isOpera || n > 0){
-                                                ret.x += isNaN(n) ? 0 : n;
-                                        }
-                                        var t = curnode.offsetTop;
-                                        ret.y += isNaN(t) ? 0 : t;
-                                        var cs = gcs(curnode);
-                                        if(curnode != node){
-                                                if(d.isSafari){
-                                                        ret.x += px(curnode, cs.borderLeftWidth);
-                                                        ret.y += px(curnode, cs.borderTopWidth);
-                                                }else if(d.isFF){
-                                                        // tried left+right with differently sized left/right borders
-                                                        // it really is 2xleft border in FF, not left+right, even in RTL!
-                                                        ret.x += 2*px(curnode,cs.borderLeftWidth);
-                                                        ret.y += 2*px(curnode,cs.borderTopWidth);
-                                                }
-                                        }
-                                        // static children in a static div in FF2 are affected by the div's border as well
-                                        // but offsetParent will skip this div!
-                                        if(d.isFF&&cs.position=="static"){
-                                                var parent=curnode.parentNode;
-                                                while(parent!=curnode.offsetParent){
-                                                        var pcs=gcs(parent);
-                                                        if(pcs.position=="static"){
-                                                                ret.x += px(curnode,pcs.borderLeftWidth);
-                                                                ret.y += px(curnode,pcs.borderTopWidth);
-                                                        }
-                                                        parent=parent.parentNode;
-                                                }
-                                        }
-                                        curnode = curnode.offsetParent;
-                                }while((curnode != endNode) && curnode);
-                        }else if(node.x && node.y){
-                                ret.x += isNaN(node.x) ? 0 : node.x;
-                                ret.y += isNaN(node.y) ? 0 : node.y;
-                        }
-                }
-                // account for document scrolling
-                // if offsetParent is used, ret value already includes scroll position
-                // so we may have to actually remove that value if !includeScroll
-                if(includeScroll){
-                        var scroll = d._docScroll();
-                        ret.y += scroll.y;
-                        ret.x += scroll.x;
-                }
-
-                return ret; // object
-        }
-
-        // FIXME: need a setter for coords or a moveTo!!
-        dojo.coords = function(/*DomNode|String*/node, /*Boolean?*/includeScroll){
-                //      summary:
-                //              Returns an object that measures margin box width/height and
-                //              absolute positioning data from dojo._abs().
-                //
-                //      description:
-                //              Returns an object that measures margin box width/height and
-                //              absolute positioning data from dojo._abs().
-                //              Return value will be in the form:
-                //                      `{ l: 50, t: 200, w: 300: h: 150, x: 100, y: 300 }`
-                //              Does not act as a setter. If includeScroll is passed, the x and
-                //              y params are affected as one would expect in dojo._abs().
-                var n=d.byId(node), s=gcs(n), mb=d._getMarginBox(n, s);
-                var abs = d._abs(n, includeScroll);
-                mb.x = abs.x;
-                mb.y = abs.y;
-                return mb;
-        }
-
-        // =============================
-        // Element attribute Functions
-        // =============================
-
-        var ieLT8 = d.isIE < 8;
-
-        var _fixAttrName = function(/*String*/name){
-                switch(name.toLowerCase()){
-                        case "tabindex":
-                                // Internet Explorer will only set or remove tabindex
-                                // if it is spelled "tabIndex"
-                                // 
-                                return ieLT8 ? "tabIndex" : "tabindex";
-                        case "for": case "htmlfor":
-                                // to pick up for attrib set in markup via getAttribute() IE<8 uses "htmlFor" and others use "for"
-                                // get/setAttribute works in all as long use same value for both get/set
-                                return ieLT8 ? "htmlFor" : "for";
-                        case "class" :
-                                return d.isIE ? "className" : "class";
-                        default:
-                                return name;
-                }
-        }
-
-        // non-deprecated HTML4 attributes with default values
-        // http://www.w3.org/TR/html401/index/attributes.html
-        // FF and Safari will return the default values if you
-        // access the attributes via a property but not
-        // via getAttribute()
-        var _attrProps = {
-                colspan: "colSpan",
-                enctype: "enctype",
-                frameborder: "frameborder",
-                method: "method",
-                rowspan: "rowSpan",
-                scrolling: "scrolling",
-                shape: "shape",
-                span: "span",
-                type: "type",
-                valuetype: "valueType"
-        }
-
-        dojo.hasAttr = function(/*DomNode|String*/node, /*String*/name){
-                //      summary:
-                //              Returns true if the requested attribute is specified on the
-                //              given element, and false otherwise.
-                //      node:
-                //              id or reference to the element to check
-                //      name:
-                //              the name of the attribute
-                //      returns:
-                //              true if the requested attribute is specified on the
-                //              given element, and false otherwise
-                node = d.byId(node);
-                var fixName = _fixAttrName(name);
-                fixName = fixName == "htmlFor" ? "for" : fixName; //IE<8 uses htmlFor except in this case
-                var attr = node.getAttributeNode && node.getAttributeNode(fixName);
-                return attr ? attr.specified : false; // Boolean
-        }
-
-        var _evtHdlrMap = {
-                
-        }
-
-        var _ctr = 0;
-        var _attrId = dojo._scopeName + "attrid";
-
-        dojo.attr = function(/*DomNode|String*/node, /*String|Object*/name, /*String?*/value){
-                //      summary:
-                //              Gets or sets an attribute on an HTML element.
-                //      description:
-                //              Handles normalized getting and setting of attributes on DOM
-                //              Nodes. If 2 arguments are passed, and a the second argumnt is a
-                //              string, acts as a getter.
-                //      
-                //              If a third argument is passed, or if the second argumnt is a
-                //              map of attributes, acts as a setter.
-                //
-                //              When passing functions as values, note that they will not be
-                //              directly assigned to slots on the node, but rather the default
-                //              behavior will be removed and the new behavior will be added
-                //              using `dojo.connect()`, meaning that event handler properties
-                //              will be normalized and that some caveats with regards to
-                //              non-standard behaviors for onsubmit apply. Namely that you
-                //              should cancel form submission using `dojo.stopEvent()` on the
-                //              passed event object instead of returning a boolean value from
-                //              the handler itself.
-                //      node:
-                //              id or reference to the element to get or set the attribute on
-                //      name:
-                //              the name of the attribute to get or set.
-                //      value:
-                //              The value to set for the attribute
-                //      returns:
-                //              when used as a getter, the value of the requested attribute
-                //              or null if that attribute does not have a specified or
-                //              default value;
-                //
-                //              when user as a setter, undefined
-                //
-                //      example:
-                //      |       // get the current value of the "foo" attribute on a node
-                //      |       dojo.attr(dojo.byId("nodeId"), "foo");
-                //      |       // or we can just pass the id:
-                //      |       dojo.attr("nodeId", "foo");
-                //
-                //      example:
-                //      |       // use attr() to set the tab index
-                //      |       dojo.attr("nodeId", "tabindex", 3);
-                //      |
-                //
-                //      example:
-                //      |       // set multiple values at once, including event handlers:
-                //      |       dojo.attr("formId", {
-                //      |               "foo": "bar",
-                //      |               "tabindex": -1,
-                //      |               "method": "POST",
-                //      |               "onsubmit": function(e){
-                //      |                       // stop submitting the form. Note that the IE behavior
-                //      |                       // of returning true or false will have no effect here
-                //      |                       // since our handler is connect()ed to the built-in
-                //      |                       // onsubmit behavior and so we need to use
-                //      |                       // dojo.stopEvent() to ensure that the submission
-                //      |                       // doesn't proceed.
-                //      |                       dojo.stopEvent(e);
-                //      |
-                //      |                       // submit the form with Ajax
-                //      |                       dojo.xhrPost({ form: "formId" });
-                //      |               }
-                //      |       });
-
-                var args = arguments.length;
-                if(args == 2 && !d.isString(name)){
-                        for(var x in name){ d.attr(node, x, name[x]); }
-                        return;
-                }
-                node = d.byId(node);
-                name = _fixAttrName(name);
-                if(args == 3){
-                        // FIXME:
-                        //              what about when the name is "style" and value is an object?
-                        //              It seems natural to pass it in to dojo.style(node,
-                        //              value)...should we support this?
-                        if(d.isFunction(value)){
-                                // clobber if we can
-                                var attrId = d.attr(node, _attrId);
-                                if(!attrId){
-                                        attrId = _ctr++;
-                                        d.attr(node, _attrId, attrId);
-                                }
-                                if(!_evtHdlrMap[attrId]){
-                                        _evtHdlrMap[attrId] = {};
-                                }
-                                var h = _evtHdlrMap[attrId][name];
-                                if(h){
-                                        d.disconnect(h);
-                                }else{
-                                        try{
-                                                delete node[name];
-                                        }catch(e){}
-                                }
-
-                                // ensure that event objects are normalized, etc.
-                                _evtHdlrMap[attrId][name] = d.connect(node, name, value);
-
-                        }else if(
-                                (typeof value == "boolean")|| // e.g. onsubmit, disabled
-                                (name == "innerHTML")
-                        ){
-                                node[name] = value;
-                        }else if((name == "style")&&(!d.isString(value))){
-                                d.style(node, value);
-                        }else{
-                                node.setAttribute(name, value);
-                        }
-                        return;
-                }else{
-                        // should we access this attribute via a property or
-                        // via getAttribute()?
-                        var prop = _attrProps[name.toLowerCase()];
-                        if(prop){
-                                return node[prop];
-                        }else{
-                                var attrValue = node[name];
-                                return (typeof attrValue == 'boolean' || typeof attrValue == 'function') ? attrValue
-                                        : (d.hasAttr(node, name) ? node.getAttribute(name) : null);
-                        }
-                }
-        }
-
-        dojo.removeAttr = function(/*DomNode|String*/node, /*String*/name){
-                //      summary:
-                //              Removes an attribute from an HTML element.
-                //      node:
-                //              id or reference to the element to remove the attribute from
-                //      name:
-                //              the name of the attribute to remove
-                d.byId(node).removeAttribute(_fixAttrName(name));
-        }
-
-        /*
-        dojo.createElement = function(type, attrs, parent, position){
-                // TODO: need to finish this!
-        }
-        */
-
-        // =============================
-        // (CSS) Class Functions
-        // =============================
-        var _className = "className";
-
-        dojo.hasClass = function(/*DomNode|String*/node, /*String*/classStr){
-                //      summary:
-                //              Returns whether or not the specified classes are a portion of the
-                //              class list currently applied to the node. 
-                return ((" "+ d.byId(node)[_className] +" ").indexOf(" "+ classStr +" ") >= 0);  // Boolean
-        };
-
-        dojo.addClass = function(/*DomNode|String*/node, /*String*/classStr){
-                //      summary:
-                //              Adds the specified classes to the end of the class list on the
-                //              passed node.
-                node = d.byId(node);
-                var cls = node[_className];
-                if((" "+ cls +" ").indexOf(" " + classStr + " ") < 0){
-                        node[_className] = cls + (cls ? ' ' : '') + classStr;
-                }
-        };
-
-        dojo.removeClass = function(/*DomNode|String*/node, /*String*/classStr){
-                // summary: Removes the specified classes from node.
-                node = d.byId(node);
-                var t = d.trim((" " + node[_className] + " ").replace(" " + classStr + " ", " "));
-                if(node[_className] != t){ node[_className] = t; }
-        };
-
-        dojo.toggleClass = function(/*DomNode|String*/node, /*String*/classStr, /*Boolean?*/condition){
-                //      summary:        
-                //              Adds a class to node if not present, or removes if present.
-                //              Pass a boolean condition if you want to explicitly add or remove.
-                //      condition:
-                //              If passed, true means to add the class, false means to remove.
-                if(condition === undefined){
-                        condition = !d.hasClass(node, classStr);
-                }
-                d[condition ? "addClass" : "removeClass"](node, classStr);
-        };
-
-})();
-
-}
-
-if(!dojo._hasResource["dojo._base.NodeList"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
-dojo._hasResource["dojo._base.NodeList"] = true;
-dojo.provide("dojo._base.NodeList");
-
-
-
-(function(){
-
-        var d = dojo;
-
-        var tnl = function(arr){
-                // decorate an array to make it look like a NodeList
-                arr.constructor = dojo.NodeList;
-                dojo._mixin(arr, dojo.NodeList.prototype);
-                return arr;
-        }
-
-        var _mapIntoDojo = function(func, alwaysThis){
-                // returns a function which, when executed in the scope of its caller,
-                // applies the passed arguments to a particular dojo.* function (named
-                // in func) and aggregates the returns. if alwaysThis is true, it
-                // always returns the scope object and not the collected returns from
-                // the Dojo method
-                return function(){
-                        var _a = arguments;
-                        var aa = d._toArray(_a, 0, [null]);
-                        var s = this.map(function(i){
-                                aa[0] = i;
-                                return d[func].apply(d, aa);
-                        });
-                        return (alwaysThis || ( (_a.length > 1) || !d.isString(_a[0]) )) ? this : s; // String||dojo.NodeList
-                }
-        };
-
-        dojo.NodeList = function(){
-                //      summary:
-                //              dojo.NodeList is as subclass of Array which adds syntactic 
-                //              sugar for chaining, common iteration operations, animation, 
-                //              and node manipulation. NodeLists are most often returned as
-                //              the result of dojo.query() calls.
-                //      example:
-                //              create a node list from a node
-                //              |       new dojo.NodeList(dojo.byId("foo"));
-
-                return tnl(Array.apply(null, arguments));
-        }
-
-        dojo.NodeList._wrap = tnl;
-
-        dojo.extend(dojo.NodeList, {
-                // http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Reference:Global_Objects:Array#Methods
-
-                // FIXME: handle return values for #3244
-                //              http://trac.dojotoolkit.org/ticket/3244
-                
-                // FIXME:
-                //              need to wrap or implement:
-                //                      join (perhaps w/ innerHTML/outerHTML overload for toString() of items?)
-                //                      reduce
-                //                      reduceRight
-
-                slice: function(/*===== begin, end =====*/){
-                        // summary:
-                        //              Returns a new NodeList, maintaining this one in place
-                        // description:
-                        //              This method behaves exactly like the Array.slice method
-                        //              with the caveat that it returns a dojo.NodeList and not a
-                        //              raw Array. For more details, see:
-                        //                      http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Reference:Global_Objects:Array:slice
-                        // begin: Integer
-                        //              Can be a positive or negative integer, with positive
-                        //              integers noting the offset to begin at, and negative
-                        //              integers denoting an offset from the end (i.e., to the left
-                        //              of the end)
-                        // end: Integer?
-                        //              Optional parameter to describe what position relative to
-                        //              the NodeList's zero index to end the slice at. Like begin,
-                        //              can be positive or negative.
-                        var a = d._toArray(arguments);
-                        return tnl(a.slice.apply(this, a));
-                },
-
-                splice: function(/*===== index, howmany, item =====*/){
-                        // summary:
-                        //              Returns a new NodeList, manipulating this NodeList based on
-                        //              the arguments passed, potentially splicing in new elements
-                        //              at an offset, optionally deleting elements
-                        // description:
-                        //              This method behaves exactly like the Array.splice method
-                        //              with the caveat that it returns a dojo.NodeList and not a
-                        //              raw Array. For more details, see:
-                        //                      <http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Reference:Global_Objects:Array:splice>
-                        // index: Integer
-                        //              begin can be a positive or negative integer, with positive
-                        //              integers noting the offset to begin at, and negative
-                        //              integers denoting an offset from the end (i.e., to the left
-                        //              of the end)
-                        // howmany: Integer?
-                        //              Optional parameter to describe what position relative to
-                        //              the NodeList's zero index to end the slice at. Like begin,
-                        //              can be positive or negative.
-                        // item: Object...?
-                        //              Any number of optional parameters may be passed in to be
-                        //              spliced into the NodeList
-                        // returns:
-                        //              dojo.NodeList
-                        var a = d._toArray(arguments);
-                        return tnl(a.splice.apply(this, a));
-                },
-
-                concat: function(/*===== item =====*/){
-                        // summary:
-                        //              Returns a new NodeList comprised of items in this NodeList
-                        //              as well as items passed in as parameters
-                        // description:
-                        //              This method behaves exactly like the Array.concat method
-                        //              with the caveat that it returns a dojo.NodeList and not a
-                        //              raw Array. For more details, see:
-                        //                      <http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Reference:Global_Objects:Array:concat>
-                        // item: Object...?
-                        //              Any number of optional parameters may be passed in to be
-                        //              spliced into the NodeList
-                        // returns:
-                        //              dojo.NodeList
-                        var a = d._toArray(arguments, 0, [this]);
-                        return tnl(a.concat.apply([], a));
-                },
-                
-                indexOf: function(/*Object*/ value, /*Integer?*/ fromIndex){
-                        //      summary:
-                        //              see dojo.indexOf(). The primary difference is that the acted-on 
-                        //              array is implicitly this NodeList
-                        // value:
-                        //              The value to search for.
-                        // fromIndex:
-                        //              The loction to start searching from. Optional. Defaults to 0.
-                        //      description:
-                        //              For more details on the behavior of indexOf, see:
-                        //                      <http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Reference:Global_Objects:Array:indexOf>
-                        //      returns:
-                        //              Positive Integer or 0 for a match, -1 of not found.
-                        return d.indexOf(this, value, fromIndex); // Integer
-                },
-
-                lastIndexOf: function(/*===== value, fromIndex =====*/){
-                        // summary:
-                        //              see dojo.lastIndexOf(). The primary difference is that the
-                        //              acted-on array is implicitly this NodeList
-                        //      description:
-                        //              For more details on the behavior of lastIndexOf, see:
-                        //                      <http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Reference:Global_Objects:Array:lastIndexOf>
-                        // value: Object
-                        //              The value to search for.
-                        // fromIndex: Integer?
-                        //              The loction to start searching from. Optional. Defaults to 0.
-                        // returns:
-                        //              Positive Integer or 0 for a match, -1 of not found.
-                        return d.lastIndexOf.apply(d, d._toArray(arguments, 0, [this])); // Integer
-                },
-
-                every: function(/*Function*/callback, /*Object?*/thisObject){
-                        //      summary:
-                        //              see `dojo.every()` and:
-                        //                      <http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Reference:Global_Objects:Array:every>
-                        //              Takes the same structure of arguments and returns as
-                        //              dojo.every() with the caveat that the passed array is
-                        //              implicitly this NodeList
-                        return d.every(this, callback, thisObject); // Boolean
-                },
-
-                some: function(/*Function*/callback, /*Object?*/thisObject){
-                        //      summary:
-                        //              see dojo.some() and:
-                        //                      http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Reference:Global_Objects:Array:some
-                        //              Takes the same structure of arguments and returns as
-                        //              dojo.some() with the caveat that the passed array is
-                        //              implicitly this NodeList
-                        return d.some(this, callback, thisObject); // Boolean
-                },
-
-                map: function(/*Function*/ func, /*Function?*/ obj){
-                        //      summary:
-                        //              see dojo.map(). The primary difference is that the acted-on
-                        //              array is implicitly this NodeList and the return is a
-                        //              dojo.NodeList (a subclass of Array)
-
-                        return d.map(this, func, obj, d.NodeList); // dojo.NodeList
-                },
-
-                forEach: function(callback, thisObj){
-                        //      summary:
-                        //              see dojo.forEach(). The primary difference is that the acted-on 
-                        //              array is implicitly this NodeList
-
-                        d.forEach(this, callback, thisObj);
-                        // non-standard return to allow easier chaining
-                        return this; // dojo.NodeList 
-                },
-
-                // custom methods
-                
-                coords: function(){
-                        //      summary:
-                        //              Returns the box objects all elements in a node list as
-                        //              an Array (*not* a NodeList)
-                        
-                        return d.map(this, d.coords); // Array
-                },
-
-                /*=====
-                attr: function(property, value){
-                        //      summary:
-                        //              gets or sets the DOM attribute for every element in the
-                        //              NodeList
-                        //      property: String
-                        //              the attribute to get/set
-                        //      value: String?
-                        //              optional. The value to set the property to
-                        //      returns:
-                        //              if no value is passed, the result is an array of attribute values
-                        //              If a value is passed, the return is this NodeList
-                        return; // dojo.NodeList
-                        return; // Array
-                },
-
-                style: function(property, value){
-                        //      summary:
-                        //              gets or sets the CSS property for every element in the NodeList
-                        //      property: String
-                        //              the CSS property to get/set, in JavaScript notation
-                        //              ("lineHieght" instead of "line-height") 
-                        //      value: String?
-                        //              optional. The value to set the property to
-                        //      returns:
-                        //              if no value is passed, the result is an array of strings.
-                        //              If a value is passed, the return is this NodeList
-                        return; // dojo.NodeList
-                        return; // Array
-                },
-
-                addClass: function(className){
-                        //      summary:
-                        //              adds the specified class to every node in the list
-                        //      className: String
-                        //              the CSS class to add
-                        return; // dojo.NodeList
-                },
-
-                removeClass: function(className){
-                        //      summary:
-                        //              removes the specified class from every node in the list
-                        //      className: String
-                        //              the CSS class to add
-                        //      returns:
-                        //              dojo.NodeList, this list
-                        return; // dojo.NodeList
-                },
-
-                toggleClass: function(className, condition){
-                        //      summary:
-                        //              Adds a class to node if not present, or removes if present.
-                        //              Pass a boolean condition if you want to explicitly add or remove.
-                        //      condition: Boolean?
-                        //              If passed, true means to add the class, false means to remove.
-                        //      className: String
-                        //              the CSS class to add
-                        return; // dojo.NodeList
-                },
-
-                connect: function(methodName, objOrFunc, funcName){
-                        //      summary:
-                        //              attach event handlers to every item of the NodeList. Uses dojo.connect()
-                        //              so event properties are normalized
-                        //      methodName: String
-                        //              the name of the method to attach to. For DOM events, this should be
-                        //              the lower-case name of the event
-                        //      objOrFunc: Object|Function|String
-                        //              if 2 arguments are passed (methodName, objOrFunc), objOrFunc should
-                        //              reference a function or be the name of the function in the global
-                        //              namespace to attach. If 3 arguments are provided
-                        //              (methodName, objOrFunc, funcName), objOrFunc must be the scope to 
-                        //              locate the bound function in
-                        //      funcName: String?
-                        //              optional. A string naming the function in objOrFunc to bind to the
-                        //              event. May also be a function reference.
-                        //      example:
-                        //              add an onclick handler to every button on the page
-                        //              |       dojo.query("div:nth-child(odd)").connect("onclick", function(e){
-                        //              |               
-                        //              |       });
-                        // example:
-                        //              attach foo.bar() to every odd div's onmouseover
-                        //              |       dojo.query("div:nth-child(odd)").connect("onmouseover", foo, "bar");
-                },
-                =====*/
-                attr: _mapIntoDojo("attr"),
-                style: _mapIntoDojo("style"),
-                addClass: _mapIntoDojo("addClass", true),
-                removeClass: _mapIntoDojo("removeClass", true),
-                toggleClass: _mapIntoDojo("toggleClass", true),
-                connect: _mapIntoDojo("connect", true),
-
-                // FIXME: connectPublisher()? connectRunOnce()?
-
-                place: function(/*String||Node*/ queryOrNode, /*String*/ position){
-                        //      summary:
-                        //              places elements of this node list relative to the first element matched
-                        //              by queryOrNode. Returns the original NodeList.
-                        //      queryOrNode:
-                        //              may be a string representing any valid CSS3 selector or a DOM node.
-                        //              In the selector case, only the first matching element will be used 
-                        //              for relative positioning.
-                        //      position:
-                        //              can be one of:
-                        //                      * "last"||"end" (default)
-                        //                      * "first||"start"
-                        //                      * "before"
-                        //                      * "after"
-                        //              or an offset in the childNodes property
-                        var item = d.query(queryOrNode)[0];
-                        return this.forEach(function(i){ d.place(i, item, position); }); // dojo.NodeList
-                },
-
-                orphan: function(/*String?*/ simpleFilter){
-                        //      summary:
-                        //              removes elements in this list that match the simple
-                        //              filter from their parents and returns them as a new
-                        //              NodeList.
-                        //      simpleFilter:
-                        //              single-expression CSS filter
-                        //      returns:
-                        //              `dojo.NodeList` containing the orpahned elements 
-                        return (simpleFilter ? d._filterQueryResult(this, simpleFilter) : this). // dojo.NodeList
-                                forEach("if(item.parentNode){ item.parentNode.removeChild(item); }"); 
-                },
-
-                adopt: function(/*String||Array||DomNode*/ queryOrListOrNode, /*String?*/ position){
-                        //      summary:
-                        //              places any/all elements in queryOrListOrNode at a
-                        //              position relative to the first element in this list.
-                        //              Returns a dojo.NodeList of the adopted elements.
-                        //      queryOrListOrNode:
-                        //              a DOM node or a query string or a query result.
-                        //              Represents the nodes to be adopted relative to the
-                        //              first element of this NodeList.
-                        //      position:
-                        //              can be one of:
-                        //                      * "last"||"end" (default)
-                        //                      * "first||"start"
-                        //                      * "before"
-                        //                      * "after"
-                        //              or an offset in the childNodes property
-                        var item = this[0];
-                        return d.query(queryOrListOrNode).forEach(function(ai){ // dojo.NodeList
-                                d.place(ai, item, position || "last"); 
-                        });
-                },
-
-                // FIXME: do we need this?
-                query: function(/*String*/ queryStr){
-                        //      summary:
-                        //              Returns a new, flattened NodeList. Elements of the new list
-                        //              satisfy the passed query but use elements of the
-                        //              current NodeList as query roots.
-
-                        if(!queryStr){ return this; }
-
-                        // FIXME: probably slow
-                        // FIXME: use map?
-                        var ret = d.NodeList();
-                        this.forEach(function(item){
-                                // FIXME: why would we ever get undefined here?
-                                ret = ret.concat(d.query(queryStr, item).filter(function(subItem){ return (subItem !== undefined); }));
-                        });
-                        return ret; // dojo.NodeList
-                },
-
-                filter: function(/*String*/ simpleQuery){
-                        //      summary:
-                        //              "masks" the built-in javascript filter() method to support
-                        //              passing a simple string filter in addition to supporting
-                        //              filtering function objects.
-                        //      example:
-                        //              "regular" JS filter syntax as exposed in dojo.filter:
-                        //              |       dojo.query("*").filter(function(item){
-                        //              |               // highlight every paragraph
-                        //              |               return (item.nodeName == "p");
-                        //              |       }).styles("backgroundColor", "yellow");
-                        // example:
-                        //              the same filtering using a CSS selector
-                        //              |       dojo.query("*").filter("p").styles("backgroundColor", "yellow");
-
-                        var items = this;
-                        var _a = arguments;
-                        var r = d.NodeList();
-                        var rp = function(t){ 
-                                if(t !== undefined){
-                                        r.push(t); 
-                                }
-                        }
-                        if(d.isString(simpleQuery)){
-                                items = d._filterQueryResult(this, _a[0]);
-                                if(_a.length == 1){
-                                        // if we only got a string query, pass back the filtered results
-                                        return items; // dojo.NodeList
-                                }
-                                // if we got a callback, run it over the filtered items
-                                _a.shift();
-                        }
-                        // handle the (callback, [thisObject]) case
-                        d.forEach(d.filter(items, _a[0], _a[1]), rp);
-                        return r; // dojo.NodeList
-                },
-                
-                /*
-                // FIXME: should this be "copyTo" and include parenting info?
-                clone: function(){
-                        // summary:
-                        //              creates node clones of each element of this list
-                        //              and returns a new list containing the clones
-                },
-                */
-
-                addContent: function(/*String*/ content, /*String||Integer?*/ position){
-                        //      summary:
-                        //              add a node or some HTML as a string to every item in the list. 
-                        //              Returns the original list.
-                        //      description:
-                        //              a copy of the HTML content is added to each item in the
-                        //              list, with an optional position argument. If no position
-                        //              argument is provided, the content is appended to the end of
-                        //              each item.
-                        //      content:
-                        //              the HTML in string format to add at position to every item
-                        //      position:
-                        //              can be one of:
-                        //                      * "last"||"end" (default)
-                        //                      * "first||"start"
-                        //                      * "before"
-                        //                      * "after"
-                        //              or an offset in the childNodes property
-                        //      example:
-                        //              appends content to the end if the position is ommitted
-                        //      |       dojo.query("h3 > p").addContent("hey there!");
-                        //      example:
-                        //              add something to the front of each element that has a "thinger" property:
-                        //      |       dojo.query("[thinger]").addContent("...", "first");
-                        //      example:
-                        //              adds a header before each element of the list
-                        //      |       dojo.query(".note").addContent("<h4>NOTE:</h4>", "before");
-                        var ta = d.doc.createElement("span");
-                        if(d.isString(content)){
-                                ta.innerHTML = content;
-                        }else{
-                                ta.appendChild(content);
-                        }
-                        if(position === undefined){
-                                position = "last";
-                        }
-                        var ct = (position == "first" || position == "after") ? "lastChild" : "firstChild";
-                        this.forEach(function(item){
-                                var tn = ta.cloneNode(true);
-                                while(tn[ct]){
-                                        d.place(tn[ct], item, position);
-                                }
-                        });
-                        return this; // dojo.NodeList
-                },
-
-                empty: function(){
-                        //      summary:
-                        //              clears all content from each node in the list
-                        return this.forEach("item.innerHTML='';"); // dojo.NodeList
-
-                        // FIXME: should we be checking for and/or disposing of widgets below these nodes?
-                },
-                
-                instantiate: function(/*String|Object*/ declaredClass, /*Object?*/ properties){
-                        //      summary:
-                        //              Create a new instance of a specified class, using the
-                        //              specified properties and each node in the nodeList as a
-                        //              srcNodeRef
-                        //
-                        var c = d.isFunction(declaredClass) ? declaredClass : d.getObject(declaredClass);
-                        return this.forEach(function(i){
-                                new c(properties||{},i);
-                        }) // dojo.NodeList
-                },
-
-                at: function(/*===== index =====*/){
-                        //      summary:
-                        //              Returns a new NodeList comprised of items in this NodeList
-                        //              at the given index or indices.
-                        //      index: Integer...
-                        //              One or more 0-based indices of items in the current NodeList.
-                        //      returns:
-                        //              dojo.NodeList
-                        var nl = new dojo.NodeList();
-                        dojo.forEach(arguments, function(i) { if(this[i]) { nl.push(this[i]); } }, this);
-                        return nl; // dojo.NodeList
-                }
-
-        });
-
-        // syntactic sugar for DOM events
-        d.forEach([
-                "blur", "focus", "click", "keydown", "keypress", "keyup", "mousedown",
-                "mouseenter", "mouseleave", "mousemove", "mouseout", "mouseover",
-                "mouseup", "submit", "load", "error"
-                ], function(evt){
-                        var _oe = "on"+evt;
-                        d.NodeList.prototype[_oe] = function(a, b){
-                                return this.connect(_oe, a, b);
-                        }
-                                // FIXME: should these events trigger publishes?
-                                /*
-                                return (a ? this.connect(_oe, a, b) : 
-                                                        this.forEach(function(n){  
-                                                                // FIXME:
-                                                                //              listeners get buried by
-                                                                //              addEventListener and can't be dug back
-                                                                //              out to be triggered externally.
-                                                                // see:
-                                                                //              http://developer.mozilla.org/en/docs/DOM:element
-
-                                                                
-
-                                                                // FIXME: need synthetic event support!
-                                                                var _e = { target: n, faux: true, type: evt };
-                                                                // dojo._event_listener._synthesizeEvent({}, { target: n, faux: true, type: evt });
-                                                                try{ n[evt](_e); }catch(e){  }
-                                                                try{ n[_oe](_e); }catch(e){  }
-                                                        })
-                                );
-                        }
-                        */
-                }
-        );
-
-})();
-
-}
-
-if(!dojo._hasResource["dojo._base.query"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
-dojo._hasResource["dojo._base.query"] = true;
-dojo.provide("dojo._base.query");
-
-
-/*
-        dojo.query() architectural overview:
-
-                dojo.query is a relatively full-featured CSS3 query library. It is
-                designed to take any valid CSS3 selector and return the nodes matching
-                the selector. To do this quickly, it processes queries in several
-                steps, applying caching where profitable.
-                
-                The steps (roughly in reverse order of the way they appear in the code):
-                        1.) check to see if we already have a "query dispatcher"
-                                - if so, use that with the given parameterization. Skip to step 4.
-                        2.) attempt to determine which branch to dispatch the query to:
-                                - JS (optimized DOM iteration)
-                                - xpath (for browsers that support it and where it's fast)
-                                - native (not available in any browser yet)
-                        3.) tokenize and convert to executable "query dispatcher"
-                                - this is where the lion's share of the complexity in the
-                                  system lies. In the DOM version, the query dispatcher is
-                                  assembled as a chain of "yes/no" test functions pertaining to
-                                  a section of a simple query statement (".blah:nth-child(odd)"
-                                  but not "div div", which is 2 simple statements). Individual
-                                  statement dispatchers are cached (to prevent re-definition)
-                                  as are entire dispatch chains (to make re-execution of the
-                                  same query fast)
-                                - in the xpath path, tokenization yields a concatenation of
-                                  parameterized xpath selectors. As with the DOM version, both
-                                  simple selector blocks and overall evaluators are cached to
-                                  prevent re-defintion
-                        4.) the resulting query dispatcher is called in the passed scope (by default the top-level document)
-                                - for DOM queries, this results in a recursive, top-down
-                                  evaluation of nodes based on each simple query section
-                                - xpath queries can, thankfully, be executed in one shot
-                        5.) matched nodes are pruned to ensure they are unique
-*/
-
-;(function(){
-        // define everything in a closure for compressability reasons. "d" is an
-        // alias to "dojo" since it's so frequently used. This seems a
-        // transformation that the build system could perform on a per-file basis.
-
-        ////////////////////////////////////////////////////////////////////////
-        // Utility code
-        ////////////////////////////////////////////////////////////////////////
-
-        var d = dojo;
-        var childNodesName = dojo.isIE ? "children" : "childNodes";
-        var caseSensitive = false;
-
-        var getQueryParts = function(query){
-                // summary: state machine for query tokenization
-                if(">~+".indexOf(query.charAt(query.length-1)) >= 0){
-                        query += " *"
-                }
-                query += " "; // ensure that we terminate the state machine
-
-                var ts = function(s, e){
-                        return d.trim(query.slice(s, e));
-                }
-
-                // the overall data graph of the full query, as represented by queryPart objects
-                var qparts = []; 
-                // state keeping vars
-                var inBrackets = -1;
-                var inParens = -1;
-                var inMatchFor = -1;
-                var inPseudo = -1;
-                var inClass = -1;
-                var inId = -1;
-                var inTag = -1;
-                var lc = ""; // the last character
-                var cc = ""; // the current character
-                var pStart;
-                // iteration vars
-                var x = 0; // index in the query
-                var ql = query.length;
-                var currentPart = null; // data structure representing the entire clause
-                var _cp = null; // the current pseudo or attr matcher
-
-                var endTag = function(){
-                        if(inTag >= 0){
-                                var tv = (inTag == x) ? null : ts(inTag, x); // .toLowerCase();
-                                currentPart[ (">~+".indexOf(tv) < 0) ? "tag" : "oper" ] = tv;
-                                inTag = -1;
-                        }
-                }
-
-                var endId = function(){
-                        if(inId >= 0){
-                                currentPart.id = ts(inId, x).replace(/\\/g, "");
-                                inId = -1;
-                        }
-                }
-
-                var endClass = function(){
-                        if(inClass >= 0){
-                                currentPart.classes.push(ts(inClass+1, x).replace(/\\/g, ""));
-                                inClass = -1;
-                        }
-                }
-
-                var endAll = function(){
-                        endId(); endTag(); endClass();
-                }
-
-                for(; lc=cc, cc=query.charAt(x),x<ql; x++){
-                        if(lc == "\\"){ continue; }
-                        if(!currentPart){
-                                // NOTE: I hate all this alloc, but it's shorter than writing tons of if's
-                                pStart = x;
-                                currentPart = {
-                                        query: null,
-                                        pseudos: [],
-                                        attrs: [],
-                                        classes: [],
-                                        tag: null,
-                                        oper: null,
-                                        id: null
-                                };
-                                inTag = x;
-                        }
-
-                        if(inBrackets >= 0){
-                                // look for a the close first
-                                if(cc == "]"){
-                                        if(!_cp.attr){
-                                                _cp.attr = ts(inBrackets+1, x);
-                                        }else{
-                                                _cp.matchFor = ts((inMatchFor||inBrackets+1), x);
-                                        }
-                                        var cmf = _cp.matchFor;
-                                        if(cmf){
-                                                if(     (cmf.charAt(0) == '"') || (cmf.charAt(0)  == "'") ){
-                                                        _cp.matchFor = cmf.substring(1, cmf.length-1);
-                                                }
-                                        }
-                                        currentPart.attrs.push(_cp);
-                                        _cp = null; // necessaray?
-                                        inBrackets = inMatchFor = -1;
-                                }else if(cc == "="){
-                                        var addToCc = ("|~^$*".indexOf(lc) >=0 ) ? lc : "";
-                                        _cp.type = addToCc+cc;
-                                        _cp.attr = ts(inBrackets+1, x-addToCc.length);
-                                        inMatchFor = x+1;
-                                }
-                                // now look for other clause parts
-                        }else if(inParens >= 0){
-                                if(cc == ")"){
-                                        if(inPseudo >= 0){
-                                                _cp.value = ts(inParens+1, x);
-                                        }
-                                        inPseudo = inParens = -1;
-                                }
-                        }else if(cc == "#"){
-                                endAll();
-                                inId = x+1;
-                        }else if(cc == "."){
-                                endAll();
-                                inClass = x;
-                        }else if(cc == ":"){
-                                endAll();
-                                inPseudo = x;
-                        }else if(cc == "["){
-                                endAll();
-                                inBrackets = x;
-                                _cp = {
-                                        /*=====
-                                        attr: null, type: null, matchFor: null
-                                        =====*/
-                                };
-                        }else if(cc == "("){
-                                if(inPseudo >= 0){
-                                        _cp = { 
-                                                name: ts(inPseudo+1, x), 
-                                                value: null
-                                        }
-                                        currentPart.pseudos.push(_cp);
-                                }
-                                inParens = x;
-                        }else if(cc == " " && lc != cc){
-                                // note that we expect the string to be " " terminated
-                                endAll();
-                                if(inPseudo >= 0){
-                                        currentPart.pseudos.push({ name: ts(inPseudo+1, x) });
-                                }
-                                currentPart.hasLoops = (        
-                                                currentPart.pseudos.length || 
-                                                currentPart.attrs.length || 
-                                                currentPart.classes.length      );
-                                currentPart.query = ts(pStart, x);
-                                currentPart.otag = currentPart.tag = (currentPart["oper"]) ? null : (currentPart.tag || "*");
-                                if(currentPart.tag){ // FIXME: not valid in case-sensitive documents
-                                        currentPart.tag = currentPart.tag.toUpperCase();
-                                }
-                                qparts.push(currentPart);
-                                currentPart = null;
-                        }
-                }
-                return qparts;
-        };
-        
-
-        ////////////////////////////////////////////////////////////////////////
-        // XPath query code
-        ////////////////////////////////////////////////////////////////////////
-
-        // this array is a lookup used to generate an attribute matching function.
-        // There is a similar lookup/generator list for the DOM branch with similar
-        // calling semantics.
-        var xPathAttrs = {
-                "*=": function(attr, value){
-                        return "[contains(@"+attr+", '"+ value +"')]";
-                },
-                "^=": function(attr, value){
-                        return "[starts-with(@"+attr+", '"+ value +"')]";
-                },
-                "$=": function(attr, value){
-                        return "[substring(@"+attr+", string-length(@"+attr+")-"+(value.length-1)+")='"+value+"']";
-                },
-                "~=": function(attr, value){
-                        return "[contains(concat(' ',@"+attr+",' '), ' "+ value +" ')]";
-                },
-                "|=": function(attr, value){
-                        return "[contains(concat(' ',@"+attr+",' '), ' "+ value +"-')]";
-                },
-                "=": function(attr, value){
-                        return "[@"+attr+"='"+ value +"']";
-                }
-        };
-
-        // takes a list of attribute searches, the overall query, a function to
-        // generate a default matcher, and a closure-bound method for providing a
-        // matching function that generates whatever type of yes/no distinguisher
-        // the query method needs. The method is a bit tortured and hard to read
-        // because it needs to be used in both the XPath and DOM branches.
-        var handleAttrs = function(     attrList, 
-                                                                query, 
-                                                                getDefault, 
-                                                                handleMatch){
-                d.forEach(query.attrs, function(attr){
-                        var matcher;
-                        // type, attr, matchFor
-                        if(attr.type && attrList[attr.type]){
-                                matcher = attrList[attr.type](attr.attr, attr.matchFor);
-                        }else if(attr.attr.length){
-                                matcher = getDefault(attr.attr);
-                        }
-                        if(matcher){ handleMatch(matcher); }
-                });
-        }
-
-        var buildPath = function(query){
-                var xpath = ".";
-                var qparts = getQueryParts(d.trim(query));
-                while(qparts.length){
-                        var tqp = qparts.shift();
-                        var prefix;
-                        var postfix = "";
-                        if(tqp.oper == ">"){
-                                prefix = "/";
-                                // prefix = "/child::*";
-                                tqp = qparts.shift();
-                        }else if(tqp.oper == "~"){
-                                prefix = "/following-sibling::"; // get element following siblings
-                                tqp = qparts.shift();
-                        }else if(tqp.oper == "+"){
-                                // FIXME: 
-                                //              fails when selecting subsequent siblings by node type
-                                //              because the position() checks the position in the list
-                                //              of matching elements and not the localized siblings
-                                prefix = "/following-sibling::";
-                                postfix = "[position()=1]";
-                                tqp = qparts.shift();
-                        }else{
-                                prefix = "//";
-                                // prefix = "/descendant::*"
-                        }
-
-                        // get the tag name (if any)
-
-                        xpath += prefix + tqp.tag + postfix;
-                        
-                        // check to see if it's got an id. Needs to come first in xpath.
-                        if(tqp.id){
-                                xpath += "[@id='"+tqp.id+"'][1]";
-                        }
-
-                        d.forEach(tqp.classes, function(cn){
-                                var cnl = cn.length;
-                                var padding = " ";
-                                if(cn.charAt(cnl-1) == "*"){
-                                        padding = ""; cn = cn.substr(0, cnl-1);
-                                }
-                                xpath += 
-                                        "[contains(concat(' ',@class,' '), ' "+
-                                        cn + padding + "')]";
-                        });
-
-                        handleAttrs(xPathAttrs, tqp, 
-                                function(condition){
-                                                return "[@"+condition+"]";
-                                },
-                                function(matcher){
-                                        xpath += matcher;
-                                }
-                        );
-
-                        // FIXME: need to implement pseudo-class checks!!
-                };
-                return xpath;
-        };
-
-        var _xpathFuncCache = {};
-        var getXPathFunc = function(path){
-                if(_xpathFuncCache[path]){
-                        return _xpathFuncCache[path];
-                }
-
-                var doc = d.doc;
-                // don't need to memoize. The closure scope handles it for us.
-                var xpath = buildPath(path);
-
-                var tf = function(parent){
-                        // XPath query strings are memoized.
-
-                        var ret = [];
-                        var xpathResult;
-                        var tdoc = doc;
-                        if(parent){
-                                tdoc = (parent.nodeType == 9) ? parent : parent.ownerDocument;
-                        }
-                        try{
-                                xpathResult = tdoc.evaluate(xpath, parent, null, 
-                                                                                                // XPathResult.UNORDERED_NODE_ITERATOR_TYPE, null);
-                                                                                                XPathResult.ANY_TYPE, null);
-                        }catch(e){
-                                
-                                
-                        }
-                        var result = xpathResult.iterateNext();
-                        while(result){
-                                ret.push(result);
-                                result = xpathResult.iterateNext();
-                        }
-                        return ret;
-                }
-                return _xpathFuncCache[path] = tf;
-        };
-
-        /*
-        d.xPathMatch = function(query){
-                // XPath based DOM query system. Handles a small subset of CSS
-                // selectors, subset is identical to the non-XPath version of this
-                // function. 
-
-                return getXPathFunc(query)();
-        }
-        */
-
-        ////////////////////////////////////////////////////////////////////////
-        // DOM query code
-        ////////////////////////////////////////////////////////////////////////
-
-        var _filtersCache = {};
-        var _simpleFiltersCache = {};
-
-        // the basic building block of the yes/no chaining system. agree(f1, f2)
-        // generates a new function which returns the boolean results of both of
-        // the passed functions to a single logical-anded result.
-        var agree = function(first, second){
-                if(!first){ return second; }
-                if(!second){ return first; }
-
-                return function(){
-                        return first.apply(window, arguments) && second.apply(window, arguments);
-                }
-        }
-
-        var _childElements = function(root){
-                var ret = [];
-                var te, x = 0, tret = root[childNodesName];
-                while((te = tret[x++])){
-                        if(te.nodeType == 1){ ret.push(te); }
-                }
-                return ret;
-        }
-
-        var _nextSiblings = function(root, single){
-                var ret = [];
-                var te = root;
-                while(te = te.nextSibling){
-                        if(te.nodeType == 1){
-                                ret.push(te);
-                                if(single){ break; }
-                        }
-                }
-                return ret;
-        }
-
-        // FIXME:
-        //              we need to re-write the way "~" and "+" selectors are handled since
-        //              the left-hand selector simply modifies the right (which is the
-        //              actual search selector). We need to locate on search selector
-        //              instead of modifier to speed up these searches.
-
-        var _filterDown = function(element, queryParts, matchArr, idx){
-                // NOTE:
-                //              in the fast path! this function is called recursively and for
-                //              every run of a query.
-                var nidx = idx+1;
-                var isFinal = (queryParts.length == nidx);
-                var tqp = queryParts[idx];
-
-                // see if we can constrain our next level to direct children
-                if(tqp.oper){
-                        // find some eligable children to search
-                        var ecn = (tqp.oper == ">") ? 
-                                _childElements(element) :
-                                _nextSiblings(element, (tqp.oper == "+"));
-
-                        if(!ecn || !ecn.length){
-                                return;
-                        }
-                        nidx++;
-                        isFinal = (queryParts.length == nidx);
-                        // kinda janky, too much array alloc
-                        var tf = getFilterFunc(queryParts[idx+1]);
-                        // for(var x=ecn.length-1, te; x>=0, te=ecn[x]; x--){
-                        for(var x=0, ecnl=ecn.length, te; x<ecnl, te=ecn[x]; x++){
-                                if(tf(te)){
-                                        if(isFinal){
-                                                matchArr.push(te);
-                                        }else{
-                                                _filterDown(te, queryParts, matchArr, nidx);
-                                        }
-                                }
-                                /*
-                                if(x==0){
-                                        break;
-                                }
-                                */
-                        }
-                }
-
-                // otherwise, keep going down, unless we'er at the end
-                var candidates = getElementsFunc(tqp)(element);
-                if(isFinal){
-                        while(candidates.length){
-                                matchArr.push(candidates.shift());
-                        }
-                        /*
-                        candidates.unshift(0, matchArr.length-1);
-                        matchArr.splice.apply(matchArr, candidates);
-                        */
-                }else{
-                        // if we're not yet at the bottom, keep going!
-                        while(candidates.length){
-                                _filterDown(candidates.shift(), queryParts, matchArr, nidx);
-                        }
-                }
-        }
-
-        var filterDown = function(elements, queryParts){
-                var ret = [];
-
-                // for every root, get the elements that match the descendant selector
-                // for(var x=elements.length-1, te; x>=0, te=elements[x]; x--){
-                var x = elements.length - 1, te;
-                while((te = elements[x--])){
-                        _filterDown(te, queryParts, ret, 0);
-                }
-                return ret;
-        }
-
-        var getFilterFunc = function(q){
-                // note: query can't have spaces!
-                if(_filtersCache[q.query]){
-                        return _filtersCache[q.query];
-                }
-                var ff = null;
-
-                // does it have a tagName component?
-                if(q.tag){
-                        if(q.tag == "*"){
-                                ff = agree(ff, 
-                                        function(elem){
-                                                return (elem.nodeType == 1);
-                                        }
-                                );
-                        }else{
-                                // tag name match
-                                ff = agree(ff, 
-                                        function(elem){
-                                                return (
-                                                        (elem.nodeType == 1) &&
-                                                        (q[ caseSensitive ? "otag" : "tag" ] == elem.tagName)
-                                                        // (q.tag == elem.tagName.toLowerCase())
-                                                );
-                                                // return isTn;
-                                        }
-                                );
-                        }
-                }
-
-                // does the node have an ID?
-                if(q.id){
-                        ff = agree(ff, 
-                                function(elem){
-                                        return (
-                                                (elem.nodeType == 1) &&
-                                                (elem.id == q.id)
-                                        );
-                                }
-                        );
-                }
-
-                if(q.hasLoops){
-                        // if we have other query param parts, make sure we add them to the
-                        // filter chain
-                        ff = agree(ff, getSimpleFilterFunc(q));
-                }
-
-                return _filtersCache[q.query] = ff;
-        }
-
-        var getNodeIndex = function(node){
-                // NOTE: 
-                //              we could have a more accurate caching mechanism by invalidating
-                //              caches after the query has finished, but I think that'd lead to
-                //              significantly more cache churn than the cache would provide
-                //              value for in the common case. Generally, we're more
-                //              conservative (and therefore, more accurate) than jQuery and
-                //              DomQuery WRT node node indexes, but there may be corner cases
-                //              in which we fall down.  How much we care about them is TBD.
-
-                var pn = node.parentNode;
-                var pnc = pn.childNodes;
-
-                // check to see if we can trust the cache. If not, re-key the whole
-                // thing and return our node match from that.
-
-                var nidx = -1;
-                var child = pn.firstChild;
-                if(!child){
-                        return nidx;
-                }
-
-                var ci = node["__cachedIndex"];
-                var cl = pn["__cachedLength"];
-
-                // only handle cache building if we've gone out of sync
-                if(((typeof cl == "number")&&(cl != pnc.length))||(typeof ci != "number")){
-                        // rip though the whole set, building cache indexes as we go
-                        pn["__cachedLength"] = pnc.length;
-                        var idx = 1;
-                        do{
-                                // we only assign indexes for nodes with nodeType == 1, as per:
-                                //              http://www.w3.org/TR/css3-selectors/#nth-child-pseudo
-                                // only elements are counted in the search order, and they
-                                // begin at 1 for the first child's index
-
-                                if(child === node){
-                                        nidx = idx;
-                                }
-                                if(child.nodeType == 1){
-                                        child["__cachedIndex"] = idx;
-                                        idx++;
-                                }
-                                child = child.nextSibling;
-                        }while(child);
-                }else{
-                        // NOTE: 
-                        //              could be incorrect in some cases (node swaps involving the
-                        //              passed node, etc.), but we ignore those due to the relative
-                        //              unlikelihood of that occuring
-                        nidx = ci;
-                }
-                return nidx;
-        }
-
-        var firedCount = 0;
-
-        var blank = "";
-        var _getAttr = function(elem, attr){
-                if(attr == "class"){
-                        return elem.className || blank;
-                }
-                if(attr == "for"){
-                        return elem.htmlFor || blank;
-                }
-                if(attr == "style"){
-                        return elem.style.cssText || blank;
-                }
-                return (caseSensitive ? elem.getAttribute(attr) : elem.getAttribute(attr, 2)) || blank;
-        }
-
-        var attrs = {
-                "*=": function(attr, value){
-                        return function(elem){
-                                // E[foo*="bar"]
-                                //              an E element whose "foo" attribute value contains
-                                //              the substring "bar"
-                                return (_getAttr(elem, attr).indexOf(value)>=0);
-                        }
-                },
-                "^=": function(attr, value){
-                        // E[foo^="bar"]
-                        //              an E element whose "foo" attribute value begins exactly
-                        //              with the string "bar"
-                        return function(elem){
-                                return (_getAttr(elem, attr).indexOf(value)==0);
-                        }
-                },
-                "$=": function(attr, value){
-                        // E[foo$="bar"]        
-                        //              an E element whose "foo" attribute value ends exactly
-                        //              with the string "bar"
-                        var tval = " "+value;
-                        return function(elem){
-                                var ea = " "+_getAttr(elem, attr);
-                                return (ea.lastIndexOf(value)==(ea.length-value.length));
-                        }
-                },
-                "~=": function(attr, value){
-                        // E[foo~="bar"]        
-                        //              an E element whose "foo" attribute value is a list of
-                        //              space-separated values, one of which is exactly equal
-                        //              to "bar"
-
-                        // return "[contains(concat(' ',@"+attr+",' '), ' "+ value +" ')]";
-                        var tval = " "+value+" ";
-                        return function(elem){
-                                var ea = " "+_getAttr(elem, attr)+" ";
-                                return (ea.indexOf(tval)>=0);
-                        }
-                },
-                "|=": function(attr, value){
-                        // E[hreflang|="en"]
-                        //              an E element whose "hreflang" attribute has a
-                        //              hyphen-separated list of values beginning (from the
-                        //              left) with "en"
-                        var valueDash = " "+value+"-";
-                        return function(elem){
-                                var ea = " "+(elem.getAttribute(attr, 2) || "");
-                                return (
-                                        (ea == value) ||
-                                        (ea.indexOf(valueDash)==0)
-                                );
-                        }
-                },
-                "=": function(attr, value){
-                        return function(elem){
-                                return (_getAttr(elem, attr) == value);
-                        }
-                }
-        };
-
-        var pseudos = {
-                "checked": function(name, condition){
-                        return function(elem){
-                                return !!d.attr(elem, "checked");
-                        }
-                },
-                "first-child": function(name, condition){
-                        return function(elem){
-                                if(elem.nodeType != 1){ return false; }
-                                // check to see if any of the previous siblings are elements
-                                var fc = elem.previousSibling;
-                                while(fc && (fc.nodeType != 1)){
-                                        fc = fc.previousSibling;
-                                }
-                                return (!fc);
-                        }
-                },
-                "last-child": function(name, condition){
-                        return function(elem){
-                                if(elem.nodeType != 1){ return false; }
-                                // check to see if any of the next siblings are elements
-                                var nc = elem.nextSibling;
-                                while(nc && (nc.nodeType != 1)){
-                                        nc = nc.nextSibling;
-                                }
-                                return (!nc);
-                        }
-                },
-                "empty": function(name, condition){
-                        return function(elem){
-                                // DomQuery and jQuery get this wrong, oddly enough.
-                                // The CSS 3 selectors spec is pretty explicit about
-                                // it, too.
-                                var cn = elem.childNodes;
-                                var cnl = elem.childNodes.length;
-                                // if(!cnl){ return true; }
-                                for(var x=cnl-1; x >= 0; x--){
-                                        var nt = cn[x].nodeType;
-                                        if((nt == 1)||(nt == 3)){ return false; }
-                                }
-                                return true;
-                        }
-                },
-                "contains": function(name, condition){
-                        return function(elem){
-                                // FIXME: I dislike this version of "contains", as
-                                // whimsical attribute could set it off. An inner-text
-                                // based version might be more accurate, but since
-                                // jQuery and DomQuery also potentially get this wrong,
-                                // I'm leaving it for now.
-                                if(condition.charAt(0)=='"' || condition.charAt(0)=="'"){//remove quote
-                                        condition=condition.substr(1,condition.length-2);
-                                }
-                                return (elem.innerHTML.indexOf(condition) >= 0);
-                        }
-                },
-                "not": function(name, condition){
-                        var ntf = getFilterFunc(getQueryParts(condition)[0]);
-                        return function(elem){
-                                return (!ntf(elem));
-                        }
-                },
-                "nth-child": function(name, condition){
-                        var pi = parseInt;
-                        if(condition == "odd"){
-                                condition = "2n+1";
-                        }else if(condition == "even"){
-                                condition = "2n";
-                        }
-                        if(condition.indexOf("n") != -1){
-                                var tparts = condition.split("n", 2);
-                                var pred = tparts[0] ? (tparts[0]=='-'?-1:pi(tparts[0])) : 1;
-                                var idx = tparts[1] ? pi(tparts[1]) : 0;
-                                var lb = 0, ub = -1;
-                                if(pred>0){
-                                        if(idx<0){
-                                                idx = (idx % pred) && (pred + (idx % pred));
-                                        }else if(idx>0){
-                                                if(idx >= pred){
-                                                        lb = idx - idx % pred;
-                                                }
-                                                idx = idx % pred;
-                                        }
-                                }else if(pred<0){
-                                        pred *= -1;
-                                        if(idx>0){
-                                                ub = idx;
-                                                idx = idx % pred;
-                                        } //idx has to be greater than 0 when pred is negative; shall we throw an error here?
-                                }
-                                if(pred>0){
-                                        return function(elem){
-                                                var i=getNodeIndex(elem);
-                                                return (i>=lb) && (ub<0 || i<=ub) && ((i % pred) == idx);
-                                        }
-                                }else{
-                                        condition=idx;
-                                }
-                        }
-                        //if(condition.indexOf("n") == -1){
-                        var ncount = pi(condition);
-                        return function(elem){
-                                return (getNodeIndex(elem) == ncount);
-                        }
-                }
-        };
-
-        var defaultGetter = (d.isIE) ? function(cond){
-                var clc = cond.toLowerCase();
-                return function(elem){
-                        return (caseSensitive ? elem.getAttribute(cond) : elem[cond]||elem[clc]);
-                }
-        } : function(cond){
-                return function(elem){
-                        return (elem && elem.getAttribute && elem.hasAttribute(cond));
-                }
-        };
-
-        var getSimpleFilterFunc = function(query){
-
-                var fcHit = (_simpleFiltersCache[query.query]||_filtersCache[query.query]);
-                if(fcHit){ return fcHit; }
-
-                var ff = null;
-
-                // the only case where we'll need the tag name is if we came from an ID query
-                if(query.id){ // do we have an ID component?
-                        if(query.tag != "*"){
-                                ff = agree(ff, function(elem){
-                                        return (elem.tagName == query[ caseSensitive ? "otag" : "tag" ]);
-                                });
-                        }
-                }
-
-                // if there's a class in our query, generate a match function for it
-                d.forEach(query.classes, function(cname, idx, arr){
-                        // get the class name
-                        var isWildcard = cname.charAt(cname.length-1) == "*";
-                        if(isWildcard){
-                                cname = cname.substr(0, cname.length-1);
-                        }
-                        // I dislike the regex thing, even if memozied in a cache, but it's VERY short
-                        var re = new RegExp("(?:^|\\s)" + cname + (isWildcard ? ".*" : "") + "(?:\\s|$)");
-                        ff = agree(ff, function(elem){
-                                return re.test(elem.className);
-                        });
-                        ff.count = idx;
-                });
-
-                d.forEach(query.pseudos, function(pseudo){
-                        if(pseudos[pseudo.name]){
-                                ff = agree(ff, pseudos[pseudo.name](pseudo.name, pseudo.value));
-                        }
-                });
-
-                handleAttrs(attrs, query, defaultGetter,
-                        function(tmatcher){ ff = agree(ff, tmatcher); }
-                );
-                if(!ff){
-                        ff = function(){ return true; };
-                }
-                return _simpleFiltersCache[query.query] = ff;
-        }
-
-        var _getElementsFuncCache = { };
-
-        var getElementsFunc = function(query, root){
-                var fHit = _getElementsFuncCache[query.query];
-                if(fHit){ return fHit; }
-
-                // NOTE: this function is in the fast path! not memoized!!!
-
-                // the query doesn't contain any spaces, so there's only so many
-                // things it could be
-
-                if(query.id && !query.hasLoops && !query.tag){
-                        // ID-only query. Easy.
-                        return _getElementsFuncCache[query.query] = function(root){
-                                // FIXME: if root != document, check for parenting!
-                                return [ d.byId(query.id) ];
-                        }
-                }
-
-                var filterFunc = getSimpleFilterFunc(query);
-
-                var retFunc;
-                if(query.tag && query.id && !query.hasLoops){
-                        // we got a filtered ID search (e.g., "h4#thinger")
-                        retFunc = function(root){
-                                var te = d.byId(query.id, (root.ownerDocument||root)); //root itself may be a document
-                                if(filterFunc(te)){
-                                        return [ te ];
-                                }
-                        }
-                }else{
-                        var tret;
-
-                        if(!query.hasLoops){
-                                // it's just a plain-ol elements-by-tag-name query from the root
-                                retFunc = function(root){
-                                        var ret = [];
-                                        var te, x=0, tret = root.getElementsByTagName(query[ caseSensitive ? "otag" : "tag"]);
-                                        while((te = tret[x++])){
-                                                ret.push(te);
-                                        }
-                                        return ret;
-                                }
-                        }else{
-                                retFunc = function(root){
-                                        var ret = [];
-                                        var te, x = 0, tret = root.getElementsByTagName(query[ caseSensitive ? "otag" : "tag"]);
-                                        while((te = tret[x++])){
-                                                if(filterFunc(te)){
-                                                        ret.push(te);
-                                                }
-                                        }
-                                        return ret;
-                                }
-                        }
-                }
-                return _getElementsFuncCache[query.query] = retFunc;
-        }
-
-        var _partsCache = {};
-
-        ////////////////////////////////////////////////////////////////////////
-        // the query runner
-        ////////////////////////////////////////////////////////////////////////
-
-        // this is the second level of spliting, from full-length queries (e.g.,
-        // "div.foo .bar") into simple query expressions (e.g., ["div.foo",
-        // ".bar"])
-        var _queryFuncCache = {
-                "*": d.isIE ? 
-                        function(root){ 
-                                        return root.all;
-                        } : 
-                        function(root){
-                                 return root.getElementsByTagName("*");
-                        },
-                "~": _nextSiblings,
-                "+": function(root){ return _nextSiblings(root, true); },
-                ">": _childElements
-        };
-
-        var getStepQueryFunc = function(query){
-                // if it's trivial, get a fast-path dispatcher
-                var qparts = getQueryParts(d.trim(query));
-                // if(query[query.length-1] == ">"){ query += " *"; }
-                if(qparts.length == 1){
-                        var tt = getElementsFunc(qparts[0]);
-                        tt.nozip = true; // FIXME: is this right? Shouldn't this be wrapped in a closure to mark the return?
-                        return tt;
-                }
-
-                // otherwise, break it up and return a runner that iterates over the parts recursively
-                var sqf = function(root){
-                        var localQueryParts = qparts.slice(0); // clone the src arr
-                        var candidates;
-                        if(localQueryParts[0].oper == ">"){ // FIXME: what if it's + or ~?
-                                candidates = [ root ];
-                                // root = document;
-                        }else{
-                                candidates = getElementsFunc(localQueryParts.shift())(root);
-                        }
-                        return filterDown(candidates, localQueryParts);
-                }
-                return sqf;
-        }
-
-        // a specialized method that implements our primoridal "query optimizer".
-        // This allows us to dispatch queries to the fastest subsystem we can get.
-        var _getQueryFunc = (
-                // NOTE: 
-                //              XPath on the Webkit is slower than it's DOM iteration for most
-                //              test cases
-                // FIXME: 
-                //              we should try to capture some runtime speed data for each query
-                //              function to determine on the fly if we should stick w/ the
-                //              potentially optimized variant or if we should try something
-                //              new.
-                (document["evaluate"] && !d.isSafari) ? 
-                function(query, root){
-                        // has xpath support that's faster than DOM
-                        var qparts = query.split(" ");
-                        // can we handle it?
-                        if(     (!caseSensitive) && // not strictly necessaray, but simplifies lots of stuff
-                                (document["evaluate"]) &&
-                                (query.indexOf(":") == -1) &&
-                                (query.indexOf("+") == -1) // skip direct sibling matches. See line ~344
-                        ){
-                                // dojo.debug(query);
-                                // should we handle it?
-
-                                // kind of a lame heuristic, but it works
-                                if(     
-                                        // a "div div div" style query
-                                        ((qparts.length > 2)&&(query.indexOf(">") == -1))||
-                                        // or something else with moderate complexity. kinda janky
-                                        (qparts.length > 3)||
-                                        (query.indexOf("[")>=0)||
-                                        // or if it's a ".thinger" query
-                                        ((1 == qparts.length)&&(0 <= query.indexOf(".")))
-
-                                ){
-                                        // use get and cache a xpath runner for this selector
-                                        return getXPathFunc(query);
-                                }
-                        }
-
-                        // fallthrough
-                        return getStepQueryFunc(query);
-                } : getStepQueryFunc
-        );
-        // uncomment to disable XPath for testing and tuning the DOM path
-        // _getQueryFunc = getStepQueryFunc;
-
-        // FIXME: we've got problems w/ the NodeList query()/filter() functions if we go XPath for everything
-
-        // uncomment to disable DOM queries for testing and tuning XPath
-        // _getQueryFunc = getXPathFunc;
-
-        // this is the primary caching for full-query results. The query dispatcher
-        // functions are generated here and then pickled for hash lookup in the
-        // future
-        var getQueryFunc = function(query){
-                // return a cached version if one is available
-                var qcz = query.charAt(0);
-                if(d.doc["querySelectorAll"] && 
-                        ( (!d.isSafari) || (d.isSafari > 3.1) ) && // see #5832
-                        // as per CSS 3, we can't currently start w/ combinator:
-                        //              http://www.w3.org/TR/css3-selectors/#w3cselgrammar
-                        (">+~".indexOf(qcz) == -1)
-                ){
-                        return function(root){
-                                var r = root.querySelectorAll(query);
-                                r.nozip = true; // skip expensive duplication checks and just wrap in a NodeList
-                                return r;
-                        };
-                }
-                if(_queryFuncCache[query]){ return _queryFuncCache[query]; }
-                if(0 > query.indexOf(",")){
-                        // if it's not a compound query (e.g., ".foo, .bar"), cache and return a dispatcher
-                        return _queryFuncCache[query] = _getQueryFunc(query);
-                }else{
-                        // if it's a complex query, break it up into it's constituent parts
-                        // and return a dispatcher that will merge the parts when run
-
-                        // var parts = query.split(", ");
-                        var parts = query.split(/\s*,\s*/);
-                        var tf = function(root){
-                                var pindex = 0; // avoid array alloc for every invocation
-                                var ret = [];
-                                var tp;
-                                while((tp = parts[pindex++])){
-                                        ret = ret.concat(_getQueryFunc(tp, tp.indexOf(" "))(root));
-                                }
-                                return ret;
-                        }
-                        // ...cache and return
-                        return _queryFuncCache[query] = tf;
-                }
-        }
-
-        // FIXME: 
-        //              Dean's Base2 uses a system whereby queries themselves note if
-        //              they'll need duplicate filtering. We need to get on that plan!!
-
-        // attempt to efficiently determine if an item in a list is a dupe,
-        // returning a list of "uniques", hopefully in doucment order
-        var _zipIdx = 0;
-        var _zip = function(arr){
-                if(arr && arr.nozip){ return d.NodeList._wrap(arr); }
-                var ret = new d.NodeList();
-                if(!arr){ return ret; }
-                if(arr[0]){
-                        ret.push(arr[0]);
-                }
-                if(arr.length < 2){ return ret; }
-
-                _zipIdx++;
-                
-                // we have to fork here for IE and XML docs because we can't set
-                // expandos on their nodes (apparently). *sigh*
-                if(d.isIE && caseSensitive){
-                        var szidx = _zipIdx+"";
-                        arr[0].setAttribute("_zipIdx", szidx);
-                        for(var x = 1, te; te = arr[x]; x++){
-                                if(arr[x].getAttribute("_zipIdx") != szidx){ 
-                                        ret.push(te);
-                                }
-                                te.setAttribute("_zipIdx", szidx);
-                        }
-                }else{
-                        arr[0]["_zipIdx"] = _zipIdx;
-                        for(var x = 1, te; te = arr[x]; x++){
-                                if(arr[x]["_zipIdx"] != _zipIdx){ 
-                                        ret.push(te);
-                                }
-                                te["_zipIdx"] = _zipIdx;
-                        }
-                }
-                // FIXME: should we consider stripping these properties?
-                return ret;
-        }
-
-        // the main executor
-        d.query = function(/*String*/ query, /*String|DOMNode?*/ root){
-                //      summary:
-                //              Returns nodes which match the given CSS3 selector, searching the
-                //              entire document by default but optionally taking a node to scope
-                //              the search by. Returns an instance of dojo.NodeList.
-                //      description:
-                //              dojo.query() is the swiss army knife of DOM node manipulation in
-                //              Dojo. Much like Prototype's "$$" (bling-bling) function or JQuery's
-                //              "$" function, dojo.query provides robust, high-performance
-                //              CSS-based node selector support with the option of scoping searches
-                //              to a particular sub-tree of a document.
-                //
-                //              Supported Selectors:
-                //              --------------------
-                //
-                //              dojo.query() supports a rich set of CSS3 selectors, including:
-                //
-                //                      * class selectors (e.g., `.foo`)
-                //                      * node type selectors like `span`
-                //                      * ` ` descendant selectors
-                //                      * `>` child element selectors 
-                //                      * `#foo` style ID selectors
-                //                      * `*` universal selector
-                //                      * `~`, the immediately preceeded-by sibling selector
-                //                      * `+`, the preceeded-by sibling selector
-                //                      * attribute queries:
-                //                      |       * `[foo]` attribute presence selector
-                //                      |       * `[foo='bar']` attribute value exact match
-                //                      |       * `[foo~='bar']` attribute value list item match
-                //                      |       * `[foo^='bar']` attribute start match
-                //                      |       * `[foo$='bar']` attribute end match
-                //                      |       * `[foo*='bar']` attribute substring match
-                //                      * `:first-child`, `:last-child` positional selectors
-                //                      * `:empty` content emtpy selector
-                //                      * `:empty` content emtpy selector
-                //                      * `:checked` pseudo selector
-                //                      * `:nth-child(n)`, `:nth-child(2n+1)` style positional calculations
-                //                      * `:nth-child(even)`, `:nth-child(odd)` positional selectors
-                //                      * `:not(...)` negation pseudo selectors
-                //
-                //              Any legal combination of these selectors will work with
-                //              `dojo.query()`, including compound selectors ("," delimited).
-                //              Very complex and useful searches can be constructed with this
-                //              palette of selectors and when combined with functions for
-                //              maniplation presented by dojo.NodeList, many types of DOM
-                //              manipulation operations become very straightforward.
-                //              
-                //              Unsupported Selectors:
-                //              ----------------------
-                //
-                //              While dojo.query handles many CSS3 selectors, some fall outside of
-                //              what's resaonable for a programmatic node querying engine to
-                //              handle. Currently unsupported selectors include:
-                //              
-                //                      * namespace-differentiated selectors of any form
-                //                      * all `::` pseduo-element selectors
-                //                      * certain pseduo-selectors which don't get a lot of day-to-day use:
-                //                      |       * `:root`, `:lang()`, `:target`, `:focus`
-                //                      * all visual and state selectors:
-                //                      |       * `:root`, `:active`, `:hover`, `:visisted`, `:link`,
-                //                                `:enabled`, `:disabled`
-                //                      * `:*-of-type` pseudo selectors
-                //              
-                //              dojo.query and XML Documents:
-                //              -----------------------------
-                //              
-                //              `dojo.query` currently only supports searching XML documents
-                //              whose tags and attributes are 100% lower-case. This is a known
-                //              limitation and will [be addressed soon](http://trac.dojotoolkit.org/ticket/3866)
-                //              Non-selector Queries:
-                //              ---------------------
-                //
-                //              If something other than a String is passed for the query,
-                //              `dojo.query` will return a new `dojo.NodeList` constructed from
-                //              that parameter alone and all further processing will stop. This
-                //              means that if you have a reference to a node or NodeList, you
-                //              can quickly construct a new NodeList from the original by
-                //              calling `dojo.query(node)` or `dojo.query(list)`.
-                //
-                //      query:
-                //              The CSS3 expression to match against. For details on the syntax of
-                //              CSS3 selectors, see <http://www.w3.org/TR/css3-selectors/#selectors>
-                //      root:
-                //              A DOMNode (or node id) to scope the search from. Optional.
-                //      returns: dojo.NodeList
-                //              An instance of `dojo.NodeList`. Many methods are available on
-                //              NodeLists for searching, iterating, manipulating, and handling
-                //              events on the matched nodes in the returned list.
-                //      example:
-                //              search the entire document for elements with the class "foo":
-                //      |       dojo.query(".foo");
-                //              these elements will match:
-                //      |       <span class="foo"></span>
-                //      |       <span class="foo bar"></span>
-                //      |       <p class="thud foo"></p>
-                //      example:
-                //              search the entire document for elements with the classes "foo" *and* "bar":
-                //      |       dojo.query(".foo.bar");
-                //              these elements will match:
-                //      |       <span class="foo bar"></span>
-                //              while these will not:
-                //      |       <span class="foo"></span>
-                //      |       <p class="thud foo"></p>
-                //      example:
-                //              find `<span>` elements which are descendants of paragraphs and
-                //              which have a "highlighted" class:
-                //      |       dojo.query("p span.highlighted");
-                //              the innermost span in this fragment matches:
-                //      |       <p class="foo">
-                //      |               <span>...
-                //      |                       <span class="highlighted foo bar">...</span>
-                //      |               </span>
-                //      |       </p>
-                //      example:
-                //              set an "odd" class on all odd table rows inside of the table
-                //              `#tabular_data`, using the `>` (direct child) selector to avoid
-                //              affecting any nested tables:
-                //      |       dojo.query("#tabular_data > tbody > tr:nth-child(odd)").addClass("odd");
-                //      example:
-                //              remove all elements with the class "error" from the document
-                //              and store them in a list:
-                //      |       var errors = dojo.query(".error").orphan();
-                //      example:
-                //              add an onclick handler to every submit button in the document
-                //              which causes the form to be sent via Ajax instead:
-                //      |       dojo.query("input[type='submit']").onclick(function(e){
-                //      |               dojo.stopEvent(e); // prevent sending the form
-                //      |               var btn = e.target;
-                //      |               dojo.xhrPost({
-                //      |                       form: btn.form,
-                //      |                       load: function(data){
-                //      |                               // replace the form with the response
-                //      |                               var div = dojo.doc.createElement("div");
-                //      |                               dojo.place(div, btn.form, "after");
-                //      |                               div.innerHTML = data;
-                //      |                               dojo.style(btn.form, "display", "none");
-                //      |                       }
-                //      |               });
-                //      |       });
-
-
-                // NOTE: elementsById is not currently supported
-                // NOTE: ignores xpath-ish queries for now
-
-                if(query.constructor == d.NodeList){
-                        return query;
-                }
-                if(!d.isString(query)){
-                        return new d.NodeList(query); // dojo.NodeList
-                }
-                if(d.isString(root)){
-                        root = d.byId(root);
-                }
-
-                root = root||d.doc;
-                var od = root.ownerDocument||root.documentElement;
-                caseSensitive = (root.contentType && root.contentType=="application/xml") || (!!od) && (d.isIE ? od.xml : (root.xmlVersion||od.xmlVersion));
-                return _zip(getQueryFunc(query)(root)); // dojo.NodeList
-        }
-
-        /*
-        // exposing this was a mistake
-        d.query.attrs = attrs;
-        */
-        // exposing this because new pseudo matches are only executed through the
-        // DOM query path (never through the xpath optimizing branch)
-        d.query.pseudos = pseudos;
-
-        // one-off function for filtering a NodeList based on a simple selector
-        d._filterQueryResult = function(nodeList, simpleFilter){
-                var tnl = new d.NodeList();
-                var ff = (simpleFilter) ? getFilterFunc(getQueryParts(simpleFilter)[0]) : function(){ return true; };
-                for(var x = 0, te; te = nodeList[x]; x++){
-                        if(ff(te)){ tnl.push(te); }
-                }
-                return tnl;
-        }
-})();
-
-}
-
-if(!dojo._hasResource["dojo._base.xhr"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
-dojo._hasResource["dojo._base.xhr"] = true;
-dojo.provide("dojo._base.xhr");
-
-
-
-
-
-(function(){
-        var _d = dojo;
-        function setValue(/*Object*/obj, /*String*/name, /*String*/value){
-                //summary:
-                //              For the named property in object, set the value. If a value
-                //              already exists and it is a string, convert the value to be an
-                //              array of values.
-                var val = obj[name];
-                if(_d.isString(val)){
-                        obj[name] = [val, value];
-                }else if(_d.isArray(val)){
-                        val.push(value);
-                }else{
-                        obj[name] = value;
-                }
-        }
-
-        dojo.formToObject = function(/*DOMNode||String*/ formNode){
-                // summary:
-                //              dojo.formToObject returns the values encoded in an HTML form as
-                //              string properties in an object which it then returns. Disabled form
-                //              elements, buttons, and other non-value form elements are skipped.
-                //              Multi-select elements are returned as an array of string values.
-                // description:
-                //              This form:
-                //
-                //              |       <form id="test_form">
-                //              |               <input type="text" name="blah" value="blah">
-                //              |               <input type="text" name="no_value" value="blah" disabled>
-                //              |               <input type="button" name="no_value2" value="blah">
-                //              |               <select type="select" multiple name="multi" size="5">
-                //              |                       <option value="blah">blah</option>
-                //              |                       <option value="thud" selected>thud</option>
-                //              |                       <option value="thonk" selected>thonk</option>
-                //              |               </select>
-                //              |       </form>
-                //
-                //              yields this object structure as the result of a call to
-                //              formToObject():
-                //
-                //              |       { 
-                //              |               blah: "blah",
-                //              |               multi: [
-                //              |                       "thud",
-                //              |                       "thonk"
-                //              |               ]
-                //              |       };
-
-                var ret = {};
-                var exclude = "file|submit|image|reset|button|";
-                _d.forEach(dojo.byId(formNode).elements, function(item){
-                        var _in = item.name;
-                        var type = (item.type||"").toLowerCase();
-                        if(_in && type && exclude.indexOf(type) == -1 && !item.disabled){
-                                if(type == "radio" || type == "checkbox"){
-                                        if(item.checked){ setValue(ret, _in, item.value); }
-                                }else if(item.multiple){
-                                        ret[_in] = [];
-                                        _d.query("option", item).forEach(function(opt){
-                                                if(opt.selected){
-                                                        setValue(ret, _in, opt.value);
-                                                }
-                                        });
-                                }else{ 
-                                        setValue(ret, _in, item.value);
-                                        if(type == "image"){
-                                                ret[_in+".x"] = ret[_in+".y"] = ret[_in].x = ret[_in].y = 0;
-                                        }
-                                }
-                        }
-                });
-                return ret; // Object
-        }
-
-        dojo.objectToQuery = function(/*Object*/ map){
-                //      summary:
-                //              takes a name/value mapping object and returns a string representing
-                //              a URL-encoded version of that object.
-                //      example:
-                //              this object:
-                //
-                //              |       { 
-                //              |               blah: "blah",
-                //              |               multi: [
-                //              |                       "thud",
-                //              |                       "thonk"
-                //              |               ]
-                //              |       };
-                //
-                //      yields the following query string:
-                //      
-                //      |       "blah=blah&multi=thud&multi=thonk"
-
-                // FIXME: need to implement encodeAscii!!
-                var enc = encodeURIComponent;
-                var pairs = [];
-                var backstop = {};
-                for(var name in map){
-                        var value = map[name];
-                        if(value != backstop[name]){
-                                var assign = enc(name) + "=";
-                                if(_d.isArray(value)){
-                                        for(var i=0; i < value.length; i++){
-                                                pairs.push(assign + enc(value[i]));
-                                        }
-                                }else{
-                                        pairs.push(assign + enc(value));
-                                }
-                        }
-                }
-                return pairs.join("&"); // String
-        }
-
-        dojo.formToQuery = function(/*DOMNode||String*/ formNode){
-                // summary:
-                //              Returns a URL-encoded string representing the form passed as either a
-                //              node or string ID identifying the form to serialize
-                return _d.objectToQuery(_d.formToObject(formNode)); // String
-        }
-
-        dojo.formToJson = function(/*DOMNode||String*/ formNode, /*Boolean?*/prettyPrint){
-                // summary:
-                //              return a serialized JSON string from a form node or string
-                //              ID identifying the form to serialize
-                return _d.toJson(_d.formToObject(formNode), prettyPrint); // String
-        }
-
-        dojo.queryToObject = function(/*String*/ str){
-                // summary:
-                //              returns an object representing a de-serialized query section of a
-                //              URL. Query keys with multiple values are returned in an array.
-                // description:
-                //              This string:
-                //
-                //      |               "foo=bar&foo=baz&thinger=%20spaces%20=blah&zonk=blarg&"
-                //              
-                //              results in this object structure:
-                //
-                //      |               {
-                //      |                       foo: [ "bar", "baz" ],
-                //      |                       thinger: " spaces =blah",
-                //      |                       zonk: "blarg"
-                //      |               }
-                //      
-                //              Note that spaces and other urlencoded entities are correctly
-                //              handled.
-
-                // FIXME: should we grab the URL string if we're not passed one?
-                var ret = {};
-                var qp = str.split("&");
-                var dec = decodeURIComponent;
-                _d.forEach(qp, function(item){
-                        if(item.length){
-                                var parts = item.split("=");
-                                var name = dec(parts.shift());
-                                var val = dec(parts.join("="));
-                                if(_d.isString(ret[name])){
-                                        ret[name] = [ret[name]];
-                                }
-                                if(_d.isArray(ret[name])){
-                                        ret[name].push(val);
-                                }else{
-                                        ret[name] = val;
-                                }
-                        }
-                });
-                return ret; // Object
-        }
-
-        /*
-                from refactor.txt:
-
-                all bind() replacement APIs take the following argument structure:
-
-                        {
-                                url: "blah.html",
-
-                                // all below are optional, but must be supported in some form by
-                                // every IO API
-                                timeout: 1000, // milliseconds
-                                handleAs: "text", // replaces the always-wrong "mimetype"
-                                content: { 
-                                        key: "value"
-                                },
-
-                                // browser-specific, MAY be unsupported
-                                sync: true, // defaults to false
-                                form: dojo.byId("someForm") 
-                        }
-        */
-
-        // need to block async callbacks from snatching this thread as the result
-        // of an async callback might call another sync XHR, this hangs khtml forever
-        // must checked by watchInFlight()
-
-        dojo._blockAsync = false;
-
-        dojo._contentHandlers = {
-                "text": function(xhr){ return xhr.responseText; },
-                "json": function(xhr){
-                        return _d.fromJson(xhr.responseText || null);
-                },
-                "json-comment-filtered": function(xhr){ 
-                        // NOTE: the json-comment-filtered option was implemented to prevent
-                        // "JavaScript Hijacking", but it is less secure than standard JSON. Use
-                        // standard JSON instead. JSON prefixing can be used to subvert hijacking.
-                        if(!dojo.config.useCommentedJson){
-                                console.warn("Consider using the standard mimetype:application/json."
-                                        + " json-commenting can introduce security issues. To"
-                                        + " decrease the chances of hijacking, use the standard the 'json' handler and"
-                                        + " prefix your json with: {}&&\n"
-                                        + "Use djConfig.useCommentedJson=true to turn off this message.");
-                        }
-
-                        var value = xhr.responseText;
-                        var cStartIdx = value.indexOf("\/*");
-                        var cEndIdx = value.lastIndexOf("*\/");
-                        if(cStartIdx == -1 || cEndIdx == -1){
-                                throw new Error("JSON was not comment filtered");
-                        }
-                        return _d.fromJson(value.substring(cStartIdx+2, cEndIdx));
-                },
-                "javascript": function(xhr){ 
-                        // FIXME: try Moz and IE specific eval variants?
-                        return _d.eval(xhr.responseText);
-                },
-                "xml": function(xhr){ 
-                        var result = xhr.responseXML;
-                        if(_d.isIE && (!result || result.documentElement == null)){
-                                _d.forEach(["MSXML2", "Microsoft", "MSXML", "MSXML3"], function(prefix){
-                                        try{
-                                                var dom = new ActiveXObject(prefix + ".XMLDOM");
-                                                dom.async = false;
-                                                dom.loadXML(xhr.responseText);
-                                                result = dom;
-                                        }catch(e){ /* Not available. Squelch and try next one. */ }
-                                });
-                        }
-                        return result; // DOMDocument
-                }
-        };
-
-        dojo._contentHandlers["json-comment-optional"] = function(xhr){
-                var handlers = _d._contentHandlers;
-                if(xhr.responseText && xhr.responseText.indexOf("\/*") != -1){
-                        return handlers["json-comment-filtered"](xhr);
-                }else{
-                        return handlers["json"](xhr);
-                }
-        };
-
-        /*=====
-        dojo.__IoArgs = function(){
-                //      url: String
-                //              URL to server endpoint.
-                //      content: Object?
-                //              Contains properties with string values. These
-                //              properties will be serialized as name1=value2 and
-                //              passed in the request.
-                //      timeout: Integer?
-                //              Milliseconds to wait for the response. If this time
-                //              passes, the then error callbacks are called.
-                //      form: DOMNode?
-                //              DOM node for a form. Used to extract the form values
-                //              and send to the server.
-                //      preventCache: Boolean?
-                //              Default is false. If true, then a
-                //              "dojo.preventCache" parameter is sent in the request
-                //              with a value that changes with each request
-                //              (timestamp). Useful only with GET-type requests.
-                //      handleAs: String?
-                //              Acceptable values depend on the type of IO
-                //              transport (see specific IO calls for more information).
-                //      load: Function?
-                //              function(response, ioArgs){} response is of type Object, ioArgs
-                //              is of type dojo.__IoCallbackArgs.  This function will be
-                //              called on a successful HTTP response code.
-                //      error: Function?
-                //              function(response, ioArgs){} response is of type Object, ioArgs
-                //              is of type dojo.__IoCallbackArgs. This function will
-                //              be called when the request fails due to a network or server error, the url
-                //              is invalid, etc. It will also be called if the load or handle callback throws an
-                //              exception, unless djConfig.isDebug is true.  This allows deployed applications
-                //              to continue to run even when a logic error happens in the callback, while making
-                //              it easier to troubleshoot while in debug mode.
-                //      handle: Function?
-                //              function(response, ioArgs){} response is of type Object, ioArgs
-                //              is of type dojo.__IoCallbackArgs.  This function will
-                //              be called at the end of every request, whether or not an error occurs.
-                this.url = url;
-                this.content = content;
-                this.timeout = timeout;
-                this.form = form;
-                this.preventCache = preventCache;
-                this.handleAs = handleAs;
-                this.load = load;
-                this.error = error;
-                this.handle = handle;
-        }
-        =====*/
-
-        /*=====
-        dojo.__IoCallbackArgs = function(args, xhr, url, query, handleAs, id, canDelete, json){
-                //      args: Object
-                //              the original object argument to the IO call.
-                //      xhr: XMLHttpRequest
-                //              For XMLHttpRequest calls only, the
-                //              XMLHttpRequest object that was used for the
-                //              request.
-                //      url: String
-                //              The final URL used for the call. Many times it
-                //              will be different than the original args.url
-                //              value.
-                //      query: String
-                //              For non-GET requests, the
-                //              name1=value1&name2=value2 parameters sent up in
-                //              the request.
-                //      handleAs: String
-                //              The final indicator on how the response will be
-                //              handled.
-                //      id: String
-                //              For dojo.io.script calls only, the internal
-                //              script ID used for the request.
-                //      canDelete: Boolean
-                //              For dojo.io.script calls only, indicates
-                //              whether the script tag that represents the
-                //              request can be deleted after callbacks have
-                //              been called. Used internally to know when
-                //              cleanup can happen on JSONP-type requests.
-                //      json: Object
-                //              For dojo.io.script calls only: holds the JSON
-                //              response for JSONP-type requests. Used
-                //              internally to hold on to the JSON responses.
-                //              You should not need to access it directly --
-                //              the same object should be passed to the success
-                //              callbacks directly.
-                this.args = args;
-                this.xhr = xhr;
-                this.url = url;
-                this.query = query;
-                this.handleAs = handleAs;
-                this.id = id;
-                this.canDelete = canDelete;
-                this.json = json;
-        }
-        =====*/
-
-
-
-        dojo._ioSetArgs = function(/*dojo.__IoArgs*/args,
-                        /*Function*/canceller,
-                        /*Function*/okHandler,
-                        /*Function*/errHandler){
-                //      summary: 
-                //              sets up the Deferred and ioArgs property on the Deferred so it
-                //              can be used in an io call.
-                //      args:
-                //              The args object passed into the public io call. Recognized properties on
-                //              the args object are:
-                //      canceller:
-                //              The canceller function used for the Deferred object. The function
-                //              will receive one argument, the Deferred object that is related to the
-                //              canceller.
-                //      okHandler:
-                //              The first OK callback to be registered with Deferred. It has the opportunity
-                //              to transform the OK response. It will receive one argument -- the Deferred
-                //              object returned from this function.
-                //      errHandler:
-                //              The first error callback to be registered with Deferred. It has the opportunity
-                //              to do cleanup on an error. It will receive two arguments: error (the 
-                //              Error object) and dfd, the Deferred object returned from this function.
-
-                var ioArgs = {args: args, url: args.url};
-
-                //Get values from form if requestd.
-                var formObject = null;
-                if(args.form){ 
-                        var form = _d.byId(args.form);
-                        //IE requires going through getAttributeNode instead of just getAttribute in some form cases, 
-                        //so use it for all.  See #2844
-                        var actnNode = form.getAttributeNode("action");
-                        ioArgs.url = ioArgs.url || (actnNode ? actnNode.value : null); 
-                        formObject = _d.formToObject(form);
-                }
-
-                // set up the query params
-                var miArgs = [{}];
-        
-                if(formObject){
-                        // potentially over-ride url-provided params w/ form values
-                        miArgs.push(formObject);
-                }
-                if(args.content){
-                        // stuff in content over-rides what's set by form
-                        miArgs.push(args.content);
-                }
-                if(args.preventCache){
-                        miArgs.push({"dojo.preventCache": new Date().valueOf()});
-                }
-                ioArgs.query = _d.objectToQuery(_d.mixin.apply(null, miArgs));
-        
-                // .. and the real work of getting the deferred in order, etc.
-                ioArgs.handleAs = args.handleAs || "text";
-                var d = new _d.Deferred(canceller);
-                d.addCallbacks(okHandler, function(error){
-                        return errHandler(error, d);
-                });
-
-                //Support specifying load, error and handle callback functions from the args.
-                //For those callbacks, the "this" object will be the args object.
-                //The callbacks will get the deferred result value as the
-                //first argument and the ioArgs object as the second argument.
-                var ld = args.load;
-                if(ld && _d.isFunction(ld)){
-                        d.addCallback(function(value){
-                                return ld.call(args, value, ioArgs);
-                        });
-                }
-                var err = args.error;
-                if(err && _d.isFunction(err)){
-                        d.addErrback(function(value){
-                                return err.call(args, value, ioArgs);
-                        });
-                }
-                var handle = args.handle;
-                if(handle && _d.isFunction(handle)){
-                        d.addBoth(function(value){
-                                return handle.call(args, value, ioArgs);
-                        });
-                }
-                
-                d.ioArgs = ioArgs;
-        
-                // FIXME: need to wire up the xhr object's abort method to something
-                // analagous in the Deferred
-                return d;
-        }
-
-        var _deferredCancel = function(/*Deferred*/dfd){
-                //summary: canceller function for dojo._ioSetArgs call.
-                
-                dfd.canceled = true;
-                var xhr = dfd.ioArgs.xhr;
-                var _at = typeof xhr.abort;
-                if(_at == "function" || _at == "object" || _at == "unknown"){
-                        xhr.abort();
-                }
-                var err = dfd.ioArgs.error;
-                if(!err){
-                        err = new Error("xhr cancelled");
-                        err.dojoType="cancel";
-                }
-                return err;
-        }
-        var _deferredOk = function(/*Deferred*/dfd){
-                //summary: okHandler function for dojo._ioSetArgs call.
-
-                var ret = _d._contentHandlers[dfd.ioArgs.handleAs](dfd.ioArgs.xhr);
-                return (typeof ret == "undefined") ? null : ret;
-        }
-        var _deferError = function(/*Error*/error, /*Deferred*/dfd){
-                //summary: errHandler function for dojo._ioSetArgs call.
-
-                
-                return error;
-        }
-
-        // avoid setting a timer per request. It degrades performance on IE
-        // something fierece if we don't use unified loops.
-        var _inFlightIntvl = null;
-        var _inFlight = [];
-        var _watchInFlight = function(){
-                //summary: 
-                //              internal method that checks each inflight XMLHttpRequest to see
-                //              if it has completed or if the timeout situation applies.
-                
-                var now = (new Date()).getTime();
-                // make sure sync calls stay thread safe, if this callback is called
-                // during a sync call and this results in another sync call before the
-                // first sync call ends the browser hangs
-                if(!_d._blockAsync){
-                        // we need manual loop because we often modify _inFlight (and therefore 'i') while iterating
-                        // note: the second clause is an assigment on purpose, lint may complain
-                        for(var i = 0, tif; i < _inFlight.length && (tif = _inFlight[i]); i++){
-                                var dfd = tif.dfd;
-                                var func = function(){
-                                        if(!dfd || dfd.canceled || !tif.validCheck(dfd)){
-                                                _inFlight.splice(i--, 1); 
-                                        }else if(tif.ioCheck(dfd)){
-                                                _inFlight.splice(i--, 1);
-                                                tif.resHandle(dfd);
-                                        }else if(dfd.startTime){
-                                                //did we timeout?
-                                                if(dfd.startTime + (dfd.ioArgs.args.timeout || 0) < now){
-                                                        _inFlight.splice(i--, 1);
-                                                        var err = new Error("timeout exceeded");
-                                                        err.dojoType = "timeout";
-                                                        dfd.errback(err);
-                                                        //Cancel the request so the io module can do appropriate cleanup.
-                                                        dfd.cancel();
-                                                }
-                                        }
-                                };
-                                if(dojo.config.isDebug){
-                                        func.call(this);
-                                }else{
-                                        try{
-                                                func.call(this);
-                                        }catch(e){
-                                                dfd.errback(e);
-                                        }
-                                }
-                        }
-                }
-
-                if(!_inFlight.length){
-                        clearInterval(_inFlightIntvl);
-                        _inFlightIntvl = null;
-                        return;
-                }
-
-        }
-
-        dojo._ioCancelAll = function(){
-                //summary: Cancels all pending IO requests, regardless of IO type
-                //(xhr, script, iframe).
-                try{
-                        _d.forEach(_inFlight, function(i){
-                                try{
-                                        i.dfd.cancel();
-                                }catch(e){/*squelch*/}
-                        });
-                }catch(e){/*squelch*/}
-        }
-
-        //Automatically call cancel all io calls on unload
-        //in IE for trac issue #2357.
-        if(_d.isIE){
-                _d.addOnWindowUnload(_d._ioCancelAll);
-        }
-
-        _d._ioWatch = function(/*Deferred*/dfd,
-                /*Function*/validCheck,
-                /*Function*/ioCheck,
-                /*Function*/resHandle){
-                //summary: watches the io request represented by dfd to see if it completes.
-                //dfd:
-                //              The Deferred object to watch.
-                //validCheck:
-                //              Function used to check if the IO request is still valid. Gets the dfd
-                //              object as its only argument.
-                //ioCheck:
-                //              Function used to check if basic IO call worked. Gets the dfd
-                //              object as its only argument.
-                //resHandle:
-                //              Function used to process response. Gets the dfd
-                //              object as its only argument.
-                if(dfd.ioArgs.args.timeout){
-                        dfd.startTime = (new Date()).getTime();
-                }
-                _inFlight.push({dfd: dfd, validCheck: validCheck, ioCheck: ioCheck, resHandle: resHandle});
-                if(!_inFlightIntvl){
-                        _inFlightIntvl = setInterval(_watchInFlight, 50);
-                }
-                _watchInFlight(); // handle sync requests
-        }
-
-        var _defaultContentType = "application/x-www-form-urlencoded";
-
-        var _validCheck = function(/*Deferred*/dfd){
-                return dfd.ioArgs.xhr.readyState; //boolean
-        }
-        var _ioCheck = function(/*Deferred*/dfd){
-                return 4 == dfd.ioArgs.xhr.readyState; //boolean
-        }
-        var _resHandle = function(/*Deferred*/dfd){
-                var xhr = dfd.ioArgs.xhr;
-                if(_d._isDocumentOk(xhr)){
-                        dfd.callback(dfd);
-                }else{
-                        var err = new Error("Unable to load " + dfd.ioArgs.url + " status:" + xhr.status);
-                        err.status = xhr.status;
-                        err.responseText = xhr.responseText;
-                        dfd.errback(err);
-                }
-        }
-
-        dojo._ioAddQueryToUrl = function(/*dojo.__IoCallbackArgs*/ioArgs){
-                //summary: Adds query params discovered by the io deferred construction to the URL.
-                //Only use this for operations which are fundamentally GET-type operations.
-                if(ioArgs.query.length){
-                        ioArgs.url += (ioArgs.url.indexOf("?") == -1 ? "?" : "&") + ioArgs.query;
-                        ioArgs.query = null;
-                }               
-        }
-
-        /*=====
-        dojo.declare("dojo.__XhrArgs", dojo.__IoArgs, {
-                constructor: function(){
-                        //      summary:
-                        //              In addition to the properties listed for the dojo._IoArgs type,
-                        //              the following properties are allowed for dojo.xhr* methods.
-                        //      handleAs: String?
-                        //              Acceptable values are: text (default), json, json-comment-optional,
-                        //              json-comment-filtered, javascript, xml
-                        //      sync: Boolean?
-                        //              false is default. Indicates whether the request should
-                        //              be a synchronous (blocking) request.
-                        //      headers: Object?
-                        //              Additional HTTP headers to send in the request.
-                        this.handleAs = handleAs;
-                        this.sync = sync;
-                        this.headers = headers;
-                }
-        });
-        =====*/
-
-        dojo.xhr = function(/*String*/ method, /*dojo.__XhrArgs*/ args, /*Boolean?*/ hasBody){
-                //      summary:
-                //              Sends an HTTP request with the given method.
-                //      description:
-                //              Sends an HTTP request with the given method.
-                //              See also dojo.xhrGet(), xhrPost(), xhrPut() and dojo.xhrDelete() for shortcuts
-                //              for those HTTP methods. There are also methods for "raw" PUT and POST methods
-                //              via dojo.rawXhrPut() and dojo.rawXhrPost() respectively.
-                //      method:
-                //              HTTP method to be used, such as GET, POST, PUT, DELETE.  Should be uppercase.
-                //      hasBody:
-                //              If the request has an HTTP body, then pass true for hasBody.
-
-                //Make the Deferred object for this xhr request.
-                var dfd = _d._ioSetArgs(args, _deferredCancel, _deferredOk, _deferError);
-
-                //Pass the args to _xhrObj, to allow xhr iframe proxy interceptions.
-                dfd.ioArgs.xhr = _d._xhrObj(dfd.ioArgs.args);
-
-                if(hasBody){
-                        if("postData" in args){
-                                dfd.ioArgs.query = args.postData;
-                        }else if("putData" in args){
-                                dfd.ioArgs.query = args.putData;
-                        }
-                }else{
-                        _d._ioAddQueryToUrl(dfd.ioArgs);
-                }
-
-                // IE 6 is a steaming pile. It won't let you call apply() on the native function (xhr.open).
-                // workaround for IE6's apply() "issues"
-                var ioArgs = dfd.ioArgs;
-                var xhr = ioArgs.xhr;
-                xhr.open(method, ioArgs.url, args.sync !== true, args.user || undefined, args.password || undefined);
-                if(args.headers){
-                        for(var hdr in args.headers){
-                                if(hdr.toLowerCase() === "content-type" && !args.contentType){
-                                        args.contentType = args.headers[hdr];
-                                }else{
-                                        xhr.setRequestHeader(hdr, args.headers[hdr]);
-                                }
-                        }
-                }
-                // FIXME: is this appropriate for all content types?
-                xhr.setRequestHeader("Content-Type", args.contentType || _defaultContentType);
-                if(!args.headers || !args.headers["X-Requested-With"]){
-                        xhr.setRequestHeader("X-Requested-With", "XMLHttpRequest");
-                }
-                // FIXME: set other headers here!
-                if(dojo.config.isDebug){
-                        xhr.send(ioArgs.query);
-                }else{
-                        try{
-                                xhr.send(ioArgs.query);
-                        }catch(e){
-                                dfd.ioArgs.error = e;
-                                dfd.cancel();
-                        }
-                }
-                _d._ioWatch(dfd, _validCheck, _ioCheck, _resHandle);
-                xhr = null;
-                return dfd; // dojo.Deferred
-        }
-
-        dojo.xhrGet = function(/*dojo.__XhrArgs*/ args){
-                //      summary: 
-                //              Sends an HTTP GET request to the server.
-                return _d.xhr("GET", args); // dojo.Deferred
-        }
-
-        dojo.rawXhrPost = dojo.xhrPost = function(/*dojo.__XhrArgs*/ args){
-                //      summary:
-                //              Sends an HTTP POST request to the server. In addtion to the properties
-                //              listed for the dojo.__XhrArgs type, the following property is allowed:
-                //      postData:
-                //              String. Send raw data in the body of the POST request.
-                return _d.xhr("POST", args, true); // dojo.Deferred
-        }
-
-        dojo.rawXhrPut = dojo.xhrPut = function(/*dojo.__XhrArgs*/ args){
-                //      summary:
-                //              Sends an HTTP PUT request to the server. In addtion to the properties
-                //              listed for the dojo.__XhrArgs type, the following property is allowed:
-                //      putData:
-                //              String. Send raw data in the body of the PUT request.
-                return _d.xhr("PUT", args, true); // dojo.Deferred
-        }
-
-        dojo.xhrDelete = function(/*dojo.__XhrArgs*/ args){
-                //      summary:
-                //              Sends an HTTP DELETE request to the server.
-                return _d.xhr("DELETE", args); //dojo.Deferred
-        }
-
-        /*
-        dojo.wrapForm = function(formNode){
-                //summary:
-                //              A replacement for FormBind, but not implemented yet.
-
-                // FIXME: need to think harder about what extensions to this we might
-                // want. What should we allow folks to do w/ this? What events to
-                // set/send?
-                throw new Error("dojo.wrapForm not yet implemented");
-        }
-        */
-})();
-
-}
-
-if(!dojo._hasResource["dojo._base.fx"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
-dojo._hasResource["dojo._base.fx"] = true;
-dojo.provide("dojo._base.fx");
-
-
-
-
-
-
-/*
-        Animation losely package based on Dan Pupius' work, contributed under CLA: 
-                http://pupius.co.uk/js/Toolkit.Drawing.js
-*/
-(function(){ 
-
-        var d = dojo;
-        
-        dojo._Line = function(/*int*/ start, /*int*/ end){
-                //      summary:
-                //              dojo._Line is the object used to generate values from a start value
-                //              to an end value
-                //      start: int
-                //              Beginning value for range
-                //      end: int
-                //              Ending value for range
-                this.start = start;
-                this.end = end;
-                this.getValue = function(/*float*/ n){
-                        //      summary: returns the point on the line
-                        //      n: a floating point number greater than 0 and less than 1
-                        return ((this.end - this.start) * n) + this.start; // Decimal
-                }
-        }
-        
-        d.declare("dojo._Animation", null, {
-                //      summary
-                //              A generic animation class that fires callbacks into its handlers
-                //              object at various states. Nearly all dojo animation functions
-                //              return an instance of this method, usually without calling the
-                //              .play() method beforehand. Therefore, you will likely need to
-                //              call .play() on instances of dojo._Animation when one is
-                //              returned.
-                constructor: function(/*Object*/ args){
-                        d.mixin(this, args);
-                        if(d.isArray(this.curve)){
-                                /* curve: Array
-                                        pId: a */
-                                this.curve = new d._Line(this.curve[0], this.curve[1]);
-                        }
-                },
-                
-                // duration: Integer
-                //      The time in milliseonds the animation will take to run
-                duration: 350,
-        
-        /*=====
-                // curve: dojo._Line||Array
-                //      A two element array of start and end values, or a dojo._Line instance to be
-                //      used in the Animation. 
-                curve: null,
-        
-                // easing: Function
-                //      A Function to adjust the acceleration (or deceleration) of the progress 
-                //      across a dojo._Line
-                easing: null,
-        =====*/
-        
-                // repeat: Integer
-                //      The number of times to loop the animation
-                repeat: 0,
-        
-                // rate: Integer
-                //      the time in milliseconds to wait before advancing to next frame 
-                //      (used as a fps timer: rate/1000 = fps)
-                rate: 10 /* 100 fps */,
-        
-        /*===== 
-                // delay: Integer
-                //      The time in milliseconds to wait before starting animation after it has been .play()'ed
-                delay: null,
-        
-                // events
-                //
-                // beforeBegin: Event
-                //      Synthetic event fired before a dojo._Animation begins playing (synchronous)
-                beforeBegin: null,
-        
-                // onBegin: Event
-                //      Synthetic event fired as a dojo._Animation begins playing (useful?)
-                onBegin: null,
-        
-                // onAnimate: Event
-                //      Synthetic event fired at each interval of a dojo._Animation
-                onAnimate: null,
-        
-                // onEnd: Event
-                //      Synthetic event fired after the final frame of a dojo._Animation
-                onEnd: null,
-        
-                // onPlay: Event
-                //      Synthetic event fired any time a dojo._Animation is play()'ed
-                onPlay: null,
-        
-                // onPause: Event
-                //      Synthetic event fired when a dojo._Animation is paused
-                onPause: null,
-        
-                // onStop: Event
-                //      Synthetic event fires when a dojo._Animation is stopped
-                onStop: null,
-        
-        =====*/
-        
-                _percent: 0,
-                _startRepeatCount: 0,
-        
-                _fire: function(/*Event*/ evt, /*Array?*/ args){
-                        //      summary:
-                        //              Convenience function.  Fire event "evt" and pass it the
-                        //              arguments specified in "args".
-                        //      evt:
-                        //              The event to fire.
-                        //      args:
-                        //              The arguments to pass to the event.
-                        if(this[evt]){
-                                if(dojo.config.isDebug){
-                                        this[evt].apply(this, args||[]);
-                                }else{
-                                        try{
-                                                this[evt].apply(this, args||[]);
-                                        }catch(e){
-                                                // squelch and log because we shouldn't allow exceptions in
-                                                // synthetic event handlers to cause the internal timer to run
-                                                // amuck, potentially pegging the CPU. I'm not a fan of this
-                                                // squelch, but hopefully logging will make it clear what's
-                                                // going on
-                                                console.error("exception in animation handler for:", evt);
-                                                console.error(e);
-                                        }
-                                }
-                        }
-                        return this; // dojo._Animation
-                },
-
-                play: function(/*int?*/ delay, /*Boolean?*/ gotoStart){
-                        // summary:
-                        //              Start the animation.
-                        // delay:
-                        //              How many milliseconds to delay before starting.
-                        // gotoStart:
-                        //              If true, starts the animation from the beginning; otherwise,
-                        //              starts it from its current position.
-                        var _t = this;
-                        if(gotoStart){
-                                _t._stopTimer();
-                                _t._active = _t._paused = false;
-                                _t._percent = 0;
-                        }else if(_t._active && !_t._paused){
-                                return _t; // dojo._Animation
-                        }
-        
-                        _t._fire("beforeBegin");
-        
-                        var de = delay||_t.delay;
-                        var _p = dojo.hitch(_t, "_play", gotoStart);
-                        if(de > 0){
-                                setTimeout(_p, de);
-                                return _t; // dojo._Animation
-                        }
-                        _p();
-                        return _t;
-                },
-        
-                _play: function(gotoStart){
-                        var _t = this;
-                        _t._startTime = new Date().valueOf();
-                        if(_t._paused){
-                                _t._startTime -= _t.duration * _t._percent;
-                        }
-                        _t._endTime = _t._startTime + _t.duration;
-        
-                        _t._active = true;
-                        _t._paused = false;
-        
-                        var value = _t.curve.getValue(_t._percent);
-                        if(!_t._percent){
-                                if(!_t._startRepeatCount){
-                                        _t._startRepeatCount = _t.repeat;
-                                }
-                                _t._fire("onBegin", [value]);
-                        }
-        
-                        _t._fire("onPlay", [value]);
-        
-                        _t._cycle();
-                        return _t; // dojo._Animation
-                },
-        
-                pause: function(){
-                        // summary: Pauses a running animation.
-                        this._stopTimer();
-                        if(!this._active){ return this; /*dojo._Animation*/ }
-                        this._paused = true;
-                        this._fire("onPause", [this.curve.getValue(this._percent)]);
-                        return this; // dojo._Animation
-                },
-        
-                gotoPercent: function(/*Decimal*/ percent, /*Boolean?*/ andPlay){
-                        //      summary:
-                        //              Sets the progress of the animation.
-                        //      percent:
-                        //              A percentage in decimal notation (between and including 0.0 and 1.0).
-                        //      andPlay:
-                        //              If true, play the animation after setting the progress.
-                        this._stopTimer();
-                        this._active = this._paused = true;
-                        this._percent = percent;
-                        if(andPlay){ this.play(); }
-                        return this; // dojo._Animation
-                },
-        
-                stop: function(/*boolean?*/ gotoEnd){
-                        // summary: Stops a running animation.
-                        // gotoEnd: If true, the animation will end.
-                        if(!this._timer){ return this; /* dojo._Animation */ }
-                        this._stopTimer();
-                        if(gotoEnd){
-                                this._percent = 1;
-                        }
-                        this._fire("onStop", [this.curve.getValue(this._percent)]);
-                        this._active = this._paused = false;
-                        return this; // dojo._Animation
-                },
-        
-                status: function(){
-                        // summary: Returns a string token representation of the status of
-                        //                      the animation, one of: "paused", "playing", "stopped"
-                        if(this._active){
-                                return this._paused ? "paused" : "playing"; // String
-                        }
-                        return "stopped"; // String
-                },
-        
-                _cycle: function(){
-                        var _t = this;
-                        if(_t._active){
-                                var curr = new Date().valueOf();
-                                var step = (curr - _t._startTime) / (_t._endTime - _t._startTime);
-        
-                                if(step >= 1){
-                                        step = 1;
-                                }
-                                _t._percent = step;
-        
-                                // Perform easing
-                                if(_t.easing){
-                                        step = _t.easing(step);
-                                }
-        
-                                _t._fire("onAnimate", [_t.curve.getValue(step)]);
-        
-                                if(_t._percent < 1){
-                                        _t._startTimer();
-                                }else{
-                                        _t._active = false;
-        
-                                        if(_t.repeat > 0){
-                                                _t.repeat--;
-                                                _t.play(null, true);
-                                        }else if(_t.repeat == -1){
-                                                _t.play(null, true);
-                                        }else{
-                                                if(_t._startRepeatCount){
-                                                        _t.repeat = _t._startRepeatCount;
-                                                        _t._startRepeatCount = 0;
-                                                }
-                                        }
-                                        _t._percent = 0;
-                                        _t._fire("onEnd");
-                                        _t._stopTimer();
-                                }
-                        }
-                        return _t; // dojo._Animation
-                }
-        });
-
-        var ctr = 0;
-        var _globalTimerList = [];
-        var runner = {
-                run: function(){ }
-        };
-        var timer = null;
-        dojo._Animation.prototype._startTimer = function(){
-                // this._timer = setTimeout(dojo.hitch(this, "_cycle"), this.rate);
-                if(!this._timer){
-                        this._timer = d.connect(runner, "run", this, "_cycle");
-                        ctr++;
-                }
-                if(!timer){
-                        timer = setInterval(d.hitch(runner, "run"), this.rate);
-                }
-        };
-
-        dojo._Animation.prototype._stopTimer = function(){
-                if(this._timer){
-                        d.disconnect(this._timer);
-                        this._timer = null;
-                        ctr--;
-                }
-                if(ctr <= 0){
-                        clearInterval(timer);
-                        timer = null;
-                        ctr = 0;
-                }
-        };
-
-        var _makeFadeable = (d.isIE) ? function(node){
-                // only set the zoom if the "tickle" value would be the same as the
-                // default
-                var ns = node.style;
-                // don't set the width to auto if it didn't already cascade that way.
-                // We don't want to f anyones designs
-                if(!ns.width.length && d.style(node, "width") == "auto"){
-                        ns.width = "auto";
-                }
-        } : function(){};
-
-        dojo._fade = function(/*Object*/ args){
-                //      summary: 
-                //              Returns an animation that will fade the node defined by
-                //              args.node from the start to end values passed (args.start
-                //              args.end) (end is mandatory, start is optional)
-
-                args.node = d.byId(args.node);
-                var fArgs = d.mixin({ properties: {} }, args);
-                var props = (fArgs.properties.opacity = {});
-                props.start = !("start" in fArgs) ?
-                        function(){ 
-                                return Number(d.style(fArgs.node, "opacity")); 
-                        } : fArgs.start;
-                props.end = fArgs.end;
-
-                var anim = d.animateProperty(fArgs);
-                d.connect(anim, "beforeBegin", d.partial(_makeFadeable, fArgs.node));
-
-                return anim; // dojo._Animation
-        }
-
-        /*=====
-        dojo.__FadeArgs = function(node, duration, easing){
-                //      node: DOMNode|String
-                //              The node referenced in the animation
-                //      duration: Integer?
-                //              Duration of the animation in milliseconds.
-                //      easing: Function?
-                //              An easing function.
-                this.node = node;
-                this.duration = duration;
-                this.easing = easing;
-        }
-        =====*/
-
-        dojo.fadeIn = function(/*dojo.__FadeArgs*/ args){
-                // summary: 
-                //              Returns an animation that will fade node defined in 'args' from
-                //              its current opacity to fully opaque.
-                return d._fade(d.mixin({ end: 1 }, args)); // dojo._Animation
-        }
-
-        dojo.fadeOut = function(/*dojo.__FadeArgs*/  args){
-                // summary: 
-                //              Returns an animation that will fade node defined in 'args'
-                //              from its current opacity to fully transparent.
-                return d._fade(d.mixin({ end: 0 }, args)); // dojo._Animation
-        }
-
-        dojo._defaultEasing = function(/*Decimal?*/ n){
-                // summary: The default easing function for dojo._Animation(s)
-                return 0.5 + ((Math.sin((n + 1.5) * Math.PI))/2);
-        }
-
-        var PropLine = function(properties){
-                // PropLine is an internal class which is used to model the values of
-                // an a group of CSS properties across an animation lifecycle. In
-                // particular, the "getValue" function handles getting interpolated
-                // values between start and end for a particular CSS value.
-                this._properties = properties;
-                for(var p in properties){
-                        var prop = properties[p];
-                        if(prop.start instanceof d.Color){
-                                // create a reusable temp color object to keep intermediate results
-                                prop.tempColor = new d.Color();
-                        }
-                }
-                this.getValue = function(r){
-                        var ret = {};
-                        for(var p in this._properties){
-                                var prop = this._properties[p];
-                                var start = prop.start;
-                                if(start instanceof d.Color){
-                                        ret[p] = d.blendColors(start, prop.end, r, prop.tempColor).toCss();
-                                }else if(!d.isArray(start)){
-                                        ret[p] = ((prop.end - start) * r) + start + (p != "opacity" ? prop.units||"px" : "");
-                                }
-                        }
-                        return ret;
-                }
-        }
-
-        /*=====
-        dojo.declare("dojo.__AnimArgs", [dojo.__FadeArgs], {
-                // Properties: Object?
-                //      A hash map of style properties to Objects describing the transition,
-                //      such as the properties of dojo._Line with an additional 'unit' property
-                properties: {}
-                
-                //TODOC: add event callbacks
-        });
-        =====*/
-
-        dojo.animateProperty = function(/*dojo.__AnimArgs*/ args){
-                //      summary: 
-                //              Returns an animation that will transition the properties of
-                //              node defined in 'args' depending how they are defined in
-                //              'args.properties'
-                //
-                // description:
-                //              dojo.animateProperty is the foundation of most dojo.fx
-                //              animations. It takes an object of "properties" corresponding to
-                //              style properties, and animates them in parallel over a set
-                //              duration.
-                //      
-                //      example:
-                //              A simple animation that changes the width of the specified node.
-                //      |       dojo.animateProperty({ 
-                //      |               node: "nodeId",
-                //      |               properties: { width: 400 },
-                //      |       }).play();
-                //              Dojo figures out the start value for the width and converts the
-                //              integer specified for the width to the more expressive but
-                //              verbose form `{ width: { end: '400', units: 'px' } }` which you
-                //              can also specify directly
-                //
-                //      example:
-                //              Animate width, height, and padding over 2 seconds... the
-                //              pedantic way:
-                //      |       dojo.animateProperty({ node: node, duration:2000,
-                //      |               properties: {
-                //      |                       width: { start: '200', end: '400', unit:"px" },
-                //      |                       height: { start:'200', end: '400', unit:"px" },
-                //      |                       paddingTop: { start:'5', end:'50', unit:"px" } 
-                //      |               }
-                //      |       }).play();
-                //              Note 'paddingTop' is used over 'padding-top'. Multi-name CSS properties
-                //              are written using "mixed case", as the hyphen is illegal as an object key.
-                //              
-                //      example:
-                //              Plug in a different easing function and register a callback for
-                //              when the animation ends. Easing functions accept values between
-                //              zero and one and return a value on that basis. In this case, an
-                //              exponential-in curve.
-                //      |       dojo.animateProperty({ 
-                //      |               node: "nodeId",
-                //      |               // dojo figures out the start value
-                //      |               properties: { width: { end: 400 } },
-                //      |               easing: function(n){
-                //      |                       return (n==0) ? 0 : Math.pow(2, 10 * (n - 1));
-                //      |               },
-                //      |               onEnd: function(){
-                //      |                       // called when the animation finishes
-                //      |               }
-                //      |       }).play(500); // delay playing half a second
-                //
-                //      example:
-                //              Like all `dojo._Animation`s, animateProperty returns a handle to the
-                //              Animation instance, which fires the events common to Dojo FX. Use `dojo.connect`
-                //              to access these events outside of the Animation definiton:
-                //      |       var anim = dojo.animateProperty({
-                //      |               node:"someId",
-                //      |               properties:{
-                //      |                       width:400, height:500
-                //      |               }
-                //      |       });
-                //      |       dojo.connect(anim,"onEnd", function(){
-                //      |               
-                //      |       });
-                //      |       // play the animation now:
-                //      |       anim.play();
-                
-                args.node = d.byId(args.node);
-                if(!args.easing){ args.easing = d._defaultEasing; }
-
-                var anim = new d._Animation(args);
-                d.connect(anim, "beforeBegin", anim, function(){
-                        var pm = {};
-                        for(var p in this.properties){
-                                // Make shallow copy of properties into pm because we overwrite
-                                // some values below. In particular if start/end are functions
-                                // we don't want to overwrite them or the functions won't be
-                                // called if the animation is reused.
-                                if(p == "width" || p == "height"){
-                                        this.node.display = "block";
-                                }
-                                var prop = this.properties[p];
-                                prop = pm[p] = d.mixin({}, (d.isObject(prop) ? prop: { end: prop }));
-
-                                if(d.isFunction(prop.start)){
-                                        prop.start = prop.start();
-                                }
-                                if(d.isFunction(prop.end)){
-                                        prop.end = prop.end();
-                                }
-                                var isColor = (p.toLowerCase().indexOf("color") >= 0);
-                                function getStyle(node, p){
-                                        // dojo.style(node, "height") can return "auto" or "" on IE; this is more reliable:
-                                        var v = ({height: node.offsetHeight, width: node.offsetWidth})[p];
-                                        if(v !== undefined){ return v; }
-                                        v = d.style(node, p);
-                                        return (p=="opacity") ? Number(v) : (isColor ? v : parseFloat(v));
-                                }
-                                if(!("end" in prop)){
-                                        prop.end = getStyle(this.node, p);
-                                }else if(!("start" in prop)){
-                                        prop.start = getStyle(this.node, p);
-                                }
-
-                                if(isColor){
-                                        prop.start = new d.Color(prop.start);
-                                        prop.end = new d.Color(prop.end);
-                                }else{
-                                        prop.start = (p == "opacity") ? Number(prop.start) : parseFloat(prop.start);
-                                }
-                        }
-                        this.curve = new PropLine(pm);
-                });
-                d.connect(anim, "onAnimate", d.hitch(d, "style", anim.node));
-                return anim; // dojo._Animation
-        }
-
-        dojo.anim = function(   /*DOMNode|String*/      node, 
-                                                        /*Object*/                      properties, 
-                                                        /*Integer?*/            duration, 
-                                                        /*Function?*/           easing, 
-                                                        /*Function?*/           onEnd,
-                                                        /*Integer?*/            delay){
-                //      summary:
-                //              A simpler interface to `dojo.animateProperty()`, also returns
-                //              an instance of `dojo._Animation` but begins the animation
-                //              immediately, unlike nearly every other Dojo animation API.
-                //      description:
-                //              `dojo.anim` is a simpler (but somewhat less powerful) version
-                //              of `dojo.animateProperty`.  It uses defaults for many basic properties
-                //              and allows for positional parameters to be used in place of the
-                //              packed "property bag" which is used for other Dojo animation
-                //              methods.
-                //
-                //              The `dojo._Animation` object returned from `dojo.anim` will be
-                //              already playing when it is returned from this function, so
-                //              calling play() on it again is (usually) a no-op.
-                //      node:
-                //              a DOM node or the id of a node to animate CSS properties on
-                //      duration:
-                //              The number of milliseconds over which the animation
-                //              should run. Defaults to the global animation default duration
-                //              (350ms).
-                //      easing:
-                //              An easing function over which to calculate acceleration
-                //              and deceleration of the animation through its duration.
-                //              A default easing algorithm is provided, but you may
-                //              plug in any you wish. A large selection of easing algorithms
-                //              are available in `dojo.fx.easing`.
-                //      onEnd:
-                //              A function to be called when the animation finishes
-                //              running.
-                //      delay:
-                //              The number of milliseconds to delay beginning the
-                //              animation by. The default is 0.
-                //      example:
-                //              Fade out a node
-                //      |       dojo.anim("id", { opacity: 0 });
-                //      example:
-                //              Fade out a node over a full second
-                //      |       dojo.anim("id", { opacity: 0 }, 1000);
-                return d.animateProperty({ 
-                        node: node,
-                        duration: duration||d._Animation.prototype.duration,
-                        properties: properties,
-                        easing: easing,
-                        onEnd: onEnd 
-                }).play(delay||0);
-        }
-})();
-
-}
-
-if(!dojo._hasResource["dojo._base.browser"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
-dojo._hasResource["dojo._base.browser"] = true;
-dojo.provide("dojo._base.browser");
-
-
-
-
-
-
-
-
-
-//Need this to be the last code segment in base, so do not place any
-//dojo.requireIf calls in this file. Otherwise, due to how the build system
-//puts all requireIf dependencies after the current file, the require calls
-//could be called before all of base is defined.
-if(dojo.config.require){
-        dojo.forEach(dojo.config.require, "dojo['require'](item);");
-}
-
-}
-
-        //INSERT dojo.i18n._preloadLocalizations HERE
-
-        if(dojo.config.afterOnLoad && dojo.isBrowser){
-                //Dojo is being added to the page after page load, so just trigger
-                //the init sequence after a timeout. Using a timeout so the rest of this
-                //script gets evaluated properly. This work needs to happen after the
-                //dojo.config.require work done in dojo._base.
-                window.setTimeout(dojo._fakeLoadInit, 1000);
-        }
-
-})();
-
diff --git a/PerformanceTests/Dromaeo/resources/dromaeo/web/lib/jquery-1.6.4.js b/PerformanceTests/Dromaeo/resources/dromaeo/web/lib/jquery-1.6.4.js
new file mode 100644 (file)
index 0000000..b83520a
--- /dev/null
@@ -0,0 +1,9046 @@
+/*!
+ * jQuery JavaScript Library v1.6.4
+ * http://jquery.com/
+ *
+ * Copyright 2011, John Resig
+ * Dual licensed under the MIT or GPL Version 2 licenses.
+ * http://jquery.org/license
+ *
+ * Includes Sizzle.js
+ * http://sizzlejs.com/
+ * Copyright 2011, The Dojo Foundation
+ * Released under the MIT, BSD, and GPL Licenses.
+ *
+ * Date: Mon Sep 12 18:54:48 2011 -0400
+ */
+(function( window, undefined ) {
+
+// Use the correct document accordingly with window argument (sandbox)
+var document = window.document,
+        navigator = window.navigator,
+        location = window.location;
+var jQuery = (function() {
+
+// Define a local copy of jQuery
+var jQuery = function( selector, context ) {
+                // The jQuery object is actually just the init constructor 'enhanced'
+                return new jQuery.fn.init( selector, context, rootjQuery );
+        },
+
+        // Map over jQuery in case of overwrite
+        _jQuery = window.jQuery,
+
+        // Map over the $ in case of overwrite
+        _$ = window.$,
+
+        // A central reference to the root jQuery(document)
+        rootjQuery,
+
+        // A simple way to check for HTML strings or ID strings
+        // Prioritize #id over <tag> to avoid XSS via location.hash (#9521)
+        quickExpr = /^(?:[^#<]*(<[\w\W]+>)[^>]*$|#([\w\-]*)$)/,
+
+        // Check if a string has a non-whitespace character in it
+        rnotwhite = /\S/,
+
+        // Used for trimming whitespace
+        trimLeft = /^\s+/,
+        trimRight = /\s+$/,
+
+        // Check for digits
+        rdigit = /\d/,
+
+        // Match a standalone tag
+        rsingleTag = /^<(\w+)\s*\/?>(?:<\/\1>)?$/,
+
+        // JSON RegExp
+        rvalidchars = /^[\],:{}\s]*$/,
+        rvalidescape = /\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g,
+        rvalidtokens = /"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g,
+        rvalidbraces = /(?:^|:|,)(?:\s*\[)+/g,
+
+        // Useragent RegExp
+        rwebkit = /(webkit)[ \/]([\w.]+)/,
+        ropera = /(opera)(?:.*version)?[ \/]([\w.]+)/,
+        rmsie = /(msie) ([\w.]+)/,
+        rmozilla = /(mozilla)(?:.*? rv:([\w.]+))?/,
+
+        // Matches dashed string for camelizing
+        rdashAlpha = /-([a-z]|[0-9])/ig,
+        rmsPrefix = /^-ms-/,
+
+        // Used by jQuery.camelCase as callback to replace()
+        fcamelCase = function( all, letter ) {
+                return ( letter + "" ).toUpperCase();
+        },
+
+        // Keep a UserAgent string for use with jQuery.browser
+        userAgent = navigator.userAgent,
+
+        // For matching the engine and version of the browser
+        browserMatch,
+
+        // The deferred used on DOM ready
+        readyList,
+
+        // The ready event handler
+        DOMContentLoaded,
+
+        // Save a reference to some core methods
+        toString = Object.prototype.toString,
+        hasOwn = Object.prototype.hasOwnProperty,
+        push = Array.prototype.push,
+        slice = Array.prototype.slice,
+        trim = String.prototype.trim,
+        indexOf = Array.prototype.indexOf,
+
+        // [[Class]] -> type pairs
+        class2type = {};
+
+jQuery.fn = jQuery.prototype = {
+        constructor: jQuery,
+        init: function( selector, context, rootjQuery ) {
+                var match, elem, ret, doc;
+
+                // Handle $(""), $(null), or $(undefined)
+                if ( !selector ) {
+                        return this;
+                }
+
+                // Handle $(DOMElement)
+                if ( selector.nodeType ) {
+                        this.context = this[0] = selector;
+                        this.length = 1;
+                        return this;
+                }
+
+                // The body element only exists once, optimize finding it
+                if ( selector === "body" && !context && document.body ) {
+                        this.context = document;
+                        this[0] = document.body;
+                        this.selector = selector;
+                        this.length = 1;
+                        return this;
+                }
+
+                // Handle HTML strings
+                if ( typeof selector === "string" ) {
+                        // Are we dealing with HTML string or an ID?
+                        if ( selector.charAt(0) === "<" && selector.charAt( selector.length - 1 ) === ">" && selector.length >= 3 ) {
+                                // Assume that strings that start and end with <> are HTML and skip the regex check
+                                match = [ null, selector, null ];
+
+                        } else {
+                                match = quickExpr.exec( selector );
+                        }
+
+                        // Verify a match, and that no context was specified for #id
+                        if ( match && (match[1] || !context) ) {
+
+                                // HANDLE: $(html) -> $(array)
+                                if ( match[1] ) {
+                                        context = context instanceof jQuery ? context[0] : context;
+                                        doc = (context ? context.ownerDocument || context : document);
+
+                                        // If a single string is passed in and it's a single tag
+                                        // just do a createElement and skip the rest
+                                        ret = rsingleTag.exec( selector );
+
+                                        if ( ret ) {
+                                                if ( jQuery.isPlainObject( context ) ) {
+                                                        selector = [ document.createElement( ret[1] ) ];
+                                                        jQuery.fn.attr.call( selector, context, true );
+
+                                                } else {
+                                                        selector = [ doc.createElement( ret[1] ) ];
+                                                }
+
+                                        } else {
+                                                ret = jQuery.buildFragment( [ match[1] ], [ doc ] );
+                                                selector = (ret.cacheable ? jQuery.clone(ret.fragment) : ret.fragment).childNodes;
+                                        }
+
+                                        return jQuery.merge( this, selector );
+
+                                // HANDLE: $("#id")
+                                } else {
+                                        elem = document.getElementById( match[2] );
+
+                                        // Check parentNode to catch when Blackberry 4.6 returns
+                                        // nodes that are no longer in the document #6963
+                                        if ( elem && elem.parentNode ) {
+                                                // Handle the case where IE and Opera return items
+                                                // by name instead of ID
+                                                if ( elem.id !== match[2] ) {
+                                                        return rootjQuery.find( selector );
+                                                }
+
+                                                // Otherwise, we inject the element directly into the jQuery object
+                                                this.length = 1;
+                                                this[0] = elem;
+                                        }
+
+                                        this.context = document;
+                                        this.selector = selector;
+                                        return this;
+                                }
+
+                        // HANDLE: $(expr, $(...))
+                        } else if ( !context || context.jquery ) {
+                                return (context || rootjQuery).find( selector );
+
+                        // HANDLE: $(expr, context)
+                        // (which is just equivalent to: $(context).find(expr)
+                        } else {
+                                return this.constructor( context ).find( selector );
+                        }
+
+                // HANDLE: $(function)
+                // Shortcut for document ready
+                } else if ( jQuery.isFunction( selector ) ) {
+                        return rootjQuery.ready( selector );
+                }
+
+                if (selector.selector !== undefined) {
+                        this.selector = selector.selector;
+                        this.context = selector.context;
+                }
+
+                return jQuery.makeArray( selector, this );
+        },
+
+        // Start with an empty selector
+        selector: "",
+
+        // The current version of jQuery being used
+        jquery: "1.6.4",
+
+        // The default length of a jQuery object is 0
+        length: 0,
+
+        // The number of elements contained in the matched element set
+        size: function() {
+                return this.length;
+        },
+
+        toArray: function() {
+                return slice.call( this, 0 );
+        },
+
+        // Get the Nth element in the matched element set OR
+        // Get the whole matched element set as a clean array
+        get: function( num ) {
+                return num == null ?
+
+                        // Return a 'clean' array
+                        this.toArray() :
+
+                        // Return just the object
+                        ( num < 0 ? this[ this.length + num ] : this[ num ] );
+        },
+
+        // Take an array of elements and push it onto the stack
+        // (returning the new matched element set)
+        pushStack: function( elems, name, selector ) {
+                // Build a new jQuery matched element set
+                var ret = this.constructor();
+
+                if ( jQuery.isArray( elems ) ) {
+                        push.apply( ret, elems );
+
+                } else {
+                        jQuery.merge( ret, elems );
+                }
+
+                // Add the old object onto the stack (as a reference)
+                ret.prevObject = this;
+
+                ret.context = this.context;
+
+                if ( name === "find" ) {
+                        ret.selector = this.selector + (this.selector ? " " : "") + selector;
+                } else if ( name ) {
+                        ret.selector = this.selector + "." + name + "(" + selector + ")";
+                }
+
+                // Return the newly-formed element set
+                return ret;
+        },
+
+        // Execute a callback for every element in the matched set.
+        // (You can seed the arguments with an array of args, but this is
+        // only used internally.)
+        each: function( callback, args ) {
+                return jQuery.each( this, callback, args );
+        },
+
+        ready: function( fn ) {
+                // Attach the listeners
+                jQuery.bindReady();
+
+                // Add the callback
+                readyList.done( fn );
+
+                return this;
+        },
+
+        eq: function( i ) {
+                return i === -1 ?
+                        this.slice( i ) :
+                        this.slice( i, +i + 1 );
+        },
+
+        first: function() {
+                return this.eq( 0 );
+        },
+
+        last: function() {
+                return this.eq( -1 );
+        },
+
+        slice: function() {
+                return this.pushStack( slice.apply( this, arguments ),
+                        "slice", slice.call(arguments).join(",") );
+        },
+
+        map: function( callback ) {
+                return this.pushStack( jQuery.map(this, function( elem, i ) {
+                        return callback.call( elem, i, elem );
+                }));
+        },
+
+        end: function() {
+                return this.prevObject || this.constructor(null);
+        },
+
+        // For internal use only.
+        // Behaves like an Array's method, not like a jQuery method.
+        push: push,
+        sort: [].sort,
+        splice: [].splice
+};
+
+// Give the init function the jQuery prototype for later instantiation
+jQuery.fn.init.prototype = jQuery.fn;
+
+jQuery.extend = jQuery.fn.extend = function() {
+        var options, name, src, copy, copyIsArray, clone,
+                target = arguments[0] || {},
+                i = 1,
+                length = arguments.length,
+                deep = false;
+
+        // Handle a deep copy situation
+        if ( typeof target === "boolean" ) {
+                deep = target;
+                target = arguments[1] || {};
+                // skip the boolean and the target
+                i = 2;
+        }
+
+        // Handle case when target is a string or something (possible in deep copy)
+        if ( typeof target !== "object" && !jQuery.isFunction(target) ) {
+                target = {};
+        }
+
+        // extend jQuery itself if only one argument is passed
+        if ( length === i ) {
+                target = this;
+                --i;
+        }
+
+        for ( ; i < length; i++ ) {
+                // Only deal with non-null/undefined values
+                if ( (options = arguments[ i ]) != null ) {
+                        // Extend the base object
+                        for ( name in options ) {
+                                src = target[ name ];
+                                copy = options[ name ];
+
+                                // Prevent never-ending loop
+                                if ( target === copy ) {
+                                        continue;
+                                }
+
+                                // Recurse if we're merging plain objects or arrays
+                                if ( deep && copy && ( jQuery.isPlainObject(copy) || (copyIsArray = jQuery.isArray(copy)) ) ) {
+                                        if ( copyIsArray ) {
+                                                copyIsArray = false;
+                                                clone = src && jQuery.isArray(src) ? src : [];
+
+                                        } else {
+                                                clone = src && jQuery.isPlainObject(src) ? src : {};
+                                        }
+
+                                        // Never move original objects, clone them
+                                        target[ name ] = jQuery.extend( deep, clone, copy );
+
+                                // Don't bring in undefined values
+                                } else if ( copy !== undefined ) {
+                                        target[ name ] = copy;
+                                }
+                        }
+                }
+        }
+
+        // Return the modified object
+        return target;
+};
+
+jQuery.extend({
+        noConflict: function( deep ) {
+                if ( window.$ === jQuery ) {
+                        window.$ = _$;
+                }
+
+                if ( deep && window.jQuery === jQuery ) {
+                        window.jQuery = _jQuery;
+                }
+
+                return jQuery;
+        },
+
+        // Is the DOM ready to be used? Set to true once it occurs.
+        isReady: false,
+
+        // A counter to track how many items to wait for before
+        // the ready event fires. See #6781
+        readyWait: 1,
+
+        // Hold (or release) the ready event
+        holdReady: function( hold ) {
+                if ( hold ) {
+                        jQuery.readyWait++;
+                } else {
+                        jQuery.ready( true );
+                }
+        },
+
+        // Handle when the DOM is ready
+        ready: function( wait ) {
+                // Either a released hold or an DOMready/load event and not yet ready
+                if ( (wait === true && !--jQuery.readyWait) || (wait !== true && !jQuery.isReady) ) {
+                        // Make sure body exists, at least, in case IE gets a little overzealous (ticket #5443).
+                        if ( !document.body ) {
+                                return setTimeout( jQuery.ready, 1 );
+                        }
+
+                        // Remember that the DOM is ready
+                        jQuery.isReady = true;
+
+                        // If a normal DOM Ready event fired, decrement, and wait if need be
+                        if ( wait !== true && --jQuery.readyWait > 0 ) {
+                                return;
+                        }
+
+                        // If there are functions bound, to execute
+                        readyList.resolveWith( document, [ jQuery ] );
+
+                        // Trigger any bound ready events
+                        if ( jQuery.fn.trigger ) {
+                                jQuery( document ).trigger( "ready" ).unbind( "ready" );
+                        }
+                }
+        },
+
+        bindReady: function() {
+                if ( readyList ) {
+                        return;
+                }
+
+                readyList = jQuery._Deferred();
+
+                // Catch cases where $(document).ready() is called after the
+                // browser event has already occurred.
+                if ( document.readyState === "complete" ) {
+                        // Handle it asynchronously to allow scripts the opportunity to delay ready
+                        return setTimeout( jQuery.ready, 1 );
+                }
+
+                // Mozilla, Opera and webkit nightlies currently support this event
+                if ( document.addEventListener ) {
+                        // Use the handy event callback
+                        document.addEventListener( "DOMContentLoaded", DOMContentLoaded, false );
+
+                        // A fallback to window.onload, that will always work
+                        window.addEventListener( "load", jQuery.ready, false );
+
+                // If IE event model is used
+                } else if ( document.attachEvent ) {
+                        // ensure firing before onload,
+                        // maybe late but safe also for iframes
+                        document.attachEvent( "onreadystatechange", DOMContentLoaded );
+
+                        // A fallback to window.onload, that will always work
+                        window.attachEvent( "onload", jQuery.ready );
+
+                        // If IE and not a frame
+                        // continually check to see if the document is ready
+                        var toplevel = false;
+
+                        try {
+                                toplevel = window.frameElement == null;
+                        } catch(e) {}
+
+                        if ( document.documentElement.doScroll && toplevel ) {
+                                doScrollCheck();
+                        }
+                }
+        },
+
+        // See test/unit/core.js for details concerning isFunction.
+        // Since version 1.3, DOM methods and functions like alert
+        // aren't supported. They return false on IE (#2968).
+        isFunction: function( obj ) {
+                return jQuery.type(obj) === "function";
+        },
+
+        isArray: Array.isArray || function( obj ) {
+                return jQuery.type(obj) === "array";
+        },
+
+        // A crude way of determining if an object is a window
+        isWindow: function( obj ) {
+                return obj && typeof obj === "object" && "setInterval" in obj;
+        },
+
+        isNaN: function( obj ) {
+                return obj == null || !rdigit.test( obj ) || isNaN( obj );
+        },
+
+        type: function( obj ) {
+                return obj == null ?
+                        String( obj ) :
+                        class2type[ toString.call(obj) ] || "object";
+        },
+
+        isPlainObject: function( obj ) {
+                // Must be an Object.
+                // Because of IE, we also have to check the presence of the constructor property.
+                // Make sure that DOM nodes and window objects don't pass through, as well
+                if ( !obj || jQuery.type(obj) !== "object" || obj.nodeType || jQuery.isWindow( obj ) ) {
+                        return false;
+                }
+
+                try {
+                        // Not own constructor property must be Object
+                        if ( obj.constructor &&
+                                !hasOwn.call(obj, "constructor") &&
+                                !hasOwn.call(obj.constructor.prototype, "isPrototypeOf") ) {
+                                return false;
+                        }
+                } catch ( e ) {
+                        // IE8,9 Will throw exceptions on certain host objects #9897
+                        return false;
+                }
+
+                // Own properties are enumerated firstly, so to speed up,
+                // if last one is own, then all properties are own.
+
+                var key;
+                for ( key in obj ) {}
+
+                return key === undefined || hasOwn.call( obj, key );
+        },
+
+        isEmptyObject: function( obj ) {
+                for ( var name in obj ) {
+                        return false;
+                }
+                return true;
+        },
+
+        error: function( msg ) {
+                throw msg;
+        },
+
+        parseJSON: function( data ) {
+                if ( typeof data !== "string" || !data ) {
+                        return null;
+                }
+
+                // Make sure leading/trailing whitespace is removed (IE can't handle it)
+                data = jQuery.trim( data );
+
+                // Attempt to parse using the native JSON parser first
+                if ( window.JSON && window.JSON.parse ) {
+                        return window.JSON.parse( data );
+                }
+
+                // Make sure the incoming data is actual JSON
+                // Logic borrowed from http://json.org/json2.js
+                if ( rvalidchars.test( data.replace( rvalidescape, "@" )
+                        .replace( rvalidtokens, "]" )
+                        .replace( rvalidbraces, "")) ) {
+
+                        return (new Function( "return " + data ))();
+
+                }
+                jQuery.error( "Invalid JSON: " + data );
+        },
+
+        // Cross-browser xml parsing
+        parseXML: function( data ) {
+                var xml, tmp;
+                try {
+                        if ( window.DOMParser ) { // Standard
+                                tmp = new DOMParser();
+                                xml = tmp.parseFromString( data , "text/xml" );
+                        } else { // IE
+                                xml = new ActiveXObject( "Microsoft.XMLDOM" );
+                                xml.async = "false";
+                                xml.loadXML( data );
+                        }
+                } catch( e ) {
+                        xml = undefined;
+                }
+                if ( !xml || !xml.documentElement || xml.getElementsByTagName( "parsererror" ).length ) {
+                        jQuery.error( "Invalid XML: " + data );
+                }
+                return xml;
+        },
+
+        noop: function() {},
+
+        // Evaluates a script in a global context
+        // Workarounds based on findings by Jim Driscoll
+        // http://weblogs.java.net/blog/driscoll/archive/2009/09/08/eval-javascript-global-context
+        globalEval: function( data ) {
+                if ( data && rnotwhite.test( data ) ) {
+                        // We use execScript on Internet Explorer
+                        // We use an anonymous function so that context is window
+                        // rather than jQuery in Firefox
+                        ( window.execScript || function( data ) {
+                                window[ "eval" ].call( window, data );
+                        } )( data );
+                }
+        },
+
+        // Convert dashed to camelCase; used by the css and data modules
+        // Microsoft forgot to hump their vendor prefix (#9572)
+        camelCase: function( string ) {
+                return string.replace( rmsPrefix, "ms-" ).replace( rdashAlpha, fcamelCase );
+        },
+
+        nodeName: function( elem, name ) {
+                return elem.nodeName && elem.nodeName.toUpperCase() === name.toUpperCase();
+        },
+
+        // args is for internal usage only
+        each: function( object, callback, args ) {
+                var name, i = 0,
+                        length = object.length,
+                        isObj = length === undefined || jQuery.isFunction( object );
+
+                if ( args ) {
+                        if ( isObj ) {
+                                for ( name in object ) {
+                                        if ( callback.apply( object[ name ], args ) === false ) {
+                                                break;
+                                        }
+                                }
+                        } else {
+                                for ( ; i < length; ) {
+                                        if ( callback.apply( object[ i++ ], args ) === false ) {
+                                                break;
+                                        }
+                                }
+                        }
+
+                // A special, fast, case for the most common use of each
+                } else {
+                        if ( isObj ) {
+                                for ( name in object ) {
+                                        if ( callback.call( object[ name ], name, object[ name ] ) === false ) {
+                                                break;
+                                        }
+                                }
+                        } else {
+                                for ( ; i < length; ) {
+                                        if ( callback.call( object[ i ], i, object[ i++ ] ) === false ) {
+                                                break;
+                                        }
+                                }
+                        }
+                }
+
+                return object;
+        },
+
+        // Use native String.trim function wherever possible
+        trim: trim ?
+                function( text ) {
+                        return text == null ?
+                                "" :
+                                trim.call( text );
+                } :
+
+                // Otherwise use our own trimming functionality
+                function( text ) {
+                        return text == null ?
+                                "" :
+                                text.toString().replace( trimLeft, "" ).replace( trimRight, "" );
+                },
+
+        // results is for internal usage only
+        makeArray: function( array, results ) {
+                var ret = results || [];
+
+                if ( array != null ) {
+                        // The window, strings (and functions) also have 'length'
+                        // The extra typeof function check is to prevent crashes
+                        // in Safari 2 (See: #3039)
+                        // Tweaked logic slightly to handle Blackberry 4.7 RegExp issues #6930
+                        var type = jQuery.type( array );
+
+                        if ( array.length == null || type === "string" || type === "function" || type === "regexp" || jQuery.isWindow( array ) ) {
+                                push.call( ret, array );
+                        } else {
+                                jQuery.merge( ret, array );
+                        }
+                }
+
+                return ret;
+        },
+
+        inArray: function( elem, array ) {
+                if ( !array ) {
+                        return -1;
+                }
+
+                if ( indexOf ) {
+                        return indexOf.call( array, elem );
+                }
+
+                for ( var i = 0, length = array.length; i < length; i++ ) {
+                        if ( array[ i ] === elem ) {
+                                return i;
+                        }
+                }
+
+                return -1;
+        },
+
+        merge: function( first, second ) {
+                var i = first.length,
+                        j = 0;
+
+                if ( typeof second.length === "number" ) {
+                        for ( var l = second.length; j < l; j++ ) {
+                                first[ i++ ] = second[ j ];
+                        }
+
+                } else {
+                        while ( second[j] !== undefined ) {
+                                first[ i++ ] = second[ j++ ];
+                        }
+                }
+
+                first.length = i;
+
+                return first;
+        },
+
+        grep: function( elems, callback, inv ) {
+                var ret = [], retVal;
+                inv = !!inv;
+
+                // Go through the array, only saving the items
+                // that pass the validator function
+                for ( var i = 0, length = elems.length; i < length; i++ ) {
+                        retVal = !!callback( elems[ i ], i );
+                        if ( inv !== retVal ) {
+                                ret.push( elems[ i ] );
+                        }
+                }
+
+                return ret;
+        },
+
+        // arg is for internal usage only
+        map: function( elems, callback, arg ) {
+                var value, key, ret = [],
+                        i = 0,
+                        length = elems.length,
+                        // jquery objects are treated as arrays
+                        isArray = elems instanceof jQuery || length !== undefined && typeof length === "number" && ( ( length > 0 && elems[ 0 ] && elems[ length -1 ] ) || length === 0 || jQuery.isArray( elems ) ) ;
+
+                // Go through the array, translating each of the items to their
+                if ( isArray ) {
+                        for ( ; i < length; i++ ) {
+                                value = callback( elems[ i ], i, arg );
+
+                                if ( value != null ) {
+                                        ret[ ret.length ] = value;
+                                }
+                        }
+
+                // Go through every key on the object,
+                } else {
+                        for ( key in elems ) {
+                                value = callback( elems[ key ], key, arg );
+
+                                if ( value != null ) {
+                                        ret[ ret.length ] = value;
+                                }
+                        }
+                }
+
+                // Flatten any nested arrays
+                return ret.concat.apply( [], ret );
+        },
+
+        // A global GUID counter for objects
+        guid: 1,
+
+        // Bind a function to a context, optionally partially applying any
+        // arguments.
+        proxy: function( fn, context ) {
+                if ( typeof context === "string" ) {
+                        var tmp = fn[ context ];
+                        context = fn;
+                        fn = tmp;
+                }
+
+                // Quick check to determine if target is callable, in the spec
+                // this throws a TypeError, but we will just return undefined.
+                if ( !jQuery.isFunction( fn ) ) {
+                        return undefined;
+                }
+
+                // Simulated bind
+                var args = slice.call( arguments, 2 ),
+                        proxy = function() {
+                                return fn.apply( context, args.concat( slice.call( arguments ) ) );
+                        };
+
+                // Set the guid of unique handler to the same of original handler, so it can be removed
+                proxy.guid = fn.guid = fn.guid || proxy.guid || jQuery.guid++;
+
+                return proxy;
+        },
+
+        // Mutifunctional method to get and set values to a collection
+        // The value/s can optionally be executed if it's a function
+        access: function( elems, key, value, exec, fn, pass ) {
+                var length = elems.length;
+
+                // Setting many attributes
+                if ( typeof key === "object" ) {
+                        for ( var k in key ) {
+                                jQuery.access( elems, k, key[k], exec, fn, value );
+                        }
+                        return elems;
+                }
+
+                // Setting one attribute
+                if ( value !== undefined ) {
+                        // Optionally, function values get executed if exec is true
+                        exec = !pass && exec && jQuery.isFunction(value);
+
+                        for ( var i = 0; i < length; i++ ) {
+                                fn( elems[i], key, exec ? value.call( elems[i], i, fn( elems[i], key ) ) : value, pass );
+                        }
+
+                        return elems;
+                }
+
+                // Getting an attribute
+                return length ? fn( elems[0], key ) : undefined;
+        },
+
+        now: function() {
+                return (new Date()).getTime();
+        },
+
+        // Use of jQuery.browser is frowned upon.
+        // More details: http://docs.jquery.com/Utilities/jQuery.browser
+        uaMatch: function( ua ) {
+                ua = ua.toLowerCase();
+
+                var match = rwebkit.exec( ua ) ||
+                        ropera.exec( ua ) ||
+                        rmsie.exec( ua ) ||
+                        ua.indexOf("compatible") < 0 && rmozilla.exec( ua ) ||
+                        [];
+
+                return { browser: match[1] || "", version: match[2] || "0" };
+        },
+
+        sub: function() {
+                function jQuerySub( selector, context ) {
+                        return new jQuerySub.fn.init( selector, context );
+                }
+                jQuery.extend( true, jQuerySub, this );
+                jQuerySub.superclass = this;
+                jQuerySub.fn = jQuerySub.prototype = this();
+                jQuerySub.fn.constructor = jQuerySub;
+                jQuerySub.sub = this.sub;
+                jQuerySub.fn.init = function init( selector, context ) {
+                        if ( context && context instanceof jQuery && !(context instanceof jQuerySub) ) {
+                                context = jQuerySub( context );
+                        }
+
+                        return jQuery.fn.init.call( this, selector, context, rootjQuerySub );
+                };
+                jQuerySub.fn.init.prototype = jQuerySub.fn;
+                var rootjQuerySub = jQuerySub(document);
+                return jQuerySub;
+        },
+
+        browser: {}
+});
+
+// Populate the class2type map
+jQuery.each("Boolean Number String Function Array Date RegExp Object".split(" "), function(i, name) {
+        class2type[ "[object " + name + "]" ] = name.toLowerCase();
+});
+
+browserMatch = jQuery.uaMatch( userAgent );
+if ( browserMatch.browser ) {
+        jQuery.browser[ browserMatch.browser ] = true;
+        jQuery.browser.version = browserMatch.version;
+}
+
+// Deprecated, use jQuery.browser.webkit instead
+if ( jQuery.browser.webkit ) {
+        jQuery.browser.safari = true;
+}
+
+// IE doesn't match non-breaking spaces with \s
+if ( rnotwhite.test( "\xA0" ) ) {
+        trimLeft = /^[\s\xA0]+/;
+        trimRight = /[\s\xA0]+$/;
+}
+
+// All jQuery objects should point back to these
+rootjQuery = jQuery(document);
+
+// Cleanup functions for the document ready method
+if ( document.addEventListener ) {
+        DOMContentLoaded = function() {
+                document.removeEventListener( "DOMContentLoaded", DOMContentLoaded, false );
+                jQuery.ready();
+        };
+
+} else if ( document.attachEvent ) {
+        DOMContentLoaded = function() {
+                // Make sure body exists, at least, in case IE gets a little overzealous (ticket #5443).
+                if ( document.readyState === "complete" ) {
+                        document.detachEvent( "onreadystatechange", DOMContentLoaded );
+                        jQuery.ready();
+                }
+        };
+}
+
+// The DOM ready check for Internet Explorer
+function doScrollCheck() {
+        if ( jQuery.isReady ) {
+                return;
+        }
+
+        try {
+                // If IE is used, use the trick by Diego Perini
+                // http://javascript.nwbox.com/IEContentLoaded/
+                document.documentElement.doScroll("left");
+        } catch(e) {
+                setTimeout( doScrollCheck, 1 );
+                return;
+        }
+
+        // and execute any waiting functions
+        jQuery.ready();
+}
+
+return jQuery;
+
+})();
+
+
+var // Promise methods
+        promiseMethods = "done fail isResolved isRejected promise then always pipe".split( " " ),
+        // Static reference to slice
+        sliceDeferred = [].slice;
+
+jQuery.extend({
+        // Create a simple deferred (one callbacks list)
+        _Deferred: function() {
+                var // callbacks list
+                        callbacks = [],
+                        // stored [ context , args ]
+                        fired,
+                        // to avoid firing when already doing so
+                        firing,
+                        // flag to know if the deferred has been cancelled
+                        cancelled,
+                        // the deferred itself
+                        deferred  = {
+
+                                // done( f1, f2, ...)
+                                done: function() {
+                                        if ( !cancelled ) {
+                                                var args = arguments,
+                                                        i,
+                                                        length,
+                                                        elem,
+                                                        type,
+                                                        _fired;
+                                                if ( fired ) {
+                                                        _fired = fired;
+                                                        fired = 0;
+                                                }
+                                                for ( i = 0, length = args.length; i < length; i++ ) {
+                                                        elem = args[ i ];
+                                                        type = jQuery.type( elem );
+                                                        if ( type === "array" ) {
+                                                                deferred.done.apply( deferred, elem );
+                                                        } else if ( type === "function" ) {
+                                                                callbacks.push( elem );
+                                                        }
+                                                }
+                                                if ( _fired ) {
+                                                        deferred.resolveWith( _fired[ 0 ], _fired[ 1 ] );
+                                                }
+                                        }
+                                        return this;
+                                },
+
+                                // resolve with given context and args
+                                resolveWith: function( context, args ) {
+                                        if ( !cancelled && !fired && !firing ) {
+                                                // make sure args are available (#8421)
+                                                args = args || [];
+                                                firing = 1;
+                                                try {
+                                                        while( callbacks[ 0 ] ) {
+                                                                callbacks.shift().apply( context, args );
+                                                        }
+                                                }
+                                                finally {
+                                                        fired = [ context, args ];
+                                                        firing = 0;
+                                                }
+                                        }
+                                        return this;
+                                },
+
+                                // resolve with this as context and given arguments
+                                resolve: function() {
+                                        deferred.resolveWith( this, arguments );
+                                        return this;
+                                },
+
+                                // Has this deferred been resolved?
+                                isResolved: function() {
+                                        return !!( firing || fired );
+                                },
+
+                                // Cancel
+                                cancel: function() {
+                                        cancelled = 1;
+                                        callbacks = [];
+                                        return this;
+                                }
+                        };
+
+                return deferred;
+        },
+
+        // Full fledged deferred (two callbacks list)
+        Deferred: function( func ) {
+                var deferred = jQuery._Deferred(),
+                        failDeferred = jQuery._Deferred(),
+                        promise;
+                // Add errorDeferred methods, then and promise
+                jQuery.extend( deferred, {
+                        then: function( doneCallbacks, failCallbacks ) {
+                                deferred.done( doneCallbacks ).fail( failCallbacks );
+                                return this;
+                        },
+                        always: function() {
+                                return deferred.done.apply( deferred, arguments ).fail.apply( this, arguments );
+                        },
+                        fail: failDeferred.done,
+                        rejectWith: failDeferred.resolveWith,
+                        reject: failDeferred.resolve,
+                        isRejected: failDeferred.isResolved,
+                        pipe: function( fnDone, fnFail ) {
+                                return jQuery.Deferred(function( newDefer ) {
+                                        jQuery.each( {
+                                                done: [ fnDone, "resolve" ],
+                                                fail: [ fnFail, "reject" ]
+                                        }, function( handler, data ) {
+                                                var fn = data[ 0 ],
+                                                        action = data[ 1 ],
+                                                        returned;
+                                                if ( jQuery.isFunction( fn ) ) {
+                                                        deferred[ handler ](function() {
+                                                                returned = fn.apply( this, arguments );
+                                                                if ( returned && jQuery.isFunction( returned.promise ) ) {
+                                                                        returned.promise().then( newDefer.resolve, newDefer.reject );
+                                                                } else {
+                                                                        newDefer[ action + "With" ]( this === deferred ? newDefer : this, [ returned ] );
+                                                                }
+                                                        });
+                                                } else {
+                                                        deferred[ handler ]( newDefer[ action ] );
+                                                }
+                                        });
+                                }).promise();
+                        },
+                        // Get a promise for this deferred
+                        // If obj is provided, the promise aspect is added to the object
+                        promise: function( obj ) {
+                                if ( obj == null ) {
+                                        if ( promise ) {
+                                                return promise;
+                                        }
+                                        promise = obj = {};
+                                }
+                                var i = promiseMethods.length;
+                                while( i-- ) {
+                                        obj[ promiseMethods[i] ] = deferred[ promiseMethods[i] ];
+                                }
+                                return obj;
+                        }
+                });
+                // Make sure only one callback list will be used
+                deferred.done( failDeferred.cancel ).fail( deferred.cancel );
+                // Unexpose cancel
+                delete deferred.cancel;
+                // Call given func if any
+                if ( func ) {
+                        func.call( deferred, deferred );
+                }
+                return deferred;
+        },
+
+        // Deferred helper
+        when: function( firstParam ) {
+                var args = arguments,
+                        i = 0,
+                        length = args.length,
+                        count = length,
+                        deferred = length <= 1 && firstParam && jQuery.isFunction( firstParam.promise ) ?
+                                firstParam :
+                                jQuery.Deferred();
+                function resolveFunc( i ) {
+                        return function( value ) {
+                                args[ i ] = arguments.length > 1 ? sliceDeferred.call( arguments, 0 ) : value;
+                                if ( !( --count ) ) {
+                                        // Strange bug in FF4:
+                                        // Values changed onto the arguments object sometimes end up as undefined values
+                                        // outside the $.when method. Cloning the object into a fresh array solves the issue
+                                        deferred.resolveWith( deferred, sliceDeferred.call( args, 0 ) );
+                                }
+                        };
+                }
+                if ( length > 1 ) {
+                        for( ; i < length; i++ ) {
+                                if ( args[ i ] && jQuery.isFunction( args[ i ].promise ) ) {
+                                        args[ i ].promise().then( resolveFunc(i), deferred.reject );
+                                } else {
+                                        --count;
+                                }
+                        }
+                        if ( !count ) {
+                                deferred.resolveWith( deferred, args );
+                        }
+                } else if ( deferred !== firstParam ) {
+                        deferred.resolveWith( deferred, length ? [ firstParam ] : [] );
+                }
+                return deferred.promise();
+        }
+});
+
+
+
+jQuery.support = (function() {
+
+        var div = document.createElement( "div" ),
+                documentElement = document.documentElement,
+                all,
+                a,
+                select,
+                opt,
+                input,
+                marginDiv,
+                support,
+                fragment,
+                body,
+                testElementParent,
+                testElement,
+                testElementStyle,
+                tds,
+                events,
+                eventName,
+                i,
+                isSupported;
+
+        // Preliminary tests
+        div.setAttribute("className", "t");
+        div.innerHTML = "   <link/><table></table><a href='/a' style='top:1px;float:left;opacity:.55;'>a</a><input type='checkbox'/>";
+
+
+        all = div.getElementsByTagName( "*" );
+        a = div.getElementsByTagName( "a" )[ 0 ];
+
+        // Can't get basic test support
+        if ( !all || !all.length || !a ) {
+                return {};
+        }
+
+        // First batch of supports tests
+        select = document.createElement( "select" );
+        opt = select.appendChild( document.createElement("option") );
+        input = div.getElementsByTagName( "input" )[ 0 ];
+
+        support = {
+                // IE strips leading whitespace when .innerHTML is used
+                leadingWhitespace: ( div.firstChild.nodeType === 3 ),
+
+                // Make sure that tbody elements aren't automatically inserted
+                // IE will insert them into empty tables
+                tbody: !div.getElementsByTagName( "tbody" ).length,
+
+                // Make sure that link elements get serialized correctly by innerHTML
+                // This requires a wrapper element in IE
+                htmlSerialize: !!div.getElementsByTagName( "link" ).length,
+
+                // Get the style information from getAttribute
+                // (IE uses .cssText instead)
+                style: /top/.test( a.getAttribute("style") ),
+
+                // Make sure that URLs aren't manipulated
+                // (IE normalizes it by default)
+                hrefNormalized: ( a.getAttribute( "href" ) === "/a" ),
+
+                // Make sure that element opacity exists
+                // (IE uses filter instead)
+                // Use a regex to work around a WebKit issue. See #5145
+                opacity: /^0.55$/.test( a.style.opacity ),
+
+                // Verify style float existence
+                // (IE uses styleFloat instead of cssFloat)
+                cssFloat: !!a.style.cssFloat,
+
+                // Make sure that if no value is specified for a checkbox
+                // that it defaults to "on".
+                // (WebKit defaults to "" instead)
+                checkOn: ( input.value === "on" ),
+
+                // Make sure that a selected-by-default option has a working selected property.
+                // (WebKit defaults to false instead of true, IE too, if it's in an optgroup)
+                optSelected: opt.selected,
+
+                // Test setAttribute on camelCase class. If it works, we need attrFixes when doing get/setAttribute (ie6/7)
+                getSetAttribute: div.className !== "t",
+
+                // Will be defined later
+                submitBubbles: true,
+                changeBubbles: true,
+                focusinBubbles: false,
+                deleteExpando: true,
+                noCloneEvent: true,
+                inlineBlockNeedsLayout: false,
+                shrinkWrapBlocks: false,
+                reliableMarginRight: true
+        };
+
+        // Make sure checked status is properly cloned
+        input.checked = true;
+        support.noCloneChecked = input.cloneNode( true ).checked;
+
+        // Make sure that the options inside disabled selects aren't marked as disabled
+        // (WebKit marks them as disabled)
+        select.disabled = true;
+        support.optDisabled = !opt.disabled;
+
+        // Test to see if it's possible to delete an expando from an element
+        // Fails in Internet Explorer
+        try {
+                delete div.test;
+        } catch( e ) {
+                support.deleteExpando = false;
+        }
+
+        if ( !div.addEventListener && div.attachEvent && div.fireEvent ) {
+                div.attachEvent( "onclick", function() {
+                        // Cloning a node shouldn't copy over any
+                        // bound event handlers (IE does this)
+                        support.noCloneEvent = false;
+                });
+                div.cloneNode( true ).fireEvent( "onclick" );
+        }
+
+        // Check if a radio maintains it's value
+        // after being appended to the DOM
+        input = document.createElement("input");
+        input.value = "t";
+        input.setAttribute("type", "radio");
+        support.radioValue = input.value === "t";
+
+        input.setAttribute("checked", "checked");
+        div.appendChild( input );
+        fragment = document.createDocumentFragment();
+        fragment.appendChild( div.firstChild );
+
+        // WebKit doesn't clone checked state correctly in fragments
+        support.checkClone = fragment.cloneNode( true ).cloneNode( true ).lastChild.checked;
+
+        div.innerHTML = "";
+
+        // Figure out if the W3C box model works as expected
+        div.style.width = div.style.paddingLeft = "1px";
+
+        body = document.getElementsByTagName( "body" )[ 0 ];
+        // We use our own, invisible, body unless the body is already present
+        // in which case we use a div (#9239)
+        testElement = document.createElement( body ? "div" : "body" );
+        testElementStyle = {
+                visibility: "hidden",
+                width: 0,
+                height: 0,
+                border: 0,
+                margin: 0,
+                background: "none"
+        };
+        if ( body ) {
+                jQuery.extend( testElementStyle, {
+                        position: "absolute",
+                        left: "-1000px",
+                        top: "-1000px"
+                });
+        }
+        for ( i in testElementStyle ) {
+                testElement.style[ i ] = testElementStyle[ i ];
+        }
+        testElement.appendChild( div );
+        testElementParent = body || documentElement;
+        testElementParent.insertBefore( testElement, testElementParent.firstChild );
+
+        // Check if a disconnected checkbox will retain its checked
+        // value of true after appended to the DOM (IE6/7)
+        support.appendChecked = input.checked;
+
+        support.boxModel = div.offsetWidth === 2;
+
+        if ( "zoom" in div.style ) {
+                // Check if natively block-level elements act like inline-block
+                // elements when setting their display to 'inline' and giving
+                // them layout
+                // (IE < 8 does this)
+                div.style.display = "inline";
+                div.style.zoom = 1;
+                support.inlineBlockNeedsLayout = ( div.offsetWidth === 2 );
+
+                // Check if elements with layout shrink-wrap their children
+                // (IE 6 does this)
+                div.style.display = "";
+                div.innerHTML = "<div style='width:4px;'></div>";
+                support.shrinkWrapBlocks = ( div.offsetWidth !== 2 );
+        }
+
+        div.innerHTML = "<table><tr><td style='padding:0;border:0;display:none'></td><td>t</td></tr></table>";
+        tds = div.getElementsByTagName( "td" );
+
+        // Check if table cells still have offsetWidth/Height when they are set
+        // to display:none and there are still other visible table cells in a
+        // table row; if so, offsetWidth/Height are not reliable for use when
+        // determining if an element has been hidden directly using
+        // display:none (it is still safe to use offsets if a parent element is
+        // hidden; don safety goggles and see bug #4512 for more information).
+        // (only IE 8 fails this test)
+        isSupported = ( tds[ 0 ].offsetHeight === 0 );
+
+        tds[ 0 ].style.display = "";
+        tds[ 1 ].style.display = "none";
+
+        // Check if empty table cells still have offsetWidth/Height
+        // (IE < 8 fail this test)
+        support.reliableHiddenOffsets = isSupported && ( tds[ 0 ].offsetHeight === 0 );
+        div.innerHTML = "";
+
+        // Check if div with explicit width and no margin-right incorrectly
+        // gets computed margin-right based on width of container. For more
+        // info see bug #3333
+        // Fails in WebKit before Feb 2011 nightlies
+        // WebKit Bug 13343 - getComputedStyle returns wrong value for margin-right
+        if ( document.defaultView && document.defaultView.getComputedStyle ) {
+                marginDiv = document.createElement( "div" );
+                marginDiv.style.width = "0";
+                marginDiv.style.marginRight = "0";
+                div.appendChild( marginDiv );
+                support.reliableMarginRight =
+                        ( parseInt( ( document.defaultView.getComputedStyle( marginDiv, null ) || { marginRight: 0 } ).marginRight, 10 ) || 0 ) === 0;
+        }
+
+        // Remove the body element we added
+        testElement.innerHTML = "";
+        testElementParent.removeChild( testElement );
+
+        // Technique from Juriy Zaytsev
+        // http://thinkweb2.com/projects/prototype/detecting-event-support-without-browser-sniffing/
+        // We only care about the case where non-standard event systems
+        // are used, namely in IE. Short-circuiting here helps us to
+        // avoid an eval call (in setAttribute) which can cause CSP
+        // to go haywire. See: https://developer.mozilla.org/en/Security/CSP
+        if ( div.attachEvent ) {
+                for( i in {
+                        submit: 1,
+                        change: 1,
+                        focusin: 1
+                } ) {
+                        eventName = "on" + i;
+                        isSupported = ( eventName in div );
+                        if ( !isSupported ) {
+                                div.setAttribute( eventName, "return;" );
+                                isSupported = ( typeof div[ eventName ] === "function" );
+                        }
+                        support[ i + "Bubbles" ] = isSupported;
+                }
+        }
+
+        // Null connected elements to avoid leaks in IE
+        testElement = fragment = select = opt = body = marginDiv = div = input = null;
+
+        return support;
+})();
+
+// Keep track of boxModel
+jQuery.boxModel = jQuery.support.boxModel;
+
+
+
+
+var rbrace = /^(?:\{.*\}|\[.*\])$/,
+        rmultiDash = /([A-Z])/g;
+
+jQuery.extend({
+        cache: {},
+
+        // Please use with caution
+        uuid: 0,
+
+        // Unique for each copy of jQuery on the page
+        // Non-digits removed to match rinlinejQuery
+        expando: "jQuery" + ( jQuery.fn.jquery + Math.random() ).replace( /\D/g, "" ),
+
+        // The following elements throw uncatchable exceptions if you
+        // attempt to add expando properties to them.
+        noData: {
+                "embed": true,
+                // Ban all objects except for Flash (which handle expandos)
+                "object": "clsid:D27CDB6E-AE6D-11cf-96B8-444553540000",
+                "applet": true
+        },
+
+        hasData: function( elem ) {
+                elem = elem.nodeType ? jQuery.cache[ elem[jQuery.expando] ] : elem[ jQuery.expando ];
+
+                return !!elem && !isEmptyDataObject( elem );
+        },
+
+        data: function( elem, name, data, pvt /* Internal Use Only */ ) {
+                if ( !jQuery.acceptData( elem ) ) {
+                        return;
+                }
+
+                var thisCache, ret,
+                        internalKey = jQuery.expando,
+                        getByName = typeof name === "string",
+
+                        // We have to handle DOM nodes and JS objects differently because IE6-7
+                        // can't GC object references properly across the DOM-JS boundary
+                        isNode = elem.nodeType,
+
+                        // Only DOM nodes need the global jQuery cache; JS object data is
+                        // attached directly to the object so GC can occur automatically
+                        cache = isNode ? jQuery.cache : elem,
+
+                        // Only defining an ID for JS objects if its cache already exists allows
+                        // the code to shortcut on the same path as a DOM node with no cache
+                        id = isNode ? elem[ jQuery.expando ] : elem[ jQuery.expando ] && jQuery.expando;
+
+                // Avoid doing any more work than we need to when trying to get data on an
+                // object that has no data at all
+                if ( (!id || (pvt && id && (cache[ id ] && !cache[ id ][ internalKey ]))) && getByName && data === undefined ) {
+                        return;
+                }
+
+                if ( !id ) {
+                        // Only DOM nodes need a new unique ID for each element since their data
+                        // ends up in the global cache
+                        if ( isNode ) {
+                                elem[ jQuery.expando ] = id = ++jQuery.uuid;
+                        } else {
+                                id = jQuery.expando;
+                        }
+                }
+
+                if ( !cache[ id ] ) {
+                        cache[ id ] = {};
+
+                        // TODO: This is a hack for 1.5 ONLY. Avoids exposing jQuery
+                        // metadata on plain JS objects when the object is serialized using
+                        // JSON.stringify
+                        if ( !isNode ) {
+                                cache[ id ].toJSON = jQuery.noop;
+                        }
+                }
+
+                // An object can be passed to jQuery.data instead of a key/value pair; this gets
+                // shallow copied over onto the existing cache
+                if ( typeof name === "object" || typeof name === "function" ) {
+                        if ( pvt ) {
+                                cache[ id ][ internalKey ] = jQuery.extend(cache[ id ][ internalKey ], name);
+                        } else {
+                                cache[ id ] = jQuery.extend(cache[ id ], name);
+                        }
+                }
+
+                thisCache = cache[ id ];
+
+                // Internal jQuery data is stored in a separate object inside the object's data
+                // cache in order to avoid key collisions between internal data and user-defined
+                // data
+                if ( pvt ) {
+                        if ( !thisCache[ internalKey ] ) {
+                                thisCache[ internalKey ] = {};
+                        }
+
+                        thisCache = thisCache[ internalKey ];
+                }
+
+                if ( data !== undefined ) {
+                        thisCache[ jQuery.camelCase( name ) ] = data;
+                }
+
+                // TODO: This is a hack for 1.5 ONLY. It will be removed in 1.6. Users should
+                // not attempt to inspect the internal events object using jQuery.data, as this
+                // internal data object is undocumented and subject to change.
+                if ( name === "events" && !thisCache[name] ) {
+                        return thisCache[ internalKey ] && thisCache[ internalKey ].events;
+                }
+
+                // Check for both converted-to-camel and non-converted data property names
+                // If a data property was specified
+                if ( getByName ) {
+
+                        // First Try to find as-is property data
+                        ret = thisCache[ name ];
+
+                        // Test for null|undefined property data
+                        if ( ret == null ) {
+
+                                // Try to find the camelCased property
+                                ret = thisCache[ jQuery.camelCase( name ) ];
+                        }
+                } else {
+                        ret = thisCache;
+                }
+
+                return ret;
+        },
+
+        removeData: function( elem, name, pvt /* Internal Use Only */ ) {
+                if ( !jQuery.acceptData( elem ) ) {
+                        return;
+                }
+
+                var thisCache,
+
+                        // Reference to internal data cache key
+                        internalKey = jQuery.expando,
+
+                        isNode = elem.nodeType,
+
+                        // See jQuery.data for more information
+                        cache = isNode ? jQuery.cache : elem,
+
+                        // See jQuery.data for more information
+                        id = isNode ? elem[ jQuery.expando ] : jQuery.expando;
+
+                // If there is already no cache entry for this object, there is no
+                // purpose in continuing
+                if ( !cache[ id ] ) {
+                        return;
+                }
+
+                if ( name ) {
+
+                        thisCache = pvt ? cache[ id ][ internalKey ] : cache[ id ];
+
+                        if ( thisCache ) {
+
+                                // Support interoperable removal of hyphenated or camelcased keys
+                                if ( !thisCache[ name ] ) {
+                                        name = jQuery.camelCase( name );
+                                }
+
+                                delete thisCache[ name ];
+
+                                // If there is no data left in the cache, we want to continue
+                                // and let the cache object itself get destroyed
+                                if ( !isEmptyDataObject(thisCache) ) {
+                                        return;
+                                }
+                        }
+                }
+
+                // See jQuery.data for more information
+                if ( pvt ) {
+                        delete cache[ id ][ internalKey ];
+
+                        // Don't destroy the parent cache unless the internal data object
+                        // had been the only thing left in it
+                        if ( !isEmptyDataObject(cache[ id ]) ) {
+                                return;
+                        }
+                }
+
+                var internalCache = cache[ id ][ internalKey ];
+
+                // Browsers that fail expando deletion also refuse to delete expandos on
+                // the window, but it will allow it on all other JS objects; other browsers
+                // don't care
+                // Ensure that `cache` is not a window object #10080
+                if ( jQuery.support.deleteExpando || !cache.setInterval ) {
+                        delete cache[ id ];
+                } else {
+                        cache[ id ] = null;
+                }
+
+                // We destroyed the entire user cache at once because it's faster than
+                // iterating through each key, but we need to continue to persist internal
+                // data if it existed
+                if ( internalCache ) {
+                        cache[ id ] = {};
+                        // TODO: This is a hack for 1.5 ONLY. Avoids exposing jQuery
+                        // metadata on plain JS objects when the object is serialized using
+                        // JSON.stringify
+                        if ( !isNode ) {
+                                cache[ id ].toJSON = jQuery.noop;
+                        }
+
+                        cache[ id ][ internalKey ] = internalCache;
+
+                // Otherwise, we need to eliminate the expando on the node to avoid
+                // false lookups in the cache for entries that no longer exist
+                } else if ( isNode ) {
+                        // IE does not allow us to delete expando properties from nodes,
+                        // nor does it have a removeAttribute function on Document nodes;
+                        // we must handle all of these cases
+                        if ( jQuery.support.deleteExpando ) {
+                                delete elem[ jQuery.expando ];
+                        } else if ( elem.removeAttribute ) {
+                                elem.removeAttribute( jQuery.expando );
+                        } else {
+                                elem[ jQuery.expando ] = null;
+                        }
+                }
+        },
+
+        // For internal use only.
+        _data: function( elem, name, data ) {
+                return jQuery.data( elem, name, data, true );
+        },
+
+        // A method for determining if a DOM node can handle the data expando
+        acceptData: function( elem ) {
+                if ( elem.nodeName ) {
+                        var match = jQuery.noData[ elem.nodeName.toLowerCase() ];
+
+                        if ( match ) {
+                                return !(match === true || elem.getAttribute("classid") !== match);
+                        }
+                }
+
+                return true;
+        }
+});
+
+jQuery.fn.extend({
+        data: function( key, value ) {
+                var data = null;
+
+                if ( typeof key === "undefined" ) {
+                        if ( this.length ) {
+                                data = jQuery.data( this[0] );
+
+                                if ( this[0].nodeType === 1 ) {
+                            var attr = this[0].attributes, name;
+                                        for ( var i = 0, l = attr.length; i < l; i++ ) {
+                                                name = attr[i].name;
+
+                                                if ( name.indexOf( "data-" ) === 0 ) {
+                                                        name = jQuery.camelCase( name.substring(5) );
+
+                                                        dataAttr( this[0], name, data[ name ] );
+                                                }
+                                        }
+                                }
+                        }
+
+                        return data;
+
+                } else if ( typeof key === "object" ) {
+                        return this.each(function() {
+                                jQuery.data( this, key );
+                        });
+                }
+
+                var parts = key.split(".");
+                parts[1] = parts[1] ? "." + parts[1] : "";
+
+                if ( value === undefined ) {
+                        data = this.triggerHandler("getData" + parts[1] + "!", [parts[0]]);
+
+                        // Try to fetch any internally stored data first
+                        if ( data === undefined && this.length ) {
+                                data = jQuery.data( this[0], key );
+                                data = dataAttr( this[0], key, data );
+                        }
+
+                        return data === undefined && parts[1] ?
+                                this.data( parts[0] ) :
+                                data;
+
+                } else {
+                        return this.each(function() {
+                                var $this = jQuery( this ),
+                                        args = [ parts[0], value ];
+
+                                $this.triggerHandler( "setData" + parts[1] + "!", args );
+                                jQuery.data( this, key, value );
+                                $this.triggerHandler( "changeData" + parts[1] + "!", args );
+                        });
+                }
+        },
+
+        removeData: function( key ) {
+                return this.each(function() {
+                        jQuery.removeData( this, key );
+                });
+        }
+});
+
+function dataAttr( elem, key, data ) {
+        // If nothing was found internally, try to fetch any
+        // data from the HTML5 data-* attribute
+        if ( data === undefined && elem.nodeType === 1 ) {
+
+                var name = "data-" + key.replace( rmultiDash, "-$1" ).toLowerCase();
+
+                data = elem.getAttribute( name );
+
+                if ( typeof data === "string" ) {
+                        try {
+                                data = data === "true" ? true :
+                                data === "false" ? false :
+                                data === "null" ? null :
+                                !jQuery.isNaN( data ) ? parseFloat( data ) :
+                                        rbrace.test( data ) ? jQuery.parseJSON( data ) :
+                                        data;
+                        } catch( e ) {}
+
+                        // Make sure we set the data so it isn't changed later
+                        jQuery.data( elem, key, data );
+
+                } else {
+                        data = undefined;
+                }
+        }
+
+        return data;
+}
+
+// TODO: This is a hack for 1.5 ONLY to allow objects with a single toJSON
+// property to be considered empty objects; this property always exists in
+// order to make sure JSON.stringify does not expose internal metadata
+function isEmptyDataObject( obj ) {
+        for ( var name in obj ) {
+                if ( name !== "toJSON" ) {
+                        return false;
+                }
+        }
+
+        return true;
+}
+
+
+
+
+function handleQueueMarkDefer( elem, type, src ) {
+        var deferDataKey = type + "defer",
+                queueDataKey = type + "queue",
+                markDataKey = type + "mark",
+                defer = jQuery.data( elem, deferDataKey, undefined, true );
+        if ( defer &&
+                ( src === "queue" || !jQuery.data( elem, queueDataKey, undefined, true ) ) &&
+                ( src === "mark" || !jQuery.data( elem, markDataKey, undefined, true ) ) ) {
+                // Give room for hard-coded callbacks to fire first
+                // and eventually mark/queue something else on the element
+                setTimeout( function() {
+                        if ( !jQuery.data( elem, queueDataKey, undefined, true ) &&
+                                !jQuery.data( elem, markDataKey, undefined, true ) ) {
+                                jQuery.removeData( elem, deferDataKey, true );
+                                defer.resolve();
+                        }
+                }, 0 );
+        }
+}
+
+jQuery.extend({
+
+        _mark: function( elem, type ) {
+                if ( elem ) {
+                        type = (type || "fx") + "mark";
+                        jQuery.data( elem, type, (jQuery.data(elem,type,undefined,true) || 0) + 1, true );
+                }
+        },
+
+        _unmark: function( force, elem, type ) {
+                if ( force !== true ) {
+                        type = elem;
+                        elem = force;
+                        force = false;
+                }
+                if ( elem ) {
+                        type = type || "fx";
+                        var key = type + "mark",
+                                count = force ? 0 : ( (jQuery.data( elem, key, undefined, true) || 1 ) - 1 );
+                        if ( count ) {
+                                jQuery.data( elem, key, count, true );
+                        } else {
+                                jQuery.removeData( elem, key, true );
+                                handleQueueMarkDefer( elem, type, "mark" );
+                        }
+                }
+        },
+
+        queue: function( elem, type, data ) {
+                if ( elem ) {
+                        type = (type || "fx") + "queue";
+                        var q = jQuery.data( elem, type, undefined, true );
+                        // Speed up dequeue by getting out quickly if this is just a lookup
+                        if ( data ) {
+                                if ( !q || jQuery.isArray(data) ) {
+                                        q = jQuery.data( elem, type, jQuery.makeArray(data), true );
+                                } else {
+                                        q.push( data );
+                                }
+                        }
+                        return q || [];
+                }
+        },
+
+        dequeue: function( elem, type ) {
+                type = type || "fx";
+
+                var queue = jQuery.queue( elem, type ),
+                        fn = queue.shift(),
+                        defer;
+
+                // If the fx queue is dequeued, always remove the progress sentinel
+                if ( fn === "inprogress" ) {
+                        fn = queue.shift();
+                }
+
+                if ( fn ) {
+                        // Add a progress sentinel to prevent the fx queue from being
+                        // automatically dequeued
+                        if ( type === "fx" ) {
+                                queue.unshift("inprogress");
+                        }
+
+                        fn.call(elem, function() {
+                                jQuery.dequeue(elem, type);
+                        });
+                }
+
+                if ( !queue.length ) {
+                        jQuery.removeData( elem, type + "queue", true );
+                        handleQueueMarkDefer( elem, type, "queue" );
+                }
+        }
+});
+
+jQuery.fn.extend({
+        queue: function( type, data ) {
+                if ( typeof type !== "string" ) {
+                        data = type;
+                        type = "fx";
+                }
+
+                if ( data === undefined ) {
+                        return jQuery.queue( this[0], type );
+                }
+                return this.each(function() {
+                        var queue = jQuery.queue( this, type, data );
+
+                        if ( type === "fx" && queue[0] !== "inprogress" ) {
+                                jQuery.dequeue( this, type );
+                        }
+                });
+        },
+        dequeue: function( type ) {
+                return this.each(function() {
+                        jQuery.dequeue( this, type );
+                });
+        },
+        // Based off of the plugin by Clint Helfers, with permission.
+        // http://blindsignals.com/index.php/2009/07/jquery-delay/
+        delay: function( time, type ) {
+                time = jQuery.fx ? jQuery.fx.speeds[time] || time : time;
+                type = type || "fx";
+
+                return this.queue( type, function() {
+                        var elem = this;
+                        setTimeout(function() {
+                                jQuery.dequeue( elem, type );
+                        }, time );
+                });
+        },
+        clearQueue: function( type ) {
+                return this.queue( type || "fx", [] );
+        },
+        // Get a promise resolved when queues of a certain type
+        // are emptied (fx is the type by default)
+        promise: function( type, object ) {
+                if ( typeof type !== "string" ) {
+                        object = type;
+                        type = undefined;
+                }
+                type = type || "fx";
+                var defer = jQuery.Deferred(),
+                        elements = this,
+                        i = elements.length,
+                        count = 1,
+                        deferDataKey = type + "defer",
+                        queueDataKey = type + "queue",
+                        markDataKey = type + "mark",
+                        tmp;
+                function resolve() {
+                        if ( !( --count ) ) {
+                                defer.resolveWith( elements, [ elements ] );
+                        }
+                }
+                while( i-- ) {
+                        if (( tmp = jQuery.data( elements[ i ], deferDataKey, undefined, true ) ||
+                                        ( jQuery.data( elements[ i ], queueDataKey, undefined, true ) ||
+                                                jQuery.data( elements[ i ], markDataKey, undefined, true ) ) &&
+                                        jQuery.data( elements[ i ], deferDataKey, jQuery._Deferred(), true ) )) {
+                                count++;
+                                tmp.done( resolve );
+                        }
+                }
+                resolve();
+                return defer.promise();
+        }
+});
+
+
+
+
+var rclass = /[\n\t\r]/g,
+        rspace = /\s+/,
+        rreturn = /\r/g,
+        rtype = /^(?:button|input)$/i,
+        rfocusable = /^(?:button|input|object|select|textarea)$/i,
+        rclickable = /^a(?:rea)?$/i,
+        rboolean = /^(?:autofocus|autoplay|async|checked|controls|defer|disabled|hidden|loop|multiple|open|readonly|required|scoped|selected)$/i,
+        nodeHook, boolHook;
+
+jQuery.fn.extend({
+        attr: function( name, value ) {
+                return jQuery.access( this, name, value, true, jQuery.attr );
+        },
+
+        removeAttr: function( name ) {
+                return this.each(function() {
+                        jQuery.removeAttr( this, name );
+                });
+        },
+        
+        prop: function( name, value ) {
+                return jQuery.access( this, name, value, true, jQuery.prop );
+        },
+        
+        removeProp: function( name ) {
+                name = jQuery.propFix[ name ] || name;
+                return this.each(function() {
+                        // try/catch handles cases where IE balks (such as removing a property on window)
+                        try {
+                                this[ name ] = undefined;
+                                delete this[ name ];
+                        } catch( e ) {}
+                });
+        },
+
+        addClass: function( value ) {
+                var classNames, i, l, elem,
+                        setClass, c, cl;
+
+                if ( jQuery.isFunction( value ) ) {
+                        return this.each(function( j ) {
+                                jQuery( this ).addClass( value.call(this, j, this.className) );
+                        });
+                }
+
+                if ( value && typeof value === "string" ) {
+                        classNames = value.split( rspace );
+
+                        for ( i = 0, l = this.length; i < l; i++ ) {
+                                elem = this[ i ];
+
+                                if ( elem.nodeType === 1 ) {
+                                        if ( !elem.className && classNames.length === 1 ) {
+                                                elem.className = value;
+
+                                        } else {
+                                                setClass = " " + elem.className + " ";
+
+                                                for ( c = 0, cl = classNames.length; c < cl; c++ ) {
+                                                        if ( !~setClass.indexOf( " " + classNames[ c ] + " " ) ) {
+                                                                setClass += classNames[ c ] + " ";
+                                                        }
+                                                }
+                                                elem.className = jQuery.trim( setClass );
+                                        }
+                                }
+                        }
+                }
+
+                return this;
+        },
+
+        removeClass: function( value ) {
+                var classNames, i, l, elem, className, c, cl;
+
+                if ( jQuery.isFunction( value ) ) {
+                        return this.each(function( j ) {
+                                jQuery( this ).removeClass( value.call(this, j, this.className) );
+                        });
+                }
+
+                if ( (value && typeof value === "string") || value === undefined ) {
+                        classNames = (value || "").split( rspace );
+
+                        for ( i = 0, l = this.length; i < l; i++ ) {
+                                elem = this[ i ];
+
+                                if ( elem.nodeType === 1 && elem.className ) {
+                                        if ( value ) {
+                                                className = (" " + elem.className + " ").replace( rclass, " " );
+                                                for ( c = 0, cl = classNames.length; c < cl; c++ ) {
+                                                        className = className.replace(" " + classNames[ c ] + " ", " ");
+                                                }
+                                                elem.className = jQuery.trim( className );
+
+                                        } else {
+                                                elem.className = "";
+                                        }
+                                }
+                        }
+                }
+
+                return this;
+        },
+
+        toggleClass: function( value, stateVal ) {
+                var type = typeof value,
+                        isBool = typeof stateVal === "boolean";
+
+                if ( jQuery.isFunction( value ) ) {
+                        return this.each(function( i ) {
+                                jQuery( this ).toggleClass( value.call(this, i, this.className, stateVal), stateVal );
+                        });
+                }
+
+                return this.each(function() {
+                        if ( type === "string" ) {
+                                // toggle individual class names
+                                var className,
+                                        i = 0,
+                                        self = jQuery( this ),
+                                        state = stateVal,
+                                        classNames = value.split( rspace );
+
+                                while ( (className = classNames[ i++ ]) ) {
+                                        // check each className given, space seperated list
+                                        state = isBool ? state : !self.hasClass( className );
+                                        self[ state ? "addClass" : "removeClass" ]( className );
+                                }
+
+                        } else if ( type === "undefined" || type === "boolean" ) {
+                                if ( this.className ) {
+                                        // store className if set
+                                        jQuery._data( this, "__className__", this.className );
+                                }
+
+                                // toggle whole className
+                                this.className = this.className || value === false ? "" : jQuery._data( this, "__className__" ) || "";
+                        }
+                });
+        },
+
+        hasClass: function( selector ) {
+                var className = " " + selector + " ";
+                for ( var i = 0, l = this.length; i < l; i++ ) {
+                        if ( this[i].nodeType === 1 && (" " + this[i].className + " ").replace(rclass, " ").indexOf( className ) > -1 ) {
+                                return true;
+                        }
+                }
+
+                return false;
+        },
+
+        val: function( value ) {
+                var hooks, ret,
+                        elem = this[0];
+                
+                if ( !arguments.length ) {
+                        if ( elem ) {
+                                hooks = jQuery.valHooks[ elem.nodeName.toLowerCase() ] || jQuery.valHooks[ elem.type ];
+
+                                if ( hooks && "get" in hooks && (ret = hooks.get( elem, "value" )) !== undefined ) {
+                                        return ret;
+                                }
+
+                                ret = elem.value;
+
+                                return typeof ret === "string" ? 
+                                        // handle most common string cases
+                                        ret.replace(rreturn, "") : 
+                                        // handle cases where value is null/undef or number
+                                        ret == null ? "" : ret;
+                        }
+
+                        return undefined;
+                }
+
+                var isFunction = jQuery.isFunction( value );
+
+                return this.each(function( i ) {
+                        var self = jQuery(this), val;
+
+                        if ( this.nodeType !== 1 ) {
+                                return;
+                        }
+
+                        if ( isFunction ) {
+                                val = value.call( this, i, self.val() );
+                        } else {
+                                val = value;
+                        }
+
+                        // Treat null/undefined as ""; convert numbers to string
+                        if ( val == null ) {
+                                val = "";
+                        } else if ( typeof val === "number" ) {
+                                val += "";
+                        } else if ( jQuery.isArray( val ) ) {
+                                val = jQuery.map(val, function ( value ) {
+                                        return value == null ? "" : value + "";
+                                });
+                        }
+
+                        hooks = jQuery.valHooks[ this.nodeName.toLowerCase() ] || jQuery.valHooks[ this.type ];
+
+                        // If set returns undefined, fall back to normal setting
+                        if ( !hooks || !("set" in hooks) || hooks.set( this, val, "value" ) === undefined ) {
+                                this.value = val;
+                        }
+                });
+        }
+});
+
+jQuery.extend({
+        valHooks: {
+                option: {
+                        get: function( elem ) {
+                                // attributes.value is undefined in Blackberry 4.7 but
+                                // uses .value. See #6932
+                                var val = elem.attributes.value;
+                                return !val || val.specified ? elem.value : elem.text;
+                        }
+                },
+                select: {
+                        get: function( elem ) {
+                                var value,
+                                        index = elem.selectedIndex,
+                                        values = [],
+                                        options = elem.options,
+                                        one = elem.type === "select-one";
+
+                                // Nothing was selected
+                                if ( index < 0 ) {
+                                        return null;
+                                }
+
+                                // Loop through all the selected options
+                                for ( var i = one ? index : 0, max = one ? index + 1 : options.length; i < max; i++ ) {
+                                        var option = options[ i ];
+
+                                        // Don't return options that are disabled or in a disabled optgroup
+                                        if ( option.selected && (jQuery.support.optDisabled ? !option.disabled : option.getAttribute("disabled") === null) &&
+                                                        (!option.parentNode.disabled || !jQuery.nodeName( option.parentNode, "optgroup" )) ) {
+
+                                                // Get the specific value for the option
+                                                value = jQuery( option ).val();
+
+                                                // We don't need an array for one selects
+                                                if ( one ) {
+                                                        return value;
+                                                }
+
+                                                // Multi-Selects return an array
+                                                values.push( value );
+                                        }
+                                }
+
+                                // Fixes Bug #2551 -- select.val() broken in IE after form.reset()
+                                if ( one && !values.length && options.length ) {
+                                        return jQuery( options[ index ] ).val();
+                                }
+
+                                return values;
+                        },
+
+                        set: function( elem, value ) {
+                                var values = jQuery.makeArray( value );
+
+                                jQuery(elem).find("option").each(function() {
+                                        this.selected = jQuery.inArray( jQuery(this).val(), values ) >= 0;
+                                });
+
+                                if ( !values.length ) {
+                                        elem.selectedIndex = -1;
+                                }
+                                return values;
+                        }
+                }
+        },
+
+        attrFn: {
+                val: true,
+                css: true,
+                html: true,
+                text: true,
+                data: true,
+                width: true,
+                height: true,
+                offset: true
+        },
+        
+        attrFix: {
+                // Always normalize to ensure hook usage
+                tabindex: "tabIndex"
+        },
+        
+        attr: function( elem, name, value, pass ) {
+                var nType = elem.nodeType;
+                
+                // don't get/set attributes on text, comment and attribute nodes
+                if ( !elem || nType === 3 || nType === 8 || nType === 2 ) {
+                        return undefined;
+                }
+
+                if ( pass && name in jQuery.attrFn ) {
+                        return jQuery( elem )[ name ]( value );
+                }
+
+                // Fallback to prop when attributes are not supported
+                if ( !("getAttribute" in elem) ) {
+                        return jQuery.prop( elem, name, value );
+                }
+
+                var ret, hooks,
+                        notxml = nType !== 1 || !jQuery.isXMLDoc( elem );
+
+                // Normalize the name if needed
+                if ( notxml ) {
+                        name = jQuery.attrFix[ name ] || name;
+
+                        hooks = jQuery.attrHooks[ name ];
+
+                        if ( !hooks ) {
+                                // Use boolHook for boolean attributes
+                                if ( rboolean.test( name ) ) {
+                                        hooks = boolHook;
+
+                                // Use nodeHook if available( IE6/7 )
+                                } else if ( nodeHook ) {
+                                        hooks = nodeHook;
+                                }
+                        }
+                }
+
+                if ( value !== undefined ) {
+
+                        if ( value === null ) {
+                                jQuery.removeAttr( elem, name );
+                                return undefined;
+
+                        } else if ( hooks && "set" in hooks && notxml && (ret = hooks.set( elem, value, name )) !== undefined ) {
+                                return ret;
+
+                        } else {
+                                elem.setAttribute( name, "" + value );
+                                return value;
+                        }
+
+                } else if ( hooks && "get" in hooks && notxml && (ret = hooks.get( elem, name )) !== null ) {
+                        return ret;
+
+                } else {
+
+                        ret = elem.getAttribute( name );
+
+                        // Non-existent attributes return null, we normalize to undefined
+                        return ret === null ?
+                                undefined :
+                                ret;
+                }
+        },
+
+        removeAttr: function( elem, name ) {
+                var propName;
+                if ( elem.nodeType === 1 ) {
+                        name = jQuery.attrFix[ name ] || name;
+
+                        jQuery.attr( elem, name, "" );
+                        elem.removeAttribute( name );
+
+                        // Set corresponding property to false for boolean attributes
+                        if ( rboolean.test( name ) && (propName = jQuery.propFix[ name ] || name) in elem ) {
+                                elem[ propName ] = false;
+                        }
+                }
+        },
+
+        attrHooks: {
+                type: {
+                        set: function( elem, value ) {
+                                // We can't allow the type property to be changed (since it causes problems in IE)
+                                if ( rtype.test( elem.nodeName ) && elem.parentNode ) {
+                                        jQuery.error( "type property can't be changed" );
+                                } else if ( !jQuery.support.radioValue && value === "radio" && jQuery.nodeName(elem, "input") ) {
+                                        // Setting the type on a radio button after the value resets the value in IE6-9
+                                        // Reset value to it's default in case type is set after value
+                                        // This is for element creation
+                                        var val = elem.value;
+                                        elem.setAttribute( "type", value );
+                                        if ( val ) {
+                                                elem.value = val;
+                                        }
+                                        return value;
+                                }
+                        }
+                },
+                // Use the value property for back compat
+                // Use the nodeHook for button elements in IE6/7 (#1954)
+                value: {
+                        get: function( elem, name ) {
+                                if ( nodeHook && jQuery.nodeName( elem, "button" ) ) {
+                                        return nodeHook.get( elem, name );
+                                }
+                                return name in elem ?
+                                        elem.value :
+                                        null;
+                        },
+                        set: function( elem, value, name ) {
+                                if ( nodeHook && jQuery.nodeName( elem, "button" ) ) {
+                                        return nodeHook.set( elem, value, name );
+                                }
+                                // Does not return so that setAttribute is also used
+                                elem.value = value;
+                        }
+                }
+        },
+
+        propFix: {
+                tabindex: "tabIndex",
+                readonly: "readOnly",
+                "for": "htmlFor",
+                "class": "className",
+                maxlength: "maxLength",
+                cellspacing: "cellSpacing",
+                cellpadding: "cellPadding",
+                rowspan: "rowSpan",
+                colspan: "colSpan",
+                usemap: "useMap",
+                frameborder: "frameBorder",
+                contenteditable: "contentEditable"
+        },
+        
+        prop: function( elem, name, value ) {
+                var nType = elem.nodeType;
+
+                // don't get/set properties on text, comment and attribute nodes
+                if ( !elem || nType === 3 || nType === 8 || nType === 2 ) {
+                        return undefined;
+                }
+
+                var ret, hooks,
+                        notxml = nType !== 1 || !jQuery.isXMLDoc( elem );
+
+                if ( notxml ) {
+                        // Fix name and attach hooks
+                        name = jQuery.propFix[ name ] || name;
+                        hooks = jQuery.propHooks[ name ];
+                }
+
+                if ( value !== undefined ) {
+                        if ( hooks && "set" in hooks && (ret = hooks.set( elem, value, name )) !== undefined ) {
+                                return ret;
+
+                        } else {
+                                return (elem[ name ] = value);
+                        }
+
+                } else {
+                        if ( hooks && "get" in hooks && (ret = hooks.get( elem, name )) !== null ) {
+                                return ret;
+
+                        } else {
+                                return elem[ name ];
+                        }
+                }
+        },
+        
+        propHooks: {
+                tabIndex: {
+                        get: function( elem ) {
+                                // elem.tabIndex doesn't always return the correct value when it hasn't been explicitly set
+                                // http://fluidproject.org/blog/2008/01/09/getting-setting-and-removing-tabindex-values-with-javascript/
+                                var attributeNode = elem.getAttributeNode("tabindex");
+
+                                return attributeNode && attributeNode.specified ?
+                                        parseInt( attributeNode.value, 10 ) :
+                                        rfocusable.test( elem.nodeName ) || rclickable.test( elem.nodeName ) && elem.href ?
+                                                0 :
+                                                undefined;
+                        }
+                }
+        }
+});
+
+// Add the tabindex propHook to attrHooks for back-compat
+jQuery.attrHooks.tabIndex = jQuery.propHooks.tabIndex;
+
+// Hook for boolean attributes
+boolHook = {
+        get: function( elem, name ) {
+                // Align boolean attributes with corresponding properties
+                // Fall back to attribute presence where some booleans are not supported
+                var attrNode;
+                return jQuery.prop( elem, name ) === true || ( attrNode = elem.getAttributeNode( name ) ) && attrNode.nodeValue !== false ?
+                        name.toLowerCase() :
+                        undefined;
+        },
+        set: function( elem, value, name ) {
+                var propName;
+                if ( value === false ) {
+                        // Remove boolean attributes when set to false
+                        jQuery.removeAttr( elem, name );
+                } else {
+                        // value is true since we know at this point it's type boolean and not false
+                        // Set boolean attributes to the same name and set the DOM property
+                        propName = jQuery.propFix[ name ] || name;
+                        if ( propName in elem ) {
+                                // Only set the IDL specifically if it already exists on the element
+                                elem[ propName ] = true;
+                        }
+
+                        elem.setAttribute( name, name.toLowerCase() );
+                }
+                return name;
+        }
+};
+
+// IE6/7 do not support getting/setting some attributes with get/setAttribute
+if ( !jQuery.support.getSetAttribute ) {
+        
+        // Use this for any attribute in IE6/7
+        // This fixes almost every IE6/7 issue
+        nodeHook = jQuery.valHooks.button = {
+                get: function( elem, name ) {
+                        var ret;
+                        ret = elem.getAttributeNode( name );
+                        // Return undefined if nodeValue is empty string
+                        return ret && ret.nodeValue !== "" ?
+                                ret.nodeValue :
+                                undefined;
+                },
+                set: function( elem, value, name ) {
+                        // Set the existing or create a new attribute node
+                        var ret = elem.getAttributeNode( name );
+                        if ( !ret ) {
+                                ret = document.createAttribute( name );
+                                elem.setAttributeNode( ret );
+                        }
+                        return (ret.nodeValue = value + "");
+                }
+        };
+
+        // Set width and height to auto instead of 0 on empty string( Bug #8150 )
+        // This is for removals
+        jQuery.each([ "width", "height" ], function( i, name ) {
+                jQuery.attrHooks[ name ] = jQuery.extend( jQuery.attrHooks[ name ], {
+                        set: function( elem, value ) {
+                                if ( value === "" ) {
+                                        elem.setAttribute( name, "auto" );
+                                        return value;
+                                }
+                        }
+                });
+        });
+}
+
+
+// Some attributes require a special call on IE
+if ( !jQuery.support.hrefNormalized ) {
+        jQuery.each([ "href", "src", "width", "height" ], function( i, name ) {
+                jQuery.attrHooks[ name ] = jQuery.extend( jQuery.attrHooks[ name ], {
+                        get: function( elem ) {
+                                var ret = elem.getAttribute( name, 2 );
+                                return ret === null ? undefined : ret;
+                        }
+                });
+        });
+}
+
+if ( !jQuery.support.style ) {
+        jQuery.attrHooks.style = {
+                get: function( elem ) {
+                        // Return undefined in the case of empty string
+                        // Normalize to lowercase since IE uppercases css property names
+                        return elem.style.cssText.toLowerCase() || undefined;
+                },
+                set: function( elem, value ) {
+                        return (elem.style.cssText = "" + value);
+                }
+        };
+}
+
+// Safari mis-reports the default selected property of an option
+// Accessing the parent's selectedIndex property fixes it
+if ( !jQuery.support.optSelected ) {
+        jQuery.propHooks.selected = jQuery.extend( jQuery.propHooks.selected, {
+                get: function( elem ) {
+                        var parent = elem.parentNode;
+
+                        if ( parent ) {
+                                parent.selectedIndex;
+
+                                // Make sure that it also works with optgroups, see #5701
+                                if ( parent.parentNode ) {
+                                        parent.parentNode.selectedIndex;
+                                }
+                        }
+                        return null;
+                }
+        });
+}
+
+// Radios and checkboxes getter/setter
+if ( !jQuery.support.checkOn ) {
+        jQuery.each([ "radio", "checkbox" ], function() {
+                jQuery.valHooks[ this ] = {
+                        get: function( elem ) {
+                                // Handle the case where in Webkit "" is returned instead of "on" if a value isn't specified
+                                return elem.getAttribute("value") === null ? "on" : elem.value;
+                        }
+                };
+        });
+}
+jQuery.each([ "radio", "checkbox" ], function() {
+        jQuery.valHooks[ this ] = jQuery.extend( jQuery.valHooks[ this ], {
+                set: function( elem, value ) {
+                        if ( jQuery.isArray( value ) ) {
+                                return (elem.checked = jQuery.inArray( jQuery(elem).val(), value ) >= 0);
+                        }
+                }
+        });
+});
+
+
+
+
+var rnamespaces = /\.(.*)$/,
+        rformElems = /^(?:textarea|input|select)$/i,
+        rperiod = /\./g,
+        rspaces = / /g,
+        rescape = /[^\w\s.|`]/g,
+        fcleanup = function( nm ) {
+                return nm.replace(rescape, "\\$&");
+        };
+
+/*
+ * A number of helper functions used for managing events.
+ * Many of the ideas behind this code originated from
+ * Dean Edwards' addEvent library.
+ */
+jQuery.event = {
+
+        // Bind an event to an element
+        // Original by Dean Edwards
+        add: function( elem, types, handler, data ) {
+                if ( elem.nodeType === 3 || elem.nodeType === 8 ) {
+                        return;
+                }
+
+                if ( handler === false ) {
+                        handler = returnFalse;
+                } else if ( !handler ) {
+                        // Fixes bug #7229. Fix recommended by jdalton
+                        return;
+                }
+
+                var handleObjIn, handleObj;
+
+                if ( handler.handler ) {
+                        handleObjIn = handler;
+                        handler = handleObjIn.handler;
+                }
+
+                // Make sure that the function being executed has a unique ID
+                if ( !handler.guid ) {
+                        handler.guid = jQuery.guid++;
+                }
+
+                // Init the element's event structure
+                var elemData = jQuery._data( elem );
+
+                // If no elemData is found then we must be trying to bind to one of the
+                // banned noData elements
+                if ( !elemData ) {
+                        return;
+                }
+
+                var events = elemData.events,
+                        eventHandle = elemData.handle;
+
+                if ( !events ) {
+                        elemData.events = events = {};
+                }
+
+                if ( !eventHandle ) {
+                        elemData.handle = eventHandle = function( e ) {
+                                // Discard the second event of a jQuery.event.trigger() and
+                                // when an event is called after a page has unloaded
+                                return typeof jQuery !== "undefined" && (!e || jQuery.event.triggered !== e.type) ?
+                                        jQuery.event.handle.apply( eventHandle.elem, arguments ) :
+                                        undefined;
+                        };
+                }
+
+                // Add elem as a property of the handle function
+                // This is to prevent a memory leak with non-native events in IE.
+                eventHandle.elem = elem;
+
+                // Handle multiple events separated by a space
+                // jQuery(...).bind("mouseover mouseout", fn);
+                types = types.split(" ");
+
+                var type, i = 0, namespaces;
+
+                while ( (type = types[ i++ ]) ) {
+                        handleObj = handleObjIn ?
+                                jQuery.extend({}, handleObjIn) :
+                                { handler: handler, data: data };
+
+                        // Namespaced event handlers
+                        if ( type.indexOf(".") > -1 ) {
+                                namespaces = type.split(".");
+                                type = namespaces.shift();
+                                handleObj.namespace = namespaces.slice(0).sort().join(".");
+
+                        } else {
+                                namespaces = [];
+                                handleObj.namespace = "";
+                        }
+
+                        handleObj.type = type;
+                        if ( !handleObj.guid ) {
+                                handleObj.guid = handler.guid;
+                        }
+
+                        // Get the current list of functions bound to this event
+                        var handlers = events[ type ],
+                                special = jQuery.event.special[ type ] || {};
+
+                        // Init the event handler queue
+                        if ( !handlers ) {
+                                handlers = events[ type ] = [];
+
+                                // Check for a special event handler
+                                // Only use addEventListener/attachEvent if the special
+                                // events handler returns false
+                                if ( !special.setup || special.setup.call( elem, data, namespaces, eventHandle ) === false ) {
+                                        // Bind the global event handler to the element
+                                        if ( elem.addEventListener ) {
+                                                elem.addEventListener( type, eventHandle, false );
+
+                                        } else if ( elem.attachEvent ) {
+                                                elem.attachEvent( "on" + type, eventHandle );
+                                        }
+                                }
+                        }
+
+                        if ( special.add ) {
+                                special.add.call( elem, handleObj );
+
+                                if ( !handleObj.handler.guid ) {
+                                        handleObj.handler.guid = handler.guid;
+                                }
+                        }
+
+                        // Add the function to the element's handler list
+                        handlers.push( handleObj );
+
+                        // Keep track of which events have been used, for event optimization
+                        jQuery.event.global[ type ] = true;
+                }
+
+                // Nullify elem to prevent memory leaks in IE
+                elem = null;
+        },
+
+        global: {},
+
+        // Detach an event or set of events from an element
+        remove: function( elem, types, handler, pos ) {
+                // don't do events on text and comment nodes
+                if ( elem.nodeType === 3 || elem.nodeType === 8 ) {
+                        return;
+                }
+
+                if ( handler === false ) {
+                        handler = returnFalse;
+                }
+
+                var ret, type, fn, j, i = 0, all, namespaces, namespace, special, eventType, handleObj, origType,
+                        elemData = jQuery.hasData( elem ) && jQuery._data( elem ),
+                        events = elemData && elemData.events;
+
+                if ( !elemData || !events ) {
+                        return;
+                }
+
+                // types is actually an event object here
+                if ( types && types.type ) {
+                        handler = types.handler;
+                        types = types.type;
+                }
+
+                // Unbind all events for the element
+                if ( !types || typeof types === "string" && types.charAt(0) === "." ) {
+                        types = types || "";
+
+                        for ( type in events ) {
+                                jQuery.event.remove( elem, type + types );
+                        }
+
+                        return;
+                }
+
+                // Handle multiple events separated by a space
+                // jQuery(...).unbind("mouseover mouseout", fn);
+                types = types.split(" ");
+
+                while ( (type = types[ i++ ]) ) {
+                        origType = type;
+                        handleObj = null;
+                        all = type.indexOf(".") < 0;
+                        namespaces = [];
+
+                        if ( !all ) {
+                                // Namespaced event handlers
+                                namespaces = type.split(".");
+                                type = namespaces.shift();
+
+                                namespace = new RegExp("(^|\\.)" +
+                                        jQuery.map( namespaces.slice(0).sort(), fcleanup ).join("\\.(?:.*\\.)?") + "(\\.|$)");
+                        }
+
+                        eventType = events[ type ];
+
+                        if ( !eventType ) {
+                                continue;
+                        }
+
+                        if ( !handler ) {
+                                for ( j = 0; j < eventType.length; j++ ) {
+                                        handleObj = eventType[ j ];
+
+                                        if ( all || namespace.test( handleObj.namespace ) ) {
+                                                jQuery.event.remove( elem, origType, handleObj.handler, j );
+                                                eventType.splice( j--, 1 );
+                                        }
+                                }
+
+                                continue;
+                        }
+
+                        special = jQuery.event.special[ type ] || {};
+
+                        for ( j = pos || 0; j < eventType.length; j++ ) {
+                                handleObj = eventType[ j ];
+
+                                if ( handler.guid === handleObj.guid ) {
+                                        // remove the given handler for the given type
+                                        if ( all || namespace.test( handleObj.namespace ) ) {
+                                                if ( pos == null ) {
+                                                        eventType.splice( j--, 1 );
+                                                }
+
+                                                if ( special.remove ) {
+                                                        special.remove.call( elem, handleObj );
+                                                }
+                                        }
+
+                                        if ( pos != null ) {
+                                                break;
+                                        }
+                                }
+                        }
+
+                        // remove generic event handler if no more handlers exist
+                        if ( eventType.length === 0 || pos != null && eventType.length === 1 ) {
+                                if ( !special.teardown || special.teardown.call( elem, namespaces ) === false ) {
+                                        jQuery.removeEvent( elem, type, elemData.handle );
+                                }
+
+                                ret = null;
+                                delete events[ type ];
+                        }
+                }
+
+                // Remove the expando if it's no longer used
+                if ( jQuery.isEmptyObject( events ) ) {
+                        var handle = elemData.handle;
+                        if ( handle ) {
+                                handle.elem = null;
+                        }
+
+                        delete elemData.events;
+                        delete elemData.handle;
+
+                        if ( jQuery.isEmptyObject( elemData ) ) {
+                                jQuery.removeData( elem, undefined, true );
+                        }
+                }
+        },
+        
+        // Events that are safe to short-circuit if no handlers are attached.
+        // Native DOM events should not be added, they may have inline handlers.
+        customEvent: {
+                "getData": true,
+                "setData": true,
+                "changeData": true
+        },
+
+        trigger: function( event, data, elem, onlyHandlers ) {
+                // Event object or event type
+                var type = event.type || event,
+                        namespaces = [],
+                        exclusive;
+
+                if ( type.indexOf("!") >= 0 ) {
+                        // Exclusive events trigger only for the exact event (no namespaces)
+                        type = type.slice(0, -1);
+                        exclusive = true;
+                }
+
+                if ( type.indexOf(".") >= 0 ) {
+                        // Namespaced trigger; create a regexp to match event type in handle()
+                        namespaces = type.split(".");
+                        type = namespaces.shift();
+                        namespaces.sort();
+                }
+
+                if ( (!elem || jQuery.event.customEvent[ type ]) && !jQuery.event.global[ type ] ) {
+                        // No jQuery handlers for this event type, and it can't have inline handlers
+                        return;
+                }
+
+                // Caller can pass in an Event, Object, or just an event type string
+                event = typeof event === "object" ?
+                        // jQuery.Event object
+                        event[ jQuery.expando ] ? event :
+                        // Object literal
+                        new jQuery.Event( type, event ) :
+                        // Just the event type (string)
+                        new jQuery.Event( type );
+
+                event.type = type;
+                event.exclusive = exclusive;
+                event.namespace = namespaces.join(".");
+                event.namespace_re = new RegExp("(^|\\.)" + namespaces.join("\\.(?:.*\\.)?") + "(\\.|$)");
+                
+                // triggerHandler() and global events don't bubble or run the default action
+                if ( onlyHandlers || !elem ) {
+                        event.preventDefault();
+                        event.stopPropagation();
+                }
+
+                // Handle a global trigger
+                if ( !elem ) {
+                        // TODO: Stop taunting the data cache; remove global events and always attach to document
+                        jQuery.each( jQuery.cache, function() {
+                                // internalKey variable is just used to make it easier to find
+                                // and potentially change this stuff later; currently it just
+                                // points to jQuery.expando
+                                var internalKey = jQuery.expando,
+                                        internalCache = this[ internalKey ];
+                                if ( internalCache && internalCache.events && internalCache.events[ type ] ) {
+                                        jQuery.event.trigger( event, data, internalCache.handle.elem );
+                                }
+                        });
+                        return;
+                }
+
+                // Don't do events on text and comment nodes
+                if ( elem.nodeType === 3 || elem.nodeType === 8 ) {
+                        return;
+                }
+
+                // Clean up the event in case it is being reused
+                event.result = undefined;
+                event.target = elem;
+
+                // Clone any incoming data and prepend the event, creating the handler arg list
+                data = data != null ? jQuery.makeArray( data ) : [];
+                data.unshift( event );
+
+                var cur = elem,
+                        // IE doesn't like method names with a colon (#3533, #8272)
+                        ontype = type.indexOf(":") < 0 ? "on" + type : "";
+
+                // Fire event on the current element, then bubble up the DOM tree
+                do {
+                        var handle = jQuery._data( cur, "handle" );
+
+                        event.currentTarget = cur;
+                        if ( handle ) {
+                                handle.apply( cur, data );
+                        }
+
+                        // Trigger an inline bound script
+                        if ( ontype && jQuery.acceptData( cur ) && cur[ ontype ] && cur[ ontype ].apply( cur, data ) === false ) {
+                                event.result = false;
+                                event.preventDefault();
+                        }
+
+                        // Bubble up to document, then to window
+                        cur = cur.parentNode || cur.ownerDocument || cur === event.target.ownerDocument && window;
+                } while ( cur && !event.isPropagationStopped() );
+
+                // If nobody prevented the default action, do it now
+                if ( !event.isDefaultPrevented() ) {
+                        var old,
+                                special = jQuery.event.special[ type ] || {};
+
+                        if ( (!special._default || special._default.call( elem.ownerDocument, event ) === false) &&
+                                !(type === "click" && jQuery.nodeName( elem, "a" )) && jQuery.acceptData( elem ) ) {
+
+                                // Call a native DOM method on the target with the same name name as the event.
+                                // Can't use an .isFunction)() check here because IE6/7 fails that test.
+                                // IE<9 dies on focus to hidden element (#1486), may want to revisit a try/catch.
+                                try {
+                                        if ( ontype && elem[ type ] ) {
+                                                // Don't re-trigger an onFOO event when we call its FOO() method
+                                                old = elem[ ontype ];
+
+                                                if ( old ) {
+                                                        elem[ ontype ] = null;
+                                                }
+
+                                                jQuery.event.triggered = type;
+                                                elem[ type ]();
+                                        }
+                                } catch ( ieError ) {}
+
+                                if ( old ) {
+                                        elem[ ontype ] = old;
+                                }
+
+                                jQuery.event.triggered = undefined;
+                        }
+                }
+                
+                return event.result;
+        },
+
+        handle: function( event ) {
+                event = jQuery.event.fix( event || window.event );
+                // Snapshot the handlers list since a called handler may add/remove events.
+                var handlers = ((jQuery._data( this, "events" ) || {})[ event.type ] || []).slice(0),
+                        run_all = !event.exclusive && !event.namespace,
+                        args = Array.prototype.slice.call( arguments, 0 );
+
+                // Use the fix-ed Event rather than the (read-only) native event
+                args[0] = event;
+                event.currentTarget = this;
+
+                for ( var j = 0, l = handlers.length; j < l; j++ ) {
+                        var handleObj = handlers[ j ];
+
+                        // Triggered event must 1) be non-exclusive and have no namespace, or
+                        // 2) have namespace(s) a subset or equal to those in the bound event.
+                        if ( run_all || event.namespace_re.test( handleObj.namespace ) ) {
+                                // Pass in a reference to the handler function itself
+                                // So that we can later remove it
+                                event.handler = handleObj.handler;
+                                event.data = handleObj.data;
+                                event.handleObj = handleObj;
+
+                                var ret = handleObj.handler.apply( this, args );
+
+                                if ( ret !== undefined ) {
+                                        event.result = ret;
+                                        if ( ret === false ) {
+                                                event.preventDefault();
+                                                event.stopPropagation();
+                                        }
+                                }
+
+                                if ( event.isImmediatePropagationStopped() ) {
+                                        break;
+                                }
+                        }
+                }
+                return event.result;
+        },
+
+        props: "altKey attrChange attrName bubbles button cancelable charCode clientX clientY ctrlKey currentTarget data detail eventPhase fromElement handler keyCode layerX layerY metaKey newValue offsetX offsetY pageX pageY prevValue relatedNode relatedTarget screenX screenY shiftKey srcElement target toElement view wheelDelta which".split(" "),
+
+        fix: function( event ) {
+                if ( event[ jQuery.expando ] ) {
+                        return event;
+                }
+
+                // store a copy of the original event object
+                // and "clone" to set read-only properties
+                var originalEvent = event;
+                event = jQuery.Event( originalEvent );
+
+                for ( var i = this.props.length, prop; i; ) {
+                        prop = this.props[ --i ];
+                        event[ prop ] = originalEvent[ prop ];
+                }
+
+                // Fix target property, if necessary
+                if ( !event.target ) {
+                        // Fixes #1925 where srcElement might not be defined either
+                        event.target = event.srcElement || document;
+                }
+
+                // check if target is a textnode (safari)
+                if ( event.target.nodeType === 3 ) {
+                        event.target = event.target.parentNode;
+                }
+
+                // Add relatedTarget, if necessary
+                if ( !event.relatedTarget && event.fromElement ) {
+                        event.relatedTarget = event.fromElement === event.target ? event.toElement : event.fromElement;
+                }
+
+                // Calculate pageX/Y if missing and clientX/Y available
+                if ( event.pageX == null && event.clientX != null ) {
+                        var eventDocument = event.target.ownerDocument || document,
+                                doc = eventDocument.documentElement,
+                                body = eventDocument.body;
+
+                        event.pageX = event.clientX + (doc && doc.scrollLeft || body && body.scrollLeft || 0) - (doc && doc.clientLeft || body && body.clientLeft || 0);
+                        event.pageY = event.clientY + (doc && doc.scrollTop  || body && body.scrollTop  || 0) - (doc && doc.clientTop  || body && body.clientTop  || 0);
+                }
+
+                // Add which for key events
+                if ( event.which == null && (event.charCode != null || event.keyCode != null) ) {
+                        event.which = event.charCode != null ? event.charCode : event.keyCode;
+                }
+
+                // Add metaKey to non-Mac browsers (use ctrl for PC's and Meta for Macs)
+                if ( !event.metaKey && event.ctrlKey ) {
+                        event.metaKey = event.ctrlKey;
+                }
+
+                // Add which for click: 1 === left; 2 === middle; 3 === right
+                // Note: button is not normalized, so don't use it
+                if ( !event.which && event.button !== undefined ) {
+                        event.which = (event.button & 1 ? 1 : ( event.button & 2 ? 3 : ( event.button & 4 ? 2 : 0 ) ));
+                }
+
+                return event;
+        },
+
+        // Deprecated, use jQuery.guid instead
+        guid: 1E8,
+
+        // Deprecated, use jQuery.proxy instead
+        proxy: jQuery.proxy,
+
+        special: {
+                ready: {
+                        // Make sure the ready event is setup
+                        setup: jQuery.bindReady,
+                        teardown: jQuery.noop
+                },
+
+                live: {
+                        add: function( handleObj ) {
+                                jQuery.event.add( this,
+                                        liveConvert( handleObj.origType, handleObj.selector ),
+                                        jQuery.extend({}, handleObj, {handler: liveHandler, guid: handleObj.handler.guid}) );
+                        },
+
+                        remove: function( handleObj ) {
+                                jQuery.event.remove( this, liveConvert( handleObj.origType, handleObj.selector ), handleObj );
+                        }
+                },
+
+                beforeunload: {
+                        setup: function( data, namespaces, eventHandle ) {
+                                // We only want to do this special case on windows
+                                if ( jQuery.isWindow( this ) ) {
+                                        this.onbeforeunload = eventHandle;
+                                }
+                        },
+
+                        teardown: function( namespaces, eventHandle ) {
+                                if ( this.onbeforeunload === eventHandle ) {
+                                        this.onbeforeunload = null;
+                                }
+                        }
+                }
+        }
+};
+
+jQuery.removeEvent = document.removeEventListener ?
+        function( elem, type, handle ) {
+                if ( elem.removeEventListener ) {
+                        elem.removeEventListener( type, handle, false );
+                }
+        } :
+        function( elem, type, handle ) {
+                if ( elem.detachEvent ) {
+                        elem.detachEvent( "on" + type, handle );
+                }
+        };
+
+jQuery.Event = function( src, props ) {
+        // Allow instantiation without the 'new' keyword
+        if ( !this.preventDefault ) {
+                return new jQuery.Event( src, props );
+        }
+
+        // Event object
+        if ( src && src.type ) {
+                this.originalEvent = src;
+                this.type = src.type;
+
+                // Events bubbling up the document may have been marked as prevented
+                // by a handler lower down the tree; reflect the correct value.
+                this.isDefaultPrevented = (src.defaultPrevented || src.returnValue === false ||
+                        src.getPreventDefault && src.getPreventDefault()) ? returnTrue : returnFalse;
+
+        // Event type
+        } else {
+                this.type = src;
+        }
+
+        // Put explicitly provided properties onto the event object
+        if ( props ) {
+                jQuery.extend( this, props );
+        }
+
+        // timeStamp is buggy for some events on Firefox(#3843)
+        // So we won't rely on the native value
+        this.timeStamp = jQuery.now();
+
+        // Mark it as fixed
+        this[ jQuery.expando ] = true;
+};
+
+function returnFalse() {
+        return false;
+}
+function returnTrue() {
+        return true;
+}
+
+// jQuery.Event is based on DOM3 Events as specified by the ECMAScript Language Binding
+// http://www.w3.org/TR/2003/WD-DOM-Level-3-Events-20030331/ecma-script-binding.html
+jQuery.Event.prototype = {
+        preventDefault: function() {
+                this.isDefaultPrevented = returnTrue;
+
+                var e = this.originalEvent;
+                if ( !e ) {
+                        return;
+                }
+
+                // if preventDefault exists run it on the original event
+                if ( e.preventDefault ) {
+                        e.preventDefault();
+
+                // otherwise set the returnValue property of the original event to false (IE)
+                } else {
+                        e.returnValue = false;
+                }
+        },
+        stopPropagation: function() {
+                this.isPropagationStopped = returnTrue;
+
+                var e = this.originalEvent;
+                if ( !e ) {
+                        return;
+                }
+                // if stopPropagation exists run it on the original event
+                if ( e.stopPropagation ) {
+                        e.stopPropagation();
+                }
+                // otherwise set the cancelBubble property of the original event to true (IE)
+                e.cancelBubble = true;
+        },
+        stopImmediatePropagation: function() {
+                this.isImmediatePropagationStopped = returnTrue;
+                this.stopPropagation();
+        },
+        isDefaultPrevented: returnFalse,
+        isPropagationStopped: returnFalse,
+        isImmediatePropagationStopped: returnFalse
+};
+
+// Checks if an event happened on an element within another element
+// Used in jQuery.event.special.mouseenter and mouseleave handlers
+var withinElement = function( event ) {
+
+        // Check if mouse(over|out) are still within the same parent element
+        var related = event.relatedTarget,
+                inside = false,
+                eventType = event.type;
+
+        event.type = event.data;
+
+        if ( related !== this ) {
+
+                if ( related ) {
+                        inside = jQuery.contains( this, related );
+                }
+
+                if ( !inside ) {
+
+                        jQuery.event.handle.apply( this, arguments );
+
+                        event.type = eventType;
+                }
+        }
+},
+
+// In case of event delegation, we only need to rename the event.type,
+// liveHandler will take care of the rest.
+delegate = function( event ) {
+        event.type = event.data;
+        jQuery.event.handle.apply( this, arguments );
+};
+
+// Create mouseenter and mouseleave events
+jQuery.each({
+        mouseenter: "mouseover",
+        mouseleave: "mouseout"
+}, function( orig, fix ) {
+        jQuery.event.special[ orig ] = {
+                setup: function( data ) {
+                        jQuery.event.add( this, fix, data && data.selector ? delegate : withinElement, orig );
+                },
+                teardown: function( data ) {
+                        jQuery.event.remove( this, fix, data && data.selector ? delegate : withinElement );
+                }
+        };
+});
+
+// submit delegation
+if ( !jQuery.support.submitBubbles ) {
+
+        jQuery.event.special.submit = {
+                setup: function( data, namespaces ) {
+                        if ( !jQuery.nodeName( this, "form" ) ) {
+                                jQuery.event.add(this, "click.specialSubmit", function( e ) {
+                                        // Avoid triggering error on non-existent type attribute in IE VML (#7071)
+                                        var elem = e.target,
+                                                type = jQuery.nodeName( elem, "input" ) || jQuery.nodeName( elem, "button" ) ? elem.type : "";
+
+                                        if ( (type === "submit" || type === "image") && jQuery( elem ).closest("form").length ) {
+                                                trigger( "submit", this, arguments );
+                                        }
+                                });
+
+                                jQuery.event.add(this, "keypress.specialSubmit", function( e ) {
+                                        var elem = e.target,
+                                                type = jQuery.nodeName( elem, "input" ) || jQuery.nodeName( elem, "button" ) ? elem.type : "";
+
+                                        if ( (type === "text" || type === "password") && jQuery( elem ).closest("form").length && e.keyCode === 13 ) {
+                                                trigger( "submit", this, arguments );
+                                        }
+                                });
+
+                        } else {
+                                return false;
+                        }
+                },
+
+                teardown: function( namespaces ) {
+                        jQuery.event.remove( this, ".specialSubmit" );
+                }
+        };
+
+}
+
+// change delegation, happens here so we have bind.
+if ( !jQuery.support.changeBubbles ) {
+
+        var changeFilters,
+
+        getVal = function( elem ) {
+                var type = jQuery.nodeName( elem, "input" ) ? elem.type : "",
+                        val = elem.value;
+
+                if ( type === "radio" || type === "checkbox" ) {
+                        val = elem.checked;
+
+                } else if ( type === "select-multiple" ) {
+                        val = elem.selectedIndex > -1 ?
+                                jQuery.map( elem.options, function( elem ) {
+                                        return elem.selected;
+                                }).join("-") :
+                                "";
+
+                } else if ( jQuery.nodeName( elem, "select" ) ) {
+                        val = elem.selectedIndex;
+                }
+
+                return val;
+        },
+
+        testChange = function testChange( e ) {
+                var elem = e.target, data, val;
+
+                if ( !rformElems.test( elem.nodeName ) || elem.readOnly ) {
+                        return;
+                }
+
+                data = jQuery._data( elem, "_change_data" );
+                val = getVal(elem);
+
+                // the current data will be also retrieved by beforeactivate
+                if ( e.type !== "focusout" || elem.type !== "radio" ) {
+                        jQuery._data( elem, "_change_data", val );
+                }
+
+                if ( data === undefined || val === data ) {
+                        return;
+                }
+
+                if ( data != null || val ) {
+                        e.type = "change";
+                        e.liveFired = undefined;
+                        jQuery.event.trigger( e, arguments[1], elem );
+                }
+        };
+
+        jQuery.event.special.change = {
+                filters: {
+                        focusout: testChange,
+
+                        beforedeactivate: testChange,
+
+                        click: function( e ) {
+                                var elem = e.target, type = jQuery.nodeName( elem, "input" ) ? elem.type : "";
+
+                                if ( type === "radio" || type === "checkbox" || jQuery.nodeName( elem, "select" ) ) {
+                                        testChange.call( this, e );
+                                }
+                        },
+
+                        // Change has to be called before submit
+                        // Keydown will be called before keypress, which is used in submit-event delegation
+                        keydown: function( e ) {
+                                var elem = e.target, type = jQuery.nodeName( elem, "input" ) ? elem.type : "";
+
+                                if ( (e.keyCode === 13 && !jQuery.nodeName( elem, "textarea" ) ) ||
+                                        (e.keyCode === 32 && (type === "checkbox" || type === "radio")) ||
+                                        type === "select-multiple" ) {
+                                        testChange.call( this, e );
+                                }
+                        },
+
+                        // Beforeactivate happens also before the previous element is blurred
+                        // with this event you can't trigger a change event, but you can store
+                        // information
+                        beforeactivate: function( e ) {
+                                var elem = e.target;
+                                jQuery._data( elem, "_change_data", getVal(elem) );
+                        }
+                },
+
+                setup: function( data, namespaces ) {
+                        if ( this.type === "file" ) {
+                                return false;
+                        }
+
+                        for ( var type in changeFilters ) {
+                                jQuery.event.add( this, type + ".specialChange", changeFilters[type] );
+                        }
+
+                        return rformElems.test( this.nodeName );
+                },
+
+                teardown: function( namespaces ) {
+                        jQuery.event.remove( this, ".specialChange" );
+
+                        return rformElems.test( this.nodeName );
+                }
+        };
+
+        changeFilters = jQuery.event.special.change.filters;
+
+        // Handle when the input is .focus()'d
+        changeFilters.focus = changeFilters.beforeactivate;
+}
+
+function trigger( type, elem, args ) {
+        // Piggyback on a donor event to simulate a different one.
+        // Fake originalEvent to avoid donor's stopPropagation, but if the
+        // simulated event prevents default then we do the same on the donor.
+        // Don't pass args or remember liveFired; they apply to the donor event.
+        var event = jQuery.extend( {}, args[ 0 ] );
+        event.type = type;
+        event.originalEvent = {};
+        event.liveFired = undefined;
+        jQuery.event.handle.call( elem, event );
+        if ( event.isDefaultPrevented() ) {
+                args[ 0 ].preventDefault();
+        }
+}
+
+// Create "bubbling" focus and blur events
+if ( !jQuery.support.focusinBubbles ) {
+        jQuery.each({ focus: "focusin", blur: "focusout" }, function( orig, fix ) {
+
+                // Attach a single capturing handler while someone wants focusin/focusout
+                var attaches = 0;
+
+                jQuery.event.special[ fix ] = {
+                        setup: function() {
+                                if ( attaches++ === 0 ) {
+                                        document.addEventListener( orig, handler, true );
+                                }
+                        },
+                        teardown: function() {
+                                if ( --attaches === 0 ) {
+                                        document.removeEventListener( orig, handler, true );
+                                }
+                        }
+                };
+
+                function handler( donor ) {
+                        // Donor event is always a native one; fix it and switch its type.
+                        // Let focusin/out handler cancel the donor focus/blur event.
+                        var e = jQuery.event.fix( donor );
+                        e.type = fix;
+                        e.originalEvent = {};
+                        jQuery.event.trigger( e, null, e.target );
+                        if ( e.isDefaultPrevented() ) {
+                                donor.preventDefault();
+                        }
+                }
+        });
+}
+
+jQuery.each(["bind", "one"], function( i, name ) {
+        jQuery.fn[ name ] = function( type, data, fn ) {
+                var handler;
+
+                // Handle object literals
+                if ( typeof type === "object" ) {
+                        for ( var key in type ) {
+                                this[ name ](key, data, type[key], fn);
+                        }
+                        return this;
+                }
+
+                if ( arguments.length === 2 || data === false ) {
+                        fn = data;
+                        data = undefined;
+                }
+
+                if ( name === "one" ) {
+                        handler = function( event ) {
+                                jQuery( this ).unbind( event, handler );
+                                return fn.apply( this, arguments );
+                        };
+                        handler.guid = fn.guid || jQuery.guid++;
+                } else {
+                        handler = fn;
+                }
+
+                if ( type === "unload" && name !== "one" ) {
+                        this.one( type, data, fn );
+
+                } else {
+                        for ( var i = 0, l = this.length; i < l; i++ ) {
+                                jQuery.event.add( this[i], type, handler, data );
+                        }
+                }
+
+                return this;
+        };
+});
+
+jQuery.fn.extend({
+        unbind: function( type, fn ) {
+                // Handle object literals
+                if ( typeof type === "object" && !type.preventDefault ) {
+                        for ( var key in type ) {
+                                this.unbind(key, type[key]);
+                        }
+
+                } else {
+                        for ( var i = 0, l = this.length; i < l; i++ ) {
+                                jQuery.event.remove( this[i], type, fn );
+                        }
+                }
+
+                return this;
+        },
+
+        delegate: function( selector, types, data, fn ) {
+                return this.live( types, data, fn, selector );
+        },
+
+        undelegate: function( selector, types, fn ) {
+                if ( arguments.length === 0 ) {
+                        return this.unbind( "live" );
+
+                } else {
+                        return this.die( types, null, fn, selector );
+                }
+        },
+
+        trigger: function( type, data ) {
+                return this.each(function() {
+                        jQuery.event.trigger( type, data, this );
+                });
+        },
+
+        triggerHandler: function( type, data ) {
+                if ( this[0] ) {
+                        return jQuery.event.trigger( type, data, this[0], true );
+                }
+        },
+
+        toggle: function( fn ) {
+                // Save reference to arguments for access in closure
+                var args = arguments,
+                        guid = fn.guid || jQuery.guid++,
+                        i = 0,
+                        toggler = function( event ) {
+                                // Figure out which function to execute
+                                var lastToggle = ( jQuery.data( this, "lastToggle" + fn.guid ) || 0 ) % i;
+                                jQuery.data( this, "lastToggle" + fn.guid, lastToggle + 1 );
+
+                                // Make sure that clicks stop
+                                event.preventDefault();
+
+                                // and execute the function
+                                return args[ lastToggle ].apply( this, arguments ) || false;
+                        };
+
+                // link all the functions, so any of them can unbind this click handler
+                toggler.guid = guid;
+                while ( i < args.length ) {
+                        args[ i++ ].guid = guid;
+                }
+
+                return this.click( toggler );
+        },
+
+        hover: function( fnOver, fnOut ) {
+                return this.mouseenter( fnOver ).mouseleave( fnOut || fnOver );
+        }
+});
+
+var liveMap = {
+        focus: "focusin",
+        blur: "focusout",
+        mouseenter: "mouseover",
+        mouseleave: "mouseout"
+};
+
+jQuery.each(["live", "die"], function( i, name ) {
+        jQuery.fn[ name ] = function( types, data, fn, origSelector /* Internal Use Only */ ) {
+                var type, i = 0, match, namespaces, preType,
+                        selector = origSelector || this.selector,
+                        context = origSelector ? this : jQuery( this.context );
+
+                if ( typeof types === "object" && !types.preventDefault ) {
+                        for ( var key in types ) {
+                                context[ name ]( key, data, types[key], selector );
+                        }
+
+                        return this;
+                }
+
+                if ( name === "die" && !types &&
+                                        origSelector && origSelector.charAt(0) === "." ) {
+
+                        context.unbind( origSelector );
+
+                        return this;
+                }
+
+                if ( data === false || jQuery.isFunction( data ) ) {
+                        fn = data || returnFalse;
+                        data = undefined;
+                }
+
+                types = (types || "").split(" ");
+
+                while ( (type = types[ i++ ]) != null ) {
+                        match = rnamespaces.exec( type );
+                        namespaces = "";
+
+                        if ( match )  {
+                                namespaces = match[0];
+                                type = type.replace( rnamespaces, "" );
+                        }
+
+                        if ( type === "hover" ) {
+                                types.push( "mouseenter" + namespaces, "mouseleave" + namespaces );
+                                continue;
+                        }
+
+                        preType = type;
+
+                        if ( liveMap[ type ] ) {
+                                types.push( liveMap[ type ] + namespaces );
+                                type = type + namespaces;
+
+                        } else {
+                                type = (liveMap[ type ] || type) + namespaces;
+                        }
+
+                        if ( name === "live" ) {
+                                // bind live handler
+                                for ( var j = 0, l = context.length; j < l; j++ ) {
+                                        jQuery.event.add( context[j], "live." + liveConvert( type, selector ),
+                                                { data: data, selector: selector, handler: fn, origType: type, origHandler: fn, preType: preType } );
+                                }
+
+                        } else {
+                                // unbind live handler
+                                context.unbind( "live." + liveConvert( type, selector ), fn );
+                        }
+                }
+
+                return this;
+        };
+});
+
+function liveHandler( event ) {
+        var stop, maxLevel, related, match, handleObj, elem, j, i, l, data, close, namespace, ret,
+                elems = [],
+                selectors = [],
+                events = jQuery._data( this, "events" );
+
+        // Make sure we avoid non-left-click bubbling in Firefox (#3861) and disabled elements in IE (#6911)
+        if ( event.liveFired === this || !events || !events.live || event.target.disabled || event.button && event.type === "click" ) {
+                return;
+        }
+
+        if ( event.namespace ) {
+                namespace = new RegExp("(^|\\.)" + event.namespace.split(".").join("\\.(?:.*\\.)?") + "(\\.|$)");
+        }
+
+        event.liveFired = this;
+
+        var live = events.live.slice(0);
+
+        for ( j = 0; j < live.length; j++ ) {
+                handleObj = live[j];
+
+                if ( handleObj.origType.replace( rnamespaces, "" ) === event.type ) {
+                        selectors.push( handleObj.selector );
+
+                } else {
+                        live.splice( j--, 1 );
+                }
+        }
+
+        match = jQuery( event.target ).closest( selectors, event.currentTarget );
+
+        for ( i = 0, l = match.length; i < l; i++ ) {
+                close = match[i];
+
+                for ( j = 0; j < live.length; j++ ) {
+                        handleObj = live[j];
+
+                        if ( close.selector === handleObj.selector && (!namespace || namespace.test( handleObj.namespace )) && !close.elem.disabled ) {
+                                elem = close.elem;
+                                related = null;
+
+                                // Those two events require additional checking
+                                if ( handleObj.preType === "mouseenter" || handleObj.preType === "mouseleave" ) {
+                                        event.type = handleObj.preType;
+                                        related = jQuery( event.relatedTarget ).closest( handleObj.selector )[0];
+
+                                        // Make sure not to accidentally match a child element with the same selector
+                                        if ( related && jQuery.contains( elem, related ) ) {
+                                                related = elem;
+                                        }
+                                }
+
+                                if ( !related || related !== elem ) {
+                                        elems.push({ elem: elem, handleObj: handleObj, level: close.level });
+                                }
+                        }
+                }
+        }
+
+        for ( i = 0, l = elems.length; i < l; i++ ) {
+                match = elems[i];
+
+                if ( maxLevel && match.level > maxLevel ) {
+                        break;
+                }
+
+                event.currentTarget = match.elem;
+                event.data = match.handleObj.data;
+                event.handleObj = match.handleObj;
+
+                ret = match.handleObj.origHandler.apply( match.elem, arguments );
+
+                if ( ret === false || event.isPropagationStopped() ) {
+                        maxLevel = match.level;
+
+                        if ( ret === false ) {
+                                stop = false;
+                        }
+                        if ( event.isImmediatePropagationStopped() ) {
+                                break;
+                        }
+                }
+        }
+
+        return stop;
+}
+
+function liveConvert( type, selector ) {
+        return (type && type !== "*" ? type + "." : "") + selector.replace(rperiod, "`").replace(rspaces, "&");
+}
+
+jQuery.each( ("blur focus focusin focusout load resize scroll unload click dblclick " +
+        "mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave " +
+        "change select submit keydown keypress keyup error").split(" "), function( i, name ) {
+
+        // Handle event binding
+        jQuery.fn[ name ] = function( data, fn ) {
+                if ( fn == null ) {
+                        fn = data;
+                        data = null;
+                }
+
+                return arguments.length > 0 ?
+                        this.bind( name, data, fn ) :
+                        this.trigger( name );
+        };
+
+        if ( jQuery.attrFn ) {
+                jQuery.attrFn[ name ] = true;
+        }
+});
+
+
+
+/*!
+ * Sizzle CSS Selector Engine
+ *  Copyright 2011, The Dojo Foundation
+ *  Released under the MIT, BSD, and GPL Licenses.
+ *  More information: http://sizzlejs.com/
+ */
+(function(){
+
+var chunker = /((?:\((?:\([^()]+\)|[^()]+)+\)|\[(?:\[[^\[\]]*\]|['"][^'"]*['"]|[^\[\]'"]+)+\]|\\.|[^ >+~,(\[\\]+)+|[>+~])(\s*,\s*)?((?:.|\r|\n)*)/g,
+        done = 0,
+        toString = Object.prototype.toString,
+        hasDuplicate = false,
+        baseHasDuplicate = true,
+        rBackslash = /\\/g,
+        rNonWord = /\W/;
+
+// Here we check if the JavaScript engine is using some sort of
+// optimization where it does not always call our comparision
+// function. If that is the case, discard the hasDuplicate value.
+//   Thus far that includes Google Chrome.
+[0, 0].sort(function() {
+        baseHasDuplicate = false;
+        return 0;
+});
+
+var Sizzle = function( selector, context, results, seed ) {
+        results = results || [];
+        context = context || document;
+
+        var origContext = context;
+
+        if ( context.nodeType !== 1 && context.nodeType !== 9 ) {
+                return [];
+        }
+        
+        if ( !selector || typeof selector !== "string" ) {
+                return results;
+        }
+
+        var m, set, checkSet, extra, ret, cur, pop, i,
+                prune = true,
+                contextXML = Sizzle.isXML( context ),
+                parts = [],
+                soFar = selector;
+        
+        // Reset the position of the chunker regexp (start from head)
+        do {
+                chunker.exec( "" );
+                m = chunker.exec( soFar );
+
+                if ( m ) {
+                        soFar = m[3];
+                
+                        parts.push( m[1] );
+                
+                        if ( m[2] ) {
+                                extra = m[3];
+                                break;
+                        }
+                }
+        } while ( m );
+
+        if ( parts.length > 1 && origPOS.exec( selector ) ) {
+
+                if ( parts.length === 2 && Expr.relative[ parts[0] ] ) {
+                        set = posProcess( parts[0] + parts[1], context );
+
+                } else {
+                        set = Expr.relative[ parts[0] ] ?
+                                [ context ] :
+                                Sizzle( parts.shift(), context );
+
+                        while ( parts.length ) {
+                                selector = parts.shift();
+
+                                if ( Expr.relative[ selector ] ) {
+                                        selector += parts.shift();
+                                }
+                                
+                                set = posProcess( selector, set );
+                        }
+                }
+
+        } else {
+                // Take a shortcut and set the context if the root selector is an ID
+                // (but not if it'll be faster if the inner selector is an ID)
+                if ( !seed && parts.length > 1 && context.nodeType === 9 && !contextXML &&
+                                Expr.match.ID.test(parts[0]) && !Expr.match.ID.test(parts[parts.length - 1]) ) {
+
+                        ret = Sizzle.find( parts.shift(), context, contextXML );
+                        context = ret.expr ?
+                                Sizzle.filter( ret.expr, ret.set )[0] :
+                                ret.set[0];
+                }
+
+                if ( context ) {
+                        ret = seed ?
+                                { expr: parts.pop(), set: makeArray(seed) } :
+                                Sizzle.find( parts.pop(), parts.length === 1 && (parts[0] === "~" || parts[0] === "+") && context.parentNode ? context.parentNode : context, contextXML );
+
+                        set = ret.expr ?
+                                Sizzle.filter( ret.expr, ret.set ) :
+                                ret.set;
+
+                        if ( parts.length > 0 ) {
+                                checkSet = makeArray( set );
+
+                        } else {
+                                prune = false;
+                        }
+
+                        while ( parts.length ) {
+                                cur = parts.pop();
+                                pop = cur;
+
+                                if ( !Expr.relative[ cur ] ) {
+                                        cur = "";
+                                } else {
+                                        pop = parts.pop();
+                                }
+
+                                if ( pop == null ) {
+                                        pop = context;
+                                }
+
+                                Expr.relative[ cur ]( checkSet, pop, contextXML );
+                        }
+
+                } else {
+                        checkSet = parts = [];
+                }
+        }
+
+        if ( !checkSet ) {
+                checkSet = set;
+        }
+
+        if ( !checkSet ) {
+                Sizzle.error( cur || selector );
+        }
+
+        if ( toString.call(checkSet) === "[object Array]" ) {
+                if ( !prune ) {
+                        results.push.apply( results, checkSet );
+
+                } else if ( context && context.nodeType === 1 ) {
+                        for ( i = 0; checkSet[i] != null; i++ ) {
+                                if ( checkSet[i] && (checkSet[i] === true || checkSet[i].nodeType === 1 && Sizzle.contains(context, checkSet[i])) ) {
+                                        results.push( set[i] );
+                                }
+                        }
+
+                } else {
+                        for ( i = 0; checkSet[i] != null; i++ ) {
+                                if ( checkSet[i] && checkSet[i].nodeType === 1 ) {
+                                        results.push( set[i] );
+                                }
+                        }
+                }
+
+        } else {
+                makeArray( checkSet, results );
+        }
+
+        if ( extra ) {
+                Sizzle( extra, origContext, results, seed );
+                Sizzle.uniqueSort( results );
+        }
+
+        return results;
+};
+
+Sizzle.uniqueSort = function( results ) {
+        if ( sortOrder ) {
+                hasDuplicate = baseHasDuplicate;
+                results.sort( sortOrder );
+
+                if ( hasDuplicate ) {
+                        for ( var i = 1; i < results.length; i++ ) {
+                                if ( results[i] === results[ i - 1 ] ) {
+                                        results.splice( i--, 1 );
+                                }
+                        }
+                }
+        }
+
+        return results;
+};
+
+Sizzle.matches = function( expr, set ) {
+        return Sizzle( expr, null, null, set );
+};
+
+Sizzle.matchesSelector = function( node, expr ) {
+        return Sizzle( expr, null, null, [node] ).length > 0;
+};
+
+Sizzle.find = function( expr, context, isXML ) {
+        var set;
+
+        if ( !expr ) {
+                return [];
+        }
+
+        for ( var i = 0, l = Expr.order.length; i < l; i++ ) {
+                var match,
+                        type = Expr.order[i];
+                
+                if ( (match = Expr.leftMatch[ type ].exec( expr )) ) {
+                        var left = match[1];
+                        match.splice( 1, 1 );
+
+                        if ( left.substr( left.length - 1 ) !== "\\" ) {
+                                match[1] = (match[1] || "").replace( rBackslash, "" );
+                                set = Expr.find[ type ]( match, context, isXML );
+
+                                if ( set != null ) {
+                                        expr = expr.replace( Expr.match[ type ], "" );
+                                        break;
+                                }
+                        }
+                }
+        }
+
+        if ( !set ) {
+                set = typeof context.getElementsByTagName !== "undefined" ?
+                        context.getElementsByTagName( "*" ) :
+                        [];
+        }
+
+        return { set: set, expr: expr };
+};
+
+Sizzle.filter = function( expr, set, inplace, not ) {
+        var match, anyFound,
+                old = expr,
+                result = [],
+                curLoop = set,
+                isXMLFilter = set && set[0] && Sizzle.isXML( set[0] );
+
+        while ( expr && set.length ) {
+                for ( var type in Expr.filter ) {
+                        if ( (match = Expr.leftMatch[ type ].exec( expr )) != null && match[2] ) {
+                                var found, item,
+                                        filter = Expr.filter[ type ],
+                                        left = match[1];
+
+                                anyFound = false;
+
+                                match.splice(1,1);
+
+                                if ( left.substr( left.length - 1 ) === "\\" ) {
+                                        continue;
+                                }
+
+                                if ( curLoop === result ) {
+                                        result = [];
+                                }
+
+                                if ( Expr.preFilter[ type ] ) {
+                                        match = Expr.preFilter[ type ]( match, curLoop, inplace, result, not, isXMLFilter );
+
+                                        if ( !match ) {
+                                                anyFound = found = true;
+
+                                        } else if ( match === true ) {
+                                                continue;
+                                        }
+                                }
+
+                                if ( match ) {
+                                        for ( var i = 0; (item = curLoop[i]) != null; i++ ) {
+                                                if ( item ) {
+                                                        found = filter( item, match, i, curLoop );
+                                                        var pass = not ^ !!found;
+
+                                                        if ( inplace && found != null ) {
+                                                                if ( pass ) {
+                                                                        anyFound = true;
+
+                                                                } else {
+                                                                        curLoop[i] = false;
+                                                                }
+
+                                                        } else if ( pass ) {
+                                                                result.push( item );
+                                                                anyFound = true;
+                                                        }
+                                                }
+                                        }
+                                }
+
+                                if ( found !== undefined ) {
+                                        if ( !inplace ) {
+                                                curLoop = result;
+                                        }
+
+                                        expr = expr.replace( Expr.match[ type ], "" );
+
+                                        if ( !anyFound ) {
+                                                return [];
+                                        }
+
+                                        break;
+                                }
+                        }
+                }
+
+                // Improper expression
+                if ( expr === old ) {
+                        if ( anyFound == null ) {
+                                Sizzle.error( expr );
+
+                        } else {
+                                break;
+                        }
+                }
+
+                old = expr;
+        }
+
+        return curLoop;
+};
+
+Sizzle.error = function( msg ) {
+        throw "Syntax error, unrecognized expression: " + msg;
+};
+
+var Expr = Sizzle.selectors = {
+        order: [ "ID", "NAME", "TAG" ],
+
+        match: {
+                ID: /#((?:[\w\u00c0-\uFFFF\-]|\\.)+)/,
+                CLASS: /\.((?:[\w\u00c0-\uFFFF\-]|\\.)+)/,
+                NAME: /\[name=['"]*((?:[\w\u00c0-\uFFFF\-]|\\.)+)['"]*\]/,
+                ATTR: /\[\s*((?:[\w\u00c0-\uFFFF\-]|\\.)+)\s*(?:(\S?=)\s*(?:(['"])(.*?)\3|(#?(?:[\w\u00c0-\uFFFF\-]|\\.)*)|)|)\s*\]/,
+                TAG: /^((?:[\w\u00c0-\uFFFF\*\-]|\\.)+)/,
+                CHILD: /:(only|nth|last|first)-child(?:\(\s*(even|odd|(?:[+\-]?\d+|(?:[+\-]?\d*)?n\s*(?:[+\-]\s*\d+)?))\s*\))?/,
+                POS: /:(nth|eq|gt|lt|first|last|even|odd)(?:\((\d*)\))?(?=[^\-]|$)/,
+                PSEUDO: /:((?:[\w\u00c0-\uFFFF\-]|\\.)+)(?:\((['"]?)((?:\([^\)]+\)|[^\(\)]*)+)\2\))?/
+        },
+
+        leftMatch: {},
+
+        attrMap: {
+                "class": "className",
+                "for": "htmlFor"
+        },
+
+        attrHandle: {
+                href: function( elem ) {
+                        return elem.getAttribute( "href" );
+                },
+                type: function( elem ) {
+                        return elem.getAttribute( "type" );
+                }
+        },
+
+        relative: {
+                "+": function(checkSet, part){
+                        var isPartStr = typeof part === "string",
+                                isTag = isPartStr && !rNonWord.test( part ),
+                                isPartStrNotTag = isPartStr && !isTag;
+
+                        if ( isTag ) {
+                                part = part.toLowerCase();
+                        }
+
+                        for ( var i = 0, l = checkSet.length, elem; i < l; i++ ) {
+                                if ( (elem = checkSet[i]) ) {
+                                        while ( (elem = elem.previousSibling) && elem.nodeType !== 1 ) {}
+
+                                        checkSet[i] = isPartStrNotTag || elem && elem.nodeName.toLowerCase() === part ?
+                                                elem || false :
+                                                elem === part;
+                                }
+                        }
+
+                        if ( isPartStrNotTag ) {
+                                Sizzle.filter( part, checkSet, true );
+                        }
+                },
+
+                ">": function( checkSet, part ) {
+                        var elem,
+                                isPartStr = typeof part === "string",
+                                i = 0,
+                                l = checkSet.length;
+
+                        if ( isPartStr && !rNonWord.test( part ) ) {
+                                part = part.toLowerCase();
+
+                                for ( ; i < l; i++ ) {
+                                        elem = checkSet[i];
+
+                                        if ( elem ) {
+                                                var parent = elem.parentNode;
+                                                checkSet[i] = parent.nodeName.toLowerCase() === part ? parent : false;
+                                        }
+                                }
+
+                        } else {
+                                for ( ; i < l; i++ ) {
+                                        elem = checkSet[i];
+
+                                        if ( elem ) {
+                                                checkSet[i] = isPartStr ?
+                                                        elem.parentNode :
+                                                        elem.parentNode === part;
+                                        }
+                                }
+
+                                if ( isPartStr ) {
+                                        Sizzle.filter( part, checkSet, true );
+                                }
+                        }
+                },
+
+                "": function(checkSet, part, isXML){
+                        var nodeCheck,
+                                doneName = done++,
+                                checkFn = dirCheck;
+
+                        if ( typeof part === "string" && !rNonWord.test( part ) ) {
+                                part = part.toLowerCase();
+                                nodeCheck = part;
+                                checkFn = dirNodeCheck;
+                        }
+
+                        checkFn( "parentNode", part, doneName, checkSet, nodeCheck, isXML );
+                },
+
+                "~": function( checkSet, part, isXML ) {
+                        var nodeCheck,
+                                doneName = done++,
+                                checkFn = dirCheck;
+
+                        if ( typeof part === "string" && !rNonWord.test( part ) ) {
+                                part = part.toLowerCase();
+                                nodeCheck = part;
+                                checkFn = dirNodeCheck;
+                        }
+
+                        checkFn( "previousSibling", part, doneName, checkSet, nodeCheck, isXML );
+                }
+        },
+
+        find: {
+                ID: function( match, context, isXML ) {
+                        if ( typeof context.getElementById !== "undefined" && !isXML ) {
+                                var m = context.getElementById(match[1]);
+                                // Check parentNode to catch when Blackberry 4.6 returns
+                                // nodes that are no longer in the document #6963
+                                return m && m.parentNode ? [m] : [];
+                        }
+                },
+
+                NAME: function( match, context ) {
+                        if ( typeof context.getElementsByName !== "undefined" ) {
+                                var ret = [],
+                                        results = context.getElementsByName( match[1] );
+
+                                for ( var i = 0, l = results.length; i < l; i++ ) {
+                                        if ( results[i].getAttribute("name") === match[1] ) {
+                                                ret.push( results[i] );
+                                        }
+                                }
+
+                                return ret.length === 0 ? null : ret;
+                        }
+                },
+
+                TAG: function( match, context ) {
+                        if ( typeof context.getElementsByTagName !== "undefined" ) {
+                                return context.getElementsByTagName( match[1] );
+                        }
+                }
+        },
+        preFilter: {
+                CLASS: function( match, curLoop, inplace, result, not, isXML ) {
+                        match = " " + match[1].replace( rBackslash, "" ) + " ";
+
+                        if ( isXML ) {
+                                return match;
+                        }
+
+                        for ( var i = 0, elem; (elem = curLoop[i]) != null; i++ ) {
+                                if ( elem ) {
+                                        if ( not ^ (elem.className && (" " + elem.className + " ").replace(/[\t\n\r]/g, " ").indexOf(match) >= 0) ) {
+                                                if ( !inplace ) {
+                                                        result.push( elem );
+                                                }
+
+                                        } else if ( inplace ) {
+                                                curLoop[i] = false;
+                                        }
+                                }
+                        }
+
+                        return false;
+                },
+
+                ID: function( match ) {
+                        return match[1].replace( rBackslash, "" );
+                },
+
+                TAG: function( match, curLoop ) {
+                        return match[1].replace( rBackslash, "" ).toLowerCase();
+                },
+
+                CHILD: function( match ) {
+                        if ( match[1] === "nth" ) {
+                                if ( !match[2] ) {
+                                        Sizzle.error( match[0] );
+                                }
+
+                                match[2] = match[2].replace(/^\+|\s*/g, '');
+
+                                // parse equations like 'even', 'odd', '5', '2n', '3n+2', '4n-1', '-n+6'
+                                var test = /(-?)(\d*)(?:n([+\-]?\d*))?/.exec(
+                                        match[2] === "even" && "2n" || match[2] === "odd" && "2n+1" ||
+                                        !/\D/.test( match[2] ) && "0n+" + match[2] || match[2]);
+
+                                // calculate the numbers (first)n+(last) including if they are negative
+                                match[2] = (test[1] + (test[2] || 1)) - 0;
+                                match[3] = test[3] - 0;
+                        }
+                        else if ( match[2] ) {
+                                Sizzle.error( match[0] );
+                        }
+
+                        // TODO: Move to normal caching system
+                        match[0] = done++;
+
+                        return match;
+                },
+
+                ATTR: function( match, curLoop, inplace, result, not, isXML ) {
+                        var name = match[1] = match[1].replace( rBackslash, "" );
+                        
+                        if ( !isXML && Expr.attrMap[name] ) {
+                                match[1] = Expr.attrMap[name];
+                        }
+
+                        // Handle if an un-quoted value was used
+                        match[4] = ( match[4] || match[5] || "" ).replace( rBackslash, "" );
+
+                        if ( match[2] === "~=" ) {
+                                match[4] = " " + match[4] + " ";
+                        }
+
+                        return match;
+                },
+
+                PSEUDO: function( match, curLoop, inplace, result, not ) {
+                        if ( match[1] === "not" ) {
+                                // If we're dealing with a complex expression, or a simple one
+                                if ( ( chunker.exec(match[3]) || "" ).length > 1 || /^\w/.test(match[3]) ) {
+                                        match[3] = Sizzle(match[3], null, null, curLoop);
+
+                                } else {
+                                        var ret = Sizzle.filter(match[3], curLoop, inplace, true ^ not);
+
+                                        if ( !inplace ) {
+                                                result.push.apply( result, ret );
+                                        }
+
+                                        return false;
+                                }
+
+                        } else if ( Expr.match.POS.test( match[0] ) || Expr.match.CHILD.test( match[0] ) ) {
+                                return true;
+                        }
+                        
+                        return match;
+                },
+
+                POS: function( match ) {
+                        match.unshift( true );
+
+                        return match;
+                }
+        },
+        
+        filters: {
+                enabled: function( elem ) {
+                        return elem.disabled === false && elem.type !== "hidden";
+                },
+
+                disabled: function( elem ) {
+                        return elem.disabled === true;
+                },
+
+                checked: function( elem ) {
+                        return elem.checked === true;
+                },
+                
+                selected: function( elem ) {
+                        // Accessing this property makes selected-by-default
+                        // options in Safari work properly
+                        if ( elem.parentNode ) {
+                                elem.parentNode.selectedIndex;
+                        }
+                        
+                        return elem.selected === true;
+                },
+
+                parent: function( elem ) {
+                        return !!elem.firstChild;
+                },
+
+                empty: function( elem ) {
+                        return !elem.firstChild;
+                },
+
+                has: function( elem, i, match ) {
+                        return !!Sizzle( match[3], elem ).length;
+                },
+
+                header: function( elem ) {
+                        return (/h\d/i).test( elem.nodeName );
+                },
+
+                text: function( elem ) {
+                        var attr = elem.getAttribute( "type" ), type = elem.type;
+                        // IE6 and 7 will map elem.type to 'text' for new HTML5 types (search, etc) 
+                        // use getAttribute instead to test this case
+                        return elem.nodeName.toLowerCase() === "input" && "text" === type && ( attr === type || attr === null );
+                },
+
+                radio: function( elem ) {
+                        return elem.nodeName.toLowerCase() === "input" && "radio" === elem.type;
+                },
+
+                checkbox: function( elem ) {
+                        return elem.nodeName.toLowerCase() === "input" && "checkbox" === elem.type;
+                },
+
+                file: function( elem ) {
+                        return elem.nodeName.toLowerCase() === "input" && "file" === elem.type;
+                },
+
+                password: function( elem ) {
+                        return elem.nodeName.toLowerCase() === "input" && "password" === elem.type;
+                },
+
+                submit: function( elem ) {
+                        var name = elem.nodeName.toLowerCase();
+                        return (name === "input" || name === "button") && "submit" === elem.type;
+                },
+
+                image: function( elem ) {
+                        return elem.nodeName.toLowerCase() === "input" && "image" === elem.type;
+                },
+
+                reset: function( elem ) {
+                        var name = elem.nodeName.toLowerCase();
+                        return (name === "input" || name === "button") && "reset" === elem.type;
+                },
+
+                button: function( elem ) {
+                        var name = elem.nodeName.toLowerCase();
+                        return name === "input" && "button" === elem.type || name === "button";
+                },
+
+                input: function( elem ) {
+                        return (/input|select|textarea|button/i).test( elem.nodeName );
+                },
+
+                focus: function( elem ) {
+                        return elem === elem.ownerDocument.activeElement;
+                }
+        },
+        setFilters: {
+                first: function( elem, i ) {
+                        return i === 0;
+                },
+
+                last: function( elem, i, match, array ) {
+                        return i === array.length - 1;
+                },
+
+                even: function( elem, i ) {
+                        return i % 2 === 0;
+                },
+
+                odd: function( elem, i ) {
+                        return i % 2 === 1;
+                },
+
+                lt: function( elem, i, match ) {
+                        return i < match[3] - 0;
+                },
+
+                gt: function( elem, i, match ) {
+                        return i > match[3] - 0;
+                },
+
+                nth: function( elem, i, match ) {
+                        return match[3] - 0 === i;
+                },
+
+                eq: function( elem, i, match ) {
+                        return match[3] - 0 === i;
+                }
+        },
+        filter: {
+                PSEUDO: function( elem, match, i, array ) {
+                        var name = match[1],
+                                filter = Expr.filters[ name ];
+
+                        if ( filter ) {
+                                return filter( elem, i, match, array );
+
+                        } else if ( name === "contains" ) {
+                                return (elem.textContent || elem.innerText || Sizzle.getText([ elem ]) || "").indexOf(match[3]) >= 0;
+
+                        } else if ( name === "not" ) {
+                                var not = match[3];
+
+                                for ( var j = 0, l = not.length; j < l; j++ ) {
+                                        if ( not[j] === elem ) {
+                                                return false;
+                                        }
+                                }
+
+                                return true;
+
+                        } else {
+                                Sizzle.error( name );
+                        }
+                },
+
+                CHILD: function( elem, match ) {
+                        var type = match[1],
+                                node = elem;
+
+                        switch ( type ) {
+                                case "only":
+                                case "first":
+                                        while ( (node = node.previousSibling) )  {
+                                                if ( node.nodeType === 1 ) { 
+                                                        return false; 
+                                                }
+                                        }
+
+                                        if ( type === "first" ) { 
+                                                return true; 
+                                        }
+
+                                        node = elem;
+
+                                case "last":
+                                        while ( (node = node.nextSibling) )      {
+                                                if ( node.nodeType === 1 ) { 
+                                                        return false; 
+                                                }
+                                        }
+
+                                        return true;
+
+                                case "nth":
+                                        var first = match[2],
+                                                last = match[3];
+
+                                        if ( first === 1 && last === 0 ) {
+                                                return true;
+                                        }
+                                        
+                                        var doneName = match[0],
+                                                parent = elem.parentNode;
+        
+                                        if ( parent && (parent.sizcache !== doneName || !elem.nodeIndex) ) {
+                                                var count = 0;
+                                                
+                                                for ( node = parent.firstChild; node; node = node.nextSibling ) {
+                                                        if ( node.nodeType === 1 ) {
+                                                                node.nodeIndex = ++count;
+                                                        }
+                                                } 
+
+                                                parent.sizcache = doneName;
+                                        }
+                                        
+                                        var diff = elem.nodeIndex - last;
+
+                                        if ( first === 0 ) {
+                                                return diff === 0;
+
+                                        } else {
+                                                return ( diff % first === 0 && diff / first >= 0 );
+                                        }
+                        }
+                },
+
+                ID: function( elem, match ) {
+                        return elem.nodeType === 1 && elem.getAttribute("id") === match;
+                },
+
+                TAG: function( elem, match ) {
+                        return (match === "*" && elem.nodeType === 1) || elem.nodeName.toLowerCase() === match;
+                },
+                
+                CLASS: function( elem, match ) {
+                        return (" " + (elem.className || elem.getAttribute("class")) + " ")
+                                .indexOf( match ) > -1;
+                },
+
+                ATTR: function( elem, match ) {
+                        var name = match[1],
+                                result = Expr.attrHandle[ name ] ?
+                                        Expr.attrHandle[ name ]( elem ) :
+                                        elem[ name ] != null ?
+                                                elem[ name ] :
+                                                elem.getAttribute( name ),
+                                value = result + "",
+                                type = match[2],
+                                check = match[4];
+
+                        return result == null ?
+                                type === "!=" :
+                                type === "=" ?
+                                value === check :
+                                type === "*=" ?
+                                value.indexOf(check) >= 0 :
+                                type === "~=" ?
+                                (" " + value + " ").indexOf(check) >= 0 :
+                                !check ?
+                                value && result !== false :
+                                type === "!=" ?
+                                value !== check :
+                                type === "^=" ?
+                                value.indexOf(check) === 0 :
+                                type === "$=" ?
+                                value.substr(value.length - check.length) === check :
+                                type === "|=" ?
+                                value === check || value.substr(0, check.length + 1) === check + "-" :
+                                false;
+                },
+
+                POS: function( elem, match, i, array ) {
+                        var name = match[2],
+                                filter = Expr.setFilters[ name ];
+
+                        if ( filter ) {
+                                return filter( elem, i, match, array );
+                        }
+                }
+        }
+};
+
+var origPOS = Expr.match.POS,
+        fescape = function(all, num){
+                return "\\" + (num - 0 + 1);
+        };
+
+for ( var type in Expr.match ) {
+        Expr.match[ type ] = new RegExp( Expr.match[ type ].source + (/(?![^\[]*\])(?![^\(]*\))/.source) );
+        Expr.leftMatch[ type ] = new RegExp( /(^(?:.|\r|\n)*?)/.source + Expr.match[ type ].source.replace(/\\(\d+)/g, fescape) );
+}
+
+var makeArray = function( array, results ) {
+        array = Array.prototype.slice.call( array, 0 );
+
+        if ( results ) {
+                results.push.apply( results, array );
+                return results;
+        }
+        
+        return array;
+};
+
+// Perform a simple check to determine if the browser is capable of
+// converting a NodeList to an array using builtin methods.
+// Also verifies that the returned array holds DOM nodes
+// (which is not the case in the Blackberry browser)
+try {
+        Array.prototype.slice.call( document.documentElement.childNodes, 0 )[0].nodeType;
+
+// Provide a fallback method if it does not work
+} catch( e ) {
+        makeArray = function( array, results ) {
+                var i = 0,
+                        ret = results || [];
+
+                if ( toString.call(array) === "[object Array]" ) {
+                        Array.prototype.push.apply( ret, array );
+
+                } else {
+                        if ( typeof array.length === "number" ) {
+                                for ( var l = array.length; i < l; i++ ) {
+                                        ret.push( array[i] );
+                                }
+
+                        } else {
+                                for ( ; array[i]; i++ ) {
+                                        ret.push( array[i] );
+                                }
+                        }
+                }
+
+                return ret;
+        };
+}
+
+var sortOrder, siblingCheck;
+
+if ( document.documentElement.compareDocumentPosition ) {
+        sortOrder = function( a, b ) {
+                if ( a === b ) {
+                        hasDuplicate = true;
+                        return 0;
+                }
+
+                if ( !a.compareDocumentPosition || !b.compareDocumentPosition ) {
+                        return a.compareDocumentPosition ? -1 : 1;
+                }
+
+                return a.compareDocumentPosition(b) & 4 ? -1 : 1;
+        };
+
+} else {
+        sortOrder = function( a, b ) {
+                // The nodes are identical, we can exit early
+                if ( a === b ) {
+                        hasDuplicate = true;
+                        return 0;
+
+                // Fallback to using sourceIndex (in IE) if it's available on both nodes
+                } else if ( a.sourceIndex && b.sourceIndex ) {
+                        return a.sourceIndex - b.sourceIndex;
+                }
+
+                var al, bl,
+                        ap = [],
+                        bp = [],
+                        aup = a.parentNode,
+                        bup = b.parentNode,
+                        cur = aup;
+
+                // If the nodes are siblings (or identical) we can do a quick check
+                if ( aup === bup ) {
+                        return siblingCheck( a, b );
+
+                // If no parents were found then the nodes are disconnected
+                } else if ( !aup ) {
+                        return -1;
+
+                } else if ( !bup ) {
+                        return 1;
+                }
+
+                // Otherwise they're somewhere else in the tree so we need
+                // to build up a full list of the parentNodes for comparison
+                while ( cur ) {
+                        ap.unshift( cur );
+                        cur = cur.parentNode;
+                }
+
+                cur = bup;
+
+                while ( cur ) {
+                        bp.unshift( cur );
+                        cur = cur.parentNode;
+                }
+
+                al = ap.length;
+                bl = bp.length;
+
+                // Start walking down the tree looking for a discrepancy
+                for ( var i = 0; i < al && i < bl; i++ ) {
+                        if ( ap[i] !== bp[i] ) {
+                                return siblingCheck( ap[i], bp[i] );
+                        }
+                }
+
+                // We ended someplace up the tree so do a sibling check
+                return i === al ?
+                        siblingCheck( a, bp[i], -1 ) :
+                        siblingCheck( ap[i], b, 1 );
+        };
+
+        siblingCheck = function( a, b, ret ) {
+                if ( a === b ) {
+                        return ret;
+                }
+
+                var cur = a.nextSibling;
+
+                while ( cur ) {
+                        if ( cur === b ) {
+                                return -1;
+                        }
+
+                        cur = cur.nextSibling;
+                }
+
+                return 1;
+        };
+}
+
+// Utility function for retreiving the text value of an array of DOM nodes
+Sizzle.getText = function( elems ) {
+        var ret = "", elem;
+
+        for ( var i = 0; elems[i]; i++ ) {
+                elem = elems[i];
+
+                // Get the text from text nodes and CDATA nodes
+                if ( elem.nodeType === 3 || elem.nodeType === 4 ) {
+                        ret += elem.nodeValue;
+
+                // Traverse everything else, except comment nodes
+                } else if ( elem.nodeType !== 8 ) {
+                        ret += Sizzle.getText( elem.childNodes );
+                }
+        }
+
+        return ret;
+};
+
+// Check to see if the browser returns elements by name when
+// querying by getElementById (and provide a workaround)
+(function(){
+        // We're going to inject a fake input element with a specified name
+        var form = document.createElement("div"),
+                id = "script" + (new Date()).getTime(),
+                root = document.documentElement;
+
+        form.innerHTML = "<a name='" + id + "'/>";
+
+        // Inject it into the root element, check its status, and remove it quickly
+        root.insertBefore( form, root.firstChild );
+
+        // The workaround has to do additional checks after a getElementById
+        // Which slows things down for other browsers (hence the branching)
+        if ( document.getElementById( id ) ) {
+                Expr.find.ID = function( match, context, isXML ) {
+                        if ( typeof context.getElementById !== "undefined" && !isXML ) {
+                                var m = context.getElementById(match[1]);
+
+                                return m ?
+                                        m.id === match[1] || typeof m.getAttributeNode !== "undefined" && m.getAttributeNode("id").nodeValue === match[1] ?
+                                                [m] :
+                                                undefined :
+                                        [];
+                        }
+                };
+
+                Expr.filter.ID = function( elem, match ) {
+                        var node = typeof elem.getAttributeNode !== "undefined" && elem.getAttributeNode("id");
+
+                        return elem.nodeType === 1 && node && node.nodeValue === match;
+                };
+        }
+
+        root.removeChild( form );
+
+        // release memory in IE
+        root = form = null;
+})();
+
+(function(){
+        // Check to see if the browser returns only elements
+        // when doing getElementsByTagName("*")
+
+        // Create a fake element
+        var div = document.createElement("div");
+        div.appendChild( document.createComment("") );
+
+        // Make sure no comments are found
+        if ( div.getElementsByTagName("*").length > 0 ) {
+                Expr.find.TAG = function( match, context ) {
+                        var results = context.getElementsByTagName( match[1] );
+
+                        // Filter out possible comments
+                        if ( match[1] === "*" ) {
+                                var tmp = [];
+
+                                for ( var i = 0; results[i]; i++ ) {
+                                        if ( results[i].nodeType === 1 ) {
+                                                tmp.push( results[i] );
+                                        }
+                                }
+
+                                results = tmp;
+                        }
+
+                        return results;
+                };
+        }
+
+        // Check to see if an attribute returns normalized href attributes
+        div.innerHTML = "<a href='#'></a>";
+
+        if ( div.firstChild && typeof div.firstChild.getAttribute !== "undefined" &&
+                        div.firstChild.getAttribute("href") !== "#" ) {
+
+                Expr.attrHandle.href = function( elem ) {
+                        return elem.getAttribute( "href", 2 );
+                };
+        }
+
+        // release memory in IE
+        div = null;
+})();
+
+if ( document.querySelectorAll ) {
+        (function(){
+                var oldSizzle = Sizzle,
+                        div = document.createElement("div"),
+                        id = "__sizzle__";
+
+                div.innerHTML = "<p class='TEST'></p>";
+
+                // Safari can't handle uppercase or unicode characters when
+                // in quirks mode.
+                if ( div.querySelectorAll && div.querySelectorAll(".TEST").length === 0 ) {
+                        return;
+                }
+        
+                Sizzle = function( query, context, extra, seed ) {
+                        context = context || document;
+
+                        // Only use querySelectorAll on non-XML documents
+                        // (ID selectors don't work in non-HTML documents)
+                        if ( !seed && !Sizzle.isXML(context) ) {
+                                // See if we find a selector to speed up
+                                var match = /^(\w+$)|^\.([\w\-]+$)|^#([\w\-]+$)/.exec( query );
+                                
+                                if ( match && (context.nodeType === 1 || context.nodeType === 9) ) {
+                                        // Speed-up: Sizzle("TAG")
+                                        if ( match[1] ) {
+                                                return makeArray( context.getElementsByTagName( query ), extra );
+                                        
+                                        // Speed-up: Sizzle(".CLASS")
+                                        } else if ( match[2] && Expr.find.CLASS && context.getElementsByClassName ) {
+                                                return makeArray( context.getElementsByClassName( match[2] ), extra );
+                                        }
+                                }
+                                
+                                if ( context.nodeType === 9 ) {
+                                        // Speed-up: Sizzle("body")
+                                        // The body element only exists once, optimize finding it
+                                        if ( query === "body" && context.body ) {
+                                                return makeArray( [ context.body ], extra );
+                                                
+                                        // Speed-up: Sizzle("#ID")
+                                        } else if ( match && match[3] ) {
+                                                var elem = context.getElementById( match[3] );
+
+                                                // Check parentNode to catch when Blackberry 4.6 returns
+                                                // nodes that are no longer in the document #6963
+                                                if ( elem && elem.parentNode ) {
+                                                        // Handle the case where IE and Opera return items
+                                                        // by name instead of ID
+                                                        if ( elem.id === match[3] ) {
+                                                                return makeArray( [ elem ], extra );
+                                                        }
+                                                        
+                                                } else {
+                                                        return makeArray( [], extra );
+                                                }
+                                        }
+                                        
+                                        try {
+                                                return makeArray( context.querySelectorAll(query), extra );
+                                        } catch(qsaError) {}
+
+                                // qSA works strangely on Element-rooted queries
+                                // We can work around this by specifying an extra ID on the root
+                                // and working up from there (Thanks to Andrew Dupont for the technique)
+                                // IE 8 doesn't work on object elements
+                                } else if ( context.nodeType === 1 && context.nodeName.toLowerCase() !== "object" ) {
+                                        var oldContext = context,
+                                                old = context.getAttribute( "id" ),
+                                                nid = old || id,
+                                                hasParent = context.parentNode,
+                                                relativeHierarchySelector = /^\s*[+~]/.test( query );
+
+                                        if ( !old ) {
+                                                context.setAttribute( "id", nid );
+                                        } else {
+                                                nid = nid.replace( /'/g, "\\$&" );
+                                        }
+                                        if ( relativeHierarchySelector && hasParent ) {
+                                                context = context.parentNode;
+                                        }
+
+                                        try {
+                                                if ( !relativeHierarchySelector || hasParent ) {
+                                                        return makeArray( context.querySelectorAll( "[id='" + nid + "'] " + query ), extra );
+                                                }
+
+                                        } catch(pseudoError) {
+                                        } finally {
+                                                if ( !old ) {
+                                                        oldContext.removeAttribute( "id" );
+                                                }
+                                        }
+                                }
+                        }
+                
+                        return oldSizzle(query, context, extra, seed);
+                };
+
+                for ( var prop in oldSizzle ) {
+                        Sizzle[ prop ] = oldSizzle[ prop ];
+                }
+
+                // release memory in IE
+                div = null;
+        })();
+}
+
+(function(){
+        var html = document.documentElement,
+                matches = html.matchesSelector || html.mozMatchesSelector || html.webkitMatchesSelector || html.msMatchesSelector;
+
+        if ( matches ) {
+                // Check to see if it's possible to do matchesSelector
+                // on a disconnected node (IE 9 fails this)
+                var disconnectedMatch = !matches.call( document.createElement( "div" ), "div" ),
+                        pseudoWorks = false;
+
+                try {
+                        // This should fail with an exception
+                        // Gecko does not error, returns false instead
+                        matches.call( document.documentElement, "[test!='']:sizzle" );
+        
+                } catch( pseudoError ) {
+                        pseudoWorks = true;
+                }
+
+                Sizzle.matchesSelector = function( node, expr ) {
+                        // Make sure that attribute selectors are quoted
+                        expr = expr.replace(/\=\s*([^'"\]]*)\s*\]/g, "='$1']");
+
+                        if ( !Sizzle.isXML( node ) ) {
+                                try { 
+                                        if ( pseudoWorks || !Expr.match.PSEUDO.test( expr ) && !/!=/.test( expr ) ) {
+                                                var ret = matches.call( node, expr );
+
+                                                // IE 9's matchesSelector returns false on disconnected nodes
+                                                if ( ret || !disconnectedMatch ||
+                                                                // As well, disconnected nodes are said to be in a document
+                                                                // fragment in IE 9, so check for that
+                                                                node.document && node.document.nodeType !== 11 ) {
+                                                        return ret;
+                                                }
+                                        }
+                                } catch(e) {}
+                        }
+
+                        return Sizzle(expr, null, null, [node]).length > 0;
+                };
+        }
+})();
+
+(function(){
+        var div = document.createElement("div");
+
+        div.innerHTML = "<div class='test e'></div><div class='test'></div>";
+
+        // Opera can't find a second classname (in 9.6)
+        // Also, make sure that getElementsByClassName actually exists
+        if ( !div.getElementsByClassName || div.getElementsByClassName("e").length === 0 ) {
+                return;
+        }
+
+        // Safari caches class attributes, doesn't catch changes (in 3.2)
+        div.lastChild.className = "e";
+
+        if ( div.getElementsByClassName("e").length === 1 ) {
+                return;
+        }
+        
+        Expr.order.splice(1, 0, "CLASS");
+        Expr.find.CLASS = function( match, context, isXML ) {
+                if ( typeof context.getElementsByClassName !== "undefined" && !isXML ) {
+                        return context.getElementsByClassName(match[1]);
+                }
+        };
+
+        // release memory in IE
+        div = null;
+})();
+
+function dirNodeCheck( dir, cur, doneName, checkSet, nodeCheck, isXML ) {
+        for ( var i = 0, l = checkSet.length; i < l; i++ ) {
+                var elem = checkSet[i];
+
+                if ( elem ) {
+                        var match = false;
+
+                        elem = elem[dir];
+
+                        while ( elem ) {
+                                if ( elem.sizcache === doneName ) {
+                                        match = checkSet[elem.sizset];
+                                        break;
+                                }
+
+                                if ( elem.nodeType === 1 && !isXML ){
+                                        elem.sizcache = doneName;
+                                        elem.sizset = i;
+                                }
+
+                                if ( elem.nodeName.toLowerCase() === cur ) {
+                                        match = elem;
+                                        break;
+                                }
+
+                                elem = elem[dir];
+                        }
+
+                        checkSet[i] = match;
+                }
+        }
+}
+
+function dirCheck( dir, cur, doneName, checkSet, nodeCheck, isXML ) {
+        for ( var i = 0, l = checkSet.length; i < l; i++ ) {
+                var elem = checkSet[i];
+
+                if ( elem ) {
+                        var match = false;
+                        
+                        elem = elem[dir];
+
+                        while ( elem ) {
+                                if ( elem.sizcache === doneName ) {
+                                        match = checkSet[elem.sizset];
+                                        break;
+                                }
+
+                                if ( elem.nodeType === 1 ) {
+                                        if ( !isXML ) {
+                                                elem.sizcache = doneName;
+                                                elem.sizset = i;
+                                        }
+
+                                        if ( typeof cur !== "string" ) {
+                                                if ( elem === cur ) {
+                                                        match = true;
+                                                        break;
+                                                }
+
+                                        } else if ( Sizzle.filter( cur, [elem] ).length > 0 ) {
+                                                match = elem;
+                                                break;
+                                        }
+                                }
+
+                                elem = elem[dir];
+                        }
+
+                        checkSet[i] = match;
+                }
+        }
+}
+
+if ( document.documentElement.contains ) {
+        Sizzle.contains = function( a, b ) {
+                return a !== b && (a.contains ? a.contains(b) : true);
+        };
+
+} else if ( document.documentElement.compareDocumentPosition ) {
+        Sizzle.contains = function( a, b ) {
+                return !!(a.compareDocumentPosition(b) & 16);
+        };
+
+} else {
+        Sizzle.contains = function() {
+                return false;
+        };
+}
+
+Sizzle.isXML = function( elem ) {
+        // documentElement is verified for cases where it doesn't yet exist
+        // (such as loading iframes in IE - #4833) 
+        var documentElement = (elem ? elem.ownerDocument || elem : 0).documentElement;
+
+        return documentElement ? documentElement.nodeName !== "HTML" : false;
+};
+
+var posProcess = function( selector, context ) {
+        var match,
+                tmpSet = [],
+                later = "",
+                root = context.nodeType ? [context] : context;
+
+        // Position selectors must be done after the filter
+        // And so must :not(positional) so we move all PSEUDOs to the end
+        while ( (match = Expr.match.PSEUDO.exec( selector )) ) {
+                later += match[0];
+                selector = selector.replace( Expr.match.PSEUDO, "" );
+        }
+
+        selector = Expr.relative[selector] ? selector + "*" : selector;
+
+        for ( var i = 0, l = root.length; i < l; i++ ) {
+                Sizzle( selector, root[i], tmpSet );
+        }
+
+        return Sizzle.filter( later, tmpSet );
+};
+
+// EXPOSE
+jQuery.find = Sizzle;
+jQuery.expr = Sizzle.selectors;
+jQuery.expr[":"] = jQuery.expr.filters;
+jQuery.unique = Sizzle.uniqueSort;
+jQuery.text = Sizzle.getText;
+jQuery.isXMLDoc = Sizzle.isXML;
+jQuery.contains = Sizzle.contains;
+
+
+})();
+
+
+var runtil = /Until$/,
+        rparentsprev = /^(?:parents|prevUntil|prevAll)/,
+        // Note: This RegExp should be improved, or likely pulled from Sizzle
+        rmultiselector = /,/,
+        isSimple = /^.[^:#\[\.,]*$/,
+        slice = Array.prototype.slice,
+        POS = jQuery.expr.match.POS,
+        // methods guaranteed to produce a unique set when starting from a unique set
+        guaranteedUnique = {
+                children: true,
+                contents: true,
+                next: true,
+                prev: true
+        };
+
+jQuery.fn.extend({
+        find: function( selector ) {
+                var self = this,
+                        i, l;
+
+                if ( typeof selector !== "string" ) {
+                        return jQuery( selector ).filter(function() {
+                                for ( i = 0, l = self.length; i < l; i++ ) {
+                                        if ( jQuery.contains( self[ i ], this ) ) {
+                                                return true;
+                                        }
+                                }
+                        });
+                }
+
+                var ret = this.pushStack( "", "find", selector ),
+                        length, n, r;
+
+                for ( i = 0, l = this.length; i < l; i++ ) {
+                        length = ret.length;
+                        jQuery.find( selector, this[i], ret );
+
+                        if ( i > 0 ) {
+                                // Make sure that the results are unique
+                                for ( n = length; n < ret.length; n++ ) {
+                                        for ( r = 0; r < length; r++ ) {
+                                                if ( ret[r] === ret[n] ) {
+                                                        ret.splice(n--, 1);
+                                                        break;
+                                                }
+                                        }
+                                }
+                        }
+                }
+
+                return ret;
+        },
+
+        has: function( target ) {
+                var targets = jQuery( target );
+                return this.filter(function() {
+                        for ( var i = 0, l = targets.length; i < l; i++ ) {
+                                if ( jQuery.contains( this, targets[i] ) ) {
+                                        return true;
+                                }
+                        }
+                });
+        },
+
+        not: function( selector ) {
+                return this.pushStack( winnow(this, selector, false), "not", selector);
+        },
+
+        filter: function( selector ) {
+                return this.pushStack( winnow(this, selector, true), "filter", selector );
+        },
+
+        is: function( selector ) {
+                return !!selector && ( typeof selector === "string" ?
+                        jQuery.filter( selector, this ).length > 0 :
+                        this.filter( selector ).length > 0 );
+        },
+
+        closest: function( selectors, context ) {
+                var ret = [], i, l, cur = this[0];
+                
+                // Array
+                if ( jQuery.isArray( selectors ) ) {
+                        var match, selector,
+                                matches = {},
+                                level = 1;
+
+                        if ( cur && selectors.length ) {
+                                for ( i = 0, l = selectors.length; i < l; i++ ) {
+                                        selector = selectors[i];
+
+                                        if ( !matches[ selector ] ) {
+                                                matches[ selector ] = POS.test( selector ) ?
+                                                        jQuery( selector, context || this.context ) :
+                                                        selector;
+                                        }
+                                }
+
+                                while ( cur && cur.ownerDocument && cur !== context ) {
+                                        for ( selector in matches ) {
+                                                match = matches[ selector ];
+
+                                                if ( match.jquery ? match.index( cur ) > -1 : jQuery( cur ).is( match ) ) {
+                                                        ret.push({ selector: selector, elem: cur, level: level });
+                                                }
+                                        }
+
+                                        cur = cur.parentNode;
+                                        level++;
+                                }
+                        }
+
+                        return ret;
+                }
+
+                // String
+                var pos = POS.test( selectors ) || typeof selectors !== "string" ?
+                                jQuery( selectors, context || this.context ) :
+                                0;
+
+                for ( i = 0, l = this.length; i < l; i++ ) {
+                        cur = this[i];
+
+                        while ( cur ) {
+                                if ( pos ? pos.index(cur) > -1 : jQuery.find.matchesSelector(cur, selectors) ) {
+                                        ret.push( cur );
+                                        break;
+
+                                } else {
+                                        cur = cur.parentNode;
+                                        if ( !cur || !cur.ownerDocument || cur === context || cur.nodeType === 11 ) {
+                                                break;
+                                        }
+                                }
+                        }
+                }
+
+                ret = ret.length > 1 ? jQuery.unique( ret ) : ret;
+
+                return this.pushStack( ret, "closest", selectors );
+        },
+
+        // Determine the position of an element within
+        // the matched set of elements
+        index: function( elem ) {
+
+                // No argument, return index in parent
+                if ( !elem ) {
+                        return ( this[0] && this[0].parentNode ) ? this.prevAll().length : -1;
+                }
+
+                // index in selector
+                if ( typeof elem === "string" ) {
+                        return jQuery.inArray( this[0], jQuery( elem ) );
+                }
+
+                // Locate the position of the desired element
+                return jQuery.inArray(
+                        // If it receives a jQuery object, the first element is used
+                        elem.jquery ? elem[0] : elem, this );
+        },
+
+        add: function( selector, context ) {
+                var set = typeof selector === "string" ?
+                                jQuery( selector, context ) :
+                                jQuery.makeArray( selector && selector.nodeType ? [ selector ] : selector ),
+                        all = jQuery.merge( this.get(), set );
+
+                return this.pushStack( isDisconnected( set[0] ) || isDisconnected( all[0] ) ?
+                        all :
+                        jQuery.unique( all ) );
+        },
+
+        andSelf: function() {
+                return this.add( this.prevObject );
+        }
+});
+
+// A painfully simple check to see if an element is disconnected
+// from a document (should be improved, where feasible).
+function isDisconnected( node ) {
+        return !node || !node.parentNode || node.parentNode.nodeType === 11;
+}
+
+jQuery.each({
+        parent: function( elem ) {
+                var parent = elem.parentNode;
+                return parent && parent.nodeType !== 11 ? parent : null;
+        },
+        parents: function( elem ) {
+                return jQuery.dir( elem, "parentNode" );
+        },
+        parentsUntil: function( elem, i, until ) {
+                return jQuery.dir( elem, "parentNode", until );
+        },
+        next: function( elem ) {
+                return jQuery.nth( elem, 2, "nextSibling" );
+        },
+        prev: function( elem ) {
+                return jQuery.nth( elem, 2, "previousSibling" );
+        },
+        nextAll: function( elem ) {
+                return jQuery.dir( elem, "nextSibling" );
+        },
+        prevAll: function( elem ) {
+                return jQuery.dir( elem, "previousSibling" );
+        },
+        nextUntil: function( elem, i, until ) {
+                return jQuery.dir( elem, "nextSibling", until );
+        },
+        prevUntil: function( elem, i, until ) {
+                return jQuery.dir( elem, "previousSibling", until );
+        },
+        siblings: function( elem ) {
+                return jQuery.sibling( elem.parentNode.firstChild, elem );
+        },
+        children: function( elem ) {
+                return jQuery.sibling( elem.firstChild );
+        },
+        contents: function( elem ) {
+                return jQuery.nodeName( elem, "iframe" ) ?
+                        elem.contentDocument || elem.contentWindow.document :
+                        jQuery.makeArray( elem.childNodes );
+        }
+}, function( name, fn ) {
+        jQuery.fn[ name ] = function( until, selector ) {
+                var ret = jQuery.map( this, fn, until ),
+                        // The variable 'args' was introduced in
+                        // https://github.com/jquery/jquery/commit/52a0238
+                        // to work around a bug in Chrome 10 (Dev) and should be removed when the bug is fixed.
+                        // http://code.google.com/p/v8/issues/detail?id=1050
+                        args = slice.call(arguments);
+
+                if ( !runtil.test( name ) ) {
+                        selector = until;
+                }
+
+                if ( selector && typeof selector === "string" ) {
+                        ret = jQuery.filter( selector, ret );
+                }
+
+                ret = this.length > 1 && !guaranteedUnique[ name ] ? jQuery.unique( ret ) : ret;
+
+                if ( (this.length > 1 || rmultiselector.test( selector )) && rparentsprev.test( name ) ) {
+                        ret = ret.reverse();
+                }
+
+                return this.pushStack( ret, name, args.join(",") );
+        };
+});
+
+jQuery.extend({
+        filter: function( expr, elems, not ) {
+                if ( not ) {
+                        expr = ":not(" + expr + ")";
+                }
+
+                return elems.length === 1 ?
+                        jQuery.find.matchesSelector(elems[0], expr) ? [ elems[0] ] : [] :
+                        jQuery.find.matches(expr, elems);
+        },
+
+        dir: function( elem, dir, until ) {
+                var matched = [],
+                        cur = elem[ dir ];
+
+                while ( cur && cur.nodeType !== 9 && (until === undefined || cur.nodeType !== 1 || !jQuery( cur ).is( until )) ) {
+                        if ( cur.nodeType === 1 ) {
+                                matched.push( cur );
+                        }
+                        cur = cur[dir];
+                }
+                return matched;
+        },
+
+        nth: function( cur, result, dir, elem ) {
+                result = result || 1;
+                var num = 0;
+
+                for ( ; cur; cur = cur[dir] ) {
+                        if ( cur.nodeType === 1 && ++num === result ) {
+                                break;
+                        }
+                }
+
+                return cur;
+        },
+
+        sibling: function( n, elem ) {
+                var r = [];
+
+                for ( ; n; n = n.nextSibling ) {
+                        if ( n.nodeType === 1 && n !== elem ) {
+                                r.push( n );
+                        }
+                }
+
+                return r;
+        }
+});
+
+// Implement the identical functionality for filter and not
+function winnow( elements, qualifier, keep ) {
+
+        // Can't pass null or undefined to indexOf in Firefox 4
+        // Set to 0 to skip string check
+        qualifier = qualifier || 0;
+
+        if ( jQuery.isFunction( qualifier ) ) {
+                return jQuery.grep(elements, function( elem, i ) {
+                        var retVal = !!qualifier.call( elem, i, elem );
+                        return retVal === keep;
+                });
+
+        } else if ( qualifier.nodeType ) {
+                return jQuery.grep(elements, function( elem, i ) {
+                        return (elem === qualifier) === keep;
+                });
+
+        } else if ( typeof qualifier === "string" ) {
+                var filtered = jQuery.grep(elements, function( elem ) {
+                        return elem.nodeType === 1;
+                });
+
+                if ( isSimple.test( qualifier ) ) {
+                        return jQuery.filter(qualifier, filtered, !keep);
+                } else {
+                        qualifier = jQuery.filter( qualifier, filtered );
+                }
+        }
+
+        return jQuery.grep(elements, function( elem, i ) {
+                return (jQuery.inArray( elem, qualifier ) >= 0) === keep;
+        });
+}
+
+
+
+
+var rinlinejQuery = / jQuery\d+="(?:\d+|null)"/g,
+        rleadingWhitespace = /^\s+/,
+        rxhtmlTag = /<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/ig,
+        rtagName = /<([\w:]+)/,
+        rtbody = /<tbody/i,
+        rhtml = /<|&#?\w+;/,
+        rnocache = /<(?:script|object|embed|option|style)/i,
+        // checked="checked" or checked
+        rchecked = /checked\s*(?:[^=]|=\s*.checked.)/i,
+        rscriptType = /\/(java|ecma)script/i,
+        rcleanScript = /^\s*<!(?:\[CDATA\[|\-\-)/,
+        wrapMap = {
+                option: [ 1, "<select multiple='multiple'>", "</select>" ],
+                legend: [ 1, "<fieldset>", "</fieldset>" ],
+                thead: [ 1, "<table>", "</table>" ],
+                tr: [ 2, "<table><tbody>", "</tbody></table>" ],
+                td: [ 3, "<table><tbody><tr>", "</tr></tbody></table>" ],
+                col: [ 2, "<table><tbody></tbody><colgroup>", "</colgroup></table>" ],
+                area: [ 1, "<map>", "</map>" ],
+                _default: [ 0, "", "" ]
+        };
+
+wrapMap.optgroup = wrapMap.option;
+wrapMap.tbody = wrapMap.tfoot = wrapMap.colgroup = wrapMap.caption = wrapMap.thead;
+wrapMap.th = wrapMap.td;
+
+// IE can't serialize <link> and <script> tags normally
+if ( !jQuery.support.htmlSerialize ) {
+        wrapMap._default = [ 1, "div<div>", "</div>" ];
+}
+
+jQuery.fn.extend({
+        text: function( text ) {
+                if ( jQuery.isFunction(text) ) {
+                        return this.each(function(i) {
+                                var self = jQuery( this );
+
+                                self.text( text.call(this, i, self.text()) );
+                        });
+                }
+
+                if ( typeof text !== "object" && text !== undefined ) {
+                        return this.empty().append( (this[0] && this[0].ownerDocument || document).createTextNode( text ) );
+                }
+
+                return jQuery.text( this );
+        },
+
+        wrapAll: function( html ) {
+                if ( jQuery.isFunction( html ) ) {
+                        return this.each(function(i) {
+                                jQuery(this).wrapAll( html.call(this, i) );
+                        });
+                }
+
+                if ( this[0] ) {
+                        // The elements to wrap the target around
+                        var wrap = jQuery( html, this[0].ownerDocument ).eq(0).clone(true);
+
+                        if ( this[0].parentNode ) {
+                                wrap.insertBefore( this[0] );
+                        }
+
+                        wrap.map(function() {
+                                var elem = this;
+
+                                while ( elem.firstChild && elem.firstChild.nodeType === 1 ) {
+                                        elem = elem.firstChild;
+                                }
+
+                                return elem;
+                        }).append( this );
+                }
+
+                return this;
+        },
+
+        wrapInner: function( html ) {
+                if ( jQuery.isFunction( html ) ) {
+                        return this.each(function(i) {
+                                jQuery(this).wrapInner( html.call(this, i) );
+                        });
+                }
+
+                return this.each(function() {
+                        var self = jQuery( this ),
+                                contents = self.contents();
+
+                        if ( contents.length ) {
+                                contents.wrapAll( html );
+
+                        } else {
+                                self.append( html );
+                        }
+                });
+        },
+
+        wrap: function( html ) {
+                return this.each(function() {
+                        jQuery( this ).wrapAll( html );
+                });
+        },
+
+        unwrap: function() {
+                return this.parent().each(function() {
+                        if ( !jQuery.nodeName( this, "body" ) ) {
+                                jQuery( this ).replaceWith( this.childNodes );
+                        }
+                }).end();
+        },
+
+        append: function() {
+                return this.domManip(arguments, true, function( elem ) {
+                        if ( this.nodeType === 1 ) {
+                                this.appendChild( elem );
+                        }
+                });
+        },
+
+        prepend: function() {
+                return this.domManip(arguments, true, function( elem ) {
+                        if ( this.nodeType === 1 ) {
+                                this.insertBefore( elem, this.firstChild );
+                        }
+                });
+        },
+
+        before: function() {
+                if ( this[0] && this[0].parentNode ) {
+                        return this.domManip(arguments, false, function( elem ) {
+                                this.parentNode.insertBefore( elem, this );
+                        });
+                } else if ( arguments.length ) {
+                        var set = jQuery(arguments[0]);
+                        set.push.apply( set, this.toArray() );
+                        return this.pushStack( set, "before", arguments );
+                }
+        },
+
+        after: function() {
+                if ( this[0] && this[0].parentNode ) {
+                        return this.domManip(arguments, false, function( elem ) {
+                                this.parentNode.insertBefore( elem, this.nextSibling );
+                        });
+                } else if ( arguments.length ) {
+                        var set = this.pushStack( this, "after", arguments );
+                        set.push.apply( set, jQuery(arguments[0]).toArray() );
+                        return set;
+                }
+        },
+
+        // keepData is for internal use only--do not document
+        remove: function( selector, keepData ) {
+                for ( var i = 0, elem; (elem = this[i]) != null; i++ ) {
+                        if ( !selector || jQuery.filter( selector, [ elem ] ).length ) {
+                                if ( !keepData && elem.nodeType === 1 ) {
+                                        jQuery.cleanData( elem.getElementsByTagName("*") );
+                                        jQuery.cleanData( [ elem ] );
+                                }
+
+                                if ( elem.parentNode ) {
+                                        elem.parentNode.removeChild( elem );
+                                }
+                        }
+                }
+
+                return this;
+        },
+
+        empty: function() {
+                for ( var i = 0, elem; (elem = this[i]) != null; i++ ) {
+                        // Remove element nodes and prevent memory leaks
+                        if ( elem.nodeType === 1 ) {
+                                jQuery.cleanData( elem.getElementsByTagName("*") );
+                        }
+
+                        // Remove any remaining nodes
+                        while ( elem.firstChild ) {
+                                elem.removeChild( elem.firstChild );
+                        }
+                }
+
+                return this;
+        },
+
+        clone: function( dataAndEvents, deepDataAndEvents ) {
+                dataAndEvents = dataAndEvents == null ? false : dataAndEvents;
+                deepDataAndEvents = deepDataAndEvents == null ? dataAndEvents : deepDataAndEvents;
+
+                return this.map( function () {
+                        return jQuery.clone( this, dataAndEvents, deepDataAndEvents );
+                });
+        },
+
+        html: function( value ) {
+                if ( value === undefined ) {
+                        return this[0] && this[0].nodeType === 1 ?
+                                this[0].innerHTML.replace(rinlinejQuery, "") :
+                                null;
+
+                // See if we can take a shortcut and just use innerHTML
+                } else if ( typeof value === "string" && !rnocache.test( value ) &&
+                        (jQuery.support.leadingWhitespace || !rleadingWhitespace.test( value )) &&
+                        !wrapMap[ (rtagName.exec( value ) || ["", ""])[1].toLowerCase() ] ) {
+
+                        value = value.replace(rxhtmlTag, "<$1></$2>");
+
+                        try {
+                                for ( var i = 0, l = this.length; i < l; i++ ) {
+                                        // Remove element nodes and prevent memory leaks
+                                        if ( this[i].nodeType === 1 ) {
+                                                jQuery.cleanData( this[i].getElementsByTagName("*") );
+                                                this[i].innerHTML = value;
+                                        }
+                                }
+
+                        // If using innerHTML throws an exception, use the fallback method
+                        } catch(e) {
+                                this.empty().append( value );
+                        }
+
+                } else if ( jQuery.isFunction( value ) ) {
+                        this.each(function(i){
+                                var self = jQuery( this );
+
+                                self.html( value.call(this, i, self.html()) );
+                        });
+
+                } else {
+                        this.empty().append( value );
+                }
+
+                return this;
+        },
+
+        replaceWith: function( value ) {
+                if ( this[0] && this[0].parentNode ) {
+                        // Make sure that the elements are removed from the DOM before they are inserted
+                        // this can help fix replacing a parent with child elements
+                        if ( jQuery.isFunction( value ) ) {
+                                return this.each(function(i) {
+                                        var self = jQuery(this), old = self.html();
+                                        self.replaceWith( value.call( this, i, old ) );
+                                });
+                        }
+
+                        if ( typeof value !== "string" ) {
+                                value = jQuery( value ).detach();
+                        }
+
+                        return this.each(function() {
+                                var next = this.nextSibling,
+                                        parent = this.parentNode;
+
+                                jQuery( this ).remove();
+
+                                if ( next ) {
+                                        jQuery(next).before( value );
+                                } else {
+                                        jQuery(parent).append( value );
+                                }
+                        });
+                } else {
+                        return this.length ?
+                                this.pushStack( jQuery(jQuery.isFunction(value) ? value() : value), "replaceWith", value ) :
+                                this;
+                }
+        },
+
+        detach: function( selector ) {
+                return this.remove( selector, true );
+        },
+
+        domManip: function( args, table, callback ) {
+                var results, first, fragment, parent,
+                        value = args[0],
+                        scripts = [];
+
+                // We can't cloneNode fragments that contain checked, in WebKit
+                if ( !jQuery.support.checkClone && arguments.length === 3 && typeof value === "string" && rchecked.test( value ) ) {
+                        return this.each(function() {
+                                jQuery(this).domManip( args, table, callback, true );
+                        });
+                }
+
+                if ( jQuery.isFunction(value) ) {
+                        return this.each(function(i) {
+                                var self = jQuery(this);
+                                args[0] = value.call(this, i, table ? self.html() : undefined);
+                                self.domManip( args, table, callback );
+                        });
+                }
+
+                if ( this[0] ) {
+                        parent = value && value.parentNode;
+
+                        // If we're in a fragment, just use that instead of building a new one
+                        if ( jQuery.support.parentNode && parent && parent.nodeType === 11 && parent.childNodes.length === this.length ) {
+                                results = { fragment: parent };
+
+                        } else {
+                                results = jQuery.buildFragment( args, this, scripts );
+                        }
+
+                        fragment = results.fragment;
+
+                        if ( fragment.childNodes.length === 1 ) {
+                                first = fragment = fragment.firstChild;
+                        } else {
+                                first = fragment.firstChild;
+                        }
+
+                        if ( first ) {
+                                table = table && jQuery.nodeName( first, "tr" );
+
+                                for ( var i = 0, l = this.length, lastIndex = l - 1; i < l; i++ ) {
+                                        callback.call(
+                                                table ?
+                                                        root(this[i], first) :
+                                                        this[i],
+                                                // Make sure that we do not leak memory by inadvertently discarding
+                                                // the original fragment (which might have attached data) instead of
+                                                // using it; in addition, use the original fragment object for the last
+                                                // item instead of first because it can end up being emptied incorrectly
+                                                // in certain situations (Bug #8070).
+                                                // Fragments from the fragment cache must always be cloned and never used
+                                                // in place.
+                                                results.cacheable || (l > 1 && i < lastIndex) ?
+                                                        jQuery.clone( fragment, true, true ) :
+                                                        fragment
+                                        );
+                                }
+                        }
+
+                        if ( scripts.length ) {
+                                jQuery.each( scripts, evalScript );
+                        }
+                }
+
+                return this;
+        }
+});
+
+function root( elem, cur ) {
+        return jQuery.nodeName(elem, "table") ?
+                (elem.getElementsByTagName("tbody")[0] ||
+                elem.appendChild(elem.ownerDocument.createElement("tbody"))) :
+                elem;
+}
+
+function cloneCopyEvent( src, dest ) {
+
+        if ( dest.nodeType !== 1 || !jQuery.hasData( src ) ) {
+                return;
+        }
+
+        var internalKey = jQuery.expando,
+                oldData = jQuery.data( src ),
+                curData = jQuery.data( dest, oldData );
+
+        // Switch to use the internal data object, if it exists, for the next
+        // stage of data copying
+        if ( (oldData = oldData[ internalKey ]) ) {
+                var events = oldData.events;
+                                curData = curData[ internalKey ] = jQuery.extend({}, oldData);
+
+                if ( events ) {
+                        delete curData.handle;
+                        curData.events = {};
+
+                        for ( var type in events ) {
+                                for ( var i = 0, l = events[ type ].length; i < l; i++ ) {
+                                        jQuery.event.add( dest, type + ( events[ type ][ i ].namespace ? "." : "" ) + events[ type ][ i ].namespace, events[ type ][ i ], events[ type ][ i ].data );
+                                }
+                        }
+                }
+        }
+}
+
+function cloneFixAttributes( src, dest ) {
+        var nodeName;
+
+        // We do not need to do anything for non-Elements
+        if ( dest.nodeType !== 1 ) {
+                return;
+        }
+
+        // clearAttributes removes the attributes, which we don't want,
+        // but also removes the attachEvent events, which we *do* want
+        if ( dest.clearAttributes ) {
+                dest.clearAttributes();
+        }
+
+        // mergeAttributes, in contrast, only merges back on the
+        // original attributes, not the events
+        if ( dest.mergeAttributes ) {
+                dest.mergeAttributes( src );
+        }
+
+        nodeName = dest.nodeName.toLowerCase();
+
+        // IE6-8 fail to clone children inside object elements that use
+        // the proprietary classid attribute value (rather than the type
+        // attribute) to identify the type of content to display
+        if ( nodeName === "object" ) {
+                dest.outerHTML = src.outerHTML;
+
+        } else if ( nodeName === "input" && (src.type === "checkbox" || src.type === "radio") ) {
+                // IE6-8 fails to persist the checked state of a cloned checkbox
+                // or radio button. Worse, IE6-7 fail to give the cloned element
+                // a checked appearance if the defaultChecked value isn't also set
+                if ( src.checked ) {
+                        dest.defaultChecked = dest.checked = src.checked;
+                }
+
+                // IE6-7 get confused and end up setting the value of a cloned
+                // checkbox/radio button to an empty string instead of "on"
+                if ( dest.value !== src.value ) {
+                        dest.value = src.value;
+                }
+
+        // IE6-8 fails to return the selected option to the default selected
+        // state when cloning options
+        } else if ( nodeName === "option" ) {
+                dest.selected = src.defaultSelected;
+
+        // IE6-8 fails to set the defaultValue to the correct value when
+        // cloning other types of input fields
+        } else if ( nodeName === "input" || nodeName === "textarea" ) {
+                dest.defaultValue = src.defaultValue;
+        }
+
+        // Event data gets referenced instead of copied if the expando
+        // gets copied too
+        dest.removeAttribute( jQuery.expando );
+}
+
+jQuery.buildFragment = function( args, nodes, scripts ) {
+        var fragment, cacheable, cacheresults, doc;
+
+  // nodes may contain either an explicit document object,
+  // a jQuery collection or context object.
+  // If nodes[0] contains a valid object to assign to doc
+  if ( nodes && nodes[0] ) {
+    doc = nodes[0].ownerDocument || nodes[0];
+  }
+
+  // Ensure that an attr object doesn't incorrectly stand in as a document object
+        // Chrome and Firefox seem to allow this to occur and will throw exception
+        // Fixes #8950
+        if ( !doc.createDocumentFragment ) {
+                doc = document;
+        }
+
+        // Only cache "small" (1/2 KB) HTML strings that are associated with the main document
+        // Cloning options loses the selected state, so don't cache them
+        // IE 6 doesn't like it when you put <object> or <embed> elements in a fragment
+        // Also, WebKit does not clone 'checked' attributes on cloneNode, so don't cache
+        if ( args.length === 1 && typeof args[0] === "string" && args[0].length < 512 && doc === document &&
+                args[0].charAt(0) === "<" && !rnocache.test( args[0] ) && (jQuery.support.checkClone || !rchecked.test( args[0] )) ) {
+
+                cacheable = true;
+
+                cacheresults = jQuery.fragments[ args[0] ];
+                if ( cacheresults && cacheresults !== 1 ) {
+                        fragment = cacheresults;
+                }
+        }
+
+        if ( !fragment ) {
+                fragment = doc.createDocumentFragment();
+                jQuery.clean( args, doc, fragment, scripts );
+        }
+
+        if ( cacheable ) {
+                jQuery.fragments[ args[0] ] = cacheresults ? fragment : 1;
+        }
+
+        return { fragment: fragment, cacheable: cacheable };
+};
+
+jQuery.fragments = {};
+
+jQuery.each({
+        appendTo: "append",
+        prependTo: "prepend",
+        insertBefore: "before",
+        insertAfter: "after",
+        replaceAll: "replaceWith"
+}, function( name, original ) {
+        jQuery.fn[ name ] = function( selector ) {
+                var ret = [],
+                        insert = jQuery( selector ),
+                        parent = this.length === 1 && this[0].parentNode;
+
+                if ( parent && parent.nodeType === 11 && parent.childNodes.length === 1 && insert.length === 1 ) {
+                        insert[ original ]( this[0] );
+                        return this;
+
+                } else {
+                        for ( var i = 0, l = insert.length; i < l; i++ ) {
+                                var elems = (i > 0 ? this.clone(true) : this).get();
+                                jQuery( insert[i] )[ original ]( elems );
+                                ret = ret.concat( elems );
+                        }
+
+                        return this.pushStack( ret, name, insert.selector );
+                }
+        };
+});
+
+function getAll( elem ) {
+        if ( "getElementsByTagName" in elem ) {
+                return elem.getElementsByTagName( "*" );
+
+        } else if ( "querySelectorAll" in elem ) {
+                return elem.querySelectorAll( "*" );
+
+        } else {
+                return [];
+        }
+}
+
+// Used in clean, fixes the defaultChecked property
+function fixDefaultChecked( elem ) {
+        if ( elem.type === "checkbox" || elem.type === "radio" ) {
+                elem.defaultChecked = elem.checked;
+        }
+}
+// Finds all inputs and passes them to fixDefaultChecked
+function findInputs( elem ) {
+        if ( jQuery.nodeName( elem, "input" ) ) {
+                fixDefaultChecked( elem );
+        } else if ( "getElementsByTagName" in elem ) {
+                jQuery.grep( elem.getElementsByTagName("input"), fixDefaultChecked );
+        }
+}
+
+jQuery.extend({
+        clone: function( elem, dataAndEvents, deepDataAndEvents ) {
+                var clone = elem.cloneNode(true),
+                                srcElements,
+                                destElements,
+                                i;
+
+                if ( (!jQuery.support.noCloneEvent || !jQuery.support.noCloneChecked) &&
+                                (elem.nodeType === 1 || elem.nodeType === 11) && !jQuery.isXMLDoc(elem) ) {
+                        // IE copies events bound via attachEvent when using cloneNode.
+                        // Calling detachEvent on the clone will also remove the events
+                        // from the original. In order to get around this, we use some
+                        // proprietary methods to clear the events. Thanks to MooTools
+                        // guys for this hotness.
+
+                        cloneFixAttributes( elem, clone );
+
+                        // Using Sizzle here is crazy slow, so we use getElementsByTagName
+                        // instead
+                        srcElements = getAll( elem );
+                        destElements = getAll( clone );
+
+                        // Weird iteration because IE will replace the length property
+                        // with an element if you are cloning the body and one of the
+                        // elements on the page has a name or id of "length"
+                        for ( i = 0; srcElements[i]; ++i ) {
+                                // Ensure that the destination node is not null; Fixes #9587
+                                if ( destElements[i] ) {
+                                        cloneFixAttributes( srcElements[i], destElements[i] );
+                                }
+                        }
+                }
+
+                // Copy the events from the original to the clone
+                if ( dataAndEvents ) {
+                        cloneCopyEvent( elem, clone );
+
+                        if ( deepDataAndEvents ) {
+                                srcElements = getAll( elem );
+                                destElements = getAll( clone );
+
+                                for ( i = 0; srcElements[i]; ++i ) {
+                                        cloneCopyEvent( srcElements[i], destElements[i] );
+                                }
+                        }
+                }
+
+                srcElements = destElements = null;
+
+                // Return the cloned set
+                return clone;
+        },
+
+        clean: function( elems, context, fragment, scripts ) {
+                var checkScriptType;
+
+                context = context || document;
+
+                // !context.createElement fails in IE with an error but returns typeof 'object'
+                if ( typeof context.createElement === "undefined" ) {
+                        context = context.ownerDocument || context[0] && context[0].ownerDocument || document;
+                }
+
+                var ret = [], j;
+
+                for ( var i = 0, elem; (elem = elems[i]) != null; i++ ) {
+                        if ( typeof elem === "number" ) {
+                                elem += "";
+                        }
+
+                        if ( !elem ) {
+                                continue;
+                        }
+
+                        // Convert html string into DOM nodes
+                        if ( typeof elem === "string" ) {
+                                if ( !rhtml.test( elem ) ) {
+                                        elem = context.createTextNode( elem );
+                                } else {
+                                        // Fix "XHTML"-style tags in all browsers
+                                        elem = elem.replace(rxhtmlTag, "<$1></$2>");
+
+                                        // Trim whitespace, otherwise indexOf won't work as expected
+                                        var tag = (rtagName.exec( elem ) || ["", ""])[1].toLowerCase(),
+                                                wrap = wrapMap[ tag ] || wrapMap._default,
+                                                depth = wrap[0],
+                                                div = context.createElement("div");
+
+                                        // Go to html and back, then peel off extra wrappers
+                                        div.innerHTML = wrap[1] + elem + wrap[2];
+
+                                        // Move to the right depth
+                                        while ( depth-- ) {
+                                                div = div.lastChild;
+                                        }
+
+                                        // Remove IE's autoinserted <tbody> from table fragments
+                                        if ( !jQuery.support.tbody ) {
+
+                                                // String was a <table>, *may* have spurious <tbody>
+                                                var hasBody = rtbody.test(elem),
+                                                        tbody = tag === "table" && !hasBody ?
+                                                                div.firstChild && div.firstChild.childNodes :
+
+                                                                // String was a bare <thead> or <tfoot>
+                                                                wrap[1] === "<table>" && !hasBody ?
+                                                                        div.childNodes :
+                                                                        [];
+
+                                                for ( j = tbody.length - 1; j >= 0 ; --j ) {
+                                                        if ( jQuery.nodeName( tbody[ j ], "tbody" ) && !tbody[ j ].childNodes.length ) {
+                                                                tbody[ j ].parentNode.removeChild( tbody[ j ] );
+                                                        }
+                                                }
+                                        }
+
+                                        // IE completely kills leading whitespace when innerHTML is used
+                                        if ( !jQuery.support.leadingWhitespace && rleadingWhitespace.test( elem ) ) {
+                                                div.insertBefore( context.createTextNode( rleadingWhitespace.exec(elem)[0] ), div.firstChild );
+                                        }
+
+                                        elem = div.childNodes;
+                                }
+                        }
+
+                        // Resets defaultChecked for any radios and checkboxes
+                        // about to be appended to the DOM in IE 6/7 (#8060)
+                        var len;
+                        if ( !jQuery.support.appendChecked ) {
+                                if ( elem[0] && typeof (len = elem.length) === "number" ) {
+                                        for ( j = 0; j < len; j++ ) {
+                                                findInputs( elem[j] );
+                                        }
+                                } else {
+                                        findInputs( elem );
+                                }
+                        }
+
+                        if ( elem.nodeType ) {
+                                ret.push( elem );
+                        } else {
+                                ret = jQuery.merge( ret, elem );
+                        }
+                }
+
+                if ( fragment ) {
+                        checkScriptType = function( elem ) {
+                                return !elem.type || rscriptType.test( elem.type );
+                        };
+                        for ( i = 0; ret[i]; i++ ) {
+                                if ( scripts && jQuery.nodeName( ret[i], "script" ) && (!ret[i].type || ret[i].type.toLowerCase() === "text/javascript") ) {
+                                        scripts.push( ret[i].parentNode ? ret[i].parentNode.removeChild( ret[i] ) : ret[i] );
+
+                                } else {
+                                        if ( ret[i].nodeType === 1 ) {
+                                                var jsTags = jQuery.grep( ret[i].getElementsByTagName( "script" ), checkScriptType );
+
+                                                ret.splice.apply( ret, [i + 1, 0].concat( jsTags ) );
+                                        }
+                                        fragment.appendChild( ret[i] );
+                                }
+                        }
+                }
+
+                return ret;
+        },
+
+        cleanData: function( elems ) {
+                var data, id, cache = jQuery.cache, internalKey = jQuery.expando, special = jQuery.event.special,
+                        deleteExpando = jQuery.support.deleteExpando;
+
+                for ( var i = 0, elem; (elem = elems[i]) != null; i++ ) {
+                        if ( elem.nodeName && jQuery.noData[elem.nodeName.toLowerCase()] ) {
+                                continue;
+                        }
+
+                        id = elem[ jQuery.expando ];
+
+                        if ( id ) {
+                                data = cache[ id ] && cache[ id ][ internalKey ];
+
+                                if ( data && data.events ) {
+                                        for ( var type in data.events ) {
+                                                if ( special[ type ] ) {
+                                                        jQuery.event.remove( elem, type );
+
+                                                // This is a shortcut to avoid jQuery.event.remove's overhead
+                                                } else {
+                                                        jQuery.removeEvent( elem, type, data.handle );
+                                                }
+                                        }
+
+                                        // Null the DOM reference to avoid IE6/7/8 leak (#7054)
+                                        if ( data.handle ) {
+                                                data.handle.elem = null;
+                                        }
+                                }
+
+                                if ( deleteExpando ) {
+                                        delete elem[ jQuery.expando ];
+
+                                } else if ( elem.removeAttribute ) {
+                                        elem.removeAttribute( jQuery.expando );
+                                }
+
+                                delete cache[ id ];
+                        }
+                }
+        }
+});
+
+function evalScript( i, elem ) {
+        if ( elem.src ) {
+                jQuery.ajax({
+                        url: elem.src,
+                        async: false,
+                        dataType: "script"
+                });
+        } else {
+                jQuery.globalEval( ( elem.text || elem.textContent || elem.innerHTML || "" ).replace( rcleanScript, "/*$0*/" ) );
+        }
+
+        if ( elem.parentNode ) {
+                elem.parentNode.removeChild( elem );
+        }
+}
+
+
+
+
+var ralpha = /alpha\([^)]*\)/i,
+        ropacity = /opacity=([^)]*)/,
+        // fixed for IE9, see #8346
+        rupper = /([A-Z]|^ms)/g,
+        rnumpx = /^-?\d+(?:px)?$/i,
+        rnum = /^-?\d/,
+        rrelNum = /^([\-+])=([\-+.\de]+)/,
+
+        cssShow = { position: "absolute", visibility: "hidden", display: "block" },
+        cssWidth = [ "Left", "Right" ],
+        cssHeight = [ "Top", "Bottom" ],
+        curCSS,
+
+        getComputedStyle,
+        currentStyle;
+
+jQuery.fn.css = function( name, value ) {
+        // Setting 'undefined' is a no-op
+        if ( arguments.length === 2 && value === undefined ) {
+                return this;
+        }
+
+        return jQuery.access( this, name, value, true, function( elem, name, value ) {
+                return value !== undefined ?
+                        jQuery.style( elem, name, value ) :
+                        jQuery.css( elem, name );
+        });
+};
+
+jQuery.extend({
+        // Add in style property hooks for overriding the default
+        // behavior of getting and setting a style property
+        cssHooks: {
+                opacity: {
+                        get: function( elem, computed ) {
+                                if ( computed ) {
+                                        // We should always get a number back from opacity
+                                        var ret = curCSS( elem, "opacity", "opacity" );
+                                        return ret === "" ? "1" : ret;
+
+                                } else {
+                                        return elem.style.opacity;
+                                }
+                        }
+                }
+        },
+
+        // Exclude the following css properties to add px
+        cssNumber: {
+                "fillOpacity": true,
+                "fontWeight": true,
+                "lineHeight": true,
+                "opacity": true,
+                "orphans": true,
+                "widows": true,
+                "zIndex": true,
+                "zoom": true
+        },
+
+        // Add in properties whose names you wish to fix before
+        // setting or getting the value
+        cssProps: {
+                // normalize float css property
+                "float": jQuery.support.cssFloat ? "cssFloat" : "styleFloat"
+        },
+
+        // Get and set the style property on a DOM Node
+        style: function( elem, name, value, extra ) {
+                // Don't set styles on text and comment nodes
+                if ( !elem || elem.nodeType === 3 || elem.nodeType === 8 || !elem.style ) {
+                        return;
+                }
+
+                // Make sure that we're working with the right name
+                var ret, type, origName = jQuery.camelCase( name ),
+                        style = elem.style, hooks = jQuery.cssHooks[ origName ];
+
+                name = jQuery.cssProps[ origName ] || origName;
+
+                // Check if we're setting a value
+                if ( value !== undefined ) {
+                        type = typeof value;
+
+                        // convert relative number strings (+= or -=) to relative numbers. #7345
+                        if ( type === "string" && (ret = rrelNum.exec( value )) ) {
+                                value = ( +( ret[1] + 1) * +ret[2] ) + parseFloat( jQuery.css( elem, name ) );
+                                // Fixes bug #9237
+                                type = "number";
+                        }
+
+                        // Make sure that NaN and null values aren't set. See: #7116
+                        if ( value == null || type === "number" && isNaN( value ) ) {
+                                return;
+                        }
+
+                        // If a number was passed in, add 'px' to the (except for certain CSS properties)
+                        if ( type === "number" && !jQuery.cssNumber[ origName ] ) {
+                                value += "px";
+                        }
+
+                        // If a hook was provided, use that value, otherwise just set the specified value
+                        if ( !hooks || !("set" in hooks) || (value = hooks.set( elem, value )) !== undefined ) {
+                                // Wrapped to prevent IE from throwing errors when 'invalid' values are provided
+                                // Fixes bug #5509
+                                try {
+                                        style[ name ] = value;
+                                } catch(e) {}
+                        }
+
+                } else {
+                        // If a hook was provided get the non-computed value from there
+                        if ( hooks && "get" in hooks && (ret = hooks.get( elem, false, extra )) !== undefined ) {
+                                return ret;
+                        }
+
+                        // Otherwise just get the value from the style object
+                        return style[ name ];
+                }
+        },
+
+        css: function( elem, name, extra ) {
+                var ret, hooks;
+
+                // Make sure that we're working with the right name
+                name = jQuery.camelCase( name );
+                hooks = jQuery.cssHooks[ name ];
+                name = jQuery.cssProps[ name ] || name;
+
+                // cssFloat needs a special treatment
+                if ( name === "cssFloat" ) {
+                        name = "float";
+                }
+
+                // If a hook was provided get the computed value from there
+                if ( hooks && "get" in hooks && (ret = hooks.get( elem, true, extra )) !== undefined ) {
+                        return ret;
+
+                // Otherwise, if a way to get the computed value exists, use that
+                } else if ( curCSS ) {
+                        return curCSS( elem, name );
+                }
+        },
+
+        // A method for quickly swapping in/out CSS properties to get correct calculations
+        swap: function( elem, options, callback ) {
+                var old = {};
+
+                // Remember the old values, and insert the new ones
+                for ( var name in options ) {
+                        old[ name ] = elem.style[ name ];
+                        elem.style[ name ] = options[ name ];
+                }
+
+                callback.call( elem );
+
+                // Revert the old values
+                for ( name in options ) {
+                        elem.style[ name ] = old[ name ];
+                }
+        }
+});
+
+// DEPRECATED, Use jQuery.css() instead
+jQuery.curCSS = jQuery.css;
+
+jQuery.each(["height", "width"], function( i, name ) {
+        jQuery.cssHooks[ name ] = {
+                get: function( elem, computed, extra ) {
+                        var val;
+
+                        if ( computed ) {
+                                if ( elem.offsetWidth !== 0 ) {
+                                        return getWH( elem, name, extra );
+                                } else {
+                                        jQuery.swap( elem, cssShow, function() {
+                                                val = getWH( elem, name, extra );
+                                        });
+                                }
+
+                                return val;
+                        }
+                },
+
+                set: function( elem, value ) {
+                        if ( rnumpx.test( value ) ) {
+                                // ignore negative width and height values #1599
+                                value = parseFloat( value );
+
+                                if ( value >= 0 ) {
+                                        return value + "px";
+                                }
+
+                        } else {
+                                return value;
+                        }
+                }
+        };
+});
+
+if ( !jQuery.support.opacity ) {
+        jQuery.cssHooks.opacity = {
+                get: function( elem, computed ) {
+                        // IE uses filters for opacity
+                        return ropacity.test( (computed && elem.currentStyle ? elem.currentStyle.filter : elem.style.filter) || "" ) ?
+                                ( parseFloat( RegExp.$1 ) / 100 ) + "" :
+                                computed ? "1" : "";
+                },
+
+                set: function( elem, value ) {
+                        var style = elem.style,
+                                currentStyle = elem.currentStyle,
+                                opacity = jQuery.isNaN( value ) ? "" : "alpha(opacity=" + value * 100 + ")",
+                                filter = currentStyle && currentStyle.filter || style.filter || "";
+
+                        // IE has trouble with opacity if it does not have layout
+                        // Force it by setting the zoom level
+                        style.zoom = 1;
+
+                        // if setting opacity to 1, and no other filters exist - attempt to remove filter attribute #6652
+                        if ( value >= 1 && jQuery.trim( filter.replace( ralpha, "" ) ) === "" ) {
+
+                                // Setting style.filter to null, "" & " " still leave "filter:" in the cssText
+                                // if "filter:" is present at all, clearType is disabled, we want to avoid this
+                                // style.removeAttribute is IE Only, but so apparently is this code path...
+                                style.removeAttribute( "filter" );
+
+                                // if there there is no filter style applied in a css rule, we are done
+                                if ( currentStyle && !currentStyle.filter ) {
+                                        return;
+                                }
+                        }
+
+                        // otherwise, set new filter values
+                        style.filter = ralpha.test( filter ) ?
+                                filter.replace( ralpha, opacity ) :
+                                filter + " " + opacity;
+                }
+        };
+}
+
+jQuery(function() {
+        // This hook cannot be added until DOM ready because the support test
+        // for it is not run until after DOM ready
+        if ( !jQuery.support.reliableMarginRight ) {
+                jQuery.cssHooks.marginRight = {
+                        get: function( elem, computed ) {
+                                // WebKit Bug 13343 - getComputedStyle returns wrong value for margin-right
+                                // Work around by temporarily setting element display to inline-block
+                                var ret;
+                                jQuery.swap( elem, { "display": "inline-block" }, function() {
+                                        if ( computed ) {
+                                                ret = curCSS( elem, "margin-right", "marginRight" );
+                                        } else {
+                                                ret = elem.style.marginRight;
+                                        }
+                                });
+                                return ret;
+                        }
+                };
+        }
+});
+
+if ( document.defaultView && document.defaultView.getComputedStyle ) {
+        getComputedStyle = function( elem, name ) {
+                var ret, defaultView, computedStyle;
+
+                name = name.replace( rupper, "-$1" ).toLowerCase();
+
+                if ( !(defaultView = elem.ownerDocument.defaultView) ) {
+                        return undefined;
+                }
+
+                if ( (computedStyle = defaultView.getComputedStyle( elem, null )) ) {
+                        ret = computedStyle.getPropertyValue( name );
+                        if ( ret === "" && !jQuery.contains( elem.ownerDocument.documentElement, elem ) ) {
+                                ret = jQuery.style( elem, name );
+                        }
+                }
+
+                return ret;
+        };
+}
+
+if ( document.documentElement.currentStyle ) {
+        currentStyle = function( elem, name ) {
+                var left,
+                        ret = elem.currentStyle && elem.currentStyle[ name ],
+                        rsLeft = elem.runtimeStyle && elem.runtimeStyle[ name ],
+                        style = elem.style;
+
+                // From the awesome hack by Dean Edwards
+                // http://erik.eae.net/archives/2007/07/27/18.54.15/#comment-102291
+
+                // If we're not dealing with a regular pixel number
+                // but a number that has a weird ending, we need to convert it to pixels
+                if ( !rnumpx.test( ret ) && rnum.test( ret ) ) {
+                        // Remember the original values
+                        left = style.left;
+
+                        // Put in the new values to get a computed value out
+                        if ( rsLeft ) {
+                                elem.runtimeStyle.left = elem.currentStyle.left;
+                        }
+                        style.left = name === "fontSize" ? "1em" : (ret || 0);
+                        ret = style.pixelLeft + "px";
+
+                        // Revert the changed values
+                        style.left = left;
+                        if ( rsLeft ) {
+                                elem.runtimeStyle.left = rsLeft;
+                        }
+                }
+
+                return ret === "" ? "auto" : ret;
+        };
+}
+
+curCSS = getComputedStyle || currentStyle;
+
+function getWH( elem, name, extra ) {
+
+        // Start with offset property
+        var val = name === "width" ? elem.offsetWidth : elem.offsetHeight,
+                which = name === "width" ? cssWidth : cssHeight;
+
+        if ( val > 0 ) {
+                if ( extra !== "border" ) {
+                        jQuery.each( which, function() {
+                                if ( !extra ) {
+                                        val -= parseFloat( jQuery.css( elem, "padding" + this ) ) || 0;
+                                }
+                                if ( extra === "margin" ) {
+                                        val += parseFloat( jQuery.css( elem, extra + this ) ) || 0;
+                                } else {
+                                        val -= parseFloat( jQuery.css( elem, "border" + this + "Width" ) ) || 0;
+                                }
+                        });
+                }
+
+                return val + "px";
+        }
+
+        // Fall back to computed then uncomputed css if necessary
+        val = curCSS( elem, name, name );
+        if ( val < 0 || val == null ) {
+                val = elem.style[ name ] || 0;
+        }
+        // Normalize "", auto, and prepare for extra
+        val = parseFloat( val ) || 0;
+
+        // Add padding, border, margin
+        if ( extra ) {
+                jQuery.each( which, function() {
+                        val += parseFloat( jQuery.css( elem, "padding" + this ) ) || 0;
+                        if ( extra !== "padding" ) {
+                                val += parseFloat( jQuery.css( elem, "border" + this + "Width" ) ) || 0;
+                        }
+                        if ( extra === "margin" ) {
+                                val += parseFloat( jQuery.css( elem, extra + this ) ) || 0;
+                        }
+                });
+        }
+
+        return val + "px";
+}
+
+if ( jQuery.expr && jQuery.expr.filters ) {
+        jQuery.expr.filters.hidden = function( elem ) {
+                var width = elem.offsetWidth,
+                        height = elem.offsetHeight;
+
+                return (width === 0 && height === 0) || (!jQuery.support.reliableHiddenOffsets && (elem.style.display || jQuery.css( elem, "display" )) === "none");
+        };
+
+        jQuery.expr.filters.visible = function( elem ) {
+                return !jQuery.expr.filters.hidden( elem );
+        };
+}
+
+
+
+
+var r20 = /%20/g,
+        rbracket = /\[\]$/,
+        rCRLF = /\r?\n/g,
+        rhash = /#.*$/,
+        rheaders = /^(.*?):[ \t]*([^\r\n]*)\r?$/mg, // IE leaves an \r character at EOL
+        rinput = /^(?:color|date|datetime|datetime-local|email|hidden|month|number|password|range|search|tel|text|time|url|week)$/i,
+        // #7653, #8125, #8152: local protocol detection
+        rlocalProtocol = /^(?:about|app|app\-storage|.+\-extension|file|res|widget):$/,
+        rnoContent = /^(?:GET|HEAD)$/,
+        rprotocol = /^\/\//,
+        rquery = /\?/,
+        rscript = /<script\b[^<]*(?:(?!<\/script>)<[^<]*)*<\/script>/gi,
+        rselectTextarea = /^(?:select|textarea)/i,
+        rspacesAjax = /\s+/,
+        rts = /([?&])_=[^&]*/,
+        rurl = /^([\w\+\.\-]+:)(?:\/\/([^\/?#:]*)(?::(\d+))?)?/,
+
+        // Keep a copy of the old load method
+        _load = jQuery.fn.load,
+
+        /* Prefilters
+         * 1) They are useful to introduce custom dataTypes (see ajax/jsonp.js for an example)
+         * 2) These are called:
+         *    - BEFORE asking for a transport
+         *    - AFTER param serialization (s.data is a string if s.processData is true)
+         * 3) key is the dataType
+         * 4) the catchall symbol "*" can be used
+         * 5) execution will start with transport dataType and THEN continue down to "*" if needed
+         */
+        prefilters = {},
+
+        /* Transports bindings
+         * 1) key is the dataType
+         * 2) the catchall symbol "*" can be used
+         * 3) selection will start with transport dataType and THEN go to "*" if needed
+         */
+        transports = {},
+
+        // Document location
+        ajaxLocation,
+
+        // Document location segments
+        ajaxLocParts,
+        
+        // Avoid comment-prolog char sequence (#10098); must appease lint and evade compression
+        allTypes = ["*/"] + ["*"];
+
+// #8138, IE may throw an exception when accessing
+// a field from window.location if document.domain has been set
+try {
+        ajaxLocation = location.href;
+} catch( e ) {
+        // Use the href attribute of an A element
+        // since IE will modify it given document.location
+        ajaxLocation = document.createElement( "a" );
+        ajaxLocation.href = "";
+        ajaxLocation = ajaxLocation.href;
+}
+
+// Segment location into parts
+ajaxLocParts = rurl.exec( ajaxLocation.toLowerCase() ) || [];
+
+// Base "constructor" for jQuery.ajaxPrefilter and jQuery.ajaxTransport
+function addToPrefiltersOrTransports( structure ) {
+
+        // dataTypeExpression is optional and defaults to "*"
+        return function( dataTypeExpression, func ) {
+
+                if ( typeof dataTypeExpression !== "string" ) {
+                        func = dataTypeExpression;
+                        dataTypeExpression = "*";
+                }
+
+                if ( jQuery.isFunction( func ) ) {
+                        var dataTypes = dataTypeExpression.toLowerCase().split( rspacesAjax ),
+                                i = 0,
+                                length = dataTypes.length,
+                                dataType,
+                                list,
+                                placeBefore;
+
+                        // For each dataType in the dataTypeExpression
+                        for(; i < length; i++ ) {
+                                dataType = dataTypes[ i ];
+                                // We control if we're asked to add before
+                                // any existing element
+                                placeBefore = /^\+/.test( dataType );
+                                if ( placeBefore ) {
+                                        dataType = dataType.substr( 1 ) || "*";
+                                }
+                                list = structure[ dataType ] = structure[ dataType ] || [];
+                                // then we add to the structure accordingly
+                                list[ placeBefore ? "unshift" : "push" ]( func );
+                        }
+                }
+        };
+}
+
+// Base inspection function for prefilters and transports
+function inspectPrefiltersOrTransports( structure, options, originalOptions, jqXHR,
+                dataType /* internal */, inspected /* internal */ ) {
+
+        dataType = dataType || options.dataTypes[ 0 ];
+        inspected = inspected || {};
+
+        inspected[ dataType ] = true;
+
+        var list = structure[ dataType ],
+                i = 0,
+                length = list ? list.length : 0,
+                executeOnly = ( structure === prefilters ),
+                selection;
+
+        for(; i < length && ( executeOnly || !selection ); i++ ) {
+                selection = list[ i ]( options, originalOptions, jqXHR );
+                // If we got redirected to another dataType
+                // we try there if executing only and not done already
+                if ( typeof selection === "string" ) {
+                        if ( !executeOnly || inspected[ selection ] ) {
+                                selection = undefined;
+                        } else {
+                                options.dataTypes.unshift( selection );
+                                selection = inspectPrefiltersOrTransports(
+                                                structure, options, originalOptions, jqXHR, selection, inspected );
+                        }
+                }
+        }
+        // If we're only executing or nothing was selected
+        // we try the catchall dataType if not done already
+        if ( ( executeOnly || !selection ) && !inspected[ "*" ] ) {
+                selection = inspectPrefiltersOrTransports(
+                                structure, options, originalOptions, jqXHR, "*", inspected );
+        }
+        // unnecessary when only executing (prefilters)
+        // but it'll be ignored by the caller in that case
+        return selection;
+}
+
+// A special extend for ajax options
+// that takes "flat" options (not to be deep extended)
+// Fixes #9887
+function ajaxExtend( target, src ) {
+        var key, deep,
+                flatOptions = jQuery.ajaxSettings.flatOptions || {};
+        for( key in src ) {
+                if ( src[ key ] !== undefined ) {
+                        ( flatOptions[ key ] ? target : ( deep || ( deep = {} ) ) )[ key ] = src[ key ];
+                }
+        }
+        if ( deep ) {
+                jQuery.extend( true, target, deep );
+        }
+}
+
+jQuery.fn.extend({
+        load: function( url, params, callback ) {
+                if ( typeof url !== "string" && _load ) {
+                        return _load.apply( this, arguments );
+
+                // Don't do a request if no elements are being requested
+                } else if ( !this.length ) {
+                        return this;
+                }
+
+                var off = url.indexOf( " " );
+                if ( off >= 0 ) {
+                        var selector = url.slice( off, url.length );
+                        url = url.slice( 0, off );
+                }
+
+                // Default to a GET request
+                var type = "GET";
+
+                // If the second parameter was provided
+                if ( params ) {
+                        // If it's a function
+                        if ( jQuery.isFunction( params ) ) {
+                                // We assume that it's the callback
+                                callback = params;
+                                params = undefined;
+
+                        // Otherwise, build a param string
+                        } else if ( typeof params === "object" ) {
+                                params = jQuery.param( params, jQuery.ajaxSettings.traditional );
+                                type = "POST";
+                        }
+                }
+
+                var self = this;
+
+                // Request the remote document
+                jQuery.ajax({
+                        url: url,
+                        type: type,
+                        dataType: "html",
+                        data: params,
+                        // Complete callback (responseText is used internally)
+                        complete: function( jqXHR, status, responseText ) {
+                                // Store the response as specified by the jqXHR object
+                                responseText = jqXHR.responseText;
+                                // If successful, inject the HTML into all the matched elements
+                                if ( jqXHR.isResolved() ) {
+                                        // #4825: Get the actual response in case
+                                        // a dataFilter is present in ajaxSettings
+                                        jqXHR.done(function( r ) {
+                                                responseText = r;
+                                        });
+                                        // See if a selector was specified
+                                        self.html( selector ?
+                                                // Create a dummy div to hold the results
+                                                jQuery("<div>")
+                                                        // inject the contents of the document in, removing the scripts
+                                                        // to avoid any 'Permission Denied' errors in IE
+                                                        .append(responseText.replace(rscript, ""))
+
+                                                        // Locate the specified elements
+                                                        .find(selector) :
+
+                                                // If not, just inject the full result
+                                                responseText );
+                                }
+
+                                if ( callback ) {
+                                        self.each( callback, [ responseText, status, jqXHR ] );
+                                }
+                        }
+                });
+
+                return this;
+        },
+
+        serialize: function() {
+                return jQuery.param( this.serializeArray() );
+        },
+
+        serializeArray: function() {
+                return this.map(function(){
+                        return this.elements ? jQuery.makeArray( this.elements ) : this;
+                })
+                .filter(function(){
+                        return this.name && !this.disabled &&
+                                ( this.checked || rselectTextarea.test( this.nodeName ) ||
+                                        rinput.test( this.type ) );
+                })
+                .map(function( i, elem ){
+                        var val = jQuery( this ).val();
+
+                        return val == null ?
+                                null :
+                                jQuery.isArray( val ) ?
+                                        jQuery.map( val, function( val, i ){
+                                                return { name: elem.name, value: val.replace( rCRLF, "\r\n" ) };
+                                        }) :
+                                        { name: elem.name, value: val.replace( rCRLF, "\r\n" ) };
+                }).get();
+        }
+});
+
+// Attach a bunch of functions for handling common AJAX events
+jQuery.each( "ajaxStart ajaxStop ajaxComplete ajaxError ajaxSuccess ajaxSend".split( " " ), function( i, o ){
+        jQuery.fn[ o ] = function( f ){
+                return this.bind( o, f );
+        };
+});
+
+jQuery.each( [ "get", "post" ], function( i, method ) {
+        jQuery[ method ] = function( url, data, callback, type ) {
+                // shift arguments if data argument was omitted
+                if ( jQuery.isFunction( data ) ) {
+                        type = type || callback;
+                        callback = data;
+                        data = undefined;
+                }
+
+                return jQuery.ajax({
+                        type: method,
+                        url: url,
+                        data: data,
+                        success: callback,
+                        dataType: type
+                });
+        };
+});
+
+jQuery.extend({
+
+        getScript: function( url, callback ) {
+                return jQuery.get( url, undefined, callback, "script" );
+        },
+
+        getJSON: function( url, data, callback ) {
+                return jQuery.get( url, data, callback, "json" );
+        },
+
+        // Creates a full fledged settings object into target
+        // with both ajaxSettings and settings fields.
+        // If target is omitted, writes into ajaxSettings.
+        ajaxSetup: function( target, settings ) {
+                if ( settings ) {
+                        // Building a settings object
+                        ajaxExtend( target, jQuery.ajaxSettings );
+                } else {
+                        // Extending ajaxSettings
+                        settings = target;
+                        target = jQuery.ajaxSettings;
+                }
+                ajaxExtend( target, settings );
+                return target;
+        },
+
+        ajaxSettings: {
+                url: ajaxLocation,
+                isLocal: rlocalProtocol.test( ajaxLocParts[ 1 ] ),
+                global: true,
+                type: "GET",
+                contentType: "application/x-www-form-urlencoded",
+                processData: true,
+                async: true,
+                /*
+                timeout: 0,
+                data: null,
+                dataType: null,
+                username: null,
+                password: null,
+                cache: null,
+                traditional: false,
+                headers: {},
+                */
+
+                accepts: {
+                        xml: "application/xml, text/xml",
+                        html: "text/html",
+                        text: "text/plain",
+                        json: "application/json, text/javascript",
+                        "*": allTypes
+                },
+
+                contents: {
+                        xml: /xml/,
+                        html: /html/,
+                        json: /json/
+                },
+
+                responseFields: {
+                        xml: "responseXML",
+                        text: "responseText"
+                },
+
+                // List of data converters
+                // 1) key format is "source_type destination_type" (a single space in-between)
+                // 2) the catchall symbol "*" can be used for source_type
+                converters: {
+
+                        // Convert anything to text
+                        "* text": window.String,
+
+                        // Text to html (true = no transformation)
+                        "text html": true,
+
+                        // Evaluate text as a json expression
+                        "text json": jQuery.parseJSON,
+
+                        // Parse text as xml
+                        "text xml": jQuery.parseXML
+                },
+
+                // For options that shouldn't be deep extended:
+                // you can add your own custom options here if
+                // and when you create one that shouldn't be
+                // deep extended (see ajaxExtend)
+                flatOptions: {
+                        context: true,
+                        url: true
+                }
+        },
+
+        ajaxPrefilter: addToPrefiltersOrTransports( prefilters ),
+        ajaxTransport: addToPrefiltersOrTransports( transports ),
+
+        // Main method
+        ajax: function( url, options ) {
+
+                // If url is an object, simulate pre-1.5 signature
+                if ( typeof url === "object" ) {
+                        options = url;
+                        url = undefined;
+                }
+
+                // Force options to be an object
+                options = options || {};
+
+                var // Create the final options object
+                        s = jQuery.ajaxSetup( {}, options ),
+                        // Callbacks context
+                        callbackContext = s.context || s,
+                        // Context for global events
+                        // It's the callbackContext if one was provided in the options
+                        // and if it's a DOM node or a jQuery collection
+                        globalEventContext = callbackContext !== s &&
+                                ( callbackContext.nodeType || callbackContext instanceof jQuery ) ?
+                                                jQuery( callbackContext ) : jQuery.event,
+                        // Deferreds
+                        deferred = jQuery.Deferred(),
+                        completeDeferred = jQuery._Deferred(),
+                        // Status-dependent callbacks
+                        statusCode = s.statusCode || {},
+                        // ifModified key
+                        ifModifiedKey,
+                        // Headers (they are sent all at once)
+                        requestHeaders = {},
+                        requestHeadersNames = {},
+                        // Response headers
+                        responseHeadersString,
+                        responseHeaders,
+                        // transport
+                        transport,
+                        // timeout handle
+                        timeoutTimer,
+                        // Cross-domain detection vars
+                        parts,
+                        // The jqXHR state
+                        state = 0,
+                        // To know if global events are to be dispatched
+                        fireGlobals,
+                        // Loop variable
+                        i,
+                        // Fake xhr
+                        jqXHR = {
+
+                                readyState: 0,
+
+                                // Caches the header
+                                setRequestHeader: function( name, value ) {
+                                        if ( !state ) {
+                                                var lname = name.toLowerCase();
+                                                name = requestHeadersNames[ lname ] = requestHeadersNames[ lname ] || name;
+                                                requestHeaders[ name ] = value;
+                                        }
+                                        return this;
+                                },
+
+                                // Raw string
+                                getAllResponseHeaders: function() {
+                                        return state === 2 ? responseHeadersString : null;
+                                },
+
+                                // Builds headers hashtable if needed
+                                getResponseHeader: function( key ) {
+                                        var match;
+                                        if ( state === 2 ) {
+                                                if ( !responseHeaders ) {
+                                                        responseHeaders = {};
+                                                        while( ( match = rheaders.exec( responseHeadersString ) ) ) {
+                                                                responseHeaders[ match[1].toLowerCase() ] = match[ 2 ];
+                                                        }
+                                                }
+                                                match = responseHeaders[ key.toLowerCase() ];
+                                        }
+                                        return match === undefined ? null : match;
+                                },
+
+                                // Overrides response content-type header
+                                overrideMimeType: function( type ) {
+                                        if ( !state ) {
+                                                s.mimeType = type;
+                                        }
+                                        return this;
+                                },
+
+                                // Cancel the request
+                                abort: function( statusText ) {
+                                        statusText = statusText || "abort";
+                                        if ( transport ) {
+                                                transport.abort( statusText );
+                                        }
+                                        done( 0, statusText );
+                                        return this;
+                                }
+                        };
+
+                // Callback for when everything is done
+                // It is defined here because jslint complains if it is declared
+                // at the end of the function (which would be more logical and readable)
+                function done( status, nativeStatusText, responses, headers ) {
+
+                        // Called once
+                        if ( state === 2 ) {
+                                return;
+                        }
+
+                        // State is "done" now
+                        state = 2;
+
+                        // Clear timeout if it exists
+                        if ( timeoutTimer ) {
+                                clearTimeout( timeoutTimer );
+                        }
+
+                        // Dereference transport for early garbage collection
+                        // (no matter how long the jqXHR object will be used)
+                        transport = undefined;
+
+                        // Cache response headers
+                        responseHeadersString = headers || "";
+
+                        // Set readyState
+                        jqXHR.readyState = status > 0 ? 4 : 0;
+
+                        var isSuccess,
+                                success,
+                                error,
+                                statusText = nativeStatusText,
+                                response = responses ? ajaxHandleResponses( s, jqXHR, responses ) : undefined,
+                                lastModified,
+                                etag;
+
+                        // If successful, handle type chaining
+                        if ( status >= 200 && status < 300 || status === 304 ) {
+
+                                // Set the If-Modified-Since and/or If-None-Match header, if in ifModified mode.
+                                if ( s.ifModified ) {
+
+                                        if ( ( lastModified = jqXHR.getResponseHeader( "Last-Modified" ) ) ) {
+                                                jQuery.lastModified[ ifModifiedKey ] = lastModified;
+                                        }
+                                        if ( ( etag = jqXHR.getResponseHeader( "Etag" ) ) ) {
+                                                jQuery.etag[ ifModifiedKey ] = etag;
+                                        }
+                                }
+
+                                // If not modified
+                                if ( status === 304 ) {
+
+                                        statusText = "notmodified";
+                                        isSuccess = true;
+
+                                // If we have data
+                                } else {
+
+                                        try {
+                                                success = ajaxConvert( s, response );
+                                                statusText = "success";
+                                                isSuccess = true;
+                                        } catch(e) {
+                                                // We have a parsererror
+                                                statusText = "parsererror";
+                                                error = e;
+                                        }
+                                }
+                        } else {
+                                // We extract error from statusText
+                                // then normalize statusText and status for non-aborts
+                                error = statusText;
+                                if( !statusText || status ) {
+                                        statusText = "error";
+                                        if ( status < 0 ) {
+                                                status = 0;
+                                        }
+                                }
+                        }
+
+                        // Set data for the fake xhr object
+                        jqXHR.status = status;
+                        jqXHR.statusText = "" + ( nativeStatusText || statusText );
+
+                        // Success/Error
+                        if ( isSuccess ) {
+                                deferred.resolveWith( callbackContext, [ success, statusText, jqXHR ] );
+                        } else {
+                                deferred.rejectWith( callbackContext, [ jqXHR, statusText, error ] );
+                        }
+
+                        // Status-dependent callbacks
+                        jqXHR.statusCode( statusCode );
+                        statusCode = undefined;
+
+                        if ( fireGlobals ) {
+                                globalEventContext.trigger( "ajax" + ( isSuccess ? "Success" : "Error" ),
+                                                [ jqXHR, s, isSuccess ? success : error ] );
+                        }
+
+                        // Complete
+                        completeDeferred.resolveWith( callbackContext, [ jqXHR, statusText ] );
+
+                        if ( fireGlobals ) {
+                                globalEventContext.trigger( "ajaxComplete", [ jqXHR, s ] );
+                                // Handle the global AJAX counter
+                                if ( !( --jQuery.active ) ) {
+                                        jQuery.event.trigger( "ajaxStop" );
+                                }
+                        }
+                }
+
+                // Attach deferreds
+                deferred.promise( jqXHR );
+                jqXHR.success = jqXHR.done;
+                jqXHR.error = jqXHR.fail;
+                jqXHR.complete = completeDeferred.done;
+
+                // Status-dependent callbacks
+                jqXHR.statusCode = function( map ) {
+                        if ( map ) {
+                                var tmp;
+                                if ( state < 2 ) {
+                                        for( tmp in map ) {
+                                                statusCode[ tmp ] = [ statusCode[tmp], map[tmp] ];
+                                        }
+                                } else {
+                                        tmp = map[ jqXHR.status ];
+                                        jqXHR.then( tmp, tmp );
+                                }
+                        }
+                        return this;
+                };
+
+                // Remove hash character (#7531: and string promotion)
+                // Add protocol if not provided (#5866: IE7 issue with protocol-less urls)
+                // We also use the url parameter if available
+                s.url = ( ( url || s.url ) + "" ).replace( rhash, "" ).replace( rprotocol, ajaxLocParts[ 1 ] + "//" );
+
+                // Extract dataTypes list
+                s.dataTypes = jQuery.trim( s.dataType || "*" ).toLowerCase().split( rspacesAjax );
+
+                // Determine if a cross-domain request is in order
+                if ( s.crossDomain == null ) {
+                        parts = rurl.exec( s.url.toLowerCase() );
+                        s.crossDomain = !!( parts &&
+                                ( parts[ 1 ] != ajaxLocParts[ 1 ] || parts[ 2 ] != ajaxLocParts[ 2 ] ||
+                                        ( parts[ 3 ] || ( parts[ 1 ] === "http:" ? 80 : 443 ) ) !=
+                                                ( ajaxLocParts[ 3 ] || ( ajaxLocParts[ 1 ] === "http:" ? 80 : 443 ) ) )
+                        );
+                }
+
+                // Convert data if not already a string
+                if ( s.data && s.processData && typeof s.data !== "string" ) {
+                        s.data = jQuery.param( s.data, s.traditional );
+                }
+
+                // Apply prefilters
+                inspectPrefiltersOrTransports( prefilters, s, options, jqXHR );
+
+                // If request was aborted inside a prefiler, stop there
+                if ( state === 2 ) {
+                        return false;
+                }
+
+                // We can fire global events as of now if asked to
+                fireGlobals = s.global;
+
+                // Uppercase the type
+                s.type = s.type.toUpperCase();
+
+                // Determine if request has content
+                s.hasContent = !rnoContent.test( s.type );
+
+                // Watch for a new set of requests
+                if ( fireGlobals && jQuery.active++ === 0 ) {
+                        jQuery.event.trigger( "ajaxStart" );
+                }
+
+                // More options handling for requests with no content
+                if ( !s.hasContent ) {
+
+                        // If data is available, append data to url
+                        if ( s.data ) {
+                                s.url += ( rquery.test( s.url ) ? "&" : "?" ) + s.data;
+                                // #9682: remove data so that it's not used in an eventual retry
+                                delete s.data;
+                        }
+
+                        // Get ifModifiedKey before adding the anti-cache parameter
+                        ifModifiedKey = s.url;
+
+                        // Add anti-cache in url if needed
+                        if ( s.cache === false ) {
+
+                                var ts = jQuery.now(),
+                                        // try replacing _= if it is there
+                                        ret = s.url.replace( rts, "$1_=" + ts );
+
+                                // if nothing was replaced, add timestamp to the end
+                                s.url = ret + ( (ret === s.url ) ? ( rquery.test( s.url ) ? "&" : "?" ) + "_=" + ts : "" );
+                        }
+                }
+
+                // Set the correct header, if data is being sent
+                if ( s.data && s.hasContent && s.contentType !== false || options.contentType ) {
+                        jqXHR.setRequestHeader( "Content-Type", s.contentType );
+                }
+
+                // Set the If-Modified-Since and/or If-None-Match header, if in ifModified mode.
+                if ( s.ifModified ) {
+                        ifModifiedKey = ifModifiedKey || s.url;
+                        if ( jQuery.lastModified[ ifModifiedKey ] ) {
+                                jqXHR.setRequestHeader( "If-Modified-Since", jQuery.lastModified[ ifModifiedKey ] );
+                        }
+                        if ( jQuery.etag[ ifModifiedKey ] ) {
+                                jqXHR.setRequestHeader( "If-None-Match", jQuery.etag[ ifModifiedKey ] );
+                        }
+                }
+
+                // Set the Accepts header for the server, depending on the dataType
+                jqXHR.setRequestHeader(
+                        "Accept",
+                        s.dataTypes[ 0 ] && s.accepts[ s.dataTypes[0] ] ?
+                                s.accepts[ s.dataTypes[0] ] + ( s.dataTypes[ 0 ] !== "*" ? ", " + allTypes + "; q=0.01" : "" ) :
+                                s.accepts[ "*" ]
+                );
+
+                // Check for headers option
+                for ( i in s.headers ) {
+                        jqXHR.setRequestHeader( i, s.headers[ i ] );
+                }
+
+                // Allow custom headers/mimetypes and early abort
+                if ( s.beforeSend && ( s.beforeSend.call( callbackContext, jqXHR, s ) === false || state === 2 ) ) {
+                                // Abort if not done already
+                                jqXHR.abort();
+                                return false;
+
+                }
+
+                // Install callbacks on deferreds
+                for ( i in { success: 1, error: 1, complete: 1 } ) {
+                        jqXHR[ i ]( s[ i ] );
+                }
+
+                // Get transport
+                transport = inspectPrefiltersOrTransports( transports, s, options, jqXHR );
+
+                // If no transport, we auto-abort
+                if ( !transport ) {
+                        done( -1, "No Transport" );
+                } else {
+                        jqXHR.readyState = 1;
+                        // Send global event
+                        if ( fireGlobals ) {
+                                globalEventContext.trigger( "ajaxSend", [ jqXHR, s ] );
+                        }
+                        // Timeout
+                        if ( s.async && s.timeout > 0 ) {
+                                timeoutTimer = setTimeout( function(){
+                                        jqXHR.abort( "timeout" );
+                                }, s.timeout );
+                        }
+
+                        try {
+                                state = 1;
+                                transport.send( requestHeaders, done );
+                        } catch (e) {
+                                // Propagate exception as error if not done
+                                if ( state < 2 ) {
+                                        done( -1, e );
+                                // Simply rethrow otherwise
+                                } else {
+                                        jQuery.error( e );
+                                }
+                        }
+                }
+
+                return jqXHR;
+        },
+
+        // Serialize an array of form elements or a set of
+        // key/values into a query string
+        param: function( a, traditional ) {
+                var s = [],
+                        add = function( key, value ) {
+                                // If value is a function, invoke it and return its value
+                                value = jQuery.isFunction( value ) ? value() : value;
+                                s[ s.length ] = encodeURIComponent( key ) + "=" + encodeURIComponent( value );
+                        };
+
+                // Set traditional to true for jQuery <= 1.3.2 behavior.
+                if ( traditional === undefined ) {
+                        traditional = jQuery.ajaxSettings.traditional;
+                }
+
+                // If an array was passed in, assume that it is an array of form elements.
+                if ( jQuery.isArray( a ) || ( a.jquery && !jQuery.isPlainObject( a ) ) ) {
+                        // Serialize the form elements
+                        jQuery.each( a, function() {
+                                add( this.name, this.value );
+                        });
+
+                } else {
+                        // If traditional, encode the "old" way (the way 1.3.2 or older
+                        // did it), otherwise encode params recursively.
+                        for ( var prefix in a ) {
+                                buildParams( prefix, a[ prefix ], traditional, add );
+                        }
+                }
+
+                // Return the resulting serialization
+                return s.join( "&" ).replace( r20, "+" );
+        }
+});
+
+function buildParams( prefix, obj, traditional, add ) {
+        if ( jQuery.isArray( obj ) ) {
+                // Serialize array item.
+                jQuery.each( obj, function( i, v ) {
+                        if ( traditional || rbracket.test( prefix ) ) {
+                                // Treat each array item as a scalar.
+                                add( prefix, v );
+
+                        } else {
+                                // If array item is non-scalar (array or object), encode its
+                                // numeric index to resolve deserialization ambiguity issues.
+                                // Note that rack (as of 1.0.0) can't currently deserialize
+                                // nested arrays properly, and attempting to do so may cause
+                                // a server error. Possible fixes are to modify rack's
+                                // deserialization algorithm or to provide an option or flag
+                                // to force array serialization to be shallow.
+                                buildParams( prefix + "[" + ( typeof v === "object" || jQuery.isArray(v) ? i : "" ) + "]", v, traditional, add );
+                        }
+                });
+
+        } else if ( !traditional && obj != null && typeof obj === "object" ) {
+                // Serialize object item.
+                for ( var name in obj ) {
+                        buildParams( prefix + "[" + name + "]", obj[ name ], traditional, add );
+                }
+
+        } else {
+                // Serialize scalar item.
+                add( prefix, obj );
+        }
+}
+
+// This is still on the jQuery object... for now
+// Want to move this to jQuery.ajax some day
+jQuery.extend({
+
+        // Counter for holding the number of active queries
+        active: 0,
+
+        // Last-Modified header cache for next request
+        lastModified: {},
+        etag: {}
+
+});
+
+/* Handles responses to an ajax request:
+ * - sets all responseXXX fields accordingly
+ * - finds the right dataType (mediates between content-type and expected dataType)
+ * - returns the corresponding response
+ */
+function ajaxHandleResponses( s, jqXHR, responses ) {
+
+        var contents = s.contents,
+                dataTypes = s.dataTypes,
+                responseFields = s.responseFields,
+                ct,
+                type,
+                finalDataType,
+                firstDataType;
+
+        // Fill responseXXX fields
+        for( type in responseFields ) {
+                if ( type in responses ) {
+                        jqXHR[ responseFields[type] ] = responses[ type ];
+                }
+        }
+
+        // Remove auto dataType and get content-type in the process
+        while( dataTypes[ 0 ] === "*" ) {
+                dataTypes.shift();
+                if ( ct === undefined ) {
+                        ct = s.mimeType || jqXHR.getResponseHeader( "content-type" );
+                }
+        }
+
+        // Check if we're dealing with a known content-type
+        if ( ct ) {
+                for ( type in contents ) {
+                        if ( contents[ type ] && contents[ type ].test( ct ) ) {
+                                dataTypes.unshift( type );
+                                break;
+                        }
+                }
+        }
+
+        // Check to see if we have a response for the expected dataType
+        if ( dataTypes[ 0 ] in responses ) {
+                finalDataType = dataTypes[ 0 ];
+        } else {
+                // Try convertible dataTypes
+                for ( type in responses ) {
+                        if ( !dataTypes[ 0 ] || s.converters[ type + " " + dataTypes[0] ] ) {
+                                finalDataType = type;
+                                break;
+                        }
+                        if ( !firstDataType ) {
+                                firstDataType = type;
+                        }
+                }
+                // Or just use first one
+                finalDataType = finalDataType || firstDataType;
+        }
+
+        // If we found a dataType
+        // We add the dataType to the list if needed
+        // and return the corresponding response
+        if ( finalDataType ) {
+                if ( finalDataType !== dataTypes[ 0 ] ) {
+                        dataTypes.unshift( finalDataType );
+                }
+                return responses[ finalDataType ];
+        }
+}
+
+// Chain conversions given the request and the original response
+function ajaxConvert( s, response ) {
+
+        // Apply the dataFilter if provided
+        if ( s.dataFilter ) {
+                response = s.dataFilter( response, s.dataType );
+        }
+
+        var dataTypes = s.dataTypes,
+                converters = {},
+                i,
+                key,
+                length = dataTypes.length,
+                tmp,
+                // Current and previous dataTypes
+                current = dataTypes[ 0 ],
+                prev,
+                // Conversion expression
+                conversion,
+                // Conversion function
+                conv,
+                // Conversion functions (transitive conversion)
+                conv1,
+                conv2;
+
+        // For each dataType in the chain
+        for( i = 1; i < length; i++ ) {
+
+                // Create converters map
+                // with lowercased keys
+                if ( i === 1 ) {
+                        for( key in s.converters ) {
+                                if( typeof key === "string" ) {
+                                        converters[ key.toLowerCase() ] = s.converters[ key ];
+                                }
+                        }
+                }
+
+                // Get the dataTypes
+                prev = current;
+                current = dataTypes[ i ];
+
+                // If current is auto dataType, update it to prev
+                if( current === "*" ) {
+                        current = prev;
+                // If no auto and dataTypes are actually different
+                } else if ( prev !== "*" && prev !== current ) {
+
+                        // Get the converter
+                        conversion = prev + " " + current;
+                        conv = converters[ conversion ] || converters[ "* " + current ];
+
+                        // If there is no direct converter, search transitively
+                        if ( !conv ) {
+                                conv2 = undefined;
+                                for( conv1 in converters ) {
+                                        tmp = conv1.split( " " );
+                                        if ( tmp[ 0 ] === prev || tmp[ 0 ] === "*" ) {
+                                                conv2 = converters[ tmp[1] + " " + current ];
+                                                if ( conv2 ) {
+                                                        conv1 = converters[ conv1 ];
+                                                        if ( conv1 === true ) {
+                                                                conv = conv2;
+                                                        } else if ( conv2 === true ) {
+                                                                conv = conv1;
+                                                        }
+                                                        break;
+                                                }
+                                        }
+                                }
+                        }
+                        // If we found no converter, dispatch an error
+                        if ( !( conv || conv2 ) ) {
+                                jQuery.error( "No conversion from " + conversion.replace(" "," to ") );
+                        }
+                        // If found converter is not an equivalence
+                        if ( conv !== true ) {
+                                // Convert with 1 or 2 converters accordingly
+                                response = conv ? conv( response ) : conv2( conv1(response) );
+                        }
+                }
+        }
+        return response;
+}
+
+
+
+
+var jsc = jQuery.now(),
+        jsre = /(\=)\?(&|$)|\?\?/i;
+
+// Default jsonp settings
+jQuery.ajaxSetup({
+        jsonp: "callback",
+        jsonpCallback: function() {
+                return jQuery.expando + "_" + ( jsc++ );
+        }
+});
+
+// Detect, normalize options and install callbacks for jsonp requests
+jQuery.ajaxPrefilter( "json jsonp", function( s, originalSettings, jqXHR ) {
+
+        var inspectData = s.contentType === "application/x-www-form-urlencoded" &&
+                ( typeof s.data === "string" );
+
+        if ( s.dataTypes[ 0 ] === "jsonp" ||
+                s.jsonp !== false && ( jsre.test( s.url ) ||
+                                inspectData && jsre.test( s.data ) ) ) {
+
+                var responseContainer,
+                        jsonpCallback = s.jsonpCallback =
+                                jQuery.isFunction( s.jsonpCallback ) ? s.jsonpCallback() : s.jsonpCallback,
+                        previous = window[ jsonpCallback ],
+                        url = s.url,
+                        data = s.data,
+                        replace = "$1" + jsonpCallback + "$2";
+
+                if ( s.jsonp !== false ) {
+                        url = url.replace( jsre, replace );
+                        if ( s.url === url ) {
+                                if ( inspectData ) {
+                                        data = data.replace( jsre, replace );
+                                }
+                                if ( s.data === data ) {
+                                        // Add callback manually
+                                        url += (/\?/.test( url ) ? "&" : "?") + s.jsonp + "=" + jsonpCallback;
+                                }
+                        }
+                }
+
+                s.url = url;
+                s.data = data;
+
+                // Install callback
+                window[ jsonpCallback ] = function( response ) {
+                        responseContainer = [ response ];
+                };
+
+                // Clean-up function
+                jqXHR.always(function() {
+                        // Set callback back to previous value
+                        window[ jsonpCallback ] = previous;
+                        // Call if it was a function and we have a response
+                        if ( responseContainer && jQuery.isFunction( previous ) ) {
+                                window[ jsonpCallback ]( responseContainer[ 0 ] );
+                        }
+                });
+
+                // Use data converter to retrieve json after script execution
+                s.converters["script json"] = function() {
+                        if ( !responseContainer ) {
+                                jQuery.error( jsonpCallback + " was not called" );
+                        }
+                        return responseContainer[ 0 ];
+                };
+
+                // force json dataType
+                s.dataTypes[ 0 ] = "json";
+
+                // Delegate to script
+                return "script";
+        }
+});
+
+
+
+
+// Install script dataType
+jQuery.ajaxSetup({
+        accepts: {
+                script: "text/javascript, application/javascript, application/ecmascript, application/x-ecmascript"
+        },
+        contents: {
+                script: /javascript|ecmascript/
+        },
+        converters: {
+                "text script": function( text ) {
+                        jQuery.globalEval( text );
+                        return text;
+                }
+        }
+});
+
+// Handle cache's special case and global
+jQuery.ajaxPrefilter( "script", function( s ) {
+        if ( s.cache === undefined ) {
+                s.cache = false;
+        }
+        if ( s.crossDomain ) {
+                s.type = "GET";
+                s.global = false;
+        }
+});
+
+// Bind script tag hack transport
+jQuery.ajaxTransport( "script", function(s) {
+
+        // This transport only deals with cross domain requests
+        if ( s.crossDomain ) {
+
+                var script,
+                        head = document.head || document.getElementsByTagName( "head" )[0] || document.documentElement;
+
+                return {
+
+                        send: function( _, callback ) {
+
+                                script = document.createElement( "script" );
+
+                                script.async = "async";
+
+                                if ( s.scriptCharset ) {
+                                        script.charset = s.scriptCharset;
+                                }
+
+                                script.src = s.url;
+
+                                // Attach handlers for all browsers
+                                script.onload = script.onreadystatechange = function( _, isAbort ) {
+
+                                        if ( isAbort || !script.readyState || /loaded|complete/.test( script.readyState ) ) {
+
+                                                // Handle memory leak in IE
+                                                script.onload = script.onreadystatechange = null;
+
+                                                // Remove the script
+                                                if ( head && script.parentNode ) {
+                                                        head.removeChild( script );
+                                                }
+
+                                                // Dereference the script
+                                                script = undefined;
+
+                                                // Callback if not abort
+                                                if ( !isAbort ) {
+                                                        callback( 200, "success" );
+                                                }
+                                        }
+                                };
+                                // Use insertBefore instead of appendChild  to circumvent an IE6 bug.
+                                // This arises when a base node is used (#2709 and #4378).
+                                head.insertBefore( script, head.firstChild );
+                        },
+
+                        abort: function() {
+                                if ( script ) {
+                                        script.onload( 0, 1 );
+                                }
+                        }
+                };
+        }
+});
+
+
+
+
+var // #5280: Internet Explorer will keep connections alive if we don't abort on unload
+        xhrOnUnloadAbort = window.ActiveXObject ? function() {
+                // Abort all pending requests
+                for ( var key in xhrCallbacks ) {
+                        xhrCallbacks[ key ]( 0, 1 );
+                }
+        } : false,
+        xhrId = 0,
+        xhrCallbacks;
+
+// Functions to create xhrs
+function createStandardXHR() {
+        try {
+                return new window.XMLHttpRequest();
+        } catch( e ) {}
+}
+
+function createActiveXHR() {
+        try {
+                return new window.ActiveXObject( "Microsoft.XMLHTTP" );
+        } catch( e ) {}
+}
+
+// Create the request object
+// (This is still attached to ajaxSettings for backward compatibility)
+jQuery.ajaxSettings.xhr = window.ActiveXObject ?
+        /* Microsoft failed to properly
+         * implement the XMLHttpRequest in IE7 (can't request local files),
+         * so we use the ActiveXObject when it is available
+         * Additionally XMLHttpRequest can be disabled in IE7/IE8 so
+         * we need a fallback.
+         */
+        function() {
+                return !this.isLocal && createStandardXHR() || createActiveXHR();
+        } :
+        // For all other browsers, use the standard XMLHttpRequest object
+        createStandardXHR;
+
+// Determine support properties
+(function( xhr ) {
+        jQuery.extend( jQuery.support, {
+                ajax: !!xhr,
+                cors: !!xhr && ( "withCredentials" in xhr )
+        });
+})( jQuery.ajaxSettings.xhr() );
+
+// Create transport if the browser can provide an xhr
+if ( jQuery.support.ajax ) {
+
+        jQuery.ajaxTransport(function( s ) {
+                // Cross domain only allowed if supported through XMLHttpRequest
+                if ( !s.crossDomain || jQuery.support.cors ) {
+
+                        var callback;
+
+                        return {
+                                send: function( headers, complete ) {
+
+                                        // Get a new xhr
+                                        var xhr = s.xhr(),
+                                                handle,
+                                                i;
+
+                                        // Open the socket
+                                        // Passing null username, generates a login popup on Opera (#2865)
+                                        if ( s.username ) {
+                                                xhr.open( s.type, s.url, s.async, s.username, s.password );
+                                        } else {
+                                                xhr.open( s.type, s.url, s.async );
+                                        }
+
+                                        // Apply custom fields if provided
+                                        if ( s.xhrFields ) {
+                                                for ( i in s.xhrFields ) {
+                                                        xhr[ i ] = s.xhrFields[ i ];
+                                                }
+                                        }
+
+                                        // Override mime type if needed
+                                        if ( s.mimeType && xhr.overrideMimeType ) {
+                                                xhr.overrideMimeType( s.mimeType );
+                                        }
+
+                                        // X-Requested-With header
+                                        // For cross-domain requests, seeing as conditions for a preflight are
+                                        // akin to a jigsaw puzzle, we simply never set it to be sure.
+                                        // (it can always be set on a per-request basis or even using ajaxSetup)
+                                        // For same-domain requests, won't change header if already provided.
+                                        if ( !s.crossDomain && !headers["X-Requested-With"] ) {
+                                                headers[ "X-Requested-With" ] = "XMLHttpRequest";
+                                        }
+
+                                        // Need an extra try/catch for cross domain requests in Firefox 3
+                                        try {
+                                                for ( i in headers ) {
+                                                        xhr.setRequestHeader( i, headers[ i ] );
+                                                }
+                                        } catch( _ ) {}
+
+                                        // Do send the request
+                                        // This may raise an exception which is actually
+                                        // handled in jQuery.ajax (so no try/catch here)
+                                        xhr.send( ( s.hasContent && s.data ) || null );
+
+                                        // Listener
+                                        callback = function( _, isAbort ) {
+
+                                                var status,
+                                                        statusText,
+                                                        responseHeaders,
+                                                        responses,
+                                                        xml;
+
+                                                // Firefox throws exceptions when accessing properties
+                                                // of an xhr when a network error occured
+                                                // http://helpful.knobs-dials.com/index.php/Component_returned_failure_code:_0x80040111_(NS_ERROR_NOT_AVAILABLE)
+                                                try {
+
+                                                        // Was never called and is aborted or complete
+                                                        if ( callback && ( isAbort || xhr.readyState === 4 ) ) {
+
+                                                                // Only called once
+                                                                callback = undefined;
+
+                                                                // Do not keep as active anymore
+                                                                if ( handle ) {
+                                                                        xhr.onreadystatechange = jQuery.noop;
+                                                                        if ( xhrOnUnloadAbort ) {
+                                                                                delete xhrCallbacks[ handle ];
+                                                                        }
+                                                                }
+
+                                                                // If it's an abort
+                                                                if ( isAbort ) {
+                                                                        // Abort it manually if needed
+                                                                        if ( xhr.readyState !== 4 ) {
+                                                                                xhr.abort();
+                                                                        }
+                                                                } else {
+                                                                        status = xhr.status;
+                                                                        responseHeaders = xhr.getAllResponseHeaders();
+                                                                        responses = {};
+                                                                        xml = xhr.responseXML;
+
+                                                                        // Construct response list
+                                                                        if ( xml && xml.documentElement /* #4958 */ ) {
+                                                                                responses.xml = xml;
+                                                                        }
+                                                                        responses.text = xhr.responseText;
+
+                                                                        // Firefox throws an exception when accessing
+                                                                        // statusText for faulty cross-domain requests
+                                                                        try {
+                                                                                statusText = xhr.statusText;
+                                                                        } catch( e ) {
+                                                                                // We normalize with Webkit giving an empty statusText
+                                                                                statusText = "";
+                                                                        }
+
+                                                                        // Filter status for non standard behaviors
+
+                                                                        // If the request is local and we have data: assume a success
+                                                                        // (success with no data won't get notified, that's the best we
+                                                                        // can do given current implementations)
+                                                                        if ( !status && s.isLocal && !s.crossDomain ) {
+                                                                                status = responses.text ? 200 : 404;
+                                                                        // IE - #1450: sometimes returns 1223 when it should be 204
+                                                                        } else if ( status === 1223 ) {
+                                                                                status = 204;
+                                                                        }
+                                                                }
+                                                        }
+                                                } catch( firefoxAccessException ) {
+                                                        if ( !isAbort ) {
+                                                                complete( -1, firefoxAccessException );
+                                                        }
+                                                }
+
+                                                // Call complete if needed
+                                                if ( responses ) {
+                                                        complete( status, statusText, responses, responseHeaders );
+                                                }
+                                        };
+
+                                        // if we're in sync mode or it's in cache
+                                        // and has been retrieved directly (IE6 & IE7)
+                                        // we need to manually fire the callback
+                                        if ( !s.async || xhr.readyState === 4 ) {
+                                                callback();
+                                        } else {
+                                                handle = ++xhrId;
+                                                if ( xhrOnUnloadAbort ) {
+                                                        // Create the active xhrs callbacks list if needed
+                                                        // and attach the unload handler
+                                                        if ( !xhrCallbacks ) {
+                                                                xhrCallbacks = {};
+                                                                jQuery( window ).unload( xhrOnUnloadAbort );
+                                                        }
+                                                        // Add to list of active xhrs callbacks
+                                                        xhrCallbacks[ handle ] = callback;
+                                                }
+                                                xhr.onreadystatechange = callback;
+                                        }
+                                },
+
+                                abort: function() {
+                                        if ( callback ) {
+                                                callback(0,1);
+                                        }
+                                }
+                        };
+                }
+        });
+}
+
+
+
+
+var elemdisplay = {},
+        iframe, iframeDoc,
+        rfxtypes = /^(?:toggle|show|hide)$/,
+        rfxnum = /^([+\-]=)?([\d+.\-]+)([a-z%]*)$/i,
+        timerId,
+        fxAttrs = [
+                // height animations
+                [ "height", "marginTop", "marginBottom", "paddingTop", "paddingBottom" ],
+                // width animations
+                [ "width", "marginLeft", "marginRight", "paddingLeft", "paddingRight" ],
+                // opacity animations
+                [ "opacity" ]
+        ],
+        fxNow;
+
+jQuery.fn.extend({
+        show: function( speed, easing, callback ) {
+                var elem, display;
+
+                if ( speed || speed === 0 ) {
+                        return this.animate( genFx("show", 3), speed, easing, callback);
+
+                } else {
+                        for ( var i = 0, j = this.length; i < j; i++ ) {
+                                elem = this[i];
+
+                                if ( elem.style ) {
+                                        display = elem.style.display;
+
+                                        // Reset the inline display of this element to learn if it is
+                                        // being hidden by cascaded rules or not
+                                        if ( !jQuery._data(elem, "olddisplay") && display === "none" ) {
+                                                display = elem.style.display = "";
+                                        }
+
+                                        // Set elements which have been overridden with display: none
+                                        // in a stylesheet to whatever the default browser style is
+                                        // for such an element
+                                        if ( display === "" && jQuery.css( elem, "display" ) === "none" ) {
+                                                jQuery._data(elem, "olddisplay", defaultDisplay(elem.nodeName));
+                                        }
+                                }
+                        }
+
+                        // Set the display of most of the elements in a second loop
+                        // to avoid the constant reflow
+                        for ( i = 0; i < j; i++ ) {
+                                elem = this[i];
+
+                                if ( elem.style ) {
+                                        display = elem.style.display;
+
+                                        if ( display === "" || display === "none" ) {
+                                                elem.style.display = jQuery._data(elem, "olddisplay") || "";
+                                        }
+                                }
+                        }
+
+                        return this;
+                }
+        },
+
+        hide: function( speed, easing, callback ) {
+                if ( speed || speed === 0 ) {
+                        return this.animate( genFx("hide", 3), speed, easing, callback);
+
+                } else {
+                        for ( var i = 0, j = this.length; i < j; i++ ) {
+                                if ( this[i].style ) {
+                                        var display = jQuery.css( this[i], "display" );
+
+                                        if ( display !== "none" && !jQuery._data( this[i], "olddisplay" ) ) {
+                                                jQuery._data( this[i], "olddisplay", display );
+                                        }
+                                }
+                        }
+
+                        // Set the display of the elements in a second loop
+                        // to avoid the constant reflow
+                        for ( i = 0; i < j; i++ ) {
+                                if ( this[i].style ) {
+                                        this[i].style.display = "none";
+                                }
+                        }
+
+                        return this;
+                }
+        },
+
+        // Save the old toggle function
+        _toggle: jQuery.fn.toggle,
+
+        toggle: function( fn, fn2, callback ) {
+                var bool = typeof fn === "boolean";
+
+                if ( jQuery.isFunction(fn) && jQuery.isFunction(fn2) ) {
+                        this._toggle.apply( this, arguments );
+
+                } else if ( fn == null || bool ) {
+                        this.each(function() {
+                                var state = bool ? fn : jQuery(this).is(":hidden");
+                                jQuery(this)[ state ? "show" : "hide" ]();
+                        });
+
+                } else {
+                        this.animate(genFx("toggle", 3), fn, fn2, callback);
+                }
+
+                return this;
+        },
+
+        fadeTo: function( speed, to, easing, callback ) {
+                return this.filter(":hidden").css("opacity", 0).show().end()
+                                        .animate({opacity: to}, speed, easing, callback);
+        },
+
+        animate: function( prop, speed, easing, callback ) {
+                var optall = jQuery.speed(speed, easing, callback);
+
+                if ( jQuery.isEmptyObject( prop ) ) {
+                        return this.each( optall.complete, [ false ] );
+                }
+
+                // Do not change referenced properties as per-property easing will be lost
+                prop = jQuery.extend( {}, prop );
+
+                return this[ optall.queue === false ? "each" : "queue" ](function() {
+                        // XXX 'this' does not always have a nodeName when running the
+                        // test suite
+
+                        if ( optall.queue === false ) {
+                                jQuery._mark( this );
+                        }
+
+                        var opt = jQuery.extend( {}, optall ),
+                                isElement = this.nodeType === 1,
+                                hidden = isElement && jQuery(this).is(":hidden"),
+                                name, val, p,
+                                display, e,
+                                parts, start, end, unit;
+
+                        // will store per property easing and be used to determine when an animation is complete
+                        opt.animatedProperties = {};
+
+                        for ( p in prop ) {
+
+                                // property name normalization
+                                name = jQuery.camelCase( p );
+                                if ( p !== name ) {
+                                        prop[ name ] = prop[ p ];
+                                        delete prop[ p ];
+                                }
+
+                                val = prop[ name ];
+
+                                // easing resolution: per property > opt.specialEasing > opt.easing > 'swing' (default)
+                                if ( jQuery.isArray( val ) ) {
+                                        opt.animatedProperties[ name ] = val[ 1 ];
+                                        val = prop[ name ] = val[ 0 ];
+                                } else {
+                                        opt.animatedProperties[ name ] = opt.specialEasing && opt.specialEasing[ name ] || opt.easing || 'swing';
+                                }
+
+                                if ( val === "hide" && hidden || val === "show" && !hidden ) {
+                                        return opt.complete.call( this );
+                                }
+
+                                if ( isElement && ( name === "height" || name === "width" ) ) {
+                                        // Make sure that nothing sneaks out
+                                        // Record all 3 overflow attributes because IE does not
+                                        // change the overflow attribute when overflowX and
+                                        // overflowY are set to the same value
+                                        opt.overflow = [ this.style.overflow, this.style.overflowX, this.style.overflowY ];
+
+                                        // Set display property to inline-block for height/width
+                                        // animations on inline elements that are having width/height
+                                        // animated
+                                        if ( jQuery.css( this, "display" ) === "inline" &&
+                                                        jQuery.css( this, "float" ) === "none" ) {
+                                                if ( !jQuery.support.inlineBlockNeedsLayout ) {
+                                                        this.style.display = "inline-block";
+
+                                                } else {
+                                                        display = defaultDisplay( this.nodeName );
+
+                                                        // inline-level elements accept inline-block;
+                                                        // block-level elements need to be inline with layout
+                                                        if ( display === "inline" ) {
+                                                                this.style.display = "inline-block";
+
+                                                        } else {
+                                                                this.style.display = "inline";
+                                                                this.style.zoom = 1;
+                                                        }
+                                                }
+                                        }
+                                }
+                        }
+
+                        if ( opt.overflow != null ) {
+                                this.style.overflow = "hidden";
+                        }
+
+                        for ( p in prop ) {
+                                e = new jQuery.fx( this, opt, p );
+                                val = prop[ p ];
+
+                                if ( rfxtypes.test(val) ) {
+                                        e[ val === "toggle" ? hidden ? "show" : "hide" : val ]();
+
+                                } else {
+                                        parts = rfxnum.exec( val );
+                                        start = e.cur();
+
+                                        if ( parts ) {
+                                                end = parseFloat( parts[2] );
+                                                unit = parts[3] || ( jQuery.cssNumber[ p ] ? "" : "px" );
+
+                                                // We need to compute starting value
+                                                if ( unit !== "px" ) {
+                                                        jQuery.style( this, p, (end || 1) + unit);
+                                                        start = ((end || 1) / e.cur()) * start;
+                                                        jQuery.style( this, p, start + unit);
+                                                }
+
+                                                // If a +=/-= token was provided, we're doing a relative animation
+                                                if ( parts[1] ) {
+                                                        end = ( (parts[ 1 ] === "-=" ? -1 : 1) * end ) + start;
+                                                }
+
+                                                e.custom( start, end, unit );
+
+                                        } else {
+                                                e.custom( start, val, "" );
+                                        }
+                                }
+                        }
+
+                        // For JS strict compliance
+                        return true;
+                });
+        },
+
+        stop: function( clearQueue, gotoEnd ) {
+                if ( clearQueue ) {
+                        this.queue([]);
+                }
+
+                this.each(function() {
+                        var timers = jQuery.timers,
+                                i = timers.length;
+                        // clear marker counters if we know they won't be
+                        if ( !gotoEnd ) {
+                                jQuery._unmark( true, this );
+                        }
+                        while ( i-- ) {
+                                if ( timers[i].elem === this ) {
+                                        if (gotoEnd) {
+                                                // force the next step to be the last
+                                                timers[i](true);
+                                        }
+
+                                        timers.splice(i, 1);
+                                }
+                        }
+                });
+
+                // start the next in the queue if the last step wasn't forced
+                if ( !gotoEnd ) {
+                        this.dequeue();
+                }
+
+                return this;
+        }
+
+});
+
+// Animations created synchronously will run synchronously
+function createFxNow() {
+        setTimeout( clearFxNow, 0 );
+        return ( fxNow = jQuery.now() );
+}
+
+function clearFxNow() {
+        fxNow = undefined;
+}
+
+// Generate parameters to create a standard animation
+function genFx( type, num ) {
+        var obj = {};
+
+        jQuery.each( fxAttrs.concat.apply([], fxAttrs.slice(0,num)), function() {
+                obj[ this ] = type;
+        });
+
+        return obj;
+}
+
+// Generate shortcuts for custom animations
+jQuery.each({
+        slideDown: genFx("show", 1),
+        slideUp: genFx("hide", 1),
+        slideToggle: genFx("toggle", 1),
+        fadeIn: { opacity: "show" },
+        fadeOut: { opacity: "hide" },
+        fadeToggle: { opacity: "toggle" }
+}, function( name, props ) {
+        jQuery.fn[ name ] = function( speed, easing, callback ) {
+                return this.animate( props, speed, easing, callback );
+        };
+});
+
+jQuery.extend({
+        speed: function( speed, easing, fn ) {
+                var opt = speed && typeof speed === "object" ? jQuery.extend({}, speed) : {
+                        complete: fn || !fn && easing ||
+                                jQuery.isFunction( speed ) && speed,
+                        duration: speed,
+                        easing: fn && easing || easing && !jQuery.isFunction(easing) && easing
+                };
+
+                opt.duration = jQuery.fx.off ? 0 : typeof opt.duration === "number" ? opt.duration :
+                        opt.duration in jQuery.fx.speeds ? jQuery.fx.speeds[opt.duration] : jQuery.fx.speeds._default;
+
+                // Queueing
+                opt.old = opt.complete;
+                opt.complete = function( noUnmark ) {
+                        if ( jQuery.isFunction( opt.old ) ) {
+                                opt.old.call( this );
+                        }
+
+                        if ( opt.queue !== false ) {
+                                jQuery.dequeue( this );
+                        } else if ( noUnmark !== false ) {
+                                jQuery._unmark( this );
+                        }
+                };
+
+                return opt;
+        },
+
+        easing: {
+                linear: function( p, n, firstNum, diff ) {
+                        return firstNum + diff * p;
+                },
+                swing: function( p, n, firstNum, diff ) {
+                        return ((-Math.cos(p*Math.PI)/2) + 0.5) * diff + firstNum;
+                }
+        },
+
+        timers: [],
+
+        fx: function( elem, options, prop ) {
+                this.options = options;
+                this.elem = elem;
+                this.prop = prop;
+
+                options.orig = options.orig || {};
+        }
+
+});
+
+jQuery.fx.prototype = {
+        // Simple function for setting a style value
+        update: function() {
+                if ( this.options.step ) {
+                        this.options.step.call( this.elem, this.now, this );
+                }
+
+                (jQuery.fx.step[this.prop] || jQuery.fx.step._default)( this );
+        },
+
+        // Get the current size
+        cur: function() {
+                if ( this.elem[this.prop] != null && (!this.elem.style || this.elem.style[this.prop] == null) ) {
+                        return this.elem[ this.prop ];
+                }
+
+                var parsed,
+                        r = jQuery.css( this.elem, this.prop );
+                // Empty strings, null, undefined and "auto" are converted to 0,
+                // complex values such as "rotate(1rad)" are returned as is,
+                // simple values such as "10px" are parsed to Float.
+                return isNaN( parsed = parseFloat( r ) ) ? !r || r === "auto" ? 0 : r : parsed;
+        },
+
+        // Start an animation from one number to another
+        custom: function( from, to, unit ) {
+                var self = this,
+                        fx = jQuery.fx;
+
+                this.startTime = fxNow || createFxNow();
+                this.start = from;
+                this.end = to;
+                this.unit = unit || this.unit || ( jQuery.cssNumber[ this.prop ] ? "" : "px" );
+                this.now = this.start;
+                this.pos = this.state = 0;
+
+                function t( gotoEnd ) {
+                        return self.step(gotoEnd);
+                }
+
+                t.elem = this.elem;
+
+                if ( t() && jQuery.timers.push(t) && !timerId ) {
+                        timerId = setInterval( fx.tick, fx.interval );
+                }
+        },
+
+        // Simple 'show' function
+        show: function() {
+                // Remember where we started, so that we can go back to it later
+                this.options.orig[this.prop] = jQuery.style( this.elem, this.prop );
+                this.options.show = true;
+
+                // Begin the animation
+                // Make sure that we start at a small width/height to avoid any
+                // flash of content
+                this.custom(this.prop === "width" || this.prop === "height" ? 1 : 0, this.cur());
+
+                // Start by showing the element
+                jQuery( this.elem ).show();
+        },
+
+        // Simple 'hide' function
+        hide: function() {
+                // Remember where we started, so that we can go back to it later
+                this.options.orig[this.prop] = jQuery.style( this.elem, this.prop );
+                this.options.hide = true;
+
+                // Begin the animation
+                this.custom(this.cur(), 0);
+        },
+
+        // Each step of an animation
+        step: function( gotoEnd ) {
+                var t = fxNow || createFxNow(),
+                        done = true,
+                        elem = this.elem,
+                        options = this.options,
+                        i, n;
+
+                if ( gotoEnd || t >= options.duration + this.startTime ) {
+                        this.now = this.end;
+                        this.pos = this.state = 1;
+                        this.update();
+
+                        options.animatedProperties[ this.prop ] = true;
+
+                        for ( i in options.animatedProperties ) {
+                                if ( options.animatedProperties[i] !== true ) {
+                                        done = false;
+                                }
+                        }
+
+                        if ( done ) {
+                                // Reset the overflow
+                                if ( options.overflow != null && !jQuery.support.shrinkWrapBlocks ) {
+
+                                        jQuery.each( [ "", "X", "Y" ], function (index, value) {
+                                                elem.style[ "overflow" + value ] = options.overflow[index];
+                                        });
+                                }
+
+                                // Hide the element if the "hide" operation was done
+                                if ( options.hide ) {
+                                        jQuery(elem).hide();
+                                }
+
+                                // Reset the properties, if the item has been hidden or shown
+                                if ( options.hide || options.show ) {
+                                        for ( var p in options.animatedProperties ) {
+                                                jQuery.style( elem, p, options.orig[p] );
+                                        }
+                                }
+
+                                // Execute the complete function
+                                options.complete.call( elem );
+                        }
+
+                        return false;
+
+                } else {
+                        // classical easing cannot be used with an Infinity duration
+                        if ( options.duration == Infinity ) {
+                                this.now = t;
+                        } else {
+                                n = t - this.startTime;
+                                this.state = n / options.duration;
+
+                                // Perform the easing function, defaults to swing
+                                this.pos = jQuery.easing[ options.animatedProperties[ this.prop ] ]( this.state, n, 0, 1, options.duration );
+                                this.now = this.start + ((this.end - this.start) * this.pos);
+                        }
+                        // Perform the next step of the animation
+                        this.update();
+                }
+
+                return true;
+        }
+};
+
+jQuery.extend( jQuery.fx, {
+        tick: function() {
+                for ( var timers = jQuery.timers, i = 0 ; i < timers.length ; ++i ) {
+                        if ( !timers[i]() ) {
+                                timers.splice(i--, 1);
+                        }
+                }
+
+                if ( !timers.length ) {
+                        jQuery.fx.stop();
+                }
+        },
+
+        interval: 13,
+
+        stop: function() {
+                clearInterval( timerId );
+                timerId = null;
+        },
+
+        speeds: {
+                slow: 600,
+                fast: 200,
+                // Default speed
+                _default: 400
+        },
+
+        step: {
+                opacity: function( fx ) {
+                        jQuery.style( fx.elem, "opacity", fx.now );
+                },
+
+                _default: function( fx ) {
+                        if ( fx.elem.style && fx.elem.style[ fx.prop ] != null ) {
+                                fx.elem.style[ fx.prop ] = (fx.prop === "width" || fx.prop === "height" ? Math.max(0, fx.now) : fx.now) + fx.unit;
+                        } else {
+                                fx.elem[ fx.prop ] = fx.now;
+                        }
+                }
+        }
+});
+
+if ( jQuery.expr && jQuery.expr.filters ) {
+        jQuery.expr.filters.animated = function( elem ) {
+                return jQuery.grep(jQuery.timers, function( fn ) {
+                        return elem === fn.elem;
+                }).length;
+        };
+}
+
+// Try to restore the default display value of an element
+function defaultDisplay( nodeName ) {
+
+        if ( !elemdisplay[ nodeName ] ) {
+
+                var body = document.body,
+                        elem = jQuery( "<" + nodeName + ">" ).appendTo( body ),
+                        display = elem.css( "display" );
+
+                elem.remove();
+
+                // If the simple way fails,
+                // get element's real default display by attaching it to a temp iframe
+                if ( display === "none" || display === "" ) {
+                        // No iframe to use yet, so create it
+                        if ( !iframe ) {
+                                iframe = document.createElement( "iframe" );
+                                iframe.frameBorder = iframe.width = iframe.height = 0;
+                        }
+
+                        body.appendChild( iframe );
+
+                        // Create a cacheable copy of the iframe document on first call.
+                        // IE and Opera will allow us to reuse the iframeDoc without re-writing the fake HTML
+                        // document to it; WebKit & Firefox won't allow reusing the iframe document.
+                        if ( !iframeDoc || !iframe.createElement ) {
+                                iframeDoc = ( iframe.contentWindow || iframe.contentDocument ).document;
+                                iframeDoc.write( ( document.compatMode === "CSS1Compat" ? "<!doctype html>" : "" ) + "<html><body>" );
+                                iframeDoc.close();
+                        }
+
+                        elem = iframeDoc.createElement( nodeName );
+
+                        iframeDoc.body.appendChild( elem );
+
+                        display = jQuery.css( elem, "display" );
+
+                        body.removeChild( iframe );
+                }
+
+                // Store the correct default display
+                elemdisplay[ nodeName ] = display;
+        }
+
+        return elemdisplay[ nodeName ];
+}
+
+
+
+
+var rtable = /^t(?:able|d|h)$/i,
+        rroot = /^(?:body|html)$/i;
+
+if ( "getBoundingClientRect" in document.documentElement ) {
+        jQuery.fn.offset = function( options ) {
+                var elem = this[0], box;
+
+                if ( options ) {
+                        return this.each(function( i ) {
+                                jQuery.offset.setOffset( this, options, i );
+                        });
+                }
+
+                if ( !elem || !elem.ownerDocument ) {
+                        return null;
+                }
+
+                if ( elem === elem.ownerDocument.body ) {
+                        return jQuery.offset.bodyOffset( elem );
+                }
+
+                try {
+                        box = elem.getBoundingClientRect();
+                } catch(e) {}
+
+                var doc = elem.ownerDocument,
+                        docElem = doc.documentElement;
+
+                // Make sure we're not dealing with a disconnected DOM node
+                if ( !box || !jQuery.contains( docElem, elem ) ) {
+                        return box ? { top: box.top, left: box.left } : { top: 0, left: 0 };
+                }
+
+                var body = doc.body,
+                        win = getWindow(doc),
+                        clientTop  = docElem.clientTop  || body.clientTop  || 0,
+                        clientLeft = docElem.clientLeft || body.clientLeft || 0,
+                        scrollTop  = win.pageYOffset || jQuery.support.boxModel && docElem.scrollTop  || body.scrollTop,
+                        scrollLeft = win.pageXOffset || jQuery.support.boxModel && docElem.scrollLeft || body.scrollLeft,
+                        top  = box.top  + scrollTop  - clientTop,
+                        left = box.left + scrollLeft - clientLeft;
+
+                return { top: top, left: left };
+        };
+
+} else {
+        jQuery.fn.offset = function( options ) {
+                var elem = this[0];
+
+                if ( options ) {
+                        return this.each(function( i ) {
+                                jQuery.offset.setOffset( this, options, i );
+                        });
+                }
+
+                if ( !elem || !elem.ownerDocument ) {
+                        return null;
+                }
+
+                if ( elem === elem.ownerDocument.body ) {
+                        return jQuery.offset.bodyOffset( elem );
+                }
+
+                jQuery.offset.initialize();
+
+                var computedStyle,
+                        offsetParent = elem.offsetParent,
+                        prevOffsetParent = elem,
+                        doc = elem.ownerDocument,
+                        docElem = doc.documentElement,
+                        body = doc.body,
+                        defaultView = doc.defaultView,
+                        prevComputedStyle = defaultView ? defaultView.getComputedStyle( elem, null ) : elem.currentStyle,
+                        top = elem.offsetTop,
+                        left = elem.offsetLeft;
+
+                while ( (elem = elem.parentNode) && elem !== body && elem !== docElem ) {
+                        if ( jQuery.offset.supportsFixedPosition && prevComputedStyle.position === "fixed" ) {
+                                break;
+                        }
+
+                        computedStyle = defaultView ? defaultView.getComputedStyle(elem, null) : elem.currentStyle;
+                        top  -= elem.scrollTop;
+                        left -= elem.scrollLeft;
+
+                        if ( elem === offsetParent ) {
+                                top  += elem.offsetTop;
+                                left += elem.offsetLeft;
+
+                                if ( jQuery.offset.doesNotAddBorder && !(jQuery.offset.doesAddBorderForTableAndCells && rtable.test(elem.nodeName)) ) {
+                                        top  += parseFloat( computedStyle.borderTopWidth  ) || 0;
+                                        left += parseFloat( computedStyle.borderLeftWidth ) || 0;
+                                }
+
+                                prevOffsetParent = offsetParent;
+                                offsetParent = elem.offsetParent;
+                        }
+
+                        if ( jQuery.offset.subtractsBorderForOverflowNotVisible && computedStyle.overflow !== "visible" ) {
+                                top  += parseFloat( computedStyle.borderTopWidth  ) || 0;
+                                left += parseFloat( computedStyle.borderLeftWidth ) || 0;
+                        }
+
+                        prevComputedStyle = computedStyle;
+                }
+
+                if ( prevComputedStyle.position === "relative" || prevComputedStyle.position === "static" ) {
+                        top  += body.offsetTop;
+                        left += body.offsetLeft;
+                }
+
+                if ( jQuery.offset.supportsFixedPosition && prevComputedStyle.position === "fixed" ) {
+                        top  += Math.max( docElem.scrollTop, body.scrollTop );
+                        left += Math.max( docElem.scrollLeft, body.scrollLeft );
+                }
+
+                return { top: top, left: left };
+        };
+}
+
+jQuery.offset = {
+        initialize: function() {
+                var body = document.body, container = document.createElement("div"), innerDiv, checkDiv, table, td, bodyMarginTop = parseFloat( jQuery.css(body, "marginTop") ) || 0,
+                        html = "<div style='position:absolute;top:0;left:0;margin:0;border:5px solid #000;padding:0;width:1px;height:1px;'><div></div></div><table style='position:absolute;top:0;left:0;margin:0;border:5px solid #000;padding:0;width:1px;height:1px;' cellpadding='0' cellspacing='0'><tr><td></td></tr></table>";
+
+                jQuery.extend( container.style, { position: "absolute", top: 0, left: 0, margin: 0, border: 0, width: "1px", height: "1px", visibility: "hidden" } );
+
+                container.innerHTML = html;
+                body.insertBefore( container, body.firstChild );
+                innerDiv = container.firstChild;
+                checkDiv = innerDiv.firstChild;
+                td = innerDiv.nextSibling.firstChild.firstChild;
+
+                this.doesNotAddBorder = (checkDiv.offsetTop !== 5);
+                this.doesAddBorderForTableAndCells = (td.offsetTop === 5);
+
+                checkDiv.style.position = "fixed";
+                checkDiv.style.top = "20px";
+
+                // safari subtracts parent border width here which is 5px
+                this.supportsFixedPosition = (checkDiv.offsetTop === 20 || checkDiv.offsetTop === 15);
+                checkDiv.style.position = checkDiv.style.top = "";
+
+                innerDiv.style.overflow = "hidden";
+                innerDiv.style.position = "relative";
+
+                this.subtractsBorderForOverflowNotVisible = (checkDiv.offsetTop === -5);
+
+                this.doesNotIncludeMarginInBodyOffset = (body.offsetTop !== bodyMarginTop);
+
+                body.removeChild( container );
+                jQuery.offset.initialize = jQuery.noop;
+        },
+
+        bodyOffset: function( body ) {
+                var top = body.offsetTop,
+                        left = body.offsetLeft;
+
+                jQuery.offset.initialize();
+
+                if ( jQuery.offset.doesNotIncludeMarginInBodyOffset ) {
+                        top  += parseFloat( jQuery.css(body, "marginTop") ) || 0;
+                        left += parseFloat( jQuery.css(body, "marginLeft") ) || 0;
+                }
+
+                return { top: top, left: left };
+        },
+
+        setOffset: function( elem, options, i ) {
+                var position = jQuery.css( elem, "position" );
+
+                // set position first, in-case top/left are set even on static elem
+                if ( position === "static" ) {
+                        elem.style.position = "relative";
+                }
+
+                var curElem = jQuery( elem ),
+                        curOffset = curElem.offset(),
+                        curCSSTop = jQuery.css( elem, "top" ),
+                        curCSSLeft = jQuery.css( elem, "left" ),
+                        calculatePosition = (position === "absolute" || position === "fixed") && jQuery.inArray("auto", [curCSSTop, curCSSLeft]) > -1,
+                        props = {}, curPosition = {}, curTop, curLeft;
+
+                // need to be able to calculate position if either top or left is auto and position is either absolute or fixed
+                if ( calculatePosition ) {
+                        curPosition = curElem.position();
+                        curTop = curPosition.top;
+                        curLeft = curPosition.left;
+                } else {
+                        curTop = parseFloat( curCSSTop ) || 0;
+                        curLeft = parseFloat( curCSSLeft ) || 0;
+                }
+
+                if ( jQuery.isFunction( options ) ) {
+                        options = options.call( elem, i, curOffset );
+                }
+
+                if (options.top != null) {
+                        props.top = (options.top - curOffset.top) + curTop;
+                }
+                if (options.left != null) {
+                        props.left = (options.left - curOffset.left) + curLeft;
+                }
+
+                if ( "using" in options ) {
+                        options.using.call( elem, props );
+                } else {
+                        curElem.css( props );
+                }
+        }
+};
+
+
+jQuery.fn.extend({
+        position: function() {
+                if ( !this[0] ) {
+                        return null;
+                }
+
+                var elem = this[0],
+
+                // Get *real* offsetParent
+                offsetParent = this.offsetParent(),
+
+                // Get correct offsets
+                offset       = this.offset(),
+                parentOffset = rroot.test(offsetParent[0].nodeName) ? { top: 0, left: 0 } : offsetParent.offset();
+
+                // Subtract element margins
+                // note: when an element has margin: auto the offsetLeft and marginLeft
+                // are the same in Safari causing offset.left to incorrectly be 0
+                offset.top  -= parseFloat( jQuery.css(elem, "marginTop") ) || 0;
+                offset.left -= parseFloat( jQuery.css(elem, "marginLeft") ) || 0;
+
+                // Add offsetParent borders
+                parentOffset.top  += parseFloat( jQuery.css(offsetParent[0], "borderTopWidth") ) || 0;
+                parentOffset.left += parseFloat( jQuery.css(offsetParent[0], "borderLeftWidth") ) || 0;
+
+                // Subtract the two offsets
+                return {
+                        top:  offset.top  - parentOffset.top,
+                        left: offset.left - parentOffset.left
+                };
+        },
+
+        offsetParent: function() {
+                return this.map(function() {
+                        var offsetParent = this.offsetParent || document.body;
+                        while ( offsetParent && (!rroot.test(offsetParent.nodeName) && jQuery.css(offsetParent, "position") === "static") ) {
+                                offsetParent = offsetParent.offsetParent;
+                        }
+                        return offsetParent;
+                });
+        }
+});
+
+
+// Create scrollLeft and scrollTop methods
+jQuery.each( ["Left", "Top"], function( i, name ) {
+        var method = "scroll" + name;
+
+        jQuery.fn[ method ] = function( val ) {
+                var elem, win;
+
+                if ( val === undefined ) {
+                        elem = this[ 0 ];
+
+                        if ( !elem ) {
+                                return null;
+                        }
+
+                        win = getWindow( elem );
+
+                        // Return the scroll offset
+                        return win ? ("pageXOffset" in win) ? win[ i ? "pageYOffset" : "pageXOffset" ] :
+                                jQuery.support.boxModel && win.document.documentElement[ method ] ||
+                                        win.document.body[ method ] :
+                                elem[ method ];
+                }
+
+                // Set the scroll offset
+                return this.each(function() {
+                        win = getWindow( this );
+
+                        if ( win ) {
+                                win.scrollTo(
+                                        !i ? val : jQuery( win ).scrollLeft(),
+                                         i ? val : jQuery( win ).scrollTop()
+                                );
+
+                        } else {
+                                this[ method ] = val;
+                        }
+                });
+        };
+});
+
+function getWindow( elem ) {
+        return jQuery.isWindow( elem ) ?
+                elem :
+                elem.nodeType === 9 ?
+                        elem.defaultView || elem.parentWindow :
+                        false;
+}
+
+
+
+
+// Create width, height, innerHeight, innerWidth, outerHeight and outerWidth methods
+jQuery.each([ "Height", "Width" ], function( i, name ) {
+
+        var type = name.toLowerCase();
+
+        // innerHeight and innerWidth
+        jQuery.fn[ "inner" + name ] = function() {
+                var elem = this[0];
+                return elem && elem.style ?
+                        parseFloat( jQuery.css( elem, type, "padding" ) ) :
+                        null;
+        };
+
+        // outerHeight and outerWidth
+        jQuery.fn[ "outer" + name ] = function( margin ) {
+                var elem = this[0];
+                return elem && elem.style ?
+                        parseFloat( jQuery.css( elem, type, margin ? "margin" : "border" ) ) :
+                        null;
+        };
+
+        jQuery.fn[ type ] = function( size ) {
+                // Get window width or height
+                var elem = this[0];
+                if ( !elem ) {
+                        return size == null ? null : this;
+                }
+
+                if ( jQuery.isFunction( size ) ) {
+                        return this.each(function( i ) {
+                                var self = jQuery( this );
+                                self[ type ]( size.call( this, i, self[ type ]() ) );
+                        });
+                }
+
+                if ( jQuery.isWindow( elem ) ) {
+                        // Everyone else use document.documentElement or document.body depending on Quirks vs Standards mode
+                        // 3rd condition allows Nokia support, as it supports the docElem prop but not CSS1Compat
+                        var docElemProp = elem.document.documentElement[ "client" + name ],
+                                body = elem.document.body;
+                        return elem.document.compatMode === "CSS1Compat" && docElemProp ||
+                                body && body[ "client" + name ] || docElemProp;
+
+                // Get document width or height
+                } else if ( elem.nodeType === 9 ) {
+                        // Either scroll[Width/Height] or offset[Width/Height], whichever is greater
+                        return Math.max(
+                                elem.documentElement["client" + name],
+                                elem.body["scroll" + name], elem.documentElement["scroll" + name],
+                                elem.body["offset" + name], elem.documentElement["offset" + name]
+                        );
+
+                // Get or set width or height on the element
+                } else if ( size === undefined ) {
+                        var orig = jQuery.css( elem, type ),
+                                ret = parseFloat( orig );
+
+                        return jQuery.isNaN( ret ) ? orig : ret;
+
+                // Set the width or height on the element (default to pixels if value is unitless)
+                } else {
+                        return this.css( type, typeof size === "string" ? size : size + "px" );
+                }
+        };
+
+});
+
+
+// Expose jQuery to the global object
+window.jQuery = window.$ = jQuery;
+})(window);
diff --git a/PerformanceTests/Dromaeo/resources/dromaeo/web/lib/jquery.js b/PerformanceTests/Dromaeo/resources/dromaeo/web/lib/jquery.js
deleted file mode 100644 (file)
index 37a5d57..0000000
+++ /dev/null
@@ -1,3549 +0,0 @@
-(function(){
-/*
- * jQuery 1.2.6 - New Wave Javascript
- *
- * Copyright (c) 2008 John Resig (jquery.com)
- * Dual licensed under the MIT (MIT-LICENSE.txt)
- * and GPL (GPL-LICENSE.txt) licenses.
- *
- * $Date: 2008-05-24 14:22:17 -0400 (Sat, 24 May 2008) $
- * $Rev: 5685 $
- */
-
-// Map over jQuery in case of overwrite
-var _jQuery = window.jQuery,
-// Map over the $ in case of overwrite
-        _$ = window.$;
-
-var jQuery = window.jQuery = window.$ = function( selector, context ) {
-        // The jQuery object is actually just the init constructor 'enhanced'
-        return new jQuery.fn.init( selector, context );
-};
-
-// A simple way to check for HTML strings or ID strings
-// (both of which we optimize for)
-var quickExpr = /^[^<]*(<(.|\s)+>)[^>]*$|^#(\w+)$/,
-
-// Is it a simple selector
-        isSimple = /^.[^:#\[\.]*$/,
-
-// Will speed up references to undefined, and allows munging its name.
-        undefined;
-
-jQuery.fn = jQuery.prototype = {
-        init: function( selector, context ) {
-                // Make sure that a selection was provided
-                selector = selector || document;
-
-                // Handle $(DOMElement)
-                if ( selector.nodeType ) {
-                        this[0] = selector;
-                        this.length = 1;
-                        return this;
-                }
-                // Handle HTML strings
-                if ( typeof selector == "string" ) {
-                        // Are we dealing with HTML string or an ID?
-                        var match = quickExpr.exec( selector );
-
-                        // Verify a match, and that no context was specified for #id
-                        if ( match && (match[1] || !context) ) {
-
-                                // HANDLE: $(html) -> $(array)
-                                if ( match[1] )
-                                        selector = jQuery.clean( [ match[1] ], context );
-
-                                // HANDLE: $("#id")
-                                else {
-                                        var elem = document.getElementById( match[3] );
-
-                                        // Make sure an element was located
-                                        if ( elem ){
-                                                // Handle the case where IE and Opera return items
-                                                // by name instead of ID
-                                                if ( elem.id != match[3] )
-                                                        return jQuery().find( selector );
-
-                                                // Otherwise, we inject the element directly into the jQuery object
-                                                return jQuery( elem );
-                                        }
-                                        selector = [];
-                                }
-
-                        // HANDLE: $(expr, [context])
-                        // (which is just equivalent to: $(content).find(expr)
-                        } else
-                                return jQuery( context ).find( selector );
-
-                // HANDLE: $(function)
-                // Shortcut for document ready
-                } else if ( jQuery.isFunction( selector ) )
-                        return jQuery( document )[ jQuery.fn.ready ? "ready" : "load" ]( selector );
-
-                return this.setArray(jQuery.makeArray(selector));
-        },
-
-        // The current version of jQuery being used
-        jquery: "1.2.6",
-
-        // The number of elements contained in the matched element set
-        size: function() {
-                return this.length;
-        },
-
-        // The number of elements contained in the matched element set
-        length: 0,
-
-        // Get the Nth element in the matched element set OR
-        // Get the whole matched element set as a clean array
-        get: function( num ) {
-                return num == undefined ?
-
-                        // Return a 'clean' array
-                        jQuery.makeArray( this ) :
-
-                        // Return just the object
-                        this[ num ];
-        },
-
-        // Take an array of elements and push it onto the stack
-        // (returning the new matched element set)
-        pushStack: function( elems ) {
-                // Build a new jQuery matched element set
-                var ret = jQuery( elems );
-
-                // Add the old object onto the stack (as a reference)
-                ret.prevObject = this;
-
-                // Return the newly-formed element set
-                return ret;
-        },
-
-        // Force the current matched set of elements to become
-        // the specified array of elements (destroying the stack in the process)
-        // You should use pushStack() in order to do this, but maintain the stack
-        setArray: function( elems ) {
-                // Resetting the length to 0, then using the native Array push
-                // is a super-fast way to populate an object with array-like properties
-                this.length = 0;
-                Array.prototype.push.apply( this, elems );
-
-                return this;
-        },
-
-        // Execute a callback for every element in the matched set.
-        // (You can seed the arguments with an array of args, but this is
-        // only used internally.)
-        each: function( callback, args ) {
-                return jQuery.each( this, callback, args );
-        },
-
-        // Determine the position of an element within
-        // the matched set of elements
-        index: function( elem ) {
-                var ret = -1;
-
-                // Locate the position of the desired element
-                return jQuery.inArray(
-                        // If it receives a jQuery object, the first element is used
-                        elem && elem.jquery ? elem[0] : elem
-                , this );
-        },
-
-        attr: function( name, value, type ) {
-                var options = name;
-
-                // Look for the case where we're accessing a style value
-                if ( name.constructor == String )
-                        if ( value === undefined )
-                                return this[0] && jQuery[ type || "attr" ]( this[0], name );
-
-                        else {
-                                options = {};
-                                options[ name ] = value;
-                        }
-
-                // Check to see if we're setting style values
-                return this.each(function(i){
-                        // Set all the styles
-                        for ( name in options )
-                                jQuery.attr(
-                                        type ?
-                                                this.style :
-                                                this,
-                                        name, jQuery.prop( this, options[ name ], type, i, name )
-                                );
-                });
-        },
-
-        css: function( key, value ) {
-                // ignore negative width and height values
-                if ( (key == 'width' || key == 'height') && parseFloat(value) < 0 )
-                        value = undefined;
-                return this.attr( key, value, "curCSS" );
-        },
-
-        text: function( text ) {
-                if ( typeof text != "object" && text != null )
-                        return this.empty().append( (this[0] && this[0].ownerDocument || document).createTextNode( text ) );
-
-                var ret = "";
-
-                jQuery.each( text || this, function(){
-                        jQuery.each( this.childNodes, function(){
-                                if ( this.nodeType != 8 )
-                                        ret += this.nodeType != 1 ?
-                                                this.nodeValue :
-                                                jQuery.fn.text( [ this ] );
-                        });
-                });
-
-                return ret;
-        },
-
-        wrapAll: function( html ) {
-                if ( this[0] )
-                        // The elements to wrap the target around
-                        jQuery( html, this[0].ownerDocument )
-                                .clone()
-                                .insertBefore( this[0] )
-                                .map(function(){
-                                        var elem = this;
-
-                                        while ( elem.firstChild )
-                                                elem = elem.firstChild;
-
-                                        return elem;
-                                })
-                                .append(this);
-
-                return this;
-        },
-
-        wrapInner: function( html ) {
-                return this.each(function(){
-                        jQuery( this ).contents().wrapAll( html );
-                });
-        },
-
-        wrap: function( html ) {
-                return this.each(function(){
-                        jQuery( this ).wrapAll( html );
-                });
-        },
-
-        append: function() {
-                return this.domManip(arguments, true, false, function(elem){
-                        if (this.nodeType == 1)
-                                this.appendChild( elem );
-                });
-        },
-
-        prepend: function() {
-                return this.domManip(arguments, true, true, function(elem){
-                        if (this.nodeType == 1)
-                                this.insertBefore( elem, this.firstChild );
-                });
-        },
-
-        before: function() {
-                return this.domManip(arguments, false, false, function(elem){
-                        this.parentNode.insertBefore( elem, this );
-                });
-        },
-
-        after: function() {
-                return this.domManip(arguments, false, true, function(elem){
-                        this.parentNode.insertBefore( elem, this.nextSibling );
-                });
-        },
-
-        end: function() {
-                return this.prevObject || jQuery( [] );
-        },
-
-        find: function( selector ) {
-                var elems = jQuery.map(this, function(elem){
-                        return jQuery.find( selector, elem );
-                });
-
-                return this.pushStack( /[^+>] [^+>]/.test( selector ) || selector.indexOf("..") > -1 ?
-                        jQuery.unique( elems ) :
-                        elems );
-        },
-
-        clone: function( events ) {
-                // Do the clone
-                var ret = this.map(function(){
-                        if ( jQuery.browser.msie && !jQuery.isXMLDoc(this) ) {
-                                // IE copies events bound via attachEvent when
-                                // using cloneNode. Calling detachEvent on the
-                                // clone will also remove the events from the orignal
-                                // In order to get around this, we use innerHTML.
-                                // Unfortunately, this means some modifications to
-                                // attributes in IE that are actually only stored
-                                // as properties will not be copied (such as the
-                                // the name attribute on an input).
-                                var clone = this.cloneNode(true),
-                                        container = document.createElement("div");
-                                container.appendChild(clone);
-                                return jQuery.clean([container.innerHTML])[0];
-                        } else
-                                return this.cloneNode(true);
-                });
-
-                // Need to set the expando to null on the cloned set if it exists
-                // removeData doesn't work here, IE removes it from the original as well
-                // this is primarily for IE but the data expando shouldn't be copied over in any browser
-                var clone = ret.find("*").andSelf().each(function(){
-                        if ( this[ expando ] != undefined )
-                                this[ expando ] = null;
-                });
-
-                // Copy the events from the original to the clone
-                if ( events === true )
-                        this.find("*").andSelf().each(function(i){
-                                if (this.nodeType == 3)
-                                        return;
-                                var events = jQuery.data( this, "events" );
-
-                                for ( var type in events )
-                                        for ( var handler in events[ type ] )
-                                                jQuery.event.add( clone[ i ], type, events[ type ][ handler ], events[ type ][ handler ].data );
-                        });
-
-                // Return the cloned set
-                return ret;
-        },
-
-        filter: function( selector ) {
-                return this.pushStack(
-                        jQuery.isFunction( selector ) &&
-                        jQuery.grep(this, function(elem, i){
-                                return selector.call( elem, i );
-                        }) ||
-
-                        jQuery.multiFilter( selector, this ) );
-        },
-
-        not: function( selector ) {
-                if ( selector.constructor == String )
-                        // test special case where just one selector is passed in
-                        if ( isSimple.test( selector ) )
-                                return this.pushStack( jQuery.multiFilter( selector, this, true ) );
-                        else
-                                selector = jQuery.multiFilter( selector, this );
-
-                var isArrayLike = selector.length && selector[selector.length - 1] !== undefined && !selector.nodeType;
-                return this.filter(function() {
-                        return isArrayLike ? jQuery.inArray( this, selector ) < 0 : this != selector;
-                });
-        },
-
-        add: function( selector ) {
-                return this.pushStack( jQuery.unique( jQuery.merge(
-                        this.get(),
-                        typeof selector == 'string' ?
-                                jQuery( selector ) :
-                                jQuery.makeArray( selector )
-                )));
-        },
-
-        is: function( selector ) {
-                return !!selector && jQuery.multiFilter( selector, this ).length > 0;
-        },
-
-        hasClass: function( selector ) {
-                return this.is( "." + selector );
-        },
-
-        val: function( value ) {
-                if ( value == undefined ) {
-
-                        if ( this.length ) {
-                                var elem = this[0];
-
-                                // We need to handle select boxes special
-                                if ( jQuery.nodeName( elem, "select" ) ) {
-                                        var index = elem.selectedIndex,
-                                                values = [],
-                                                options = elem.options,
-                                                one = elem.type == "select-one";
-
-                                        // Nothing was selected
-                                        if ( index < 0 )
-                                                return null;
-
-                                        // Loop through all the selected options
-                                        for ( var i = one ? index : 0, max = one ? index + 1 : options.length; i < max; i++ ) {
-                                                var option = options[ i ];
-
-                                                if ( option.selected ) {
-                                                        // Get the specifc value for the option
-                                                        value = jQuery.browser.msie && !option.attributes.value.specified ? option.text : option.value;
-
-                                                        // We don't need an array for one selects
-                                                        if ( one )
-                                                                return value;
-
-                                                        // Multi-Selects return an array
-                                                        values.push( value );
-                                                }
-                                        }
-
-                                        return values;
-
-                                // Everything else, we just grab the value
-                                } else
-                                        return (this[0].value || "").replace(/\r/g, "");
-
-                        }
-
-                        return undefined;
-                }
-
-                if( value.constructor == Number )
-                        value += '';
-
-                return this.each(function(){
-                        if ( this.nodeType != 1 )
-                                return;
-
-                        if ( value.constructor == Array && /radio|checkbox/.test( this.type ) )
-                                this.checked = (jQuery.inArray(this.value, value) >= 0 ||
-                                        jQuery.inArray(this.name, value) >= 0);
-
-                        else if ( jQuery.nodeName( this, "select" ) ) {
-                                var values = jQuery.makeArray(value);
-
-                                jQuery( "option", this ).each(function(){
-                                        this.selected = (jQuery.inArray( this.value, values ) >= 0 ||
-                                                jQuery.inArray( this.text, values ) >= 0);
-                                });
-
-                                if ( !values.length )
-                                        this.selectedIndex = -1;
-
-                        } else
-                                this.value = value;
-                });
-        },
-
-        html: function( value ) {
-                return value == undefined ?
-                        (this[0] ?
-                                this[0].innerHTML :
-                                null) :
-                        this.empty().append( value );
-        },
-
-        replaceWith: function( value ) {
-                return this.after( value ).remove();
-        },
-
-        eq: function( i ) {
-                return this.slice( i, i + 1 );
-        },
-
-        slice: function() {
-                return this.pushStack( Array.prototype.slice.apply( this, arguments ) );
-        },
-
-        map: function( callback ) {
-                return this.pushStack( jQuery.map(this, function(elem, i){
-                        return callback.call( elem, i, elem );
-                }));
-        },
-
-        andSelf: function() {
-                return this.add( this.prevObject );
-        },
-
-        data: function( key, value ){
-                var parts = key.split(".");
-                parts[1] = parts[1] ? "." + parts[1] : "";
-
-                if ( value === undefined ) {
-                        var data = this.triggerHandler("getData" + parts[1] + "!", [parts[0]]);
-
-                        if ( data === undefined && this.length )
-                                data = jQuery.data( this[0], key );
-
-                        return data === undefined && parts[1] ?
-                                this.data( parts[0] ) :
-                                data;
-                } else
-                        return this.trigger("setData" + parts[1] + "!", [parts[0], value]).each(function(){
-                                jQuery.data( this, key, value );
-                        });
-        },
-
-        removeData: function( key ){
-                return this.each(function(){
-                        jQuery.removeData( this, key );
-                });
-        },
-
-        domManip: function( args, table, reverse, callback ) {
-                var clone = this.length > 1, elems;
-
-                return this.each(function(){
-                        if ( !elems ) {
-                                elems = jQuery.clean( args, this.ownerDocument );
-
-                                if ( reverse )
-                                        elems.reverse();
-                        }
-
-                        var obj = this;
-
-                        if ( table && jQuery.nodeName( this, "table" ) && jQuery.nodeName( elems[0], "tr" ) )
-                                obj = this.getElementsByTagName("tbody")[0] || this.appendChild( this.ownerDocument.createElement("tbody") );
-
-                        var scripts = jQuery( [] );
-
-                        jQuery.each(elems, function(){
-                                var elem = clone ?
-                                        jQuery( this ).clone( true )[0] :
-                                        this;
-
-                                // execute all scripts after the elements have been injected
-                                if ( jQuery.nodeName( elem, "script" ) )
-                                        scripts = scripts.add( elem );
-                                else {
-                                        // Remove any inner scripts for later evaluation
-                                        if ( elem.nodeType == 1 )
-                                                scripts = scripts.add( jQuery( "script", elem ).remove() );
-
-                                        // Inject the elements into the document
-                                        callback.call( obj, elem );
-                                }
-                        });
-
-                        scripts.each( evalScript );
-                });
-        }
-};
-
-// Give the init function the jQuery prototype for later instantiation
-jQuery.fn.init.prototype = jQuery.fn;
-
-function evalScript( i, elem ) {
-        if ( elem.src )
-                jQuery.ajax({
-                        url: elem.src,
-                        async: false,
-                        dataType: "script"
-                });
-
-        else
-                jQuery.globalEval( elem.text || elem.textContent || elem.innerHTML || "" );
-
-        if ( elem.parentNode )
-                elem.parentNode.removeChild( elem );
-}
-
-function now(){
-        return +new Date;
-}
-
-jQuery.extend = jQuery.fn.extend = function() {
-        // copy reference to target object
-        var target = arguments[0] || {}, i = 1, length = arguments.length, deep = false, options;
-
-        // Handle a deep copy situation
-        if ( target.constructor == Boolean ) {
-                deep = target;
-                target = arguments[1] || {};
-                // skip the boolean and the target
-                i = 2;
-        }
-
-        // Handle case when target is a string or something (possible in deep copy)
-        if ( typeof target != "object" && typeof target != "function" )
-                target = {};
-
-        // extend jQuery itself if only one argument is passed
-        if ( length == i ) {
-                target = this;
-                --i;
-        }
-
-        for ( ; i < length; i++ )
-                // Only deal with non-null/undefined values
-                if ( (options = arguments[ i ]) != null )
-                        // Extend the base object
-                        for ( var name in options ) {
-                                var src = target[ name ], copy = options[ name ];
-
-                                // Prevent never-ending loop
-                                if ( target === copy )
-                                        continue;
-
-                                // Recurse if we're merging object values
-                                if ( deep && copy && typeof copy == "object" && !copy.nodeType )
-                                        target[ name ] = jQuery.extend( deep, 
-                                                // Never move original objects, clone them
-                                                src || ( copy.length != null ? [ ] : { } )
-                                        , copy );
-
-                                // Don't bring in undefined values
-                                else if ( copy !== undefined )
-                                        target[ name ] = copy;
-
-                        }
-
-        // Return the modified object
-        return target;
-};
-
-var expando = "jQuery" + now(), uuid = 0, windowData = {},
-        // exclude the following css properties to add px
-        exclude = /z-?index|font-?weight|opacity|zoom|line-?height/i,
-        // cache defaultView
-        defaultView = document.defaultView || {};
-
-jQuery.extend({
-        noConflict: function( deep ) {
-                window.$ = _$;
-
-                if ( deep )
-                        window.jQuery = _jQuery;
-
-                return jQuery;
-        },
-
-        // See test/unit/core.js for details concerning this function.
-        isFunction: function( fn ) {
-                return !!fn && typeof fn != "string" && !fn.nodeName &&
-                        fn.constructor != Array && /^[\s[]?function/.test( fn + "" );
-        },
-
-        // check if an element is in a (or is an) XML document
-        isXMLDoc: function( elem ) {
-                return elem.documentElement && !elem.body ||
-                        elem.tagName && elem.ownerDocument && !elem.ownerDocument.body;
-        },
-
-        // Evalulates a script in a global context
-        globalEval: function( data ) {
-                data = jQuery.trim( data );
-
-                if ( data ) {
-                        // Inspired by code by Andrea Giammarchi
-                        // http://webreflection.blogspot.com/2007/08/global-scope-evaluation-and-dom.html
-                        var head = document.getElementsByTagName("head")[0] || document.documentElement,
-                                script = document.createElement("script");
-
-                        script.type = "text/javascript";
-                        if ( jQuery.browser.msie )
-                                script.text = data;
-                        else
-                                script.appendChild( document.createTextNode( data ) );
-
-                        // Use insertBefore instead of appendChild  to circumvent an IE6 bug.
-                        // This arises when a base node is used (#2709).
-                        head.insertBefore( script, head.firstChild );
-                        head.removeChild( script );
-                }
-        },
-
-        nodeName: function( elem, name ) {
-                return elem.nodeName && elem.nodeName.toUpperCase() == name.toUpperCase();
-        },
-
-        cache: {},
-
-        data: function( elem, name, data ) {
-                elem = elem == window ?
-                        windowData :
-                        elem;
-
-                var id = elem[ expando ];
-
-                // Compute a unique ID for the element
-                if ( !id )
-                        id = elem[ expando ] = ++uuid;
-
-                // Only generate the data cache if we're
-                // trying to access or manipulate it
-                if ( name && !jQuery.cache[ id ] )
-                        jQuery.cache[ id ] = {};
-
-                // Prevent overriding the named cache with undefined values
-                if ( data !== undefined )
-                        jQuery.cache[ id ][ name ] = data;
-
-                // Return the named cache data, or the ID for the element
-                return name ?
-                        jQuery.cache[ id ][ name ] :
-                        id;
-        },
-
-        removeData: function( elem, name ) {
-                elem = elem == window ?
-                        windowData :
-                        elem;
-
-                var id = elem[ expando ];
-
-                // If we want to remove a specific section of the element's data
-                if ( name ) {
-                        if ( jQuery.cache[ id ] ) {
-                                // Remove the section of cache data
-                                delete jQuery.cache[ id ][ name ];
-
-                                // If we've removed all the data, remove the element's cache
-                                name = "";
-
-                                for ( name in jQuery.cache[ id ] )
-                                        break;
-
-                                if ( !name )
-                                        jQuery.removeData( elem );
-                        }
-
-                // Otherwise, we want to remove all of the element's data
-                } else {
-                        // Clean up the element expando
-                        try {
-                                delete elem[ expando ];
-                        } catch(e){
-                                // IE has trouble directly removing the expando
-                                // but it's ok with using removeAttribute
-                                if ( elem.removeAttribute )
-                                        elem.removeAttribute( expando );
-                        }
-
-                        // Completely remove the data cache
-                        delete jQuery.cache[ id ];
-                }
-        },
-
-        // args is for internal usage only
-        each: function( object, callback, args ) {
-                var name, i = 0, length = object.length;
-
-                if ( args ) {
-                        if ( length == undefined ) {
-                                for ( name in object )
-                                        if ( callback.apply( object[ name ], args ) === false )
-                                                break;
-                        } else
-                                for ( ; i < length; )
-                                        if ( callback.apply( object[ i++ ], args ) === false )
-                                                break;
-
-                // A special, fast, case for the most common use of each
-                } else {
-                        if ( length == undefined ) {
-                                for ( name in object )
-                                        if ( callback.call( object[ name ], name, object[ name ] ) === false )
-                                                break;
-                        } else
-                                for ( var value = object[0];
-                                        i < length && callback.call( value, i, value ) !== false; value = object[++i] ){}
-                }
-
-                return object;
-        },
-
-        prop: function( elem, value, type, i, name ) {
-                // Handle executable functions
-                if ( jQuery.isFunction( value ) )
-                        value = value.call( elem, i );
-
-                // Handle passing in a number to a CSS property
-                return value && value.constructor == Number && type == "curCSS" && !exclude.test( name ) ?
-                        value + "px" :
-                        value;
-        },
-
-        className: {
-                // internal only, use addClass("class")
-                add: function( elem, classNames ) {
-                        jQuery.each((classNames || "").split(/\s+/), function(i, className){
-                                if ( elem.nodeType == 1 && !jQuery.className.has( elem.className, className ) )
-                                        elem.className += (elem.className ? " " : "") + className;
-                        });
-                },
-
-                // internal only, use removeClass("class")
-                remove: function( elem, classNames ) {
-                        if (elem.nodeType == 1)
-                                elem.className = classNames != undefined ?
-                                        jQuery.grep(elem.className.split(/\s+/), function(className){
-                                                return !jQuery.className.has( classNames, className );
-                                        }).join(" ") :
-                                        "";
-                },
-
-                // internal only, use hasClass("class")
-                has: function( elem, className ) {
-                        return jQuery.inArray( className, (elem.className || elem).toString().split(/\s+/) ) > -1;
-                }
-        },
-
-        // A method for quickly swapping in/out CSS properties to get correct calculations
-        swap: function( elem, options, callback ) {
-                var old = {};
-                // Remember the old values, and insert the new ones
-                for ( var name in options ) {
-                        old[ name ] = elem.style[ name ];
-                        elem.style[ name ] = options[ name ];
-                }
-
-                callback.call( elem );
-
-                // Revert the old values
-                for ( var name in options )
-                        elem.style[ name ] = old[ name ];
-        },
-
-        css: function( elem, name, force ) {
-                if ( name == "width" || name == "height" ) {
-                        var val, props = { position: "absolute", visibility: "hidden", display:"block" }, which = name == "width" ? [ "Left", "Right" ] : [ "Top", "Bottom" ];
-
-                        function getWH() {
-                                val = name == "width" ? elem.offsetWidth : elem.offsetHeight;
-                                var padding = 0, border = 0;
-                                jQuery.each( which, function() {
-                                        padding += parseFloat(jQuery.curCSS( elem, "padding" + this, true)) || 0;
-                                        border += parseFloat(jQuery.curCSS( elem, "border" + this + "Width", true)) || 0;
-                                });
-                                val -= Math.round(padding + border);
-                        }
-
-                        if ( jQuery(elem).is(":visible") )
-                                getWH();
-                        else
-                                jQuery.swap( elem, props, getWH );
-
-                        return Math.max(0, val);
-                }
-
-                return jQuery.curCSS( elem, name, force );
-        },
-
-        curCSS: function( elem, name, force ) {
-                var ret, style = elem.style;
-
-                // A helper method for determining if an element's values are broken
-                function color( elem ) {
-                        if ( !jQuery.browser.safari )
-                                return false;
-
-                        // defaultView is cached
-                        var ret = defaultView.getComputedStyle( elem, null );
-                        return !ret || ret.getPropertyValue("color") == "";
-                }
-
-                // We need to handle opacity special in IE
-                if ( name == "opacity" && jQuery.browser.msie ) {
-                        ret = jQuery.attr( style, "opacity" );
-
-                        return ret == "" ?
-                                "1" :
-                                ret;
-                }
-                // Opera sometimes will give the wrong display answer, this fixes it, see #2037
-                if ( jQuery.browser.opera && name == "display" ) {
-                        var save = style.outline;
-                        style.outline = "0 solid black";
-                        style.outline = save;
-                }
-
-                // Make sure we're using the right name for getting the float value
-                if ( name.match( /float/i ) )
-                        name = styleFloat;
-
-                if ( !force && style && style[ name ] )
-                        ret = style[ name ];
-
-                else if ( defaultView.getComputedStyle ) {
-
-                        // Only "float" is needed here
-                        if ( name.match( /float/i ) )
-                                name = "float";
-
-                        name = name.replace( /([A-Z])/g, "-$1" ).toLowerCase();
-
-                        var computedStyle = defaultView.getComputedStyle( elem, null );
-
-                        if ( computedStyle && !color( elem ) )
-                                ret = computedStyle.getPropertyValue( name );
-
-                        // If the element isn't reporting its values properly in Safari
-                        // then some display: none elements are involved
-                        else {
-                                var swap = [], stack = [], a = elem, i = 0;
-
-                                // Locate all of the parent display: none elements
-                                for ( ; a && color(a); a = a.parentNode )
-                                        stack.unshift(a);
-
-                                // Go through and make them visible, but in reverse
-                                // (It would be better if we knew the exact display type that they had)
-                                for ( ; i < stack.length; i++ )
-                                        if ( color( stack[ i ] ) ) {
-                                                swap[ i ] = stack[ i ].style.display;
-                                                stack[ i ].style.display = "block";
-                                        }
-
-                                // Since we flip the display style, we have to handle that
-                                // one special, otherwise get the value
-                                ret = name == "display" && swap[ stack.length - 1 ] != null ?
-                                        "none" :
-                                        ( computedStyle && computedStyle.getPropertyValue( name ) ) || "";
-
-                                // Finally, revert the display styles back
-                                for ( i = 0; i < swap.length; i++ )
-                                        if ( swap[ i ] != null )
-                                                stack[ i ].style.display = swap[ i ];
-                        }
-
-                        // We should always get a number back from opacity
-                        if ( name == "opacity" && ret == "" )
-                                ret = "1";
-
-                } else if ( elem.currentStyle ) {
-                        var camelCase = name.replace(/\-(\w)/g, function(all, letter){
-                                return letter.toUpperCase();
-                        });
-
-                        ret = elem.currentStyle[ name ] || elem.currentStyle[ camelCase ];
-
-                        // From the awesome hack by Dean Edwards
-                        // http://erik.eae.net/archives/2007/07/27/18.54.15/#comment-102291
-
-                        // If we're not dealing with a regular pixel number
-                        // but a number that has a weird ending, we need to convert it to pixels
-                        if ( !/^\d+(px)?$/i.test( ret ) && /^\d/.test( ret ) ) {
-                                // Remember the original values
-                                var left = style.left, rsLeft = elem.runtimeStyle.left;
-
-                                // Put in the new values to get a computed value out
-                                elem.runtimeStyle.left = elem.currentStyle.left;
-                                style.left = ret || 0;
-                                ret = style.pixelLeft + "px";
-
-                                // Revert the changed values
-                                style.left = left;
-                                elem.runtimeStyle.left = rsLeft;
-                        }
-                }
-
-                return ret;
-        },
-
-        clean: function( elems, context ) {
-                var ret = [];
-                context = context || document;
-                // !context.createElement fails in IE with an error but returns typeof 'object'
-                if (typeof context.createElement == 'undefined')
-                        context = context.ownerDocument || context[0] && context[0].ownerDocument || document;
-
-                jQuery.each(elems, function(i, elem){
-                        if ( !elem )
-                                return;
-
-                        if ( elem.constructor == Number )
-                                elem += '';
-
-                        // Convert html string into DOM nodes
-                        if ( typeof elem == "string" ) {
-                                // Fix "XHTML"-style tags in all browsers
-                                elem = elem.replace(/(<(\w+)[^>]*?)\/>/g, function(all, front, tag){
-                                        return tag.match(/^(abbr|br|col|img|input|link|meta|param|hr|area|embed)$/i) ?
-                                                all :
-                                                front + "></" + tag + ">";
-                                });
-
-                                // Trim whitespace, otherwise indexOf won't work as expected
-                                var tags = jQuery.trim( elem ).toLowerCase(), div = context.createElement("div");
-
-                                var wrap =
-                                        // option or optgroup
-                                        !tags.indexOf("<opt") &&
-                                        [ 1, "<select multiple='multiple'>", "</select>" ] ||
-
-                                        !tags.indexOf("<leg") &&
-                                        [ 1, "<fieldset>", "</fieldset>" ] ||
-
-                                        tags.match(/^<(thead|tbody|tfoot|colg|cap)/) &&
-                                        [ 1, "<table>", "</table>" ] ||
-
-                                        !tags.indexOf("<tr") &&
-                                        [ 2, "<table><tbody>", "</tbody></table>" ] ||
-
-                                        // <thead> matched above
-                                        (!tags.indexOf("<td") || !tags.indexOf("<th")) &&
-                                        [ 3, "<table><tbody><tr>", "</tr></tbody></table>" ] ||
-
-                                        !tags.indexOf("<col") &&
-                                        [ 2, "<table><tbody></tbody><colgroup>", "</colgroup></table>" ] ||
-
-                                        // IE can't serialize <link> and <script> tags normally
-                                        jQuery.browser.msie &&
-                                        [ 1, "div<div>", "</div>" ] ||
-
-                                        [ 0, "", "" ];
-
-                                // Go to html and back, then peel off extra wrappers
-                                div.innerHTML = wrap[1] + elem + wrap[2];
-
-                                // Move to the right depth
-                                while ( wrap[0]-- )
-                                        div = div.lastChild;
-
-                                // Remove IE's autoinserted <tbody> from table fragments
-                                if ( jQuery.browser.msie ) {
-
-                                        // String was a <table>, *may* have spurious <tbody>
-                                        var tbody = !tags.indexOf("<table") && tags.indexOf("<tbody") < 0 ?
-                                                div.firstChild && div.firstChild.childNodes :
-
-                                                // String was a bare <thead> or <tfoot>
-                                                wrap[1] == "<table>" && tags.indexOf("<tbody") < 0 ?
-                                                        div.childNodes :
-                                                        [];
-
-                                        for ( var j = tbody.length - 1; j >= 0 ; --j )
-                                                if ( jQuery.nodeName( tbody[ j ], "tbody" ) && !tbody[ j ].childNodes.length )
-                                                        tbody[ j ].parentNode.removeChild( tbody[ j ] );
-
-                                        // IE completely kills leading whitespace when innerHTML is used
-                                        if ( /^\s/.test( elem ) )
-                                                div.insertBefore( context.createTextNode( elem.match(/^\s*/)[0] ), div.firstChild );
-
-                                }
-
-                                elem = jQuery.makeArray( div.childNodes );
-                        }
-
-                        if ( elem.length === 0 && (!jQuery.nodeName( elem, "form" ) && !jQuery.nodeName( elem, "select" )) )
-                                return;
-
-                        if ( elem[0] == undefined || jQuery.nodeName( elem, "form" ) || elem.options )
-                                ret.push( elem );
-
-                        else
-                                ret = jQuery.merge( ret, elem );
-
-                });
-
-                return ret;
-        },
-
-        attr: function( elem, name, value ) {
-                // don't set attributes on text and comment nodes
-                if (!elem || elem.nodeType == 3 || elem.nodeType == 8)
-                        return undefined;
-
-                var notxml = !jQuery.isXMLDoc( elem ),
-                        // Whether we are setting (or getting)
-                        set = value !== undefined,
-                        msie = jQuery.browser.msie;
-
-                // Try to normalize/fix the name
-                name = notxml && jQuery.props[ name ] || name;
-
-                // Only do all the following if this is a node (faster for style)
-                // IE elem.getAttribute passes even for style
-                if ( elem.tagName ) {
-
-                        // These attributes require special treatment
-                        var special = /href|src|style/.test( name );
-
-                        // Safari mis-reports the default selected property of a hidden option
-                        // Accessing the parent's selectedIndex property fixes it
-                        if ( name == "selected" && jQuery.browser.safari )
-                                elem.parentNode.selectedIndex;
-
-                        // If applicable, access the attribute via the DOM 0 way
-                        if ( name in elem && notxml && !special ) {
-                                if ( set ){
-                                        // We can't allow the type property to be changed (since it causes problems in IE)
-                                        if ( name == "type" && jQuery.nodeName( elem, "input" ) && elem.parentNode )
-                                                throw "type property can't be changed";
-
-                                        elem[ name ] = value;
-                                }
-
-                                // browsers index elements by id/name on forms, give priority to attributes.
-                                if( jQuery.nodeName( elem, "form" ) && elem.getAttributeNode(name) )
-                                        return elem.getAttributeNode( name ).nodeValue;
-
-                                return elem[ name ];
-                        }
-
-                        if ( msie && notxml &&  name == "style" )
-                                return jQuery.attr( elem.style, "cssText", value );
-
-                        if ( set )
-                                // convert the value to a string (all browsers do this but IE) see #1070
-                                elem.setAttribute( name, "" + value );
-
-                        var attr = msie && notxml && special
-                                        // Some attributes require a special call on IE
-                                        ? elem.getAttribute( name, 2 )
-                                        : elem.getAttribute( name );
-
-                        // Non-existent attributes return null, we normalize to undefined
-                        return attr === null ? undefined : attr;
-                }
-
-                // elem is actually elem.style ... set the style
-
-                // IE uses filters for opacity
-                if ( msie && name == "opacity" ) {
-                        if ( set ) {
-                                // IE has trouble with opacity if it does not have layout
-                                // Force it by setting the zoom level
-                                elem.zoom = 1;
-
-                                // Set the alpha filter to set the opacity
-                                elem.filter = (elem.filter || "").replace( /alpha\([^)]*\)/, "" ) +
-                                        (parseInt( value ) + '' == "NaN" ? "" : "alpha(opacity=" + value * 100 + ")");
-                        }
-
-                        return elem.filter && elem.filter.indexOf("opacity=") >= 0 ?
-                                (parseFloat( elem.filter.match(/opacity=([^)]*)/)[1] ) / 100) + '':
-                                "";
-                }
-
-                name = name.replace(/-([a-z])/ig, function(all, letter){
-                        return letter.toUpperCase();
-                });
-
-                if ( set )
-                        elem[ name ] = value;
-
-                return elem[ name ];
-        },
-
-        trim: function( text ) {
-                return (text || "").replace( /^\s+|\s+$/g, "" );
-        },
-
-        makeArray: function( array ) {
-                var ret = [];
-
-                if( array != null ){
-                        var i = array.length;
-                        //the window, strings and functions also have 'length'
-                        if( i == null || array.split || array.setInterval || array.call )
-                                ret[0] = array;
-                        else
-                                while( i )
-                                        ret[--i] = array[i];
-                }
-
-                return ret;
-        },
-
-        inArray: function( elem, array ) {
-                for ( var i = 0, length = array.length; i < length; i++ )
-                // Use === because on IE, window == document
-                        if ( array[ i ] === elem )
-                                return i;
-
-                return -1;
-        },
-
-        merge: function( first, second ) {
-                // We have to loop this way because IE & Opera overwrite the length
-                // expando of getElementsByTagName
-                var i = 0, elem, pos = first.length;
-                // Also, we need to make sure that the correct elements are being returned
-                // (IE returns comment nodes in a '*' query)
-                if ( jQuery.browser.msie ) {
-                        while ( elem = second[ i++ ] )
-                                if ( elem.nodeType != 8 )
-                                        first[ pos++ ] = elem;
-
-                } else
-                        while ( elem = second[ i++ ] )
-                                first[ pos++ ] = elem;
-
-                return first;
-        },
-
-        unique: function( array ) {
-                var ret = [], done = {};
-
-                try {
-
-                        for ( var i = 0, length = array.length; i < length; i++ ) {
-                                var id = jQuery.data( array[ i ] );
-
-                                if ( !done[ id ] ) {
-                                        done[ id ] = true;
-                                        ret.push( array[ i ] );
-                                }
-                        }
-
-                } catch( e ) {
-                        ret = array;
-                }
-
-                return ret;
-        },
-
-        grep: function( elems, callback, inv ) {
-                var ret = [];
-
-                // Go through the array, only saving the items
-                // that pass the validator function
-                for ( var i = 0, length = elems.length; i < length; i++ )
-                        if ( !inv != !callback( elems[ i ], i ) )
-                                ret.push( elems[ i ] );
-
-                return ret;
-        },
-
-        map: function( elems, callback ) {
-                var ret = [];
-
-                // Go through the array, translating each of the items to their
-                // new value (or values).
-                for ( var i = 0, length = elems.length; i < length; i++ ) {
-                        var value = callback( elems[ i ], i );
-
-                        if ( value != null )
-                                ret[ ret.length ] = value;
-                }
-
-                return ret.concat.apply( [], ret );
-        }
-});
-
-var userAgent = navigator.userAgent.toLowerCase();
-
-// Figure out what browser is being used
-jQuery.browser = {
-        version: (userAgent.match( /.+(?:rv|it|ra|ie)[\/: ]([\d.]+)/ ) || [])[1],
-        safari: /webkit/.test( userAgent ),
-        opera: /opera/.test( userAgent ),
-        msie: /msie/.test( userAgent ) && !/opera/.test( userAgent ),
-        mozilla: /mozilla/.test( userAgent ) && !/(compatible|webkit)/.test( userAgent )
-};
-
-var styleFloat = jQuery.browser.msie ?
-        "styleFloat" :
-        "cssFloat";
-
-jQuery.extend({
-        // Check to see if the W3C box model is being used
-        boxModel: !jQuery.browser.msie || document.compatMode == "CSS1Compat",
-
-        props: {
-                "for": "htmlFor",
-                "class": "className",
-                "float": styleFloat,
-                cssFloat: styleFloat,
-                styleFloat: styleFloat,
-                readonly: "readOnly",
-                maxlength: "maxLength",
-                cellspacing: "cellSpacing"
-        }
-});
-
-jQuery.each({
-        parent: function(elem){return elem.parentNode;},
-        parents: function(elem){return jQuery.dir(elem,"parentNode");},
-        next: function(elem){return jQuery.nth(elem,2,"nextSibling");},
-        prev: function(elem){return jQuery.nth(elem,2,"previousSibling");},
-        nextAll: function(elem){return jQuery.dir(elem,"nextSibling");},
-        prevAll: function(elem){return jQuery.dir(elem,"previousSibling");},
-        siblings: function(elem){return jQuery.sibling(elem.parentNode.firstChild,elem);},
-        children: function(elem){return jQuery.sibling(elem.firstChild);},
-        contents: function(elem){return jQuery.nodeName(elem,"iframe")?elem.contentDocument||elem.contentWindow.document:jQuery.makeArray(elem.childNodes);}
-}, function(name, fn){
-        jQuery.fn[ name ] = function( selector ) {
-                var ret = jQuery.map( this, fn );
-
-                if ( selector && typeof selector == "string" )
-                        ret = jQuery.multiFilter( selector, ret );
-
-                return this.pushStack( jQuery.unique( ret ) );
-        };
-});
-
-jQuery.each({
-        appendTo: "append",
-        prependTo: "prepend",
-        insertBefore: "before",
-        insertAfter: "after",
-        replaceAll: "replaceWith"
-}, function(name, original){
-        jQuery.fn[ name ] = function() {
-                var args = arguments;
-
-                return this.each(function(){
-                        for ( var i = 0, length = args.length; i < length; i++ )
-                                jQuery( args[ i ] )[ original ]( this );
-                });
-        };
-});
-
-jQuery.each({
-        removeAttr: function( name ) {
-                jQuery.attr( this, name, "" );
-                if (this.nodeType == 1)
-                        this.removeAttribute( name );
-        },
-
-        addClass: function( classNames ) {
-                jQuery.className.add( this, classNames );
-        },
-
-        removeClass: function( classNames ) {
-                jQuery.className.remove( this, classNames );
-        },
-
-        toggleClass: function( classNames ) {
-                jQuery.className[ jQuery.className.has( this, classNames ) ? "remove" : "add" ]( this, classNames );
-        },
-
-        remove: function( selector ) {
-                if ( !selector || jQuery.filter( selector, [ this ] ).r.length ) {
-                        // Prevent memory leaks
-                        jQuery( "*", this ).add(this).each(function(){
-                                jQuery.event.remove(this);
-                                jQuery.removeData(this);
-                        });
-                        if (this.parentNode)
-                                this.parentNode.removeChild( this );
-                }
-        },
-
-        empty: function() {
-                // Remove element nodes and prevent memory leaks
-                jQuery( ">*", this ).remove();
-
-                // Remove any remaining nodes
-                while ( this.firstChild )
-                        this.removeChild( this.firstChild );
-        }
-}, function(name, fn){
-        jQuery.fn[ name ] = function(){
-                return this.each( fn, arguments );
-        };
-});
-
-jQuery.each([ "Height", "Width" ], function(i, name){
-        var type = name.toLowerCase();
-
-        jQuery.fn[ type ] = function( size ) {
-                // Get window width or height
-                return this[0] == window ?
-                        // Opera reports document.body.client[Width/Height] properly in both quirks and standards
-                        jQuery.browser.opera && document.body[ "client" + name ] ||
-
-                        // Safari reports inner[Width/Height] just fine (Mozilla and Opera include scroll bar widths)
-                        jQuery.browser.safari && window[ "inner" + name ] ||
-
-                        // Everyone else use document.documentElement or document.body depending on Quirks vs Standards mode
-                        document.compatMode == "CSS1Compat" && document.documentElement[ "client" + name ] || document.body[ "client" + name ] :
-
-                        // Get document width or height
-                        this[0] == document ?
-                                // Either scroll[Width/Height] or offset[Width/Height], whichever is greater
-                                Math.max(
-                                        Math.max(document.body["scroll" + name], document.documentElement["scroll" + name]),
-                                        Math.max(document.body["offset" + name], document.documentElement["offset" + name])
-                                ) :
-
-                                // Get or set width or height on the element
-                                size == undefined ?
-                                        // Get width or height on the element
-                                        (this.length ? jQuery.css( this[0], type ) : null) :
-
-                                        // Set the width or height on the element (default to pixels if value is unitless)
-                                        this.css( type, size.constructor == String ? size : size + "px" );
-        };
-});
-
-// Helper function used by the dimensions and offset modules
-function num(elem, prop) {
-        return elem[0] && parseInt( jQuery.curCSS(elem[0], prop, true), 10 ) || 0;
-}var chars = jQuery.browser.safari && parseInt(jQuery.browser.version) < 417 ?
-                "(?:[\\w*_-]|\\\\.)" :
-                "(?:[\\w\u0128-\uFFFF*_-]|\\\\.)",
-        quickChild = new RegExp("^>\\s*(" + chars + "+)"),
-        quickID = new RegExp("^(" + chars + "+)(#)(" + chars + "+)"),
-        quickClass = new RegExp("^([#.]?)(" + chars + "*)");
-
-jQuery.extend({
-        expr: {
-                "": function(a,i,m){return m[2]=="*"||jQuery.nodeName(a,m[2]);},
-                "#": function(a,i,m){return a.getAttribute("id")==m[2];},
-                ":": {
-                        // Position Checks
-                        lt: function(a,i,m){return i<m[3]-0;},
-                        gt: function(a,i,m){return i>m[3]-0;},
-                        nth: function(a,i,m){return m[3]-0==i;},
-                        eq: function(a,i,m){return m[3]-0==i;},
-                        first: function(a,i){return i==0;},
-                        last: function(a,i,m,r){return i==r.length-1;},
-                        even: function(a,i){return i%2==0;},
-                        odd: function(a,i){return i%2;},
-
-                        // Child Checks
-                        "first-child": function(a){return a.parentNode.getElementsByTagName("*")[0]==a;},
-                        "last-child": function(a){return jQuery.nth(a.parentNode.lastChild,1,"previousSibling")==a;},
-                        "only-child": function(a){return !jQuery.nth(a.parentNode.lastChild,2,"previousSibling");},
-
-                        // Parent Checks
-                        parent: function(a){return a.firstChild;},
-                        empty: function(a){return !a.firstChild;},
-
-                        // Text Check
-                        contains: function(a,i,m){return (a.textContent||a.innerText||jQuery(a).text()||"").indexOf(m[3])>=0;},
-
-                        // Visibility
-                        visible: function(a){return "hidden"!=a.type&&jQuery.css(a,"display")!="none"&&jQuery.css(a,"visibility")!="hidden";},
-                        hidden: function(a){return "hidden"==a.type||jQuery.css(a,"display")=="none"||jQuery.css(a,"visibility")=="hidden";},
-
-                        // Form attributes
-                        enabled: function(a){return !a.disabled;},
-                        disabled: function(a){return a.disabled;},
-                        checked: function(a){return a.checked;},
-                        selected: function(a){return a.selected||jQuery.attr(a,"selected");},
-
-                        // Form elements
-                        text: function(a){return "text"==a.type;},
-                        radio: function(a){return "radio"==a.type;},
-                        checkbox: function(a){return "checkbox"==a.type;},
-                        file: function(a){return "file"==a.type;},
-                        password: function(a){return "password"==a.type;},
-                        submit: function(a){return "submit"==a.type;},
-                        image: function(a){return "image"==a.type;},
-                        reset: function(a){return "reset"==a.type;},
-                        button: function(a){return "button"==a.type||jQuery.nodeName(a,"button");},
-                        input: function(a){return /input|select|textarea|button/i.test(a.nodeName);},
-
-                        // :has()
-                        has: function(a,i,m){return jQuery.find(m[3],a).length;},
-
-                        // :header
-                        header: function(a){return /h\d/i.test(a.nodeName);},
-
-                        // :animated
-                        animated: function(a){return jQuery.grep(jQuery.timers,function(fn){return a==fn.elem;}).length;}
-                }
-        },
-
-        // The regular expressions that power the parsing engine
-        parse: [
-                // Match: [@value='test'], [@foo]
-                /^(\[) *@?([\w-]+) *([!*$^~=]*) *('?"?)(.*?)\4 *\]/,
-
-                // Match: :contains('foo')
-                /^(:)([\w-]+)\("?'?(.*?(\(.*?\))?[^(]*?)"?'?\)/,
-
-                // Match: :even, :last-child, #id, .class
-                new RegExp("^([:.#]*)(" + chars + "+)")
-        ],
-
-        multiFilter: function( expr, elems, not ) {
-                var old, cur = [];
-
-                while ( expr && expr != old ) {
-                        old = expr;
-                        var f = jQuery.filter( expr, elems, not );
-                        expr = f.t.replace(/^\s*,\s*/, "" );
-                        cur = not ? elems = f.r : jQuery.merge( cur, f.r );
-                }
-
-                return cur;
-        },
-
-        find: function( t, context ) {
-                // Quickly handle non-string expressions
-                if ( typeof t != "string" )
-                        return [ t ];
-
-                // check to make sure context is a DOM element or a document
-                if ( context && context.nodeType != 1 && context.nodeType != 9)
-                        return [ ];
-
-                // Set the correct context (if none is provided)
-                context = context || document;
-
-                // Initialize the search
-                var ret = [context], done = [], last, nodeName;
-
-                // Continue while a selector expression exists, and while
-                // we're no longer looping upon ourselves
-                while ( t && last != t ) {
-                        var r = [];
-                        last = t;
-
-                        t = jQuery.trim(t);
-
-                        var foundToken = false,
-
-                        // An attempt at speeding up child selectors that
-                        // point to a specific element tag
-                                re = quickChild,
-
-                                m = re.exec(t);
-
-                        if ( m ) {
-                                nodeName = m[1].toUpperCase();
-
-                                // Perform our own iteration and filter
-                                for ( var i = 0; ret[i]; i++ )
-                                        for ( var c = ret[i].firstChild; c; c = c.nextSibling )
-                                                if ( c.nodeType == 1 && (nodeName == "*" || c.nodeName.toUpperCase() == nodeName) )
-                                                        r.push( c );
-
-                                ret = r;
-                                t = t.replace( re, "" );
-                                if ( t.indexOf(" ") == 0 ) continue;
-                                foundToken = true;
-                        } else {
-                                re = /^([>+~])\s*(\w*)/i;
-
-                                if ( (m = re.exec(t)) != null ) {
-                                        r = [];
-
-                                        var merge = {};
-                                        nodeName = m[2].toUpperCase();
-                                        m = m[1];
-
-                                        for ( var j = 0, rl = ret.length; j < rl; j++ ) {
-                                                var n = m == "~" || m == "+" ? ret[j].nextSibling : ret[j].firstChild;
-                                                for ( ; n; n = n.nextSibling )
-                                                        if ( n.nodeType == 1 ) {
-                                                                var id = jQuery.data(n);
-
-                                                                if ( m == "~" && merge[id] ) break;
-
-                                                                if (!nodeName || n.nodeName.toUpperCase() == nodeName ) {
-                                                                        if ( m == "~" ) merge[id] = true;
-                                                                        r.push( n );
-                                                                }
-
-                                                                if ( m == "+" ) break;
-                                                        }
-                                        }
-
-                                        ret = r;
-
-                                        // And remove the token
-                                        t = jQuery.trim( t.replace( re, "" ) );
-                                        foundToken = true;
-                                }
-                        }
-
-                        // See if there's still an expression, and that we haven't already
-                        // matched a token
-                        if ( t && !foundToken ) {
-                                // Handle multiple expressions
-                                if ( !t.indexOf(",") ) {
-                                        // Clean the result set
-                                        if ( context == ret[0] ) ret.shift();
-
-                                        // Merge the result sets
-                                        done = jQuery.merge( done, ret );
-
-                                        // Reset the context
-                                        r = ret = [context];
-
-                                        // Touch up the selector string
-                                        t = " " + t.substr(1,t.length);
-
-                                } else {
-                                        // Optimize for the case nodeName#idName
-                                        var re2 = quickID;
-                                        var m = re2.exec(t);
-
-                                        // Re-organize the results, so that they're consistent
-                                        if ( m ) {
-                                                m = [ 0, m[2], m[3], m[1] ];
-
-                                        } else {
-                                                // Otherwise, do a traditional filter check for
-                                                // ID, class, and element selectors
-                                                re2 = quickClass;
-                                                m = re2.exec(t);
-                                        }
-
-                                        m[2] = m[2].replace(/\\/g, "");
-
-                                        var elem = ret[ret.length-1];
-
-                                        // Try to do a global search by ID, where we can
-                                        if ( m[1] == "#" && elem && elem.getElementById && !jQuery.isXMLDoc(elem) ) {
-                                                // Optimization for HTML document case
-                                                var oid = elem.getElementById(m[2]);
-
-                                                // Do a quick check for the existence of the actual ID attribute
-                                                // to avoid selecting by the name attribute in IE
-                                                // also check to insure id is a string to avoid selecting an element with the name of 'id' inside a form
-                                                if ( (jQuery.browser.msie||jQuery.browser.opera) && oid && typeof oid.id == "string" && oid.id != m[2] )
-                                                        oid = jQuery('[@id="'+m[2]+'"]', elem)[0];
-
-                                                // Do a quick check for node name (where applicable) so
-                                                // that div#foo searches will be really fast
-                                                ret = r = oid && (!m[3] || jQuery.nodeName(oid, m[3])) ? [oid] : [];
-                                        } else {
-                                                // We need to find all descendant elements
-                                                for ( var i = 0; ret[i]; i++ ) {
-                                                        // Grab the tag name being searched for
-                                                        var tag = m[1] == "#" && m[3] ? m[3] : m[1] != "" || m[0] == "" ? "*" : m[2];
-
-                                                        // Handle IE7 being really dumb about <object>s
-                                                        if ( tag == "*" && ret[i].nodeName.toLowerCase() == "object" )
-                                                                tag = "param";
-
-                                                        r = jQuery.merge( r, ret[i].getElementsByTagName( tag ));
-                                                }
-
-                                                // It's faster to filter by class and be done with it
-                                                if ( m[1] == "." )
-                                                        r = jQuery.classFilter( r, m[2] );
-
-                                                // Same with ID filtering
-                                                if ( m[1] == "#" ) {
-                                                        var tmp = [];
-
-                                                        // Try to find the element with the ID
-                                                        for ( var i = 0; r[i]; i++ )
-                                                                if ( r[i].getAttribute("id") == m[2] ) {
-                                                                        tmp = [ r[i] ];
-                                                                        break;
-                                                                }
-
-                                                        r = tmp;
-                                                }
-
-                                                ret = r;
-                                        }
-
-                                        t = t.replace( re2, "" );
-                                }
-
-                        }
-
-                        // If a selector string still exists
-                        if ( t ) {
-                                // Attempt to filter it
-                                var val = jQuery.filter(t,r);
-                                ret = r = val.r;
-                                t = jQuery.trim(val.t);
-                        }
-                }
-
-                // An error occurred with the selector;
-                // just return an empty set instead
-                if ( t )
-                        ret = [];
-
-                // Remove the root context
-                if ( ret && context == ret[0] )
-                        ret.shift();
-
-                // And combine the results
-                done = jQuery.merge( done, ret );
-
-                return done;
-        },
-
-        classFilter: function(r,m,not){
-                m = " " + m + " ";
-                var tmp = [];
-                for ( var i = 0; r[i]; i++ ) {
-                        var pass = (" " + r[i].className + " ").indexOf( m ) >= 0;
-                        if ( !not && pass || not && !pass )
-                                tmp.push( r[i] );
-                }
-                return tmp;
-        },
-
-        filter: function(t,r,not) {
-                var last;
-
-                // Look for common filter expressions
-                while ( t && t != last ) {
-                        last = t;
-
-                        var p = jQuery.parse, m;
-
-                        for ( var i = 0; p[i]; i++ ) {
-                                m = p[i].exec( t );
-
-                                if ( m ) {
-                                        // Remove what we just matched
-                                        t = t.substring( m[0].length );
-
-                                        m[2] = m[2].replace(/\\/g, "");
-                                        break;
-                                }
-                        }
-
-                        if ( !m )
-                                break;
-
-                        // :not() is a special case that can be optimized by
-                        // keeping it out of the expression list
-                        if ( m[1] == ":" && m[2] == "not" )
-                                // optimize if only one selector found (most common case)
-                                r = isSimple.test( m[3] ) ?
-                                        jQuery.filter(m[3], r, true).r :
-                                        jQuery( r ).not( m[3] );
-
-                        // We can get a big speed boost by filtering by class here
-                        else if ( m[1] == "." )
-                                r = jQuery.classFilter(r, m[2], not);
-
-                        else if ( m[1] == "[" ) {
-                                var tmp = [], type = m[3];
-
-                                for ( var i = 0, rl = r.length; i < rl; i++ ) {
-                                        var a = r[i], z = a[ jQuery.props[m[2]] || m[2] ];
-
-                                        if ( z == null || /href|src|selected/.test(m[2]) )
-                                                z = jQuery.attr(a,m[2]) || '';
-
-                                        if ( (type == "" && !!z ||
-                                                 type == "=" && z == m[5] ||
-                                                 type == "!=" && z != m[5] ||
-                                                 type == "^=" && z && !z.indexOf(m[5]) ||
-                                                 type == "$=" && z.substr(z.length - m[5].length) == m[5] ||
-                                                 (type == "*=" || type == "~=") && z.indexOf(m[5]) >= 0) ^ not )
-                                                        tmp.push( a );
-                                }
-
-                                r = tmp;
-
-                        // We can get a speed boost by handling nth-child here
-                        } else if ( m[1] == ":" && m[2] == "nth-child" ) {
-                                var merge = {}, tmp = [],
-                                        // parse equations like 'even', 'odd', '5', '2n', '3n+2', '4n-1', '-n+6'
-                                        test = /(-?)(\d*)n((?:\+|-)?\d*)/.exec(
-                                                m[3] == "even" && "2n" || m[3] == "odd" && "2n+1" ||
-                                                !/\D/.test(m[3]) && "0n+" + m[3] || m[3]),
-                                        // calculate the numbers (first)n+(last) including if they are negative
-                                        first = (test[1] + (test[2] || 1)) - 0, last = test[3] - 0;
-
-                                // loop through all the elements left in the jQuery object
-                                for ( var i = 0, rl = r.length; i < rl; i++ ) {
-                                        var node = r[i], parentNode = node.parentNode, id = jQuery.data(parentNode);
-
-                                        if ( !merge[id] ) {
-                                                var c = 1;
-
-                                                for ( var n = parentNode.firstChild; n; n = n.nextSibling )
-                                                        if ( n.nodeType == 1 )
-                                                                n.nodeIndex = c++;
-
-                                                merge[id] = true;
-                                        }
-
-                                        var add = false;
-
-                                        if ( first == 0 ) {
-                                                if ( node.nodeIndex == last )
-                                                        add = true;
-                                        } else if ( (node.nodeIndex - last) % first == 0 && (node.nodeIndex - last) / first >= 0 )
-                                                add = true;
-
-                                        if ( add ^ not )
-                                                tmp.push( node );
-                                }
-
-                                r = tmp;
-
-                        // Otherwise, find the expression to execute
-                        } else {
-                                var fn = jQuery.expr[ m[1] ];
-                                if ( typeof fn == "object" )
-                                        fn = fn[ m[2] ];
-
-                                if ( typeof fn == "string" )
-                                        fn = eval("false||function(a,i){return " + fn + ";}");
-
-                                // Execute it against the current filter
-                                r = jQuery.grep( r, function(elem, i){
-                                        return fn(elem, i, m, r);
-                                }, not );
-                        }
-                }
-
-                // Return an array of filtered elements (r)
-                // and the modified expression string (t)
-                return { r: r, t: t };
-        },
-
-        dir: function( elem, dir ){
-                var matched = [],
-                        cur = elem[dir];
-                while ( cur && cur != document ) {
-                        if ( cur.nodeType == 1 )
-                                matched.push( cur );
-                        cur = cur[dir];
-                }
-                return matched;
-        },
-
-        nth: function(cur,result,dir,elem){
-                result = result || 1;
-                var num = 0;
-
-                for ( ; cur; cur = cur[dir] )
-                        if ( cur.nodeType == 1 && ++num == result )
-                                break;
-
-                return cur;
-        },
-
-        sibling: function( n, elem ) {
-                var r = [];
-
-                for ( ; n; n = n.nextSibling ) {
-                        if ( n.nodeType == 1 && n != elem )
-                                r.push( n );
-                }
-
-                return r;
-        }
-});
-/*
- * A number of helper functions used for managing events.
- * Many of the ideas behind this code orignated from
- * Dean Edwards' addEvent library.
- */
-jQuery.event = {
-
-        // Bind an event to an element
-        // Original by Dean Edwards
-        add: function(elem, types, handler, data) {
-                if ( elem.nodeType == 3 || elem.nodeType == 8 )
-                        return;
-
-                // For whatever reason, IE has trouble passing the window object
-                // around, causing it to be cloned in the process
-                if ( jQuery.browser.msie && elem.setInterval )
-                        elem = window;
-
-                // Make sure that the function being executed has a unique ID
-                if ( !handler.guid )
-                        handler.guid = this.guid++;
-
-                // if data is passed, bind to handler
-                if( data != undefined ) {
-                        // Create temporary function pointer to original handler
-                        var fn = handler;
-
-                        // Create unique handler function, wrapped around original handler
-                        handler = this.proxy( fn, function() {
-                                // Pass arguments and context to original handler
-                                return fn.apply(this, arguments);
-                        });
-
-                        // Store data in unique handler
-                        handler.data = data;
-                }
-
-                // Init the element's event structure
-                var events = jQuery.data(elem, "events") || jQuery.data(elem, "events", {}),
-                        handle = jQuery.data(elem, "handle") || jQuery.data(elem, "handle", function(){
-                                // Handle the second event of a trigger and when
-                                // an event is called after a page has unloaded
-                                if ( typeof jQuery != "undefined" && !jQuery.event.triggered )
-                                        return jQuery.event.handle.apply(arguments.callee.elem, arguments);
-                        });
-                // Add elem as a property of the handle function
-                // This is to prevent a memory leak with non-native
-                // event in IE.
-                handle.elem = elem;
-
-                // Handle multiple events separated by a space
-                // jQuery(...).bind("mouseover mouseout", fn);
-                jQuery.each(types.split(/\s+/), function(index, type) {
-                        // Namespaced event handlers
-                        var parts = type.split(".");
-                        type = parts[0];
-                        handler.type = parts[1];
-
-                        // Get the current list of functions bound to this event
-                        var handlers = events[type];
-
-                        // Init the event handler queue
-                        if (!handlers) {
-                                handlers = events[type] = {};
-
-                                // Check for a special event handler
-                                // Only use addEventListener/attachEvent if the special
-                                // events handler returns false
-                                if ( !jQuery.event.special[type] || jQuery.event.special[type].setup.call(elem) === false ) {
-                                        // Bind the global event handler to the element
-                                        if (elem.addEventListener)
-                                                elem.addEventListener(type, handle, false);
-                                        else if (elem.attachEvent)
-                                                elem.attachEvent("on" + type, handle);
-                                }
-                        }
-
-                        // Add the function to the element's handler list
-                        handlers[handler.guid] = handler;
-
-                        // Keep track of which events have been used, for global triggering
-                        jQuery.event.global[type] = true;
-                });
-
-                // Nullify elem to prevent memory leaks in IE
-                elem = null;
-        },
-
-        guid: 1,
-        global: {},
-
-        // Detach an event or set of events from an element
-        remove: function(elem, types, handler) {
-                // don't do events on text and comment nodes
-                if ( elem.nodeType == 3 || elem.nodeType == 8 )
-                        return;
-
-                var events = jQuery.data(elem, "events"), ret, index;
-
-                if ( events ) {
-                        // Unbind all events for the element
-                        if ( types == undefined || (typeof types == "string" && types.charAt(0) == ".") )
-                                for ( var type in events )
-                                        this.remove( elem, type + (types || "") );
-                        else {
-                                // types is actually an event object here
-                                if ( types.type ) {
-                                        handler = types.handler;
-                                        types = types.type;
-                                }
-
-                                // Handle multiple events seperated by a space
-                                // jQuery(...).unbind("mouseover mouseout", fn);
-                                jQuery.each(types.split(/\s+/), function(index, type){
-                                        // Namespaced event handlers
-                                        var parts = type.split(".");
-                                        type = parts[0];
-
-                                        if ( events[type] ) {
-                                                // remove the given handler for the given type
-                                                if ( handler )
-                                                        delete events[type][handler.guid];
-
-                                                // remove all handlers for the given type
-                                                else
-                                                        for ( handler in events[type] )
-                                                                // Handle the removal of namespaced events
-                                                                if ( !parts[1] || events[type][handler].type == parts[1] )
-                                                                        delete events[type][handler];
-
-                                                // remove generic event handler if no more handlers exist
-                                                for ( ret in events[type] ) break;
-                                                if ( !ret ) {
-                                                        if ( !jQuery.event.special[type] || jQuery.event.special[type].teardown.call(elem) === false ) {
-                                                                if (elem.removeEventListener)
-                                                                        elem.removeEventListener(type, jQuery.data(elem, "handle"), false);
-                                                                else if (elem.detachEvent)
-                                                                        elem.detachEvent("on" + type, jQuery.data(elem, "handle"));
-                                                        }
-                                                        ret = null;
-                                                        delete events[type];
-                                                }
-                                        }
-                                });
-                        }
-
-                        // Remove the expando if it's no longer used
-                        for ( ret in events ) break;
-                        if ( !ret ) {
-                                var handle = jQuery.data( elem, "handle" );
-                                if ( handle ) handle.elem = null;
-                                jQuery.removeData( elem, "events" );
-                                jQuery.removeData( elem, "handle" );
-                        }
-                }
-        },
-
-        trigger: function(type, data, elem, donative, extra) {
-                // Clone the incoming data, if any
-                data = jQuery.makeArray(data);
-
-                if ( type.indexOf("!") >= 0 ) {
-                        type = type.slice(0, -1);
-                        var exclusive = true;
-                }
-
-                // Handle a global trigger
-                if ( !elem ) {
-                        // Only trigger if we've ever bound an event for it
-                        if ( this.global[type] )
-                                jQuery("*").add([window, document]).trigger(type, data);
-
-                // Handle triggering a single element
-                } else {
-                        // don't do events on text and comment nodes
-                        if ( elem.nodeType == 3 || elem.nodeType == 8 )
-                                return undefined;
-
-                        var val, ret, fn = jQuery.isFunction( elem[ type ] || null ),
-                                // Check to see if we need to provide a fake event, or not
-                                event = !data[0] || !data[0].preventDefault;
-
-                        // Pass along a fake event
-                        if ( event ) {
-                                data.unshift({
-                                        type: type,
-                                        target: elem,
-                                        preventDefault: function(){},
-                                        stopPropagation: function(){},
-                                        timeStamp: now()
-                                });
-                                data[0][expando] = true; // no need to fix fake event
-                        }
-
-                        // Enforce the right trigger type
-                        data[0].type = type;
-                        if ( exclusive )
-                                data[0].exclusive = true;
-
-                        // Trigger the event, it is assumed that "handle" is a function
-                        var handle = jQuery.data(elem, "handle");
-                        if ( handle )
-                                val = handle.apply( elem, data );
-
-                        // Handle triggering native .onfoo handlers (and on links since we don't call .click() for links)
-                        if ( (!fn || (jQuery.nodeName(elem, 'a') && type == "click")) && elem["on"+type] && elem["on"+type].apply( elem, data ) === false )
-                                val = false;
-
-                        // Extra functions don't get the custom event object
-                        if ( event )
-                                data.shift();
-
-                        // Handle triggering of extra function
-                        if ( extra && jQuery.isFunction( extra ) ) {
-                                // call the extra function and tack the current return value on the end for possible inspection
-                                ret = extra.apply( elem, val == null ? data : data.concat( val ) );
-                                // if anything is returned, give it precedence and have it overwrite the previous value
-                                if (ret !== undefined)
-                                        val = ret;
-                        }
-
-                        // Trigger the native events (except for clicks on links)
-                        if ( fn && donative !== false && val !== false && !(jQuery.nodeName(elem, 'a') && type == "click") ) {
-                                this.triggered = true;
-                                try {
-                                        elem[ type ]();
-                                // prevent IE from throwing an error for some hidden elements
-                                } catch (e) {}
-                        }
-
-                        this.triggered = false;
-                }
-
-                return val;
-        },
-
-        handle: function(event) {
-                // returned undefined or false
-                var val, ret, namespace, all, handlers;
-
-                event = arguments[0] = jQuery.event.fix( event || window.event );
-
-                // Namespaced event handlers
-                namespace = event.type.split(".");
-                event.type = namespace[0];
-                namespace = namespace[1];
-                // Cache this now, all = true means, any handler
-                all = !namespace && !event.exclusive;
-
-                handlers = ( jQuery.data(this, "events") || {} )[event.type];
-
-                for ( var j in handlers ) {
-                        var handler = handlers[j];
-
-                        // Filter the functions by class
-                        if ( all || handler.type == namespace ) {
-                                // Pass in a reference to the handler function itself
-                                // So that we can later remove it
-                                event.handler = handler;
-                                event.data = handler.data;
-
-                                ret = handler.apply( this, arguments );
-
-                                if ( val !== false )
-                                        val = ret;
-
-                                if ( ret === false ) {
-                                        event.preventDefault();
-                                        event.stopPropagation();
-                                }
-                        }
-                }
-
-                return val;
-        },
-
-        fix: function(event) {
-                if ( event[expando] == true )
-                        return event;
-
-                // store a copy of the original event object
-                // and "clone" to set read-only properties
-                var originalEvent = event;
-                event = { originalEvent: originalEvent };
-                var props = "altKey attrChange attrName bubbles button cancelable charCode clientX clientY ctrlKey currentTarget data detail eventPhase fromElement handler keyCode metaKey newValue originalTarget pageX pageY prevValue relatedNode relatedTarget screenX screenY shiftKey srcElement target timeStamp toElement type view wheelDelta which".split(" ");
-                for ( var i=props.length; i; i-- )
-                        event[ props[i] ] = originalEvent[ props[i] ];
-
-                // Mark it as fixed
-                event[expando] = true;
-
-                // add preventDefault and stopPropagation since
-                // they will not work on the clone
-                event.preventDefault = function() {
-                        // if preventDefault exists run it on the original event
-                        if (originalEvent.preventDefault)
-                                originalEvent.preventDefault();
-                        // otherwise set the returnValue property of the original event to false (IE)
-                        originalEvent.returnValue = false;
-                };
-                event.stopPropagation = function() {
-                        // if stopPropagation exists run it on the original event
-                        if (originalEvent.stopPropagation)
-                                originalEvent.stopPropagation();
-                        // otherwise set the cancelBubble property of the original event to true (IE)
-                        originalEvent.cancelBubble = true;
-                };
-
-                // Fix timeStamp
-                event.timeStamp = event.timeStamp || now();
-
-                // Fix target property, if necessary
-                if ( !event.target )
-                        event.target = event.srcElement || document; // Fixes #1925 where srcElement might not be defined either
-
-                // check if target is a textnode (safari)
-                if ( event.target.nodeType == 3 )
-                        event.target = event.target.parentNode;
-
-                // Add relatedTarget, if necessary
-                if ( !event.relatedTarget && event.fromElement )
-                        event.relatedTarget = event.fromElement == event.target ? event.toElement : event.fromElement;
-
-                // Calculate pageX/Y if missing and clientX/Y available
-                if ( event.pageX == null && event.clientX != null ) {
-                        var doc = document.documentElement, body = document.body;
-                        event.pageX = event.clientX + (doc && doc.scrollLeft || body && body.scrollLeft || 0) - (doc.clientLeft || 0);
-                        event.pageY = event.clientY + (doc && doc.scrollTop || body && body.scrollTop || 0) - (doc.clientTop || 0);
-                }
-
-                // Add which for key events
-                if ( !event.which && ((event.charCode || event.charCode === 0) ? event.charCode : event.keyCode) )
-                        event.which = event.charCode || event.keyCode;
-
-                // Add metaKey to non-Mac browsers (use ctrl for PC's and Meta for Macs)
-                if ( !event.metaKey && event.ctrlKey )
-                        event.metaKey = event.ctrlKey;
-
-                // Add which for click: 1 == left; 2 == middle; 3 == right
-                // Note: button is not normalized, so don't use it
-                if ( !event.which && event.button )
-                        event.which = (event.button & 1 ? 1 : ( event.button & 2 ? 3 : ( event.button & 4 ? 2 : 0 ) ));
-
-                return event;
-        },
-
-        proxy: function( fn, proxy ){
-                // Set the guid of unique handler to the same of original handler, so it can be removed
-                proxy.guid = fn.guid = fn.guid || proxy.guid || this.guid++;
-                // So proxy can be declared as an argument
-                return proxy;
-        },
-
-        special: {
-                ready: {
-                        setup: function() {
-                                // Make sure the ready event is setup
-                                bindReady();
-                                return;
-                        },
-
-                        teardown: function() { return; }
-                },
-
-                mouseenter: {
-                        setup: function() {
-                                if ( jQuery.browser.msie ) return false;
-                                jQuery(this).bind("mouseover", jQuery.event.special.mouseenter.handler);
-                                return true;
-                        },
-
-                        teardown: function() {
-                                if ( jQuery.browser.msie ) return false;
-                                jQuery(this).unbind("mouseover", jQuery.event.special.mouseenter.handler);
-                                return true;
-                        },
-
-                        handler: function(event) {
-                                // If we actually just moused on to a sub-element, ignore it
-                                if ( withinElement(event, this) ) return true;
-                                // Execute the right handlers by setting the event type to mouseenter
-                                event.type = "mouseenter";
-                                return jQuery.event.handle.apply(this, arguments);
-                        }
-                },
-
-                mouseleave: {
-                        setup: function() {
-                                if ( jQuery.browser.msie ) return false;
-                                jQuery(this).bind("mouseout", jQuery.event.special.mouseleave.handler);
-                                return true;
-                        },
-
-                        teardown: function() {
-                                if ( jQuery.browser.msie ) return false;
-                                jQuery(this).unbind("mouseout", jQuery.event.special.mouseleave.handler);
-                                return true;
-                        },
-
-                        handler: function(event) {
-                                // If we actually just moused on to a sub-element, ignore it
-                                if ( withinElement(event, this) ) return true;
-                                // Execute the right handlers by setting the event type to mouseleave
-                                event.type = "mouseleave";
-                                return jQuery.event.handle.apply(this, arguments);
-                        }
-                }
-        }
-};
-
-jQuery.fn.extend({
-        bind: function( type, data, fn ) {
-                return type == "unload" ? this.one(type, data, fn) : this.each(function(){
-                        jQuery.event.add( this, type, fn || data, fn && data );
-                });
-        },
-
-        one: function( type, data, fn ) {
-                var one = jQuery.event.proxy( fn || data, function(event) {
-                        jQuery(this).unbind(event, one);
-                        return (fn || data).apply( this, arguments );
-                });
-                return this.each(function(){
-                        jQuery.event.add( this, type, one, fn && data);
-                });
-        },
-
-        unbind: function( type, fn ) {
-                return this.each(function(){
-                        jQuery.event.remove( this, type, fn );
-                });
-        },
-
-        trigger: function( type, data, fn ) {
-                return this.each(function(){
-                        jQuery.event.trigger( type, data, this, true, fn );
-                });
-        },
-
-        triggerHandler: function( type, data, fn ) {
-                return this[0] && jQuery.event.trigger( type, data, this[0], false, fn );
-        },
-
-        toggle: function( fn ) {
-                // Save reference to arguments for access in closure
-                var args = arguments, i = 1;
-
-                // link all the functions, so any of them can unbind this click handler
-                while( i < args.length )
-                        jQuery.event.proxy( fn, args[i++] );
-
-                return this.click( jQuery.event.proxy( fn, function(event) {
-                        // Figure out which function to execute
-                        this.lastToggle = ( this.lastToggle || 0 ) % i;
-
-                        // Make sure that clicks stop
-                        event.preventDefault();
-
-                        // and execute the function
-                        return args[ this.lastToggle++ ].apply( this, arguments ) || false;
-                }));
-        },
-
-        hover: function(fnOver, fnOut) {
-                return this.bind('mouseenter', fnOver).bind('mouseleave', fnOut);
-        },
-
-        ready: function(fn) {
-                // Attach the listeners
-                bindReady();
-
-                // If the DOM is already ready
-                if ( jQuery.isReady )
-                        // Execute the function immediately
-                        fn.call( document, jQuery );
-
-                // Otherwise, remember the function for later
-                else
-                        // Add the function to the wait list
-                        jQuery.readyList.push( function() { return fn.call(this, jQuery); } );
-
-                return this;
-        }
-});
-
-jQuery.extend({
-        isReady: false,
-        readyList: [],
-        // Handle when the DOM is ready
-        ready: function() {
-                // Make sure that the DOM is not already loaded
-                if ( !jQuery.isReady ) {
-                        // Remember that the DOM is ready
-                        jQuery.isReady = true;
-
-                        // If there are functions bound, to execute
-                        if ( jQuery.readyList ) {
-                                // Execute all of them
-                                jQuery.each( jQuery.readyList, function(){
-                                        this.call( document );
-                                });
-
-                                // Reset the list of functions
-                                jQuery.readyList = null;
-                        }
-
-                        // Trigger any bound ready events
-                        jQuery(document).triggerHandler("ready");
-                }
-        }
-});
-
-var readyBound = false;
-
-function bindReady(){
-        if ( readyBound ) return;
-        readyBound = true;
-
-        // Mozilla, Opera (see further below for it) and webkit nightlies currently support this event
-        if ( document.addEventListener && !jQuery.browser.opera)
-                // Use the handy event callback
-                document.addEventListener( "DOMContentLoaded", jQuery.ready, false );
-
-        // If IE is used and is not in a frame
-        // Continually check to see if the document is ready
-        if ( jQuery.browser.msie && window == top ) (function(){
-                if (jQuery.isReady) return;
-                try {
-                        // If IE is used, use the trick by Diego Perini
-                        // http://javascript.nwbox.com/IEContentLoaded/
-                        document.documentElement.doScroll("left");
-                } catch( error ) {
-                        setTimeout( arguments.callee, 0 );
-                        return;
-                }
-                // and execute any waiting functions
-                jQuery.ready();
-        })();
-
-        if ( jQuery.browser.opera )
-                document.addEventListener( "DOMContentLoaded", function () {
-                        if (jQuery.isReady) return;
-                        for (var i = 0; i < document.styleSheets.length; i++)
-                                if (document.styleSheets[i].disabled) {
-                                        setTimeout( arguments.callee, 0 );
-                                        return;
-                                }
-                        // and execute any waiting functions
-                        jQuery.ready();
-                }, false);
-
-        if ( jQuery.browser.safari ) {
-                var numStyles;
-                (function(){
-                        if (jQuery.isReady) return;
-                        if ( document.readyState != "loaded" && document.readyState != "complete" ) {
-                                setTimeout( arguments.callee, 0 );
-                                return;
-                        }
-                        if ( numStyles === undefined )
-                                numStyles = jQuery("style, link[rel=stylesheet]").length;
-                        if ( document.styleSheets.length != numStyles ) {
-                                setTimeout( arguments.callee, 0 );
-                                return;
-                        }
-                        // and execute any waiting functions
-                        jQuery.ready();
-                })();
-        }
-
-        // A fallback to window.onload, that will always work
-        jQuery.event.add( window, "load", jQuery.ready );
-}
-
-jQuery.each( ("blur,focus,load,resize,scroll,unload,click,dblclick," +
-        "mousedown,mouseup,mousemove,mouseover,mouseout,change,select," +
-        "submit,keydown,keypress,keyup,error").split(","), function(i, name){
-
-        // Handle event binding
-        jQuery.fn[name] = function(fn){
-                return fn ? this.bind(name, fn) : this.trigger(name);
-        };
-});
-
-// Checks if an event happened on an element within another element
-// Used in jQuery.event.special.mouseenter and mouseleave handlers
-var withinElement = function(event, elem) {
-        // Check if mouse(over|out) are still within the same parent element
-        var parent = event.relatedTarget;
-        // Traverse up the tree
-        while ( parent && parent != elem ) try { parent = parent.parentNode; } catch(error) { parent = elem; }
-        // Return true if we actually just moused on to a sub-element
-        return parent == elem;
-};
-
-// Prevent memory leaks in IE
-// And prevent errors on refresh with events like mouseover in other browsers
-// Window isn't included so as not to unbind existing unload events
-jQuery(window).bind("unload", function() {
-        jQuery("*").add(document).unbind();
-});
-jQuery.fn.extend({
-        // Keep a copy of the old load
-        _load: jQuery.fn.load,
-
-        load: function( url, params, callback ) {
-                if ( typeof url != 'string' )
-                        return this._load( url );
-
-                var off = url.indexOf(" ");
-                if ( off >= 0 ) {
-                        var selector = url.slice(off, url.length);
-                        url = url.slice(0, off);
-                }
-
-                callback = callback || function(){};
-
-                // Default to a GET request
-                var type = "GET";
-
-                // If the second parameter was provided
-                if ( params )
-                        // If it's a function
-                        if ( jQuery.isFunction( params ) ) {
-                                // We assume that it's the callback
-                                callback = params;
-                                params = null;
-
-                        // Otherwise, build a param string
-                        } else {
-                                params = jQuery.param( params );
-                                type = "POST";
-                        }
-
-                var self = this;
-
-                // Request the remote document
-                jQuery.ajax({
-                        url: url,
-                        type: type,
-                        dataType: "html",
-                        data: params,
-                        complete: function(res, status){
-                                // If successful, inject the HTML into all the matched elements
-                                if ( status == "success" || status == "notmodified" )
-                                        // See if a selector was specified
-                                        self.html( selector ?
-                                                // Create a dummy div to hold the results
-                                                jQuery("<div/>")
-                                                        // inject the contents of the document in, removing the scripts
-                                                        // to avoid any 'Permission Denied' errors in IE
-                                                        .append(res.responseText.replace(/<script(.|\s)*?\/script>/g, ""))
-
-                                                        // Locate the specified elements
-                                                        .find(selector) :
-
-                                                // If not, just inject the full result
-                                                res.responseText );
-
-                                self.each( callback, [res.responseText, status, res] );
-                        }
-                });
-                return this;
-        },
-
-        serialize: function() {
-                return jQuery.param(this.serializeArray());
-        },
-        serializeArray: function() {
-                return this.map(function(){
-                        return jQuery.nodeName(this, "form") ?
-                                jQuery.makeArray(this.elements) : this;
-                })
-                .filter(function(){
-                        return this.name && !this.disabled &&
-                                (this.checked || /select|textarea/i.test(this.nodeName) ||
-                                        /text|hidden|password/i.test(this.type));
-                })
-                .map(function(i, elem){
-                        var val = jQuery(this).val();
-                        return val == null ? null :
-                                val.constructor == Array ?
-                                        jQuery.map( val, function(val, i){
-                                                return {name: elem.name, value: val};
-                                        }) :
-                                        {name: elem.name, value: val};
-                }).get();
-        }
-});
-
-// Attach a bunch of functions for handling common AJAX events
-jQuery.each( "ajaxStart,ajaxStop,ajaxComplete,ajaxError,ajaxSuccess,ajaxSend".split(","), function(i,o){
-        jQuery.fn[o] = function(f){
-                return this.bind(o, f);
-        };
-});
-
-var jsc = now();
-
-jQuery.extend({
-        get: function( url, data, callback, type ) {
-                // shift arguments if data argument was ommited
-                if ( jQuery.isFunction( data ) ) {
-                        callback = data;
-                        data = null;
-                }
-
-                return jQuery.ajax({
-                        type: "GET",
-                        url: url,
-                        data: data,
-                        success: callback,
-                        dataType: type
-                });
-        },
-
-        getScript: function( url, callback ) {
-                return jQuery.get(url, null, callback, "script");
-        },
-
-        getJSON: function( url, data, callback ) {
-                return jQuery.get(url, data, callback, "json");
-        },
-
-        post: function( url, data, callback, type ) {
-                if ( jQuery.isFunction( data ) ) {
-                        callback = data;
-                        data = {};
-                }
-
-                return jQuery.ajax({
-                        type: "POST",
-                        url: url,
-                        data: data,
-                        success: callback,
-                        dataType: type
-                });
-        },
-
-        ajaxSetup: function( settings ) {
-                jQuery.extend( jQuery.ajaxSettings, settings );
-        },
-
-        ajaxSettings: {
-                url: location.href,
-                global: true,
-                type: "GET",
-                timeout: 0,
-                contentType: "application/x-www-form-urlencoded",
-                processData: true,
-                async: true,
-                data: null,
-                username: null,
-                password: null,
-                accepts: {
-                        xml: "application/xml, text/xml",
-                        html: "text/html",
-                        script: "text/javascript, application/javascript",
-                        json: "application/json, text/javascript",
-                        text: "text/plain",
-                        _default: "*/*"
-                }
-        },
-
-        // Last-Modified header cache for next request
-        lastModified: {},
-
-        ajax: function( s ) {
-                // Extend the settings, but re-extend 's' so that it can be
-                // checked again later (in the test suite, specifically)
-                s = jQuery.extend(true, s, jQuery.extend(true, {}, jQuery.ajaxSettings, s));
-
-                var jsonp, jsre = /=\?(&|$)/g, status, data,
-                        type = s.type.toUpperCase();
-
-                // convert data if not already a string
-                if ( s.data && s.processData && typeof s.data != "string" )
-                        s.data = jQuery.param(s.data);
-
-                // Handle JSONP Parameter Callbacks
-                if ( s.dataType == "jsonp" ) {
-                        if ( type == "GET" ) {
-                                if ( !s.url.match(jsre) )
-                                        s.url += (s.url.match(/\?/) ? "&" : "?") + (s.jsonp || "callback") + "=?";
-                        } else if ( !s.data || !s.data.match(jsre) )
-                                s.data = (s.data ? s.data + "&" : "") + (s.jsonp || "callback") + "=?";
-                        s.dataType = "json";
-                }
-
-                // Build temporary JSONP function
-                if ( s.dataType == "json" && (s.data && s.data.match(jsre) || s.url.match(jsre)) ) {
-                        jsonp = "jsonp" + jsc++;
-
-                        // Replace the =? sequence both in the query string and the data
-                        if ( s.data )
-                                s.data = (s.data + "").replace(jsre, "=" + jsonp + "$1");
-                        s.url = s.url.replace(jsre, "=" + jsonp + "$1");
-
-                        // We need to make sure
-                        // that a JSONP style response is executed properly
-                        s.dataType = "script";
-
-                        // Handle JSONP-style loading
-                        window[ jsonp ] = function(tmp){
-                                data = tmp;
-                                success();
-                                complete();
-                                // Garbage collect
-                                window[ jsonp ] = undefined;
-                                try{ delete window[ jsonp ]; } catch(e){}
-                                if ( head )
-                                        head.removeChild( script );
-                        };
-                }
-
-                if ( s.dataType == "script" && s.cache == null )
-                        s.cache = false;
-
-                if ( s.cache === false && type == "GET" ) {
-                        var ts = now();
-                        // try replacing _= if it is there
-                        var ret = s.url.replace(/(\?|&)_=.*?(&|$)/, "$1_=" + ts + "$2");
-                        // if nothing was replaced, add timestamp to the end
-                        s.url = ret + ((ret == s.url) ? (s.url.match(/\?/) ? "&" : "?") + "_=" + ts : "");
-                }
-
-                // If data is available, append data to url for get requests
-                if ( s.data && type == "GET" ) {
-                        s.url += (s.url.match(/\?/) ? "&" : "?") + s.data;
-
-                        // IE likes to send both get and post data, prevent this
-                        s.data = null;
-                }
-
-                // Watch for a new set of requests
-                if ( s.global && ! jQuery.active++ )
-                        jQuery.event.trigger( "ajaxStart" );
-
-                // Matches an absolute URL, and saves the domain
-                var remote = /^(?:\w+:)?\/\/([^\/?#]+)/;
-
-                // If we're requesting a remote document
-                // and trying to load JSON or Script with a GET
-                if ( s.dataType == "script" && type == "GET"
-                                && remote.test(s.url) && remote.exec(s.url)[1] != location.host ){
-                        var head = document.getElementsByTagName("head")[0];
-                        var script = document.createElement("script");
-                        script.src = s.url;
-                        if (s.scriptCharset)
-                                script.charset = s.scriptCharset;
-
-                        // Handle Script loading
-                        if ( !jsonp ) {
-                                var done = false;
-
-                                // Attach handlers for all browsers
-                                script.onload = script.onreadystatechange = function(){
-                                        if ( !done && (!this.readyState ||
-                                                        this.readyState == "loaded" || this.readyState == "complete") ) {
-                                                done = true;
-                                                success();
-                                                complete();
-                                                head.removeChild( script );
-                                        }
-                                };
-                        }
-
-                        head.appendChild(script);
-
-                        // We handle everything using the script element injection
-                        return undefined;
-                }
-
-                var requestDone = false;
-
-                // Create the request object; Microsoft failed to properly
-                // implement the XMLHttpRequest in IE7, so we use the ActiveXObject when it is available
-                var xhr = window.ActiveXObject ? new ActiveXObject("Microsoft.XMLHTTP") : new XMLHttpRequest();
-
-                // Open the socket
-                // Passing null username, generates a login popup on Opera (#2865)
-                if( s.username )
-                        xhr.open(type, s.url, s.async, s.username, s.password);
-                else
-                        xhr.open(type, s.url, s.async);
-
-                // Need an extra try/catch for cross domain requests in Firefox 3
-                try {
-                        // Set the correct header, if data is being sent
-                        if ( s.data )
-                                xhr.setRequestHeader("Content-Type", s.contentType);
-
-                        // Set the If-Modified-Since header, if ifModified mode.
-                        if ( s.ifModified )
-                                xhr.setRequestHeader("If-Modified-Since",
-                                        jQuery.lastModified[s.url] || "Thu, 01 Jan 1970 00:00:00 GMT" );
-
-                        // Set header so the called script knows that it's an XMLHttpRequest
-                        xhr.setRequestHeader("X-Requested-With", "XMLHttpRequest");
-
-                        // Set the Accepts header for the server, depending on the dataType
-                        xhr.setRequestHeader("Accept", s.dataType && s.accepts[ s.dataType ] ?
-                                s.accepts[ s.dataType ] + ", */*" :
-                                s.accepts._default );
-                } catch(e){}
-
-                // Allow custom headers/mimetypes
-                if ( s.beforeSend && s.beforeSend(xhr, s) === false ) {
-                        // cleanup active request counter
-                        s.global && jQuery.active--;
-                        // close opended socket
-                        xhr.abort();
-                        return false;
-                }
-
-                if ( s.global )
-                        jQuery.event.trigger("ajaxSend", [xhr, s]);
-
-                // Wait for a response to come back
-                var onreadystatechange = function(isTimeout){
-                        // The transfer is complete and the data is available, or the request timed out
-                        if ( !requestDone && xhr && (xhr.readyState == 4 || isTimeout == "timeout") ) {
-                                requestDone = true;
-
-                                // clear poll interval
-                                if (ival) {
-                                        clearInterval(ival);
-                                        ival = null;
-                                }
-
-                                status = isTimeout == "timeout" && "timeout" ||
-                                        !jQuery.httpSuccess( xhr ) && "error" ||
-                                        s.ifModified && jQuery.httpNotModified( xhr, s.url ) && "notmodified" ||
-                                        "success";
-
-                                if ( status == "success" ) {
-                                        // Watch for, and catch, XML document parse errors
-                                        try {
-                                                // process the data (runs the xml through httpData regardless of callback)
-                                                data = jQuery.httpData( xhr, s.dataType, s.dataFilter );
-                                        } catch(e) {
-                                                status = "parsererror";
-                                        }
-                                }
-
-                                // Make sure that the request was successful or notmodified
-                                if ( status == "success" ) {
-                                        // Cache Last-Modified header, if ifModified mode.
-                                        var modRes;
-                                        try {
-                                                modRes = xhr.getResponseHeader("Last-Modified");
-                                        } catch(e) {} // swallow exception thrown by FF if header is not available
-
-                                        if ( s.ifModified && modRes )
-                                                jQuery.lastModified[s.url] = modRes;
-
-                                        // JSONP handles its own success callback
-                                        if ( !jsonp )
-                                                success();
-                                } else
-                                        jQuery.handleError(s, xhr, status);
-
-                                // Fire the complete handlers
-                                complete();
-
-                                // Stop memory leaks
-                                if ( s.async )
-                                        xhr = null;
-                        }
-                };
-
-                if ( s.async ) {
-                        // don't attach the handler to the request, just poll it instead
-                        var ival = setInterval(onreadystatechange, 13);
-
-                        // Timeout checker
-                        if ( s.timeout > 0 )
-                                setTimeout(function(){
-                                        // Check to see if the request is still happening
-                                        if ( xhr ) {
-                                                // Cancel the request
-                                                xhr.abort();
-
-                                                if( !requestDone )
-                                                        onreadystatechange( "timeout" );
-                                        }
-                                }, s.timeout);
-                }
-
-                // Send the data
-                try {
-                        xhr.send(s.data);
-                } catch(e) {
-                        jQuery.handleError(s, xhr, null, e);
-                }
-
-                // firefox 1.5 doesn't fire statechange for sync requests
-                if ( !s.async )
-                        onreadystatechange();
-
-                function success(){
-                        // If a local callback was specified, fire it and pass it the data
-                        if ( s.success )
-                                s.success( data, status );
-
-                        // Fire the global callback
-                        if ( s.global )
-                                jQuery.event.trigger( "ajaxSuccess", [xhr, s] );
-                }
-
-                function complete(){
-                        // Process result
-                        if ( s.complete )
-                                s.complete(xhr, status);
-
-                        // The request was completed
-                        if ( s.global )
-                                jQuery.event.trigger( "ajaxComplete", [xhr, s] );
-
-                        // Handle the global AJAX counter
-                        if ( s.global && ! --jQuery.active )
-                                jQuery.event.trigger( "ajaxStop" );
-                }
-
-                // return XMLHttpRequest to allow aborting the request etc.
-                return xhr;
-        },
-
-        handleError: function( s, xhr, status, e ) {
-                // If a local callback was specified, fire it
-                if ( s.error ) s.error( xhr, status, e );
-
-                // Fire the global callback
-                if ( s.global )
-                        jQuery.event.trigger( "ajaxError", [xhr, s, e] );
-        },
-
-        // Counter for holding the number of active queries
-        active: 0,
-
-        // Determines if an XMLHttpRequest was successful or not
-        httpSuccess: function( xhr ) {
-                try {
-                        // IE error sometimes returns 1223 when it should be 204 so treat it as success, see #1450
-                        return !xhr.status && location.protocol == "file:" ||
-                                ( xhr.status >= 200 && xhr.status < 300 ) || xhr.status == 304 || xhr.status == 1223 ||
-                                jQuery.browser.safari && xhr.status == undefined;
-                } catch(e){}
-                return false;
-        },
-
-        // Determines if an XMLHttpRequest returns NotModified
-        httpNotModified: function( xhr, url ) {
-                try {
-                        var xhrRes = xhr.getResponseHeader("Last-Modified");
-
-                        // Firefox always returns 200. check Last-Modified date
-                        return xhr.status == 304 || xhrRes == jQuery.lastModified[url] ||
-                                jQuery.browser.safari && xhr.status == undefined;
-                } catch(e){}
-                return false;
-        },
-
-        httpData: function( xhr, type, filter ) {
-                var ct = xhr.getResponseHeader("content-type"),
-                        xml = type == "xml" || !type && ct && ct.indexOf("xml") >= 0,
-                        data = xml ? xhr.responseXML : xhr.responseText;
-
-                if ( xml && data.documentElement.tagName == "parsererror" )
-                        throw "parsererror";
-                        
-                // Allow a pre-filtering function to sanitize the response
-                if( filter )
-                        data = filter( data, type );
-
-                // If the type is "script", eval it in global context
-                if ( type == "script" )
-                        jQuery.globalEval( data );
-
-                // Get the JavaScript object, if JSON is used.
-                if ( type == "json" )
-                        data = eval("(" + data + ")");
-
-                return data;
-        },
-
-        // Serialize an array of form elements or a set of
-        // key/values into a query string
-        param: function( a ) {
-                var s = [];
-
-                // If an array was passed in, assume that it is an array
-                // of form elements
-                if ( a.constructor == Array || a.jquery )
-                        // Serialize the form elements
-                        jQuery.each( a, function(){
-                                s.push( encodeURIComponent(this.name) + "=" + encodeURIComponent( this.value ) );
-                        });
-
-                // Otherwise, assume that it's an object of key/value pairs
-                else
-                        // Serialize the key/values
-                        for ( var j in a )
-                                // If the value is an array then the key names need to be repeated
-                                if ( a[j] && a[j].constructor == Array )
-                                        jQuery.each( a[j], function(){
-                                                s.push( encodeURIComponent(j) + "=" + encodeURIComponent( this ) );
-                                        });
-                                else
-                                        s.push( encodeURIComponent(j) + "=" + encodeURIComponent( jQuery.isFunction(a[j]) ? a[j]() : a[j] ) );
-
-                // Return the resulting serialization
-                return s.join("&").replace(/%20/g, "+");
-        }
-
-});
-jQuery.fn.extend({
-        show: function(speed,callback){
-                return speed ?
-                        this.animate({
-                                height: "show", width: "show", opacity: "show"
-                        }, speed, callback) :
-
-                        this.filter(":hidden").each(function(){
-                                this.style.display = this.oldblock || "";
-                                if ( jQuery.css(this,"display") == "none" ) {
-                                        var elem = jQuery("<" + this.tagName + " />").appendTo("body");
-                                        this.style.display = elem.css("display");
-                                        // handle an edge condition where css is - div { display:none; } or similar
-                                        if (this.style.display == "none")
-                                                this.style.display = "block";
-                                        elem.remove();
-                                }
-                        }).end();
-        },
-
-        hide: function(speed,callback){
-                return speed ?
-                        this.animate({
-                                height: "hide", width: "hide", opacity: "hide"
-                        }, speed, callback) :
-
-                        this.filter(":visible").each(function(){
-                                this.oldblock = this.oldblock || jQuery.css(this,"display");
-                                this.style.display = "none";
-                        }).end();
-        },
-
-        // Save the old toggle function
-        _toggle: jQuery.fn.toggle,
-
-        toggle: function( fn, fn2 ){
-                return jQuery.isFunction(fn) && jQuery.isFunction(fn2) ?
-                        this._toggle.apply( this, arguments ) :
-                        fn ?
-                                this.animate({
-                                        height: "toggle", width: "toggle", opacity: "toggle"
-                                }, fn, fn2) :
-                                this.each(function(){
-                                        jQuery(this)[ jQuery(this).is(":hidden") ? "show" : "hide" ]();
-                                });
-        },
-
-        slideDown: function(speed,callback){
-                return this.animate({height: "show"}, speed, callback);
-        },
-
-        slideUp: function(speed,callback){
-                return this.animate({height: "hide"}, speed, callback);
-        },
-
-        slideToggle: function(speed, callback){
-                return this.animate({height: "toggle"}, speed, callback);
-        },
-
-        fadeIn: function(speed, callback){
-                return this.animate({opacity: "show"}, speed, callback);
-        },
-
-        fadeOut: function(speed, callback){
-                return this.animate({opacity: "hide"}, speed, callback);
-        },
-
-        fadeTo: function(speed,to,callback){
-                return this.animate({opacity: to}, speed, callback);
-        },
-
-        animate: function( prop, speed, easing, callback ) {
-                var optall = jQuery.speed(speed, easing, callback);
-
-                return this[ optall.queue === false ? "each" : "queue" ](function(){
-                        if ( this.nodeType != 1)
-                                return false;
-
-                        var opt = jQuery.extend({}, optall), p,
-                                hidden = jQuery(this).is(":hidden"), self = this;
-
-                        for ( p in prop ) {
-                                if ( prop[p] == "hide" && hidden || prop[p] == "show" && !hidden )
-                                        return opt.complete.call(this);
-
-                                if ( p == "height" || p == "width" ) {
-                                        // Store display property
-                                        opt.display = jQuery.css(this, "display");
-
-                                        // Make sure that nothing sneaks out
-                                        opt.overflow = this.style.overflow;
-                                }
-                        }
-
-                        if ( opt.overflow != null )
-                                this.style.overflow = "hidden";
-
-                        opt.curAnim = jQuery.extend({}, prop);
-
-                        jQuery.each( prop, function(name, val){
-                                var e = new jQuery.fx( self, opt, name );
-
-                                if ( /toggle|show|hide/.test(val) )
-                                        e[ val == "toggle" ? hidden ? "show" : "hide" : val ]( prop );
-                                else {
-                                        var parts = val.toString().match(/^([+-]=)?([\d+-.]+)(.*)$/),
-                                                start = e.cur(true) || 0;
-
-                                        if ( parts ) {
-                                                var end = parseFloat(parts[2]),
-                                                        unit = parts[3] || "px";
-
-                                                // We need to compute starting value
-                                                if ( unit != "px" ) {
-                                                        self.style[ name ] = (end || 1) + unit;
-                                                        start = ((end || 1) / e.cur(true)) * start;
-                                                        self.style[ name ] = start + unit;
-                                                }
-
-                                                // If a +=/-= token was provided, we're doing a relative animation
-                                                if ( parts[1] )
-                                                        end = ((parts[1] == "-=" ? -1 : 1) * end) + start;
-
-                                                e.custom( start, end, unit );
-                                        } else
-                                                e.custom( start, val, "" );
-                                }
-                        });
-
-                        // For JS strict compliance
-                        return true;
-                });
-        },
-
-        queue: function(type, fn){
-                if ( jQuery.isFunction(type) || ( type && type.constructor == Array )) {
-                        fn = type;
-                        type = "fx";
-                }
-
-                if ( !type || (typeof type == "string" && !fn) )
-                        return queue( this[0], type );
-
-                return this.each(function(){
-                        if ( fn.constructor == Array )
-                                queue(this, type, fn);
-                        else {
-                                queue(this, type).push( fn );
-
-                                if ( queue(this, type).length == 1 )
-                                        fn.call(this);
-                        }
-                });
-        },
-
-        stop: function(clearQueue, gotoEnd){
-                var timers = jQuery.timers;
-
-                if (clearQueue)
-                        this.queue([]);
-
-                this.each(function(){
-                        // go in reverse order so anything added to the queue during the loop is ignored
-                        for ( var i = timers.length - 1; i >= 0; i-- )
-                                if ( timers[i].elem == this ) {
-                                        if (gotoEnd)
-                                                // force the next step to be the last
-                                                timers[i](true);
-                                        timers.splice(i, 1);
-                                }
-                });
-
-                // start the next in the queue if the last step wasn't forced
-                if (!gotoEnd)
-                        this.dequeue();
-
-                return this;
-        }
-
-});
-
-var queue = function( elem, type, array ) {
-        if ( elem ){
-
-                type = type || "fx";
-
-                var q = jQuery.data( elem, type + "queue" );
-
-                if ( !q || array )
-                        q = jQuery.data( elem, type + "queue", jQuery.makeArray(array) );
-
-        }
-        return q;
-};
-
-jQuery.fn.dequeue = function(type){
-        type = type || "fx";
-
-        return this.each(function(){
-                var q = queue(this, type);
-
-                q.shift();
-
-                if ( q.length )
-                        q[0].call( this );
-        });
-};
-
-jQuery.extend({
-
-        speed: function(speed, easing, fn) {
-                var opt = speed && speed.constructor == Object ? speed : {
-                        complete: fn || !fn && easing ||
-                                jQuery.isFunction( speed ) && speed,
-                        duration: speed,
-                        easing: fn && easing || easing && easing.constructor != Function && easing
-                };
-
-                opt.duration = (opt.duration && opt.duration.constructor == Number ?
-                        opt.duration :
-                        jQuery.fx.speeds[opt.duration]) || jQuery.fx.speeds.def;
-
-                // Queueing
-                opt.old = opt.complete;
-                opt.complete = function(){
-                        if ( opt.queue !== false )
-                                jQuery(this).dequeue();
-                        if ( jQuery.isFunction( opt.old ) )
-                                opt.old.call( this );
-                };
-
-                return opt;
-        },
-
-        easing: {
-                linear: function( p, n, firstNum, diff ) {
-                        return firstNum + diff * p;
-                },
-                swing: function( p, n, firstNum, diff ) {
-                        return ((-Math.cos(p*Math.PI)/2) + 0.5) * diff + firstNum;
-                }
-        },
-
-        timers: [],
-        timerId: null,
-
-        fx: function( elem, options, prop ){
-                this.options = options;
-                this.elem = elem;
-                this.prop = prop;
-
-                if ( !options.orig )
-                        options.orig = {};
-        }
-
-});
-
-jQuery.fx.prototype = {
-
-        // Simple function for setting a style value
-        update: function(){
-                if ( this.options.step )
-                        this.options.step.call( this.elem, this.now, this );
-
-                (jQuery.fx.step[this.prop] || jQuery.fx.step._default)( this );
-
-                // Set display property to block for height/width animations
-                if ( this.prop == "height" || this.prop == "width" )
-                        this.elem.style.display = "block";
-        },
-
-        // Get the current size
-        cur: function(force){
-                if ( this.elem[this.prop] != null && this.elem.style[this.prop] == null )
-                        return this.elem[ this.prop ];
-
-                var r = parseFloat(jQuery.css(this.elem, this.prop, force));
-                return r && r > -10000 ? r : parseFloat(jQuery.curCSS(this.elem, this.prop)) || 0;
-        },
-
-        // Start an animation from one number to another
-        custom: function(from, to, unit){
-                this.startTime = now();
-                this.start = from;
-                this.end = to;
-                this.unit = unit || this.unit || "px";
-                this.now = this.start;
-                this.pos = this.state = 0;
-                this.update();
-
-                var self = this;
-                function t(gotoEnd){
-                        return self.step(gotoEnd);
-                }
-
-                t.elem = this.elem;
-
-                jQuery.timers.push(t);
-
-                if ( jQuery.timerId == null ) {
-                        jQuery.timerId = setInterval(function(){
-                                var timers = jQuery.timers;
-
-                                for ( var i = 0; i < timers.length; i++ )
-                                        if ( !timers[i]() )
-                                                timers.splice(i--, 1);
-
-                                if ( !timers.length ) {
-                                        clearInterval( jQuery.timerId );
-                                        jQuery.timerId = null;
-                                }
-                        }, 13);
-                }
-        },
-
-        // Simple 'show' function
-        show: function(){
-                // Remember where we started, so that we can go back to it later
-                this.options.orig[this.prop] = jQuery.attr( this.elem.style, this.prop );
-                this.options.show = true;
-
-                // Begin the animation
-                this.custom(0, this.cur());
-
-                // Make sure that we start at a small width/height to avoid any
-                // flash of content
-                if ( this.prop == "width" || this.prop == "height" )
-                        this.elem.style[this.prop] = "1px";
-
-                // Start by showing the element
-                jQuery(this.elem).show();
-        },
-
-        // Simple 'hide' function
-        hide: function(){
-                // Remember where we started, so that we can go back to it later
-                this.options.orig[this.prop] = jQuery.attr( this.elem.style, this.prop );
-                this.options.hide = true;
-
-                // Begin the animation
-                this.custom(this.cur(), 0);
-        },
-
-        // Each step of an animation
-        step: function(gotoEnd){
-                var t = now();
-
-                if ( gotoEnd || t > this.options.duration + this.startTime ) {
-                        this.now = this.end;
-                        this.pos = this.state = 1;
-                        this.update();
-
-                        this.options.curAnim[ this.prop ] = true;
-
-                        var done = true;
-                        for ( var i in this.options.curAnim )
-                                if ( this.options.curAnim[i] !== true )
-                                        done = false;
-
-                        if ( done ) {
-                                if ( this.options.display != null ) {
-                                        // Reset the overflow
-                                        this.elem.style.overflow = this.options.overflow;
-
-                                        // Reset the display
-                                        this.elem.style.display = this.options.display;
-                                        if ( jQuery.css(this.elem, "display") == "none" )
-                                                this.elem.style.display = "block";
-                                }
-
-                                // Hide the element if the "hide" operation was done
-                                if ( this.options.hide )
-                                        this.elem.style.display = "none";
-
-                                // Reset the properties, if the item has been hidden or shown
-                                if ( this.options.hide || this.options.show )
-                                        for ( var p in this.options.curAnim )
-                                                jQuery.attr(this.elem.style, p, this.options.orig[p]);
-                        }
-
-                        if ( done )
-                                // Execute the complete function
-                                this.options.complete.call( this.elem );
-
-                        return false;
-                } else {
-                        var n = t - this.startTime;
-                        this.state = n / this.options.duration;
-
-                        // Perform the easing function, defaults to swing
-                        this.pos = jQuery.easing[this.options.easing || (jQuery.easing.swing ? "swing" : "linear")](this.state, n, 0, 1, this.options.duration);
-                        this.now = this.start + ((this.end - this.start) * this.pos);
-
-                        // Perform the next step of the animation
-                        this.update();
-                }
-
-                return true;
-        }
-
-};
-
-jQuery.extend( jQuery.fx, {
-        speeds:{
-                slow: 600,
-                fast: 200,
-                // Default speed
-                def: 400
-        },
-        step: {
-                scrollLeft: function(fx){
-                        fx.elem.scrollLeft = fx.now;
-                },
-
-                scrollTop: function(fx){
-                        fx.elem.scrollTop = fx.now;
-                },
-
-                opacity: function(fx){
-                        jQuery.attr(fx.elem.style, "opacity", fx.now);
-                },
-
-                _default: function(fx){
-                        fx.elem.style[ fx.prop ] = fx.now + fx.unit;
-                }
-        }
-});
-// The Offset Method
-// Originally By Brandon Aaron, part of the Dimension Plugin
-// http://jquery.com/plugins/project/dimensions
-jQuery.fn.offset = function() {
-        var left = 0, top = 0, elem = this[0], results;
-
-        if ( elem ) with ( jQuery.browser ) {
-                var parent       = elem.parentNode,
-                    offsetChild  = elem,
-                    offsetParent = elem.offsetParent,
-                    doc          = elem.ownerDocument,
-                    safari2      = safari && parseInt(version) < 522 && !/adobeair/i.test(userAgent),
-                    css          = jQuery.curCSS,
-                    fixed        = css(elem, "position") == "fixed";
-
-                // Use getBoundingClientRect if available
-                if ( elem.getBoundingClientRect ) {
-                        var box = elem.getBoundingClientRect();
-
-                        // Add the document scroll offsets
-                        add(box.left + Math.max(doc.documentElement.scrollLeft, doc.body.scrollLeft),
-                                box.top  + Math.max(doc.documentElement.scrollTop,  doc.body.scrollTop));
-
-                        // IE adds the HTML element's border, by default it is medium which is 2px
-                        // IE 6 and 7 quirks mode the border width is overwritable by the following css html { border: 0; }
-                        // IE 7 standards mode, the border is always 2px
-                        // This border/offset is typically represented by the clientLeft and clientTop properties
-                        // However, in IE6 and 7 quirks mode the clientLeft and clientTop properties are not updated when overwriting it via CSS
-                        // Therefore this method will be off by 2px in IE while in quirksmode
-                        add( -doc.documentElement.clientLeft, -doc.documentElement.clientTop );
-
-                // Otherwise loop through the offsetParents and parentNodes
-                } else {
-
-                        // Initial element offsets
-                        add( elem.offsetLeft, elem.offsetTop );
-
-                        // Get parent offsets
-                        while ( offsetParent ) {
-                                // Add offsetParent offsets
-                                add( offsetParent.offsetLeft, offsetParent.offsetTop );
-
-                                // Mozilla and Safari > 2 does not include the border on offset parents
-                                // However Mozilla adds the border for table or table cells
-                                if ( mozilla && !/^t(able|d|h)$/i.test(offsetParent.tagName) || safari && !safari2 )
-                                        border( offsetParent );
-
-                                // Add the document scroll offsets if position is fixed on any offsetParent
-                                if ( !fixed && css(offsetParent, "position") == "fixed" )
-                                        fixed = true;
-
-                                // Set offsetChild to previous offsetParent unless it is the body element
-                                offsetChild  = /^body$/i.test(offsetParent.tagName) ? offsetChild : offsetParent;
-                                // Get next offsetParent
-                                offsetParent = offsetParent.offsetParent;
-                        }
-
-                        // Get parent scroll offsets
-                        while ( parent && parent.tagName && !/^body|html$/i.test(parent.tagName) ) {
-                                // Remove parent scroll UNLESS that parent is inline or a table to work around Opera inline/table scrollLeft/Top bug
-                                if ( !/^inline|table.*$/i.test(css(parent, "display")) )
-                                        // Subtract parent scroll offsets
-                                        add( -parent.scrollLeft, -parent.scrollTop );
-
-                                // Mozilla does not add the border for a parent that has overflow != visible
-                                if ( mozilla && css(parent, "overflow") != "visible" )
-                                        border( parent );
-
-                                // Get next parent
-                                parent = parent.parentNode;
-                        }
-
-                        // Safari <= 2 doubles body offsets with a fixed position element/offsetParent or absolutely positioned offsetChild
-                        // Mozilla doubles body offsets with a non-absolutely positioned offsetChild
-                        if ( (safari2 && (fixed || css(offsetChild, "position") == "absolute")) ||
-                                (mozilla && css(offsetChild, "position") != "absolute") )
-                                        add( -doc.body.offsetLeft, -doc.body.offsetTop );
-
-                        // Add the document scroll offsets if position is fixed
-                        if ( fixed )
-                                add(Math.max(doc.documentElement.scrollLeft, doc.body.scrollLeft),
-                                        Math.max(doc.documentElement.scrollTop,  doc.body.scrollTop));
-                }
-
-                // Return an object with top and left properties
-                results = { top: top, left: left };
-        }
-
-        function border(elem) {
-                add( jQuery.curCSS(elem, "borderLeftWidth", true), jQuery.curCSS(elem, "borderTopWidth", true) );
-        }
-
-        function add(l, t) {
-                left += parseInt(l, 10) || 0;
-                top += parseInt(t, 10) || 0;
-        }
-
-        return results;
-};
-
-
-jQuery.fn.extend({
-        position: function() {
-                var left = 0, top = 0, results;
-
-                if ( this[0] ) {
-                        // Get *real* offsetParent
-                        var offsetParent = this.offsetParent(),
-
-                        // Get correct offsets
-                        offset       = this.offset(),
-                        parentOffset = /^body|html$/i.test(offsetParent[0].tagName) ? { top: 0, left: 0 } : offsetParent.offset();
-
-                        // Subtract element margins
-                        // note: when an element has margin: auto the offsetLeft and marginLeft 
-                        // are the same in Safari causing offset.left to incorrectly be 0
-                        offset.top  -= num( this, 'marginTop' );
-                        offset.left -= num( this, 'marginLeft' );
-
-                        // Add offsetParent borders
-                        parentOffset.top  += num( offsetParent, 'borderTopWidth' );
-                        parentOffset.left += num( offsetParent, 'borderLeftWidth' );
-
-                        // Subtract the two offsets
-                        results = {
-                                top:  offset.top  - parentOffset.top,
-                                left: offset.left - parentOffset.left
-                        };
-                }
-
-                return results;
-        },
-
-        offsetParent: function() {
-                var offsetParent = this[0].offsetParent;
-                while ( offsetParent && (!/^body|html$/i.test(offsetParent.tagName) && jQuery.css(offsetParent, 'position') == 'static') )
-                        offsetParent = offsetParent.offsetParent;
-                return jQuery(offsetParent);
-        }
-});
-
-
-// Create scrollLeft and scrollTop methods
-jQuery.each( ['Left', 'Top'], function(i, name) {
-        var method = 'scroll' + name;
-        
-        jQuery.fn[ method ] = function(val) {
-                if (!this[0]) return;
-
-                return val != undefined ?
-
-                        // Set the scroll offset
-                        this.each(function() {
-                                this == window || this == document ?
-                                        window.scrollTo(
-                                                !i ? val : jQuery(window).scrollLeft(),
-                                                 i ? val : jQuery(window).scrollTop()
-                                        ) :
-                                        this[ method ] = val;
-                        }) :
-
-                        // Return the scroll offset
-                        this[0] == window || this[0] == document ?
-                                self[ i ? 'pageYOffset' : 'pageXOffset' ] ||
-                                        jQuery.boxModel && document.documentElement[ method ] ||
-                                        document.body[ method ] :
-                                this[0][ method ];
-        };
-});
-// Create innerHeight, innerWidth, outerHeight and outerWidth methods
-jQuery.each([ "Height", "Width" ], function(i, name){
-
-        var tl = i ? "Left"  : "Top",  // top or left
-                br = i ? "Right" : "Bottom"; // bottom or right
-
-        // innerHeight and innerWidth
-        jQuery.fn["inner" + name] = function(){
-                return this[ name.toLowerCase() ]() +
-                        num(this, "padding" + tl) +
-                        num(this, "padding" + br);
-        };
-
-        // outerHeight and outerWidth
-        jQuery.fn["outer" + name] = function(margin) {
-                return this["inner" + name]() +
-                        num(this, "border" + tl + "Width") +
-                        num(this, "border" + br + "Width") +
-                        (margin ?
-                                num(this, "margin" + tl) + num(this, "margin" + br) : 0);
-        };
-
-});})();
diff --git a/PerformanceTests/Dromaeo/resources/dromaeo/web/lib/mootools.js b/PerformanceTests/Dromaeo/resources/dromaeo/web/lib/mootools.js
deleted file mode 100644 (file)
index fc726b2..0000000
+++ /dev/null
@@ -1,3946 +0,0 @@
-/*
-Script: Core.js
-        MooTools - My Object Oriented JavaScript Tools.
-
-License:
-        MIT-style license.
-
-Copyright:
-        Copyright (c) 2006-2008 [Valerio Proietti](http://mad4milk.net/).
-
-Code & Documentation:
-        [The MooTools production team](http://mootools.net/developers/).
-
-Inspiration:
-        - Class implementation inspired by [Base.js](http://dean.edwards.name/weblog/2006/03/base/) Copyright (c) 2006 Dean Edwards, [GNU Lesser General Public License](http://opensource.org/licenses/lgpl-license.php)
-        - Some functionality inspired by [Prototype.js](http://prototypejs.org) Copyright (c) 2005-2007 Sam Stephenson, [MIT License](http://opensource.org/licenses/mit-license.php)
-*/
-
-var MooTools = {
-        'version': '1.2.1',
-        'build': '0d4845aab3d9a4fdee2f0d4a6dd59210e4b697cf'
-};
-
-var Native = function(options){
-        options = options || {};
-        var name = options.name;
-        var legacy = options.legacy;
-        var protect = options.protect;
-        var methods = options.implement;
-        var generics = options.generics;
-        var initialize = options.initialize;
-        var afterImplement = options.afterImplement || function(){};
-        var object = initialize || legacy;
-        generics = generics !== false;
-
-        object.constructor = Native;
-        object.$family = {name: 'native'};
-        if (legacy && initialize) object.prototype = legacy.prototype;
-        object.prototype.constructor = object;
-
-        if (name){
-                var family = name.toLowerCase();
-                object.prototype.$family = {name: family};
-                Native.typize(object, family);
-        }
-
-        var add = function(obj, name, method, force){
-                if (!protect || force || !obj.prototype[name]) obj.prototype[name] = method;
-                if (generics) Native.genericize(obj, name, protect);
-                afterImplement.call(obj, name, method);
-                return obj;
-        };
-
-        object.alias = function(a1, a2, a3){
-                if (typeof a1 == 'string'){
-                        if ((a1 = this.prototype[a1])) return add(this, a2, a1, a3);
-                }
-                for (var a in a1) this.alias(a, a1[a], a2);
-                return this;
-        };
-
-        object.implement = function(a1, a2, a3){
-                if (typeof a1 == 'string') return add(this, a1, a2, a3);
-                for (var p in a1) add(this, p, a1[p], a2);
-                return this;
-        };
-
-        if (methods) object.implement(methods);
-
-        return object;
-};
-
-Native.genericize = function(object, property, check){
-        if ((!check || !object[property]) && typeof object.prototype[property] == 'function') object[property] = function(){
-                var args = Array.prototype.slice.call(arguments);
-                return object.prototype[property].apply(args.shift(), args);
-        };
-};
-
-Native.implement = function(objects, properties){
-        for (var i = 0, l = objects.length; i < l; i++) objects[i].implement(properties);
-};
-
-Native.typize = function(object, family){
-        if (!object.type) object.type = function(item){
-                return ($type(item) === family);
-        };
-};
-
-(function(){
-        var natives = {'Array': Array, 'Date': Date, 'Function': Function, 'Number': Number, 'RegExp': RegExp, 'String': String};
-        for (var n in natives) new Native({name: n, initialize: natives[n], protect: true});
-
-        var types = {'boolean': Boolean, 'native': Native, 'object': Object};
-        for (var t in types) Native.typize(types[t], t);
-
-        var generics = {
-                'Array': ["concat", "indexOf", "join", "lastIndexOf", "pop", "push", "reverse", "shift", "slice", "sort", "splice", "toString", "unshift", "valueOf"],
-                'String': ["charAt", "charCodeAt", "concat", "indexOf", "lastIndexOf", "match", "replace", "search", "slice", "split", "substr", "substring", "toLowerCase", "toUpperCase", "valueOf"]
-        };
-        for (var g in generics){
-                for (var i = generics[g].length; i--;) Native.genericize(window[g], generics[g][i], true);
-        };
-})();
-
-var Hash = new Native({
-
-        name: 'Hash',
-
-        initialize: function(object){
-                if ($type(object) == 'hash') object = $unlink(object.getClean());
-                for (var key in object) this[key] = object[key];
-                return this;
-        }
-
-});
-
-Hash.implement({
-
-        forEach: function(fn, bind){
-                for (var key in this){
-                        if (this.hasOwnProperty(key)) fn.call(bind, this[key], key, this);
-                }
-        },
-
-        getClean: function(){
-                var clean = {};
-                for (var key in this){
-                        if (this.hasOwnProperty(key)) clean[key] = this[key];
-                }
-                return clean;
-        },
-
-        getLength: function(){
-                var length = 0;
-                for (var key in this){
-                        if (this.hasOwnProperty(key)) length++;
-                }
-                return length;
-        }
-
-});
-
-Hash.alias('forEach', 'each');
-
-Array.implement({
-
-        forEach: function(fn, bind){
-                for (var i = 0, l = this.length; i < l; i++) fn.call(bind, this[i], i, this);
-        }
-
-});
-
-Array.alias('forEach', 'each');
-
-function $A(iterable){
-        if (iterable.item){
-                var array = [];
-                for (var i = 0, l = iterable.length; i < l; i++) array[i] = iterable[i];
-                return array;
-        }
-        return Array.prototype.slice.call(iterable);
-};
-
-function $arguments(i){
-        return function(){
-                return arguments[i];
-        };
-};
-
-function $chk(obj){
-        return !!(obj || obj === 0);
-};
-
-function $clear(timer){
-        clearTimeout(timer);
-        clearInterval(timer);
-        return null;
-};
-
-function $defined(obj){
-        return (obj != undefined);
-};
-
-function $each(iterable, fn, bind){
-        var type = $type(iterable);
-        ((type == 'arguments' || type == 'collection' || type == 'array') ? Array : Hash).each(iterable, fn, bind);
-};
-
-function $empty(){};
-
-function $extend(original, extended){
-        for (var key in (extended || {})) original[key] = extended[key];
-        return original;
-};
-
-function $H(object){
-        return new Hash(object);
-};
-
-function $lambda(value){
-        return (typeof value == 'function') ? value : function(){
-                return value;
-        };
-};
-
-function $merge(){
-        var mix = {};
-        for (var i = 0, l = arguments.length; i < l; i++){
-                var object = arguments[i];
-                if ($type(object) != 'object') continue;
-                for (var key in object){
-                        var op = object[key], mp = mix[key];
-                        mix[key] = (mp && $type(op) == 'object' && $type(mp) == 'object') ? $merge(mp, op) : $unlink(op);
-                }
-        }
-        return mix;
-};
-
-function $pick(){
-        for (var i = 0, l = arguments.length; i < l; i++){
-                if (arguments[i] != undefined) return arguments[i];
-        }
-        return null;
-};
-
-function $random(min, max){
-        return Math.floor(Math.random() * (max - min + 1) + min);
-};
-
-function $splat(obj){
-        var type = $type(obj);
-        return (type) ? ((type != 'array' && type != 'arguments') ? [obj] : obj) : [];
-};
-
-var $time = Date.now || function(){
-        return +new Date;
-};
-
-function $try(){
-        for (var i = 0, l = arguments.length; i < l; i++){
-                try {
-                        return arguments[i]();
-                } catch(e){}
-        }
-        return null;
-};
-
-function $type(obj){
-        if (obj == undefined) return false;
-        if (obj.$family) return (obj.$family.name == 'number' && !isFinite(obj)) ? false : obj.$family.name;
-        if (obj.nodeName){
-                switch (obj.nodeType){
-                        case 1: return 'element';
-                        case 3: return (/\S/).test(obj.nodeValue) ? 'textnode' : 'whitespace';
-                }
-        } else if (typeof obj.length == 'number'){
-                if (obj.callee) return 'arguments';
-                else if (obj.item) return 'collection';
-        }
-        return typeof obj;
-};
-
-function $unlink(object){
-        var unlinked;
-        switch ($type(object)){
-                case 'object':
-                        unlinked = {};
-                        for (var p in object) unlinked[p] = $unlink(object[p]);
-                break;
-                case 'hash':
-                        unlinked = new Hash(object);
-                break;
-                case 'array':
-                        unlinked = [];
-                        for (var i = 0, l = object.length; i < l; i++) unlinked[i] = $unlink(object[i]);
-                break;
-                default: return object;
-        }
-        return unlinked;
-};
-
-
-/*
-Script: Browser.js
-        The Browser Core. Contains Browser initialization, Window and Document, and the Browser Hash.
-
-License:
-        MIT-style license.
-*/
-
-var Browser = $merge({
-
-        Engine: {name: 'unknown', version: 0},
-
-        Platform: {name: (window.orientation != undefined) ? 'ipod' : (navigator.platform.match(/mac|win|linux/i) || ['other'])[0].toLowerCase()},
-
-        Features: {xpath: !!(document.evaluate), air: !!(window.runtime), query: !!(document.querySelector)},
-
-        Plugins: {},
-
-        Engines: {
-
-                presto: function(){
-                        return (!window.opera) ? false : ((arguments.callee.caller) ? 960 : ((document.getElementsByClassName) ? 950 : 925));
-                },
-
-                trident: function(){
-                        return (!window.ActiveXObject) ? false : ((window.XMLHttpRequest) ? 5 : 4);
-                },
-
-                webkit: function(){
-                        return (navigator.taintEnabled) ? false : ((Browser.Features.xpath) ? ((Browser.Features.query) ? 525 : 420) : 419);
-                },
-
-                gecko: function(){
-                        return (document.getBoxObjectFor == undefined) ? false : ((document.getElementsByClassName) ? 19 : 18);
-                }
-
-        }
-
-}, Browser || {});
-
-Browser.Platform[Browser.Platform.name] = true;
-
-Browser.detect = function(){
-
-        for (var engine in this.Engines){
-                var version = this.Engines[engine]();
-                if (version){
-                        this.Engine = {name: engine, version: version};
-                        this.Engine[engine] = this.Engine[engine + version] = true;
-                        break;
-                }
-        }
-
-        return {name: engine, version: version};
-
-};
-
-Browser.detect();
-
-Browser.Request = function(){
-        return $try(function(){
-                return new XMLHttpRequest();
-        }, function(){
-                return new ActiveXObject('MSXML2.XMLHTTP');
-        });
-};
-
-Browser.Features.xhr = !!(Browser.Request());
-
-Browser.Plugins.Flash = (function(){
-        var version = ($try(function(){
-                return navigator.plugins['Shockwave Flash'].description;
-        }, function(){
-                return new ActiveXObject('ShockwaveFlash.ShockwaveFlash').GetVariable('$version');
-        }) || '0 r0').match(/\d+/g);
-        return {version: parseInt(version[0] || 0 + '.' + version[1] || 0), build: parseInt(version[2] || 0)};
-})();
-
-function $exec(text){
-        if (!text) return text;
-        if (window.execScript){
-                window.execScript(text);
-        } else {
-                var script = document.createElement('script');
-                script.setAttribute('type', 'text/javascript');
-                script[(Browser.Engine.webkit && Browser.Engine.version < 420) ? 'innerText' : 'text'] = text;
-                document.head.appendChild(script);
-                document.head.removeChild(script);
-        }
-        return text;
-};
-
-Native.UID = 1;
-
-var $uid = (Browser.Engine.trident) ? function(item){
-        return (item.uid || (item.uid = [Native.UID++]))[0];
-} : function(item){
-        return item.uid || (item.uid = Native.UID++);
-};
-
-var Window = new Native({
-
-        name: 'Window',
-
-        legacy: (Browser.Engine.trident) ? null: window.Window,
-
-        initialize: function(win){
-                $uid(win);
-                if (!win.Element){
-                        win.Element = $empty;
-                        if (Browser.Engine.webkit) win.document.createElement("iframe"); //fixes safari 2
-                        win.Element.prototype = (Browser.Engine.webkit) ? window["[[DOMElement.prototype]]"] : {};
-                }
-                win.document.window = win;
-                return $extend(win, Window.Prototype);
-        },
-
-        afterImplement: function(property, value){
-                window[property] = Window.Prototype[property] = value;
-        }
-
-});
-
-Window.Prototype = {$family: {name: 'window'}};
-
-new Window(window);
-
-var Document = new Native({
-
-        name: 'Document',
-
-        legacy: (Browser.Engine.trident) ? null: window.Document,
-
-        initialize: function(doc){
-                $uid(doc);
-                doc.head = doc.getElementsByTagName('head')[0];
-                doc.html = doc.getElementsByTagName('html')[0];
-                if (Browser.Engine.trident && Browser.Engine.version <= 4) $try(function(){
-                        doc.execCommand("BackgroundImageCache", false, true);
-                });
-                if (Browser.Engine.trident) doc.window.attachEvent('onunload', function() {
-                        doc.window.detachEvent('onunload', arguments.callee);
-                        doc.head = doc.html = doc.window = null;
-                });
-                return $extend(doc, Document.Prototype);
-        },
-
-        afterImplement: function(property, value){
-                document[property] = Document.Prototype[property] = value;
-        }
-
-});
-
-Document.Prototype = {$family: {name: 'document'}};
-
-new Document(document);
-
-
-/*
-Script: Array.js
-        Contains Array Prototypes like each, contains, and erase.
-
-License:
-        MIT-style license.
-*/
-
-Array.implement({
-
-        every: function(fn, bind){
-                for (var i = 0, l = this.length; i < l; i++){
-                        if (!fn.call(bind, this[i], i, this)) return false;
-                }
-                return true;
-        },
-
-        filter: function(fn, bind){
-                var results = [];
-                for (var i = 0, l = this.length; i < l; i++){
-                        if (fn.call(bind, this[i], i, this)) results.push(this[i]);
-                }
-                return results;
-        },
-
-        clean: function() {
-                return this.filter($defined);
-        },
-
-        indexOf: function(item, from){
-                var len = this.length;
-                for (var i = (from < 0) ? Math.max(0, len + from) : from || 0; i < len; i++){
-                        if (this[i] === item) return i;
-                }
-                return -1;
-        },
-
-        map: function(fn, bind){
-                var results = [];
-                for (var i = 0, l = this.length; i < l; i++) results[i] = fn.call(bind, this[i], i, this);
-                return results;
-        },
-
-        some: function(fn, bind){
-                for (var i = 0, l = this.length; i < l; i++){
-                        if (fn.call(bind, this[i], i, this)) return true;
-                }
-                return false;
-        },
-
-        associate: function(keys){
-                var obj = {}, length = Math.min(this.length, keys.length);
-                for (var i = 0; i < length; i++) obj[keys[i]] = this[i];
-                return obj;
-        },
-
-        link: function(object){
-                var result = {};
-                for (var i = 0, l = this.length; i < l; i++){
-                        for (var key in object){
-                                if (object[key](this[i])){
-                                        result[key] = this[i];
-                                        delete object[key];
-                                        break;
-                                }
-                        }
-                }
-                return result;
-        },
-
-        contains: function(item, from){
-                return this.indexOf(item, from) != -1;
-        },
-
-        extend: function(array){
-                for (var i = 0, j = array.length; i < j; i++) this.push(array[i]);
-                return this;
-        },
-
-        getLast: function(){
-                return (this.length) ? this[this.length - 1] : null;
-        },
-
-        getRandom: function(){
-                return (this.length) ? this[$random(0, this.length - 1)] : null;
-        },
-
-        include: function(item){
-                if (!this.contains(item)) this.push(item);
-                return this;
-        },
-
-        combine: function(array){
-                for (var i = 0, l = array.length; i < l; i++) this.include(array[i]);
-                return this;
-        },
-
-        erase: function(item){
-                for (var i = this.length; i--; i){
-                        if (this[i] === item) this.splice(i, 1);
-                }
-                return this;
-        },
-
-        empty: function(){
-                this.length = 0;
-                return this;
-        },
-
-        flatten: function(){
-                var array = [];
-                for (var i = 0, l = this.length; i < l; i++){
-                        var type = $type(this[i]);
-                        if (!type) continue;
-                        array = array.concat((type == 'array' || type == 'collection' || type == 'arguments') ? Array.flatten(this[i]) : this[i]);
-                }
-                return array;
-        },
-
-        hexToRgb: function(array){
-                if (this.length != 3) return null;
-                var rgb = this.map(function(value){
-                        if (value.length == 1) value += value;
-                        return value.toInt(16);
-                });
-                return (array) ? rgb : 'rgb(' + rgb + ')';
-        },
-
-        rgbToHex: function(array){
-                if (this.length < 3) return null;
-                if (this.length == 4 && this[3] == 0 && !array) return 'transparent';
-                var hex = [];
-                for (var i = 0; i < 3; i++){
-                        var bit = (this[i] - 0).toString(16);
-                        hex.push((bit.length == 1) ? '0' + bit : bit);
-                }
-                return (array) ? hex : '#' + hex.join('');
-        }
-
-});
-
-
-/*
-Script: Function.js
-        Contains Function Prototypes like create, bind, pass, and delay.
-
-License:
-        MIT-style license.
-*/
-
-Function.implement({
-
-        extend: function(properties){
-                for (var property in properties) this[property] = properties[property];
-                return this;
-        },
-
-        create: function(options){
-                var self = this;
-                options = options || {};
-                return function(event){
-                        var args = options.arguments;
-                        args = (args != undefined) ? $splat(args) : Array.slice(arguments, (options.event) ? 1 : 0);
-                        if (options.event) args = [event || window.event].extend(args);
-                        var returns = function(){
-                                return self.apply(options.bind || null, args);
-                        };
-                        if (options.delay) return setTimeout(returns, options.delay);
-                        if (options.periodical) return setInterval(returns, options.periodical);
-                        if (options.attempt) return $try(returns);
-                        return returns();
-                };
-        },
-
-        run: function(args, bind){
-                return this.apply(bind, $splat(args));
-        },
-
-        pass: function(args, bind){
-                return this.create({bind: bind, arguments: args});
-        },
-
-        bind: function(bind, args){
-                return this.create({bind: bind, arguments: args});
-        },
-
-        bindWithEvent: function(bind, args){
-                return this.create({bind: bind, arguments: args, event: true});
-        },
-
-        attempt: function(args, bind){
-                return this.create({bind: bind, arguments: args, attempt: true})();
-        },
-
-        delay: function(delay, bind, args){
-                return this.create({bind: bind, arguments: args, delay: delay})();
-        },
-
-        periodical: function(periodical, bind, args){
-                return this.create({bind: bind, arguments: args, periodical: periodical})();
-        }
-
-});
-
-
-/*
-Script: Number.js
-        Contains Number Prototypes like limit, round, times, and ceil.
-
-License:
-        MIT-style license.
-*/
-
-Number.implement({
-
-        limit: function(min, max){
-                return Math.min(max, Math.max(min, this));
-        },
-
-        round: function(precision){
-                precision = Math.pow(10, precision || 0);
-                return Math.round(this * precision) / precision;
-        },
-
-        times: function(fn, bind){
-                for (var i = 0; i < this; i++) fn.call(bind, i, this);
-        },
-
-        toFloat: function(){
-                return parseFloat(this);
-        },
-
-        toInt: function(base){
-                return parseInt(this, base || 10);
-        }
-
-});
-
-Number.alias('times', 'each');
-
-(function(math){
-        var methods = {};
-        math.each(function(name){
-                if (!Number[name]) methods[name] = function(){
-                        return Math[name].apply(null, [this].concat($A(arguments)));
-                };
-        });
-        Number.implement(methods);
-})(['abs', 'acos', 'asin', 'atan', 'atan2', 'ceil', 'cos', 'exp', 'floor', 'log', 'max', 'min', 'pow', 'sin', 'sqrt', 'tan']);
-
-
-/*
-Script: String.js
-        Contains String Prototypes like camelCase, capitalize, test, and toInt.
-
-License:
-        MIT-style license.
-*/
-
-String.implement({
-
-        test: function(regex, params){
-                return ((typeof regex == 'string') ? new RegExp(regex, params) : regex).test(this);
-        },
-
-        contains: function(string, separator){
-                return (separator) ? (separator + this + separator).indexOf(separator + string + separator) > -1 : this.indexOf(string) > -1;
-        },
-
-        trim: function(){
-                return this.replace(/^\s+|\s+$/g, '');
-        },
-
-        clean: function(){
-                return this.replace(/\s+/g, ' ').trim();
-        },
-
-        camelCase: function(){
-                return this.replace(/-\D/g, function(match){
-                        return match.charAt(1).toUpperCase();
-                });
-        },
-
-        hyphenate: function(){
-                return this.replace(/[A-Z]/g, function(match){
-                        return ('-' + match.charAt(0).toLowerCase());
-                });
-        },
-
-        capitalize: function(){
-                return this.replace(/\b[a-z]/g, function(match){
-                        return match.toUpperCase();
-                });
-        },
-
-        escapeRegExp: function(){
-                return this.replace(/([-.*+?^${}()|[\]\/\\])/g, '\\$1');
-        },
-
-        toInt: function(base){
-                return parseInt(this, base || 10);
-        },
-
-        toFloat: function(){
-                return parseFloat(this);
-        },
-
-        hexToRgb: function(array){
-                var hex = this.match(/^#?(\w{1,2})(\w{1,2})(\w{1,2})$/);
-                return (hex) ? hex.slice(1).hexToRgb(array) : null;
-        },
-
-        rgbToHex: function(array){
-                var rgb = this.match(/\d{1,3}/g);
-                return (rgb) ? rgb.rgbToHex(array) : null;
-        },
-
-        stripScripts: function(option){
-                var scripts = '';
-                var text = this.replace(/<script[^>]*>([\s\S]*?)<\/script>/gi, function(){
-                        scripts += arguments[1] + '\n';
-                        return '';
-                });
-                if (option === true) $exec(scripts);
-                else if ($type(option) == 'function') option(scripts, text);
-                return text;
-        },
-
-        substitute: function(object, regexp){
-                return this.replace(regexp || (/\\?\{([^{}]+)\}/g), function(match, name){
-                        if (match.charAt(0) == '\\') return match.slice(1);
-                        return (object[name] != undefined) ? object[name] : '';
-                });
-        }
-
-});
-
-
-/*
-Script: Hash.js
-        Contains Hash Prototypes. Provides a means for overcoming the JavaScript practical impossibility of extending native Objects.
-
-License:
-        MIT-style license.
-*/
-
-Hash.implement({
-
-        has: Object.prototype.hasOwnProperty,
-
-        keyOf: function(value){
-                for (var key in this){
-                        if (this.hasOwnProperty(key) && this[key] === value) return key;
-                }
-                return null;
-        },
-
-        hasValue: function(value){
-                return (Hash.keyOf(this, value) !== null);
-        },
-
-        extend: function(properties){
-                Hash.each(properties, function(value, key){
-                        Hash.set(this, key, value);
-                }, this);
-                return this;
-        },
-
-        combine: function(properties){
-                Hash.each(properties, function(value, key){
-                        Hash.include(this, key, value);
-                }, this);
-                return this;
-        },
-
-        erase: function(key){
-                if (this.hasOwnProperty(key)) delete this[key];
-                return this;
-        },
-
-        get: function(key){
-                return (this.hasOwnProperty(key)) ? this[key] : null;
-        },
-
-        set: function(key, value){
-                if (!this[key] || this.hasOwnProperty(key)) this[key] = value;
-                return this;
-        },
-
-        empty: function(){
-                Hash.each(this, function(value, key){
-                        delete this[key];
-                }, this);
-                return this;
-        },
-
-        include: function(key, value){
-                var k = this[key];
-                if (k == undefined) this[key] = value;
-                return this;
-        },
-
-        map: function(fn, bind){
-                var results = new Hash;
-                Hash.each(this, function(value, key){
-                        results.set(key, fn.call(bind, value, key, this));
-                }, this);
-                return results;
-        },
-
-        filter: function(fn, bind){
-                var results = new Hash;
-                Hash.each(this, function(value, key){
-                        if (fn.call(bind, value, key, this)) results.set(key, value);
-                }, this);
-                return results;
-        },
-
-        every: function(fn, bind){
-                for (var key in this){
-                        if (this.hasOwnProperty(key) && !fn.call(bind, this[key], key)) return false;
-                }
-                return true;
-        },
-
-        some: function(fn, bind){
-                for (var key in this){
-                        if (this.hasOwnProperty(key) && fn.call(bind, this[key], key)) return true;
-                }
-                return false;
-        },
-
-        getKeys: function(){
-                var keys = [];
-                Hash.each(this, function(value, key){
-                        keys.push(key);
-                });
-                return keys;
-        },
-
-        getValues: function(){
-                var values = [];
-                Hash.each(this, function(value){
-                        values.push(value);
-                });
-                return values;
-        },
-
-        toQueryString: function(base){
-                var queryString = [];
-                Hash.each(this, function(value, key){
-                        if (base) key = base + '[' + key + ']';
-                        var result;
-                        switch ($type(value)){
-                                case 'object': result = Hash.toQueryString(value, key); break;
-                                case 'array':
-                                        var qs = {};
-                                        value.each(function(val, i){
-                                                qs[i] = val;
-                                        });
-                                        result = Hash.toQueryString(qs, key);
-                                break;
-                                default: result = key + '=' + encodeURIComponent(value);
-                        }
-                        if (value != undefined) queryString.push(result);
-                });
-
-                return queryString.join('&');
-        }
-
-});
-
-Hash.alias({keyOf: 'indexOf', hasValue: 'contains'});
-
-
-/*
-Script: Event.js
-        Contains the Event Native, to make the event object completely crossbrowser.
-
-License:
-        MIT-style license.
-*/
-
-var Event = new Native({
-
-        name: 'Event',
-
-        initialize: function(event, win){
-                win = win || window;
-                var doc = win.document;
-                event = event || win.event;
-                if (event.$extended) return event;
-                this.$extended = true;
-                var type = event.type;
-                var target = event.target || event.srcElement;
-                while (target && target.nodeType == 3) target = target.parentNode;
-
-                if (type.test(/key/)){
-                        var code = event.which || event.keyCode;
-                        var key = Event.Keys.keyOf(code);
-                        if (type == 'keydown'){
-                                var fKey = code - 111;
-                                if (fKey > 0 && fKey < 13) key = 'f' + fKey;
-                        }
-                        key = key || String.fromCharCode(code).toLowerCase();
-                } else if (type.match(/(click|mouse|menu)/i)){
-                        doc = (!doc.compatMode || doc.compatMode == 'CSS1Compat') ? doc.html : doc.body;
-                        var page = {
-                                x: event.pageX || event.clientX + doc.scrollLeft,
-                                y: event.pageY || event.clientY + doc.scrollTop
-                        };
-                        var client = {
-                                x: (event.pageX) ? event.pageX - win.pageXOffset : event.clientX,
-                                y: (event.pageY) ? event.pageY - win.pageYOffset : event.clientY
-                        };
-                        if (type.match(/DOMMouseScroll|mousewheel/)){
-                                var wheel = (event.wheelDelta) ? event.wheelDelta / 120 : -(event.detail || 0) / 3;
-                        }
-                        var rightClick = (event.which == 3) || (event.button == 2);
-                        var related = null;
-                        if (type.match(/over|out/)){
-                                switch (type){
-                                        case 'mouseover': related = event.relatedTarget || event.fromElement; break;
-                                        case 'mouseout': related = event.relatedTarget || event.toElement;
-                                }
-                                if (!(function(){
-                                        while (related && related.nodeType == 3) related = related.parentNode;
-                                        return true;
-                                }).create({attempt: Browser.Engine.gecko})()) related = false;
-                        }
-                }
-
-                return $extend(this, {
-                        event: event,
-                        type: type,
-
-                        page: page,
-                        client: client,
-                        rightClick: rightClick,
-
-                        wheel: wheel,
-
-                        relatedTarget: related,
-                        target: target,
-
-                        code: code,
-                        key: key,
-
-                        shift: event.shiftKey,
-                        control: event.ctrlKey,
-                        alt: event.altKey,
-                        meta: event.metaKey
-                });
-        }
-
-});
-
-Event.Keys = new Hash({
-        'enter': 13,
-        'up': 38,
-        'down': 40,
-        'left': 37,
-        'right': 39,
-        'esc': 27,
-        'space': 32,
-        'backspace': 8,
-        'tab': 9,
-        'delete': 46
-});
-
-Event.implement({
-
-        stop: function(){
-                return this.stopPropagation().preventDefault();
-        },
-
-        stopPropagation: function(){
-                if (this.event.stopPropagation) this.event.stopPropagation();
-                else this.event.cancelBubble = true;
-                return this;
-        },
-
-        preventDefault: function(){
-                if (this.event.preventDefault) this.event.preventDefault();
-                else this.event.returnValue = false;
-                return this;
-        }
-
-});
-
-
-/*
-Script: Class.js
-        Contains the Class Function for easily creating, extending, and implementing reusable Classes.
-
-License:
-        MIT-style license.
-*/
-
-var Class = new Native({
-
-        name: 'Class',
-
-        initialize: function(properties){
-                properties = properties || {};
-                var klass = function(){
-                        for (var key in this){
-                                if ($type(this[key]) != 'function') this[key] = $unlink(this[key]);
-                        }
-                        this.constructor = klass;
-                        if (Class.prototyping) return this;
-                        var instance = (this.initialize) ? this.initialize.apply(this, arguments) : this;
-                        if (this.options && this.options.initialize) this.options.initialize.call(this);
-                        return instance;
-                };
-
-                for (var mutator in Class.Mutators){
-                        if (!properties[mutator]) continue;
-                        properties = Class.Mutators[mutator](properties, properties[mutator]);
-                        delete properties[mutator];
-                }
-
-                $extend(klass, this);
-                klass.constructor = Class;
-                klass.prototype = properties;
-                return klass;
-        }
-
-});
-
-Class.Mutators = {
-
-        Extends: function(self, klass){
-                Class.prototyping = klass.prototype;
-                var subclass = new klass;
-                delete subclass.parent;
-                subclass = Class.inherit(subclass, self);
-                delete Class.prototyping;
-                return subclass;
-        },
-
-        Implements: function(self, klasses){
-                $splat(klasses).each(function(klass){
-                        Class.prototying = klass;
-                        $extend(self, ($type(klass) == 'class') ? new klass : klass);
-                        delete Class.prototyping;
-                });
-                return self;
-        }
-
-};
-
-Class.extend({
-
-        inherit: function(object, properties){
-                var caller = arguments.callee.caller;
-                for (var key in properties){
-                        var override = properties[key];
-                        var previous = object[key];
-                        var type = $type(override);
-                        if (previous && type == 'function'){
-                                if (override != previous){
-                                        if (caller){
-                                                override.__parent = previous;
-                                                object[key] = override;
-                                        } else {
-                                                Class.override(object, key, override);
-                                        }
-                                }
-                        } else if(type == 'object'){
-                                object[key] = $merge(previous, override);
-                        } else {
-                                object[key] = override;
-                        }
-                }
-
-                if (caller) object.parent = function(){
-                        return arguments.callee.caller.__parent.apply(this, arguments);
-                };
-
-                return object;
-        },
-
-        override: function(object, name, method){
-                var parent = Class.prototyping;
-                if (parent && object[name] != parent[name]) parent = null;
-                var override = function(){
-                        var previous = this.parent;
-                        this.parent = parent ? parent[name] : object[name];
-                        var value = method.apply(this, arguments);
-                        this.parent = previous;
-                        return value;
-                };
-                object[name] = override;
-        }
-
-});
-
-Class.implement({
-
-        implement: function(){
-                var proto = this.prototype;
-                $each(arguments, function(properties){
-                        Class.inherit(proto, properties);
-                });
-                return this;
-        }
-
-});
-
-
-/*
-Script: Class.Extras.js
-        Contains Utility Classes that can be implemented into your own Classes to ease the execution of many common tasks.
-
-License:
-        MIT-style license.
-*/
-
-var Chain = new Class({
-
-        $chain: [],
-
-        chain: function(){
-                this.$chain.extend(Array.flatten(arguments));
-                return this;
-        },
-
-        callChain: function(){
-                return (this.$chain.length) ? this.$chain.shift().apply(this, arguments) : false;
-        },
-
-        clearChain: function(){
-                this.$chain.empty();
-                return this;
-        }
-
-});
-
-var Events = new Class({
-
-        $events: {},
-
-        addEvent: function(type, fn, internal){
-                type = Events.removeOn(type);
-                if (fn != $empty){
-                        this.$events[type] = this.$events[type] || [];
-                        this.$events[type].include(fn);
-                        if (internal) fn.internal = true;
-                }
-                return this;
-        },
-
-        addEvents: function(events){
-                for (var type in events) this.addEvent(type, events[type]);
-                return this;
-        },
-
-        fireEvent: function(type, args, delay){
-                type = Events.removeOn(type);
-                if (!this.$events || !this.$events[type]) return this;
-                this.$events[type].each(function(fn){
-                        fn.create({'bind': this, 'delay': delay, 'arguments': args})();
-                }, this);
-                return this;
-        },
-
-        removeEvent: function(type, fn){
-                type = Events.removeOn(type);
-                if (!this.$events[type]) return this;
-                if (!fn.internal) this.$events[type].erase(fn);
-                return this;
-        },
-
-        removeEvents: function(events){
-                if ($type(events) == 'object'){
-                        for (var type in events) this.removeEvent(type, events[type]);
-                        return this;
-                }
-                if (events) events = Events.removeOn(events);
-                for (var type in this.$events){
-                        if (events && events != type) continue;
-                        var fns = this.$events[type];
-                        for (var i = fns.length; i--; i) this.removeEvent(type, fns[i]);
-                }
-                return this;
-        }
-
-});
-
-Events.removeOn = function(string){
-        return string.replace(/^on([A-Z])/, function(full, first) {
-                return first.toLowerCase();
-        });
-};
-
-var Options = new Class({
-
-        setOptions: function(){
-                this.options = $merge.run([this.options].extend(arguments));
-                if (!this.addEvent) return this;
-                for (var option in this.options){
-                        if ($type(this.options[option]) != 'function' || !(/^on[A-Z]/).test(option)) continue;
-                        this.addEvent(option, this.options[option]);
-                        delete this.options[option];
-                }
-                return this;
-        }
-
-});
-
-
-/*
-Script: Element.js
-        One of the most important items in MooTools. Contains the dollar function, the dollars function, and an handful of cross-browser,
-        time-saver methods to let you easily work with HTML Elements.
-
-License:
-        MIT-style license.
-*/
-
-var Element = new Native({
-
-        name: 'Element',
-
-        legacy: window.Element,
-
-        initialize: function(tag, props){
-                var konstructor = Element.Constructors.get(tag);
-                if (konstructor) return konstructor(props);
-                if (typeof tag == 'string') return document.newElement(tag, props);
-                return $(tag).set(props);
-        },
-
-        afterImplement: function(key, value){
-                Element.Prototype[key] = value;
-                if (Array[key]) return;
-                Elements.implement(key, function(){
-                        var items = [], elements = true;
-                        for (var i = 0, j = this.length; i < j; i++){
-                                var returns = this[i][key].apply(this[i], arguments);
-                                items.push(returns);
-                                if (elements) elements = ($type(returns) == 'element');
-                        }
-                        return (elements) ? new Elements(items) : items;
-                });
-        }
-
-});
-
-Element.Prototype = {$family: {name: 'element'}};
-
-Element.Constructors = new Hash;
-
-var IFrame = new Native({
-
-        name: 'IFrame',
-
-        generics: false,
-
-        initialize: function(){
-                var params = Array.link(arguments, {properties: Object.type, iframe: $defined});
-                var props = params.properties || {};
-                var iframe = $(params.iframe) || false;
-                var onload = props.onload || $empty;
-                delete props.onload;
-                props.id = props.name = $pick(props.id, props.name, iframe.id, iframe.name, 'IFrame_' + $time());
-                iframe = new Element(iframe || 'iframe', props);
-                var onFrameLoad = function(){
-                        var host = $try(function(){
-                                return iframe.contentWindow.location.host;
-                        });
-                        if (host && host == window.location.host){
-                                var win = new Window(iframe.contentWindow);
-                                new Document(iframe.contentWindow.document);
-                                $extend(win.Element.prototype, Element.Prototype);
-                        }
-                        onload.call(iframe.contentWindow, iframe.contentWindow.document);
-                };
-                (window.frames[props.id]) ? onFrameLoad() : iframe.addListener('load', onFrameLoad);
-                return iframe;
-        }
-
-});
-
-var Elements = new Native({
-
-        initialize: function(elements, options){
-                options = $extend({ddup: true, cash: true}, options);
-                elements = elements || [];
-                if (options.ddup || options.cash){
-                        var uniques = {}, returned = [];
-                        for (var i = 0, l = elements.length; i < l; i++){
-                                var el = $.element(elements[i], !options.cash);
-                                if (options.ddup){
-                                        if (uniques[el.uid]) continue;
-                                        uniques[el.uid] = true;
-                                }
-                                returned.push(el);
-                        }
-                        elements = returned;
-                }
-                return (options.cash) ? $extend(elements, this) : elements;
-        }
-
-});
-
-Elements.implement({
-
-        filter: function(filter, bind){
-                if (!filter) return this;
-                return new Elements(Array.filter(this, (typeof filter == 'string') ? function(item){
-                        return item.match(filter);
-                } : filter, bind));
-        }
-
-});
-
-Document.implement({
-
-        newElement: function(tag, props){
-                if (Browser.Engine.trident && props){
-                        ['name', 'type', 'checked'].each(function(attribute){
-                                if (!props[attribute]) return;
-                                tag += ' ' + attribute + '="' + props[attribute] + '"';
-                                if (attribute != 'checked') delete props[attribute];
-                        });
-                        tag = '<' + tag + '>';
-                }
-                return $.element(this.createElement(tag)).set(props);
-        },
-
-        newTextNode: function(text){
-                return this.createTextNode(text);
-        },
-
-        getDocument: function(){
-                return this;
-        },
-
-        getWindow: function(){
-                return this.window;
-        }
-
-});
-
-Window.implement({
-
-        $: function(el, nocash){
-                if (el && el.$family && el.uid) return el;
-                var type = $type(el);
-                return ($[type]) ? $[type](el, nocash, this.document) : null;
-        },
-
-        $$: function(selector){
-                if (arguments.length == 1 && typeof selector == 'string') return this.document.getElements(selector);
-                var elements = [];
-                var args = Array.flatten(arguments);
-                for (var i = 0, l = args.length; i < l; i++){
-                        var item = args[i];
-                        switch ($type(item)){
-                                case 'element': elements.push(item); break;
-                                case 'string': elements.extend(this.document.getElements(item, true));
-                        }
-                }
-                return new Elements(elements);
-        },
-
-        getDocument: function(){
-                return this.document;
-        },
-
-        getWindow: function(){
-                return this;
-        }
-
-});
-
-$.string = function(id, nocash, doc){
-        id = doc.getElementById(id);
-        return (id) ? $.element(id, nocash) : null;
-};
-
-$.element = function(el, nocash){
-        $uid(el);
-        if (!nocash && !el.$family && !(/^object|embed$/i).test(el.tagName)){
-                var proto = Element.Prototype;
-                for (var p in proto) el[p] = proto[p];
-        };
-        return el;
-};
-
-$.object = function(obj, nocash, doc){
-        if (obj.toElement) return $.element(obj.toElement(doc), nocash);
-        return null;
-};
-
-$.textnode = $.whitespace = $.window = $.document = $arguments(0);
-
-Native.implement([Element, Document], {
-
-        getElement: function(selector, nocash){
-                return $(this.getElements(selector, true)[0] || null, nocash);
-        },
-
-        getElements: function(tags, nocash){
-                tags = tags.split(',');
-                var elements = [];
-                var ddup = (tags.length > 1);
-                tags.each(function(tag){
-                        var partial = this.getElementsByTagName(tag.trim());
-                        (ddup) ? elements.extend(partial) : elements = partial;
-                }, this);
-                return new Elements(elements, {ddup: ddup, cash: !nocash});
-        }
-
-});
-
-(function(){
-
-var collected = {}, storage = {};
-var props = {input: 'checked', option: 'selected', textarea: (Browser.Engine.webkit && Browser.Engine.version < 420) ? 'innerHTML' : 'value'};
-
-var get = function(uid){
-        return (storage[uid] || (storage[uid] = {}));
-};
-
-var clean = function(item, retain){
-        if (!item) return;
-        var uid = item.uid;
-        if (Browser.Engine.trident){
-                if (item.clearAttributes){
-                        var clone = retain && item.cloneNode(false);
-                        item.clearAttributes();
-                        if (clone) item.mergeAttributes(clone);
-                } else if (item.removeEvents){
-                        item.removeEvents();
-                }
-                if ((/object/i).test(item.tagName)){
-                        for (var p in item){
-                                if (typeof item[p] == 'function') item[p] = $empty;
-                        }
-                        Element.dispose(item);
-                }
-        }       
-        if (!uid) return;
-        collected[uid] = storage[uid] = null;
-};
-
-var purge = function(){
-        Hash.each(collected, clean);
-        if (Browser.Engine.trident) $A(document.getElementsByTagName('object')).each(clean);
-        if (window.CollectGarbage) CollectGarbage();
-        collected = storage = null;
-};
-
-var walk = function(element, walk, start, match, all, nocash){
-        var el = element[start || walk];
-        var elements = [];
-        while (el){
-                if (el.nodeType == 1 && (!match || Element.match(el, match))){
-                        if (!all) return $(el, nocash);
-                        elements.push(el);
-                }
-                el = el[walk];
-        }
-        return (all) ? new Elements(elements, {ddup: false, cash: !nocash}) : null;
-};
-
-var attributes = {
-        'html': 'innerHTML',
-        'class': 'className',
-        'for': 'htmlFor',
-        'text': (Browser.Engine.trident || (Browser.Engine.webkit && Browser.Engine.version < 420)) ? 'innerText' : 'textContent'
-};
-var bools = ['compact', 'nowrap', 'ismap', 'declare', 'noshade', 'checked', 'disabled', 'readonly', 'multiple', 'selected', 'noresize', 'defer'];
-var camels = ['value', 'accessKey', 'cellPadding', 'cellSpacing', 'colSpan', 'frameBorder', 'maxLength', 'readOnly', 'rowSpan', 'tabIndex', 'useMap'];
-
-Hash.extend(attributes, bools.associate(bools));
-Hash.extend(attributes, camels.associate(camels.map(String.toLowerCase)));
-
-var inserters = {
-
-        before: function(context, element){
-                if (element.parentNode) element.parentNode.insertBefore(context, element);
-        },
-
-        after: function(context, element){
-                if (!element.parentNode) return;
-                var next = element.nextSibling;
-                (next) ? element.parentNode.insertBefore(context, next) : element.parentNode.appendChild(context);
-        },
-
-        bottom: function(context, element){
-                element.appendChild(context);
-        },
-
-        top: function(context, element){
-                var first = element.firstChild;
-                (first) ? element.insertBefore(context, first) : element.appendChild(context);
-        }
-
-};
-
-inserters.inside = inserters.bottom;
-
-Hash.each(inserters, function(inserter, where){
-
-        where = where.capitalize();
-
-        Element.implement('inject' + where, function(el){
-                inserter(this, $(el, true));
-                return this;
-        });
-
-        Element.implement('grab' + where, function(el){
-                inserter($(el, true), this);
-                return this;
-        });
-
-});
-
-Element.implement({
-
-        set: function(prop, value){
-                switch ($type(prop)){
-                        case 'object':
-                                for (var p in prop) this.set(p, prop[p]);
-                                break;
-                        case 'string':
-                                var property = Element.Properties.get(prop);
-                                (property && property.set) ? property.set.apply(this, Array.slice(arguments, 1)) : this.setProperty(prop, value);
-                }
-                return this;
-        },
-
-        get: function(prop){
-                var property = Element.Properties.get(prop);
-                return (property && property.get) ? property.get.apply(this, Array.slice(arguments, 1)) : this.getProperty(prop);
-        },
-
-        erase: function(prop){
-                var property = Element.Properties.get(prop);
-                (property && property.erase) ? property.erase.apply(this) : this.removeProperty(prop);
-                return this;
-        },
-
-        setProperty: function(attribute, value){
-                var key = attributes[attribute];
-                if (value == undefined) return this.removeProperty(attribute);
-                if (key && bools[attribute]) value = !!value;
-                (key) ? this[key] = value : this.setAttribute(attribute, '' + value);
-                return this;
-        },
-
-        setProperties: function(attributes){
-                for (var attribute in attributes) this.setProperty(attribute, attributes[attribute]);
-                return this;
-        },
-
-        getProperty: function(attribute){
-                var key = attributes[attribute];
-                var value = (key) ? this[key] : this.getAttribute(attribute, 2);
-                return (bools[attribute]) ? !!value : (key) ? value : value || null;
-        },
-
-        getProperties: function(){
-                var args = $A(arguments);
-                return args.map(this.getProperty, this).associate(args);
-        },
-
-        removeProperty: function(attribute){
-                var key = attributes[attribute];
-                (key) ? this[key] = (key && bools[attribute]) ? false : '' : this.removeAttribute(attribute);
-                return this;
-        },
-
-        removeProperties: function(){
-                Array.each(arguments, this.removeProperty, this);
-                return this;
-        },
-
-        hasClass: function(className){
-                return this.className.contains(className, ' ');
-        },
-
-        addClass: function(className){
-                if (!this.hasClass(className)) this.className = (this.className + ' ' + className).clean();
-                return this;
-        },
-
-        removeClass: function(className){
-                this.className = this.className.replace(new RegExp('(^|\\s)' + className + '(?:\\s|$)'), '$1');
-                return this;
-        },
-
-        toggleClass: function(className){
-                return this.hasClass(className) ? this.removeClass(className) : this.addClass(className);
-        },
-
-        adopt: function(){
-                Array.flatten(arguments).each(function(element){
-                        element = $(element, true);
-                        if (element) this.appendChild(element);
-                }, this);
-                return this;
-        },
-
-        appendText: function(text, where){
-                return this.grab(this.getDocument().newTextNode(text), where);
-        },
-
-        grab: function(el, where){
-                inserters[where || 'bottom']($(el, true), this);
-                return this;
-        },
-
-        inject: function(el, where){
-                inserters[where || 'bottom'](this, $(el, true));
-                return this;
-        },
-
-        replaces: function(el){
-                el = $(el, true);
-                el.parentNode.replaceChild(this, el);
-                return this;
-        },
-
-        wraps: function(el, where){
-                el = $(el, true);
-                return this.replaces(el).grab(el, where);
-        },
-
-        getPrevious: function(match, nocash){
-                return walk(this, 'previousSibling', null, match, false, nocash);
-        },
-
-        getAllPrevious: function(match, nocash){
-                return walk(this, 'previousSibling', null, match, true, nocash);
-        },
-
-        getNext: function(match, nocash){
-                return walk(this, 'nextSibling', null, match, false, nocash);
-        },
-
-        getAllNext: function(match, nocash){
-                return walk(this, 'nextSibling', null, match, true, nocash);
-        },
-
-        getFirst: function(match, nocash){
-                return walk(this, 'nextSibling', 'firstChild', match, false, nocash);
-        },
-
-        getLast: function(match, nocash){
-                return walk(this, 'previousSibling', 'lastChild', match, false, nocash);
-        },
-
-        getParent: function(match, nocash){
-                return walk(this, 'parentNode', null, match, false, nocash);
-        },
-
-        getParents: function(match, nocash){
-                return walk(this, 'parentNode', null, match, true, nocash);
-        },
-
-        getChildren: function(match, nocash){
-                return walk(this, 'nextSibling', 'firstChild', match, true, nocash);
-        },
-
-        getWindow: function(){
-                return this.ownerDocument.window;
-        },
-
-        getDocument: function(){
-                return this.ownerDocument;
-        },
-
-        getElementById: function(id, nocash){
-                var el = this.ownerDocument.getElementById(id);
-                if (!el) return null;
-                for (var parent = el.parentNode; parent != this; parent = parent.parentNode){
-                        if (!parent) return null;
-                }
-                return $.element(el, nocash);
-        },
-
-        getSelected: function(){
-                return new Elements($A(this.options).filter(function(option){
-                        return option.selected;
-                }));
-        },
-
-        getComputedStyle: function(property){
-                if (this.currentStyle) return this.currentStyle[property.camelCase()];
-                var computed = this.getDocument().defaultView.getComputedStyle(this, null);
-                return (computed) ? computed.getPropertyValue([property.hyphenate()]) : null;
-        },
-
-        toQueryString: function(){
-                var queryString = [];
-                this.getElements('input, select, textarea', true).each(function(el){
-                        if (!el.name || el.disabled) return;
-                        var value = (el.tagName.toLowerCase() == 'select') ? Element.getSelected(el).map(function(opt){
-                                return opt.value;
-                        }) : ((el.type == 'radio' || el.type == 'checkbox') && !el.checked) ? null : el.value;
-                        $splat(value).each(function(val){
-                                if (typeof val != 'undefined') queryString.push(el.name + '=' + encodeURIComponent(val));
-                        });
-                });
-                return queryString.join('&');
-        },
-
-        clone: function(contents, keepid){
-                contents = contents !== false;
-                var clone = this.cloneNode(contents);
-                var clean = function(node, element){
-                        if (!keepid) node.removeAttribute('id');
-                        if (Browser.Engine.trident){
-                                node.clearAttributes();
-                                node.mergeAttributes(element);
-                                node.removeAttribute('uid');
-                                if (node.options){
-                                        var no = node.options, eo = element.options;
-                                        for (var j = no.length; j--;) no[j].selected = eo[j].selected;
-                                }
-                        }
-                        var prop = props[element.tagName.toLowerCase()];
-                        if (prop && element[prop]) node[prop] = element[prop];
-                };
-
-                if (contents){
-                        var ce = clone.getElementsByTagName('*'), te = this.getElementsByTagName('*');
-                        for (var i = ce.length; i--;) clean(ce[i], te[i]);
-                }
-
-                clean(clone, this);
-                return $(clone);
-        },
-
-        destroy: function(){
-                Element.empty(this);
-                Element.dispose(this);
-                clean(this, true);
-                return null;
-        },
-
-        empty: function(){
-                $A(this.childNodes).each(function(node){
-                        Element.destroy(node);
-                });
-                return this;
-        },
-
-        dispose: function(){
-                return (this.parentNode) ? this.parentNode.removeChild(this) : this;
-        },
-
-        hasChild: function(el){
-                el = $(el, true);
-                if (!el) return false;
-                if (Browser.Engine.webkit && Browser.Engine.version < 420) return $A(this.getElementsByTagName(el.tagName)).contains(el);
-                return (this.contains) ? (this != el && this.contains(el)) : !!(this.compareDocumentPosition(el) & 16);
-        },
-
-        match: function(tag){
-                return (!tag || (tag == this) || (Element.get(this, 'tag') == tag));
-        }
-
-});
-
-Native.implement([Element, Window, Document], {
-
-        addListener: function(type, fn){
-                if (type == 'unload'){
-                        var old = fn, self = this;
-                        fn = function(){
-                                self.removeListener('unload', fn);
-                                old();
-                        };
-                } else {
-                        collected[this.uid] = this;
-                }
-                if (this.addEventListener) this.addEventListener(type, fn, false);
-                else this.attachEvent('on' + type, fn);
-                return this;
-        },
-
-        removeListener: function(type, fn){
-                if (this.removeEventListener) this.removeEventListener(type, fn, false);
-                else this.detachEvent('on' + type, fn);
-                return this;
-        },
-
-        retrieve: function(property, dflt){
-                var storage = get(this.uid), prop = storage[property];
-                if (dflt != undefined && prop == undefined) prop = storage[property] = dflt;
-                return $pick(prop);
-        },
-
-        store: function(property, value){
-                var storage = get(this.uid);
-                storage[property] = value;
-                return this;
-        },
-
-        eliminate: function(property){
-                var storage = get(this.uid);
-                delete storage[property];
-                return this;
-        }
-
-});
-
-window.addListener('unload', purge);
-
-})();
-
-Element.Properties = new Hash;
-
-Element.Properties.style = {
-
-        set: function(style){
-                this.style.cssText = style;
-        },
-
-        get: function(){
-                return this.style.cssText;
-        },
-
-        erase: function(){
-                this.style.cssText = '';
-        }
-
-};
-
-Element.Properties.tag = {
-
-        get: function(){
-                return this.tagName.toLowerCase();
-        }
-
-};
-
-Element.Properties.html = (function(){
-        var wrapper = document.createElement('div');
-
-        var translations = {
-                table: [1, '<table>', '</table>'],
-                select: [1, '<select>', '</select>'],
-                tbody: [2, '<table><tbody>', '</tbody></table>'],
-                tr: [3, '<table><tbody><tr>', '</tr></tbody></table>']
-        };
-        translations.thead = translations.tfoot = translations.tbody;
-
-        var html = {
-                set: function(){
-                        var html = Array.flatten(arguments).join('');
-                        var wrap = Browser.Engine.trident && translations[this.get('tag')];
-                        if (wrap){
-                                var first = wrapper;
-                                first.innerHTML = wrap[1] + html + wrap[2];
-                                for (var i = wrap[0]; i--;) first = first.firstChild;
-                                this.empty().adopt(first.childNodes);
-                        } else {
-                                this.innerHTML = html;
-                        }
-                }
-        };
-
-        html.erase = html.set;
-
-        return html;
-})();
-
-if (Browser.Engine.webkit && Browser.Engine.version < 420) Element.Properties.text = {
-        get: function(){
-                if (this.innerText) return this.innerText;
-                var temp = this.ownerDocument.newElement('div', {html: this.innerHTML}).inject(this.ownerDocument.body);
-                var text = temp.innerText;
-                temp.destroy();
-                return text;
-        }
-};
-
-
-/*
-Script: Element.Event.js
-        Contains Element methods for dealing with events, and custom Events.
-
-License:
-        MIT-style license.
-*/
-
-Element.Properties.events = {set: function(events){
-        this.addEvents(events);
-}};
-
-Native.implement([Element, Window, Document], {
-
-        addEvent: function(type, fn){
-                var events = this.retrieve('events', {});
-                events[type] = events[type] || {'keys': [], 'values': []};
-                if (events[type].keys.contains(fn)) return this;
-                events[type].keys.push(fn);
-                var realType = type, custom = Element.Events.get(type), condition = fn, self = this;
-                if (custom){
-                        if (custom.onAdd) custom.onAdd.call(this, fn);
-                        if (custom.condition){
-                                condition = function(event){
-                                        if (custom.condition.call(this, event)) return fn.call(this, event);
-                                        return true;
-                                };
-                        }
-                        realType = custom.base || realType;
-                }
-                var defn = function(){
-                        return fn.call(self);
-                };
-                var nativeEvent = Element.NativeEvents[realType];
-                if (nativeEvent){
-                        if (nativeEvent == 2){
-                                defn = function(event){
-                                        event = new Event(event, self.getWindow());
-                                        if (condition.call(self, event) === false) event.stop();
-                                };
-                        }
-                        this.addListener(realType, defn);
-                }
-                events[type].values.push(defn);
-                return this;
-        },
-
-        removeEvent: function(type, fn){
-                var events = this.retrieve('events');
-                if (!events || !events[type]) return this;
-                var pos = events[type].keys.indexOf(fn);
-                if (pos == -1) return this;
-                events[type].keys.splice(pos, 1);
-                var value = events[type].values.splice(pos, 1)[0];
-                var custom = Element.Events.get(type);
-                if (custom){
-                        if (custom.onRemove) custom.onRemove.call(this, fn);
-                        type = custom.base || type;
-                }
-                return (Element.NativeEvents[type]) ? this.removeListener(type, value) : this;
-        },
-
-        addEvents: function(events){
-                for (var event in events) this.addEvent(event, events[event]);
-                return this;
-        },
-
-        removeEvents: function(events){
-                if ($type(events) == 'object'){
-                        for (var type in events) this.removeEvent(type, events[type]);
-                        return this;
-                }
-                var attached = this.retrieve('events');
-                if (!attached) return this;
-                if (!events){
-                        for (var type in attached) this.removeEvents(type);
-                        this.eliminate('events');
-                } else if (attached[events]){
-                        while (attached[events].keys[0]) this.removeEvent(events, attached[events].keys[0]);
-                        attached[events] = null;
-                }
-                return this;
-        },
-
-        fireEvent: function(type, args, delay){
-                var events = this.retrieve('events');
-                if (!events || !events[type]) return this;
-                events[type].keys.each(function(fn){
-                        fn.create({'bind': this, 'delay': delay, 'arguments': args})();
-                }, this);
-                return this;
-        },
-
-        cloneEvents: function(from, type){
-                from = $(from);
-                var fevents = from.retrieve('events');
-                if (!fevents) return this;
-                if (!type){
-                        for (var evType in fevents) this.cloneEvents(from, evType);
-                } else if (fevents[type]){
-                        fevents[type].keys.each(function(fn){
-                                this.addEvent(type, fn);
-                        }, this);
-                }
-                return this;
-        }
-
-});
-
-Element.NativeEvents = {
-        click: 2, dblclick: 2, mouseup: 2, mousedown: 2, contextmenu: 2, //mouse buttons
-        mousewheel: 2, DOMMouseScroll: 2, //mouse wheel
-        mouseover: 2, mouseout: 2, mousemove: 2, selectstart: 2, selectend: 2, //mouse movement
-        keydown: 2, keypress: 2, keyup: 2, //keyboard
-        focus: 2, blur: 2, change: 2, reset: 2, select: 2, submit: 2, //form elements
-        load: 1, unload: 1, beforeunload: 2, resize: 1, move: 1, DOMContentLoaded: 1, readystatechange: 1, //window
-        error: 1, abort: 1, scroll: 1 //misc
-};
-
-(function(){
-
-var $check = function(event){
-        var related = event.relatedTarget;
-        if (related == undefined) return true;
-        if (related === false) return false;
-        return ($type(this) != 'document' && related != this && related.prefix != 'xul' && !this.hasChild(related));
-};
-
-Element.Events = new Hash({
-
-        mouseenter: {
-                base: 'mouseover',
-                condition: $check
-        },
-
-        mouseleave: {
-                base: 'mouseout',
-                condition: $check
-        },
-
-        mousewheel: {
-                base: (Browser.Engine.gecko) ? 'DOMMouseScroll' : 'mousewheel'
-        }
-
-});
-
-})();
-
-
-/*
-Script: Element.Style.js
-        Contains methods for interacting with the styles of Elements in a fashionable way.
-
-License:
-        MIT-style license.
-*/
-
-Element.Properties.styles = {set: function(styles){
-        this.setStyles(styles);
-}};
-
-Element.Properties.opacity = {
-
-        set: function(opacity, novisibility){
-                if (!novisibility){
-                        if (opacity == 0){
-                                if (this.style.visibility != 'hidden') this.style.visibility = 'hidden';
-                        } else {
-                                if (this.style.visibility != 'visible') this.style.visibility = 'visible';
-                        }
-                }
-                if (!this.currentStyle || !this.currentStyle.hasLayout) this.style.zoom = 1;
-                if (Browser.Engine.trident) this.style.filter = (opacity == 1) ? '' : 'alpha(opacity=' + opacity * 100 + ')';
-                this.style.opacity = opacity;
-                this.store('opacity', opacity);
-        },
-
-        get: function(){
-                return this.retrieve('opacity', 1);
-        }
-
-};
-
-Element.implement({
-
-        setOpacity: function(value){
-                return this.set('opacity', value, true);
-        },
-
-        getOpacity: function(){
-                return this.get('opacity');
-        },
-
-        setStyle: function(property, value){
-                switch (property){
-                        case 'opacity': return this.set('opacity', parseFloat(value));
-                        case 'float': property = (Browser.Engine.trident) ? 'styleFloat' : 'cssFloat';
-                }
-                property = property.camelCase();
-                if ($type(value) != 'string'){
-                        var map = (Element.Styles.get(property) || '@').split(' ');
-                        value = $splat(value).map(function(val, i){
-                                if (!map[i]) return '';
-                                return ($type(val) == 'number') ? map[i].replace('@', Math.round(val)) : val;
-                        }).join(' ');
-                } else if (value == String(Number(value))){
-                        value = Math.round(value);
-                }
-                this.style[property] = value;
-                return this;
-        },
-
-        getStyle: function(property){
-                switch (property){
-                        case 'opacity': return this.get('opacity');
-                        case 'float': property = (Browser.Engine.trident) ? 'styleFloat' : 'cssFloat';
-                }
-                property = property.camelCase();
-                var result = this.style[property];
-                if (!$chk(result)){
-                        result = [];
-                        for (var style in Element.ShortStyles){
-                                if (property != style) continue;
-                                for (var s in Element.ShortStyles[style]) result.push(this.getStyle(s));
-                                return result.join(' ');
-                        }
-                        result = this.getComputedStyle(property);
-                }
-                if (result){
-                        result = String(result);
-                        var color = result.match(/rgba?\([\d\s,]+\)/);
-                        if (color) result = result.replace(color[0], color[0].rgbToHex());
-                }
-                if (Browser.Engine.presto || (Browser.Engine.trident && !$chk(parseInt(result)))){
-                        if (property.test(/^(height|width)$/)){
-                                var values = (property == 'width') ? ['left', 'right'] : ['top', 'bottom'], size = 0;
-                                values.each(function(value){
-                                        size += this.getStyle('border-' + value + '-width').toInt() + this.getStyle('padding-' + value).toInt();
-                                }, this);
-                                return this['offset' + property.capitalize()] - size + 'px';
-                        }
-                        if ((Browser.Engine.presto) && String(result).test('px')) return result;
-                        if (property.test(/(border(.+)Width|margin|padding)/)) return '0px';
-                }
-                return result;
-        },
-
-        setStyles: function(styles){
-                for (var style in styles) this.setStyle(style, styles[style]);
-                return this;
-        },
-
-        getStyles: function(){
-                var result = {};
-                Array.each(arguments, function(key){
-                        result[key] = this.getStyle(key);
-                }, this);
-                return result;
-        }
-
-});
-
-Element.Styles = new Hash({
-        left: '@px', top: '@px', bottom: '@px', right: '@px',
-        width: '@px', height: '@px', maxWidth: '@px', maxHeight: '@px', minWidth: '@px', minHeight: '@px',
-        backgroundColor: 'rgb(@, @, @)', backgroundPosition: '@px @px', color: 'rgb(@, @, @)',
-        fontSize: '@px', letterSpacing: '@px', lineHeight: '@px', clip: 'rect(@px @px @px @px)',
-        margin: '@px @px @px @px', padding: '@px @px @px @px', border: '@px @ rgb(@, @, @) @px @ rgb(@, @, @) @px @ rgb(@, @, @)',
-        borderWidth: '@px @px @px @px', borderStyle: '@ @ @ @', borderColor: 'rgb(@, @, @) rgb(@, @, @) rgb(@, @, @) rgb(@, @, @)',
-        zIndex: '@', 'zoom': '@', fontWeight: '@', textIndent: '@px', opacity: '@'
-});
-
-Element.ShortStyles = {margin: {}, padding: {}, border: {}, borderWidth: {}, borderStyle: {}, borderColor: {}};
-
-['Top', 'Right', 'Bottom', 'Left'].each(function(direction){
-        var Short = Element.ShortStyles;
-        var All = Element.Styles;
-        ['margin', 'padding'].each(function(style){
-                var sd = style + direction;
-                Short[style][sd] = All[sd] = '@px';
-        });
-        var bd = 'border' + direction;
-        Short.border[bd] = All[bd] = '@px @ rgb(@, @, @)';
-        var bdw = bd + 'Width', bds = bd + 'Style', bdc = bd + 'Color';
-        Short[bd] = {};
-        Short.borderWidth[bdw] = Short[bd][bdw] = All[bdw] = '@px';
-        Short.borderStyle[bds] = Short[bd][bds] = All[bds] = '@';
-        Short.borderColor[bdc] = Short[bd][bdc] = All[bdc] = 'rgb(@, @, @)';
-});
-
-
-/*
-Script: Element.Dimensions.js
-        Contains methods to work with size, scroll, or positioning of Elements and the window object.
-
-License:
-        MIT-style license.
-
-Credits:
-        - Element positioning based on the [qooxdoo](http://qooxdoo.org/) code and smart browser fixes, [LGPL License](http://www.gnu.org/licenses/lgpl.html).
-        - Viewport dimensions based on [YUI](http://developer.yahoo.com/yui/) code, [BSD License](http://developer.yahoo.com/yui/license.html).
-*/
-
-(function(){
-
-Element.implement({
-
-        scrollTo: function(x, y){
-                if (isBody(this)){
-                        this.getWindow().scrollTo(x, y);
-                } else {
-                        this.scrollLeft = x;
-                        this.scrollTop = y;
-                }
-                return this;
-        },
-
-        getSize: function(){
-                if (isBody(this)) return this.getWindow().getSize();
-                return {x: this.offsetWidth, y: this.offsetHeight};
-        },
-
-        getScrollSize: function(){
-                if (isBody(this)) return this.getWindow().getScrollSize();
-                return {x: this.scrollWidth, y: this.scrollHeight};
-        },
-
-        getScroll: function(){
-                if (isBody(this)) return this.getWindow().getScroll();
-                return {x: this.scrollLeft, y: this.scrollTop};
-        },
-
-        getScrolls: function(){
-                var element = this, position = {x: 0, y: 0};
-                while (element && !isBody(element)){
-                        position.x += element.scrollLeft;
-                        position.y += element.scrollTop;
-                        element = element.parentNode;
-                }
-                return position;
-        },
-
-        getOffsetParent: function(){
-                var element = this;
-                if (isBody(element)) return null;
-                if (!Browser.Engine.trident) return element.offsetParent;
-                while ((element = element.parentNode) && !isBody(element)){
-                        if (styleString(element, 'position') != 'static') return element;
-                }
-                return null;
-        },
-
-        getOffsets: function(){
-                if (Browser.Engine.trident){
-                        var bound = this.getBoundingClientRect(), html = this.getDocument().documentElement;
-                        return {
-                                x: bound.left + html.scrollLeft - html.clientLeft,
-                                y: bound.top + html.scrollTop - html.clientTop
-                        };
-                }
-
-                var element = this, position = {x: 0, y: 0};
-                if (isBody(this)) return position;
-
-                while (element && !isBody(element)){
-                        position.x += element.offsetLeft;
-                        position.y += element.offsetTop;
-
-                        if (Browser.Engine.gecko){
-                                if (!borderBox(element)){
-                                        position.x += leftBorder(element);
-                                        position.y += topBorder(element);
-                                }
-                                var parent = element.parentNode;
-                                if (parent && styleString(parent, 'overflow') != 'visible'){
-                                        position.x += leftBorder(parent);
-                                        position.y += topBorder(parent);
-                                }
-                        } else if (element != this && Browser.Engine.webkit){
-                                position.x += leftBorder(element);
-                                position.y += topBorder(element);
-                        }
-
-                        element = element.offsetParent;
-                }
-                if (Browser.Engine.gecko && !borderBox(this)){
-                        position.x -= leftBorder(this);
-                        position.y -= topBorder(this);
-                }
-                return position;
-        },
-
-        getPosition: function(relative){
-                if (isBody(this)) return {x: 0, y: 0};
-                var offset = this.getOffsets(), scroll = this.getScrolls();
-                var position = {x: offset.x - scroll.x, y: offset.y - scroll.y};
-                var relativePosition = (relative && (relative = $(relative))) ? relative.getPosition() : {x: 0, y: 0};
-                return {x: position.x - relativePosition.x, y: position.y - relativePosition.y};
-        },
-
-        getCoordinates: function(element){
-                if (isBody(this)) return this.getWindow().getCoordinates();
-                var position = this.getPosition(element), size = this.getSize();
-                var obj = {left: position.x, top: position.y, width: size.x, height: size.y};
-                obj.right = obj.left + obj.width;
-                obj.bottom = obj.top + obj.height;
-                return obj;
-        },
-
-        computePosition: function(obj){
-                return {left: obj.x - styleNumber(this, 'margin-left'), top: obj.y - styleNumber(this, 'margin-top')};
-        },
-
-        position: function(obj){
-                return this.setStyles(this.computePosition(obj));
-        }
-
-});
-
-Native.implement([Document, Window], {
-
-        getSize: function(){
-                var win = this.getWindow();
-                if (Browser.Engine.presto || Browser.Engine.webkit) return {x: win.innerWidth, y: win.innerHeight};
-                var doc = getCompatElement(this);
-                return {x: doc.clientWidth, y: doc.clientHeight};
-        },
-
-        getScroll: function(){
-                var win = this.getWindow();
-                var doc = getCompatElement(this);
-                return {x: win.pageXOffset || doc.scrollLeft, y: win.pageYOffset || doc.scrollTop};
-        },
-
-        getScrollSize: function(){
-                var doc = getCompatElement(this);
-                var min = this.getSize();
-                return {x: Math.max(doc.scrollWidth, min.x), y: Math.max(doc.scrollHeight, min.y)};
-        },
-
-        getPosition: function(){
-                return {x: 0, y: 0};
-        },
-
-        getCoordinates: function(){
-                var size = this.getSize();
-                return {top: 0, left: 0, bottom: size.y, right: size.x, height: size.y, width: size.x};
-        }
-
-});
-
-// private methods
-
-var styleString = Element.getComputedStyle;
-
-function styleNumber(element, style){
-        return styleString(element, style).toInt() || 0;
-};
-
-function borderBox(element){
-        return styleString(element, '-moz-box-sizing') == 'border-box';
-};
-
-function topBorder(element){
-        return styleNumber(element, 'border-top-width');
-};
-
-function leftBorder(element){
-        return styleNumber(element, 'border-left-width');
-};
-
-function isBody(element){
-        return (/^(?:body|html)$/i).test(element.tagName);
-};
-
-function getCompatElement(element){
-        var doc = element.getDocument();
-        return (!doc.compatMode || doc.compatMode == 'CSS1Compat') ? doc.html : doc.body;
-};
-
-})();
-
-//aliases
-
-Native.implement([Window, Document, Element], {
-
-        getHeight: function(){
-                return this.getSize().y;
-        },
-
-        getWidth: function(){
-                return this.getSize().x;
-        },
-
-        getScrollTop: function(){
-                return this.getScroll().y;
-        },
-
-        getScrollLeft: function(){
-                return this.getScroll().x;
-        },
-
-        getScrollHeight: function(){
-                return this.getScrollSize().y;
-        },
-
-        getScrollWidth: function(){
-                return this.getScrollSize().x;
-        },
-
-        getTop: function(){
-                return this.getPosition().y;
-        },
-
-        getLeft: function(){
-                return this.getPosition().x;
-        }
-
-});
-
-
-/*
-Script: Selectors.js
-        Adds advanced CSS Querying capabilities for targeting elements. Also includes pseudoselectors support.
-
-License:
-        MIT-style license.
-*/
-
-Native.implement([Document, Element], {
-
-        getElements: function(expression, nocash){
-                expression = expression.split(',');
-                var items, local = {};
-                for (var i = 0, l = expression.length; i < l; i++){
-                        var selector = expression[i], elements = Selectors.Utils.search(this, selector, local);
-                        if (i != 0 && elements.item) elements = $A(elements);
-                        items = (i == 0) ? elements : (items.item) ? $A(items).concat(elements) : items.concat(elements);
-                }
-                return new Elements(items, {ddup: (expression.length > 1), cash: !nocash});
-        }
-
-});
-
-Element.implement({
-
-        match: function(selector){
-                if (!selector || (selector == this)) return true;
-                var tagid = Selectors.Utils.parseTagAndID(selector);
-                var tag = tagid[0], id = tagid[1];
-                if (!Selectors.Filters.byID(this, id) || !Selectors.Filters.byTag(this, tag)) return false;
-                var parsed = Selectors.Utils.parseSelector(selector);
-                return (parsed) ? Selectors.Utils.filter(this, parsed, {}) : true;
-        }
-
-});
-
-var Selectors = {Cache: {nth: {}, parsed: {}}};
-
-Selectors.RegExps = {
-        id: (/#([\w-]+)/),
-        tag: (/^(\w+|\*)/),
-        quick: (/^(\w+|\*)$/),
-        splitter: (/\s*([+>~\s])\s*([a-zA-Z#.*:\[])/g),
-        combined: (/\.([\w-]+)|\[(\w+)(?:([!*^$~|]?=)(["']?)([^\4]*?)\4)?\]|:([\w-]+)(?:\(["']?(.*?)?["']?\)|$)/g)
-};
-
-Selectors.Utils = {
-
-        chk: function(item, uniques){
-                if (!uniques) return true;
-                var uid = $uid(item);
-                if (!uniques[uid]) return uniques[uid] = true;
-                return false;
-        },
-
-        parseNthArgument: function(argument){
-                if (Selectors.Cache.nth[argument]) return Selectors.Cache.nth[argument];
-                var parsed = argument.match(/^([+-]?\d*)?([a-z]+)?([+-]?\d*)?$/);
-                if (!parsed) return false;
-                var inta = parseInt(parsed[1]);
-                var a = (inta || inta === 0) ? inta : 1;
-                var special = parsed[2] || false;
-                var b = parseInt(parsed[3]) || 0;
-                if (a != 0){
-                        b--;
-                        while (b < 1) b += a;
-                        while (b >= a) b -= a;
-                } else {
-                        a = b;
-                        special = 'index';
-                }
-                switch (special){
-                        case 'n': parsed = {a: a, b: b, special: 'n'}; break;
-                        case 'odd': parsed = {a: 2, b: 0, special: 'n'}; break;
-                        case 'even': parsed = {a: 2, b: 1, special: 'n'}; break;
-                        case 'first': parsed = {a: 0, special: 'index'}; break;
-                        case 'last': parsed = {special: 'last-child'}; break;
-                        case 'only': parsed = {special: 'only-child'}; break;
-                        default: parsed = {a: (a - 1), special: 'index'};
-                }
-
-                return Selectors.Cache.nth[argument] = parsed;
-        },
-
-        parseSelector: function(selector){
-                if (Selectors.Cache.parsed[selector]) return Selectors.Cache.parsed[selector];
-                var m, parsed = {classes: [], pseudos: [], attributes: []};
-                while ((m = Selectors.RegExps.combined.exec(selector))){
-                        var cn = m[1], an = m[2], ao = m[3], av = m[5], pn = m[6], pa = m[7];
-                        if (cn){
-                                parsed.classes.push(cn);
-                        } else if (pn){
-                                var parser = Selectors.Pseudo.get(pn);
-                                if (parser) parsed.pseudos.push({parser: parser, argument: pa});
-                                else parsed.attributes.push({name: pn, operator: '=', value: pa});
-                        } else if (an){
-                                parsed.attributes.push({name: an, operator: ao, value: av});
-                        }
-                }
-                if (!parsed.classes.length) delete parsed.classes;
-                if (!parsed.attributes.length) delete parsed.attributes;
-                if (!parsed.pseudos.length) delete parsed.pseudos;
-                if (!parsed.classes && !parsed.attributes && !parsed.pseudos) parsed = null;
-                return Selectors.Cache.parsed[selector] = parsed;
-        },
-
-        parseTagAndID: function(selector){
-                var tag = selector.match(Selectors.RegExps.tag);
-                var id = selector.match(Selectors.RegExps.id);
-                return [(tag) ? tag[1] : '*', (id) ? id[1] : false];
-        },
-
-        filter: function(item, parsed, local){
-                var i;
-                if (parsed.classes){
-                        for (i = parsed.classes.length; i--; i){
-                                var cn = parsed.classes[i];
-                                if (!Selectors.Filters.byClass(item, cn)) return false;
-                        }
-                }
-                if (parsed.attributes){
-                        for (i = parsed.attributes.length; i--; i){
-                                var att = parsed.attributes[i];
-                                if (!Selectors.Filters.byAttribute(item, att.name, att.operator, att.value)) return false;
-                        }
-                }
-                if (parsed.pseudos){
-                        for (i = parsed.pseudos.length; i--; i){
-                                var psd = parsed.pseudos[i];
-                                if (!Selectors.Filters.byPseudo(item, psd.parser, psd.argument, local)) return false;
-                        }
-                }
-                return true;
-        },
-
-        getByTagAndID: function(ctx, tag, id){
-                if (id){
-                        var item = (ctx.getElementById) ? ctx.getElementById(id, true) : Element.getElementById(ctx, id, true);
-                        return (item && Selectors.Filters.byTag(item, tag)) ? [item] : [];
-                } else {
-                        return ctx.getElementsByTagName(tag);
-                }
-        },
-
-        search: function(self, expression, local){
-                var splitters = [];
-
-                var selectors = expression.trim().replace(Selectors.RegExps.splitter, function(m0, m1, m2){
-                        splitters.push(m1);
-                        return ':)' + m2;
-                }).split(':)');
-
-                var items, filtered, item;
-
-                for (var i = 0, l = selectors.length; i < l; i++){
-
-                        var selector = selectors[i];
-
-                        if (i == 0 && Selectors.RegExps.quick.test(selector)){
-                                items = self.getElementsByTagName(selector);
-                                continue;
-                        }
-
-                        var splitter = splitters[i - 1];
-
-                        var tagid = Selectors.Utils.parseTagAndID(selector);
-                        var tag = tagid[0], id = tagid[1];
-
-                        if (i == 0){
-                                items = Selectors.Utils.getByTagAndID(self, tag, id);
-                        } else {
-                                var uniques = {}, found = [];
-                                for (var j = 0, k = items.length; j < k; j++) found = Selectors.Getters[splitter](found, items[j], tag, id, uniques);
-                                items = found;
-                        }
-
-                        var parsed = Selectors.Utils.parseSelector(selector);
-
-                        if (parsed){
-                                filtered = [];
-                                for (var m = 0, n = items.length; m < n; m++){
-                                        item = items[m];
-                                        if (Selectors.Utils.filter(item, parsed, local)) filtered.push(item);
-                                }
-                                items = filtered;
-                        }
-
-                }
-
-                return items;
-
-        }
-
-};
-
-Selectors.Getters = {
-
-        ' ': function(found, self, tag, id, uniques){
-                var items = Selectors.Utils.getByTagAndID(self, tag, id);
-                for (var i = 0, l = items.length; i < l; i++){
-                        var item = items[i];
-                        if (Selectors.Utils.chk(item, uniques)) found.push(item);
-                }
-                return found;
-        },
-
-        '>': function(found, self, tag, id, uniques){
-                var children = Selectors.Utils.getByTagAndID(self, tag, id);
-                for (var i = 0, l = children.length; i < l; i++){
-                        var child = children[i];
-                        if (child.parentNode == self && Selectors.Utils.chk(child, uniques)) found.push(child);
-                }
-                return found;
-        },
-
-        '+': function(found, self, tag, id, uniques){
-                while ((self = self.nextSibling)){
-                        if (self.nodeType == 1){
-                                if (Selectors.Utils.chk(self, uniques) && Selectors.Filters.byTag(self, tag) && Selectors.Filters.byID(self, id)) found.push(self);
-                                break;
-                        }
-                }
-                return found;
-        },
-
-        '~': function(found, self, tag, id, uniques){
-                while ((self = self.nextSibling)){
-                        if (self.nodeType == 1){
-                                if (!Selectors.Utils.chk(self, uniques)) break;
-                                if (Selectors.Filters.byTag(self, tag) && Selectors.Filters.byID(self, id)) found.push(self);
-                        }
-                }
-                return found;
-        }
-
-};
-
-Selectors.Filters = {
-
-        byTag: function(self, tag){
-                return (tag == '*' || (self.tagName && self.tagName.toLowerCase() == tag));
-        },
-
-        byID: function(self, id){
-                return (!id || (self.id && self.id == id));
-        },
-
-        byClass: function(self, klass){
-                return (self.className && self.className.contains(klass, ' '));
-        },
-
-        byPseudo: function(self, parser, argument, local){
-                return parser.call(self, argument, local);
-        },
-
-        byAttribute: function(self, name, operator, value){
-                var result = Element.prototype.getProperty.call(self, name);
-                if (!result) return (operator == '!=');
-                if (!operator || value == undefined) return true;
-                switch (operator){
-                        case '=': return (result == value);
-                        case '*=': return (result.contains(value));
-                        case '^=': return (result.substr(0, value.length) == value);
-                        case '$=': return (result.substr(result.length - value.length) == value);
-                        case '!=': return (result != value);
-                        case '~=': return result.contains(value, ' ');
-                        case '|=': return result.contains(value, '-');
-                }
-                return false;
-        }
-
-};
-
-Selectors.Pseudo = new Hash({
-
-        // w3c pseudo selectors
-
-        checked: function(){
-                return this.checked;
-        },
-
-        empty: function(){
-                return !(this.innerText || this.textContent || '').length;
-        },
-
-        not: function(selector){
-                return !Element.match(this, selector);
-        },
-
-        contains: function(text){
-                return (this.innerText || this.textContent || '').contains(text);
-        },
-
-        'first-child': function(){
-                return Selectors.Pseudo.index.call(this, 0);
-        },
-
-        'last-child': function(){
-                var element = this;
-                while ((element = element.nextSibling)){
-                        if (element.nodeType == 1) return false;
-                }
-                return true;
-        },
-
-        'only-child': function(){
-                var prev = this;
-                while ((prev = prev.previousSibling)){
-                        if (prev.nodeType == 1) return false;
-                }
-                var next = this;
-                while ((next = next.nextSibling)){
-                        if (next.nodeType == 1) return false;
-                }
-                return true;
-        },
-
-        'nth-child': function(argument, local){
-                argument = (argument == undefined) ? 'n' : argument;
-                var parsed = Selectors.Utils.parseNthArgument(argument);
-                if (parsed.special != 'n') return Selectors.Pseudo[parsed.special].call(this, parsed.a, local);
-                var count = 0;
-                local.positions = local.positions || {};
-                var uid = $uid(this);
-                if (!local.positions[uid]){
-                        var self = this;
-                        while ((self = self.previousSibling)){
-                                if (self.nodeType != 1) continue;
-                                count ++;
-                                var position = local.positions[$uid(self)];
-                                if (position != undefined){
-                                        count = position + count;
-                                        break;
-                                }
-                        }
-                        local.positions[uid] = count;
-                }
-                return (local.positions[uid] % parsed.a == parsed.b);
-        },
-
-        // custom pseudo selectors
-
-        index: function(index){
-                var element = this, count = 0;
-                while ((element = element.previousSibling)){
-                        if (element.nodeType == 1 && ++count > index) return false;
-                }
-                return (count == index);
-        },
-
-        even: function(argument, local){
-                return Selectors.Pseudo['nth-child'].call(this, '2n+1', local);
-        },
-
-        odd: function(argument, local){
-                return Selectors.Pseudo['nth-child'].call(this, '2n', local);
-        }
-
-});
-
-
-/*
-Script: Domready.js
-        Contains the domready custom event.
-
-License:
-        MIT-style license.
-*/
-
-Element.Events.domready = {
-
-        onAdd: function(fn){
-                if (Browser.loaded) fn.call(this);
-        }
-
-};
-
-(function(){
-
-        var domready = function(){
-                if (Browser.loaded) return;
-                Browser.loaded = true;
-                window.fireEvent('domready');
-                document.fireEvent('domready');
-        };
-
-        if (Browser.Engine.trident){
-                var temp = document.createElement('div');
-                (function(){
-                        ($try(function(){
-                                temp.doScroll('left');
-                                return $(temp).inject(document.body).set('html', 'temp').dispose();
-                        })) ? domready() : arguments.callee.delay(50);
-                })();
-        } else if (Browser.Engine.webkit && Browser.Engine.version < 525){
-                (function(){
-                        (['loaded', 'complete'].contains(document.readyState)) ? domready() : arguments.callee.delay(50);
-                })();
-        } else {
-                window.addEvent('load', domready);
-                document.addEvent('DOMContentLoaded', domready);
-        }
-
-})();
-
-
-/*
-Script: JSON.js
-        JSON encoder and decoder.
-
-License:
-        MIT-style license.
-
-See Also:
-        <http://www.json.org/>
-*/
-
-var JSON = new Hash({
-
-        $specialChars: {'\b': '\\b', '\t': '\\t', '\n': '\\n', '\f': '\\f', '\r': '\\r', '"' : '\\"', '\\': '\\\\'},
-
-        $replaceChars: function(chr){
-                return JSON.$specialChars[chr] || '\\u00' + Math.floor(chr.charCodeAt() / 16).toString(16) + (chr.charCodeAt() % 16).toString(16);
-        },
-
-        encode: function(obj){
-                switch ($type(obj)){
-                        case 'string':
-                                return '"' + obj.replace(/[\x00-\x1f\\"]/g, JSON.$replaceChars) + '"';
-                        case 'array':
-                                return '[' + String(obj.map(JSON.encode).filter($defined)) + ']';
-                        case 'object': case 'hash':
-                                var string = [];
-                                Hash.each(obj, function(value, key){
-                                        var json = JSON.encode(value);
-                                        if (json) string.push(JSON.encode(key) + ':' + json);
-                                });
-                                return '{' + string + '}';
-                        case 'number': case 'boolean': return String(obj);
-                        case false: return 'null';
-                }
-                return null;
-        },
-
-        decode: function(string, secure){
-                if ($type(string) != 'string' || !string.length) return null;
-                if (secure && !(/^[,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t]*$/).test(string.replace(/\\./g, '@').replace(/"[^"\\\n\r]*"/g, ''))) return null;
-                return eval('(' + string + ')');
-        }
-
-});
-
-Native.implement([Hash, Array, String, Number], {
-
-        toJSON: function(){
-                return JSON.encode(this);
-        }
-
-});
-
-
-/*
-Script: Cookie.js
-        Class for creating, loading, and saving browser Cookies.
-
-License:
-        MIT-style license.
-
-Credits:
-        Based on the functions by Peter-Paul Koch (http://quirksmode.org).
-*/
-
-var Cookie = new Class({
-
-        Implements: Options,
-
-        options: {
-                path: false,
-                domain: false,
-                duration: false,
-                secure: false,
-                document: document
-        },
-
-        initialize: function(key, options){
-                this.key = key;
-                this.setOptions(options);
-        },
-
-        write: function(value){
-                value = encodeURIComponent(value);
-                if (this.options.domain) value += '; domain=' + this.options.domain;
-                if (this.options.path) value += '; path=' + this.options.path;
-                if (this.options.duration){
-                        var date = new Date();
-                        date.setTime(date.getTime() + this.options.duration * 24 * 60 * 60 * 1000);
-                        value += '; expires=' + date.toGMTString();
-                }
-                if (this.options.secure) value += '; secure';
-                this.options.document.cookie = this.key + '=' + value;
-                return this;
-        },
-
-        read: function(){
-                var value = this.options.document.cookie.match('(?:^|;)\\s*' + this.key.escapeRegExp() + '=([^;]*)');
-                return (value) ? decodeURIComponent(value[1]) : null;
-        },
-
-        dispose: function(){
-                new Cookie(this.key, $merge(this.options, {duration: -1})).write('');
-                return this;
-        }
-
-});
-
-Cookie.write = function(key, value, options){
-        return new Cookie(key, options).write(value);
-};
-
-Cookie.read = function(key){
-        return new Cookie(key).read();
-};
-
-Cookie.dispose = function(key, options){
-        return new Cookie(key, options).dispose();
-};
-
-
-/*
-Script: Swiff.js
-        Wrapper for embedding SWF movies. Supports (and fixes) External Interface Communication.
-
-License:
-        MIT-style license.
-
-Credits:
-        Flash detection & Internet Explorer + Flash Player 9 fix inspired by SWFObject.
-*/
-
-var Swiff = new Class({
-
-        Implements: [Options],
-
-        options: {
-                id: null,
-                height: 1,
-                width: 1,
-                container: null,
-                properties: {},
-                params: {
-                        quality: 'high',
-                        allowScriptAccess: 'always',
-                        wMode: 'transparent',
-                        swLiveConnect: true
-                },
-                callBacks: {},
-                vars: {}
-        },
-
-        toElement: function(){
-                return this.object;
-        },
-
-        initialize: function(path, options){
-                this.instance = 'Swiff_' + $time();
-
-                this.setOptions(options);
-                options = this.options;
-                var id = this.id = options.id || this.instance;
-                var container = $(options.container);
-
-                Swiff.CallBacks[this.instance] = {};
-
-                var params = options.params, vars = options.vars, callBacks = options.callBacks;
-                var properties = $extend({height: options.height, width: options.width}, options.properties);
-
-                var self = this;
-
-                for (var callBack in callBacks){
-                        Swiff.CallBacks[this.instance][callBack] = (function(option){
-                                return function(){
-                                        return option.apply(self.object, arguments);
-                                };
-                        })(callBacks[callBack]);
-                        vars[callBack] = 'Swiff.CallBacks.' + this.instance + '.' + callBack;
-                }
-
-                params.flashVars = Hash.toQueryString(vars);
-                if (Browser.Engine.trident){
-                        properties.classid = 'clsid:D27CDB6E-AE6D-11cf-96B8-444553540000';
-                        params.movie = path;
-                } else {
-                        properties.type = 'application/x-shockwave-flash';
-                        properties.data = path;
-                }
-                var build = '<object id="' + id + '"';
-                for (var property in properties) build += ' ' + property + '="' + properties[property] + '"';
-                build += '>';
-                for (var param in params){
-                        if (params[param]) build += '<param name="' + param + '" value="' + params[param] + '" />';
-                }
-                build += '</object>';
-                this.object = ((container) ? container.empty() : new Element('div')).set('html', build).firstChild;
-        },
-
-        replaces: function(element){
-                element = $(element, true);
-                element.parentNode.replaceChild(this.toElement(), element);
-                return this;
-        },
-
-        inject: function(element){
-                $(element, true).appendChild(this.toElement());
-                return this;
-        },
-
-        remote: function(){
-                return Swiff.remote.apply(Swiff, [this.toElement()].extend(arguments));
-        }
-
-});
-
-Swiff.CallBacks = {};
-
-Swiff.remote = function(obj, fn){
-        var rs = obj.CallFunction('<invoke name="' + fn + '" returntype="javascript">' + __flash__argumentsToXML(arguments, 2) + '</invoke>');
-        return eval(rs);
-};
-
-
-/*
-Script: Fx.js
-        Contains the basic animation logic to be extended by all other Fx Classes.
-
-License:
-        MIT-style license.
-*/
-
-var Fx = new Class({
-
-        Implements: [Chain, Events, Options],
-
-        options: {
-                /*
-                onStart: $empty,
-                onCancel: $empty,
-                onComplete: $empty,
-                */
-                fps: 50,
-                unit: false,
-                duration: 500,
-                link: 'ignore'
-        },
-
-        initialize: function(options){
-                this.subject = this.subject || this;
-                this.setOptions(options);
-                this.options.duration = Fx.Durations[this.options.duration] || this.options.duration.toInt();
-                var wait = this.options.wait;
-                if (wait === false) this.options.link = 'cancel';
-        },
-
-        getTransition: function(){
-                return function(p){
-                        return -(Math.cos(Math.PI * p) - 1) / 2;
-                };
-        },
-
-        step: function(){
-                var time = $time();
-                if (time < this.time + this.options.duration){
-                        var delta = this.transition((time - this.time) / this.options.duration);
-                        this.set(this.compute(this.from, this.to, delta));
-                } else {
-                        this.set(this.compute(this.from, this.to, 1));
-                        this.complete();
-                }
-        },
-
-        set: function(now){
-                return now;
-        },
-
-        compute: function(from, to, delta){
-                return Fx.compute(from, to, delta);
-        },
-
-        check: function(caller){
-                if (!this.timer) return true;
-                switch (this.options.link){
-                        case 'cancel': this.cancel(); return true;
-                        case 'chain': this.chain(caller.bind(this, Array.slice(arguments, 1))); return false;
-                }
-                return false;
-        },
-
-        start: function(from, to){
-                if (!this.check(arguments.callee, from, to)) return this;
-                this.from = from;
-                this.to = to;
-                this.time = 0;
-                this.transition = this.getTransition();
-                this.startTimer();
-                this.onStart();
-                return this;
-        },
-
-        complete: function(){
-                if (this.stopTimer()) this.onComplete();
-                return this;
-        },
-
-        cancel: function(){
-                if (this.stopTimer()) this.onCancel();
-                return this;
-        },
-
-        onStart: function(){
-                this.fireEvent('start', this.subject);
-        },
-
-        onComplete: function(){
-                this.fireEvent('complete', this.subject);
-                if (!this.callChain()) this.fireEvent('chainComplete', this.subject);
-        },
-
-        onCancel: function(){
-                this.fireEvent('cancel', this.subject).clearChain();
-        },
-
-        pause: function(){
-                this.stopTimer();
-                return this;
-        },
-
-        resume: function(){
-                this.startTimer();
-                return this;
-        },
-
-        stopTimer: function(){
-                if (!this.timer) return false;
-                this.time = $time() - this.time;
-                this.timer = $clear(this.timer);
-                return true;
-        },
-
-        startTimer: function(){
-                if (this.timer) return false;
-                this.time = $time() - this.time;
-                this.timer = this.step.periodical(Math.round(1000 / this.options.fps), this);
-                return true;
-        }
-
-});
-
-Fx.compute = function(from, to, delta){
-        return (to - from) * delta + from;
-};
-
-Fx.Durations = {'short': 250, 'normal': 500, 'long': 1000};
-
-
-/*
-Script: Fx.CSS.js
-        Contains the CSS animation logic. Used by Fx.Tween, Fx.Morph, Fx.Elements.
-
-License:
-        MIT-style license.
-*/
-
-Fx.CSS = new Class({
-
-        Extends: Fx,
-
-        //prepares the base from/to object
-
-        prepare: function(element, property, values){
-                values = $splat(values);
-                var values1 = values[1];
-                if (!$chk(values1)){
-                        values[1] = values[0];
-                        values[0] = element.getStyle(property);
-                }
-                var parsed = values.map(this.parse);
-                return {from: parsed[0], to: parsed[1]};
-        },
-
-        //parses a value into an array
-
-        parse: function(value){
-                value = $lambda(value)();
-                value = (typeof value == 'string') ? value.split(' ') : $splat(value);
-                return value.map(function(val){
-                        val = String(val);
-                        var found = false;
-                        Fx.CSS.Parsers.each(function(parser, key){
-                                if (found) return;
-                                var parsed = parser.parse(val);
-                                if ($chk(parsed)) found = {value: parsed, parser: parser};
-                        });
-                        found = found || {value: val, parser: Fx.CSS.Parsers.String};
-                        return found;
-                });
-        },
-
-        //computes by a from and to prepared objects, using their parsers.
-
-        compute: function(from, to, delta){
-                var computed = [];
-                (Math.min(from.length, to.length)).times(function(i){
-                        computed.push({value: from[i].parser.compute(from[i].value, to[i].value, delta), parser: from[i].parser});
-                });
-                computed.$family = {name: 'fx:css:value'};
-                return computed;
-        },
-
-        //serves the value as settable
-
-        serve: function(value, unit){
-                if ($type(value) != 'fx:css:value') value = this.parse(value);
-                var returned = [];
-                value.each(function(bit){
-                        returned = returned.concat(bit.parser.serve(bit.value, unit));
-                });
-                return returned;
-        },
-
-        //renders the change to an element
-
-        render: function(element, property, value, unit){
-                element.setStyle(property, this.serve(value, unit));
-        },
-
-        //searches inside the page css to find the values for a selector
-
-        search: function(selector){
-                if (Fx.CSS.Cache[selector]) return Fx.CSS.Cache[selector];
-                var to = {};
-                Array.each(document.styleSheets, function(sheet, j){
-                        var href = sheet.href;
-                        if (href && href.contains('://') && !href.contains(document.domain)) return;
-                        var rules = sheet.rules || sheet.cssRules;
-                        Array.each(rules, function(rule, i){
-                                if (!rule.style) return;
-                                var selectorText = (rule.selectorText) ? rule.selectorText.replace(/^\w+/, function(m){
-                                        return m.toLowerCase();
-                                }) : null;
-                                if (!selectorText || !selectorText.test('^' + selector + '$')) return;
-                                Element.Styles.each(function(value, style){
-                                        if (!rule.style[style] || Element.ShortStyles[style]) return;
-                                        value = String(rule.style[style]);
-                                        to[style] = (value.test(/^rgb/)) ? value.rgbToHex() : value;
-                                });
-                        });
-                });
-                return Fx.CSS.Cache[selector] = to;
-        }
-
-});
-
-Fx.CSS.Cache = {};
-
-Fx.CSS.Parsers = new Hash({
-
-        Color: {
-                parse: function(value){
-                        if (value.match(/^#[0-9a-f]{3,6}$/i)) return value.hexToRgb(true);
-                        return ((value = value.match(/(\d+),\s*(\d+),\s*(\d+)/))) ? [value[1], value[2], value[3]] : false;
-                },
-                compute: function(from, to, delta){
-                        return from.map(function(value, i){
-                                return Math.round(Fx.compute(from[i], to[i], delta));
-                        });
-                },
-                serve: function(value){
-                        return value.map(Number);
-                }
-        },
-
-        Number: {
-                parse: parseFloat,
-                compute: Fx.compute,
-                serve: function(value, unit){
-                        return (unit) ? value + unit : value;
-                }
-        },
-
-        String: {
-                parse: $lambda(false),
-                compute: $arguments(1),
-                serve: $arguments(0)
-        }
-
-});
-
-
-/*
-Script: Fx.Tween.js
-        Formerly Fx.Style, effect to transition any CSS property for an element.
-
-License:
-        MIT-style license.
-*/
-
-Fx.Tween = new Class({
-
-        Extends: Fx.CSS,
-
-        initialize: function(element, options){
-                this.element = this.subject = $(element);
-                this.parent(options);
-        },
-
-        set: function(property, now){
-                if (arguments.length == 1){
-                        now = property;
-                        property = this.property || this.options.property;
-                }
-                this.render(this.element, property, now, this.options.unit);
-                return this;
-        },
-
-        start: function(property, from, to){
-                if (!this.check(arguments.callee, property, from, to)) return this;
-                var args = Array.flatten(arguments);
-                this.property = this.options.property || args.shift();
-                var parsed = this.prepare(this.element, this.property, args);
-                return this.parent(parsed.from, parsed.to);
-        }
-
-});
-
-Element.Properties.tween = {
-
-        set: function(options){
-                var tween = this.retrieve('tween');
-                if (tween) tween.cancel();
-                return this.eliminate('tween').store('tween:options', $extend({link: 'cancel'}, options));
-        },
-
-        get: function(options){
-                if (options || !this.retrieve('tween')){
-                        if (options || !this.retrieve('tween:options')) this.set('tween', options);
-                        this.store('tween', new Fx.Tween(this, this.retrieve('tween:options')));
-                }
-                return this.retrieve('tween');
-        }
-
-};
-
-Element.implement({
-
-        tween: function(property, from, to){
-                this.get('tween').start(arguments);
-                return this;
-        },
-
-        fade: function(how){
-                var fade = this.get('tween'), o = 'opacity', toggle;
-                how = $pick(how, 'toggle');
-                switch (how){
-                        case 'in': fade.start(o, 1); break;
-                        case 'out': fade.start(o, 0); break;
-                        case 'show': fade.set(o, 1); break;
-                        case 'hide': fade.set(o, 0); break;
-                        case 'toggle':
-                                var flag = this.retrieve('fade:flag', this.get('opacity') == 1);
-                                fade.start(o, (flag) ? 0 : 1);
-                                this.store('fade:flag', !flag);
-                                toggle = true;
-                        break;
-                        default: fade.start(o, arguments);
-                }
-                if (!toggle) this.eliminate('fade:flag');
-                return this;
-        },
-
-        highlight: function(start, end){
-                if (!end){
-                        end = this.retrieve('highlight:original', this.getStyle('background-color'));
-                        end = (end == 'transparent') ? '#fff' : end;
-                }
-                var tween = this.get('tween');
-                tween.start('background-color', start || '#ffff88', end).chain(function(){
-                        this.setStyle('background-color', this.retrieve('highlight:original'));
-                        tween.callChain();
-                }.bind(this));
-                return this;
-        }
-
-});
-
-
-/*
-Script: Fx.Morph.js
-        Formerly Fx.Styles, effect to transition any number of CSS properties for an element using an object of rules, or CSS based selector rules.
-
-License:
-        MIT-style license.
-*/
-
-Fx.Morph = new Class({
-
-        Extends: Fx.CSS,
-
-        initialize: function(element, options){
-                this.element = this.subject = $(element);
-                this.parent(options);
-        },
-
-        set: function(now){
-                if (typeof now == 'string') now = this.search(now);
-                for (var p in now) this.render(this.element, p, now[p], this.options.unit);
-                return this;
-        },
-
-        compute: function(from, to, delta){
-                var now = {};
-                for (var p in from) now[p] = this.parent(from[p], to[p], delta);
-                return now;
-        },
-
-        start: function(properties){
-                if (!this.check(arguments.callee, properties)) return this;
-                if (typeof properties == 'string') properties = this.search(properties);
-                var from = {}, to = {};
-                for (var p in properties){
-                        var parsed = this.prepare(this.element, p, properties[p]);
-                        from[p] = parsed.from;
-                        to[p] = parsed.to;
-                }
-                return this.parent(from, to);
-        }
-
-});
-
-Element.Properties.morph = {
-
-        set: function(options){
-                var morph = this.retrieve('morph');
-                if (morph) morph.cancel();
-                return this.eliminate('morph').store('morph:options', $extend({link: 'cancel'}, options));
-        },
-
-        get: function(options){
-                if (options || !this.retrieve('morph')){
-                        if (options || !this.retrieve('morph:options')) this.set('morph', options);
-                        this.store('morph', new Fx.Morph(this, this.retrieve('morph:options')));
-                }
-                return this.retrieve('morph');
-        }
-
-};
-
-Element.implement({
-
-        morph: function(props){
-                this.get('morph').start(props);
-                return this;
-        }
-
-});
-
-
-/*
-Script: Fx.Transitions.js
-        Contains a set of advanced transitions to be used with any of the Fx Classes.
-
-License:
-        MIT-style license.
-
-Credits:
-        Easing Equations by Robert Penner, <http://www.robertpenner.com/easing/>, modified and optimized to be used with MooTools.
-*/
-
-Fx.implement({
-
-        getTransition: function(){
-                var trans = this.options.transition || Fx.Transitions.Sine.easeInOut;
-                if (typeof trans == 'string'){
-                        var data = trans.split(':');
-                        trans = Fx.Transitions;
-                        trans = trans[data[0]] || trans[data[0].capitalize()];
-                        if (data[1]) trans = trans['ease' + data[1].capitalize() + (data[2] ? data[2].capitalize() : '')];
-                }
-                return trans;
-        }
-
-});
-
-Fx.Transition = function(transition, params){
-        params = $splat(params);
-        return $extend(transition, {
-                easeIn: function(pos){
-                        return transition(pos, params);
-                },
-                easeOut: function(pos){
-                        return 1 - transition(1 - pos, params);
-                },
-                easeInOut: function(pos){
-                        return (pos <= 0.5) ? transition(2 * pos, params) / 2 : (2 - transition(2 * (1 - pos), params)) / 2;
-                }
-        });
-};
-
-Fx.Transitions = new Hash({
-
-        linear: $arguments(0)
-
-});
-
-Fx.Transitions.extend = function(transitions){
-        for (var transition in transitions) Fx.Transitions[transition] = new Fx.Transition(transitions[transition]);
-};
-
-Fx.Transitions.extend({
-
-        Pow: function(p, x){
-                return Math.pow(p, x[0] || 6);
-        },
-
-        Expo: function(p){
-                return Math.pow(2, 8 * (p - 1));
-        },
-
-        Circ: function(p){
-                return 1 - Math.sin(Math.acos(p));
-        },
-
-        Sine: function(p){
-                return 1 - Math.sin((1 - p) * Math.PI / 2);
-        },
-
-        Back: function(p, x){
-                x = x[0] || 1.618;
-                return Math.pow(p, 2) * ((x + 1) * p - x);
-        },
-
-        Bounce: function(p){
-                var value;
-                for (var a = 0, b = 1; 1; a += b, b /= 2){
-                        if (p >= (7 - 4 * a) / 11){
-                                value = b * b - Math.pow((11 - 6 * a - 11 * p) / 4, 2);
-                                break;
-                        }
-                }
-                return value;
-        },
-
-        Elastic: function(p, x){
-                return Math.pow(2, 10 * --p) * Math.cos(20 * p * Math.PI * (x[0] || 1) / 3);
-        }
-
-});
-
-['Quad', 'Cubic', 'Quart', 'Quint'].each(function(transition, i){
-        Fx.Transitions[transition] = new Fx.Transition(function(p){
-                return Math.pow(p, [i + 2]);
-        });
-});
-
-
-/*
-Script: Request.js
-        Powerful all purpose Request Class. Uses XMLHTTPRequest.
-
-License:
-        MIT-style license.
-*/
-
-var Request = new Class({
-
-        Implements: [Chain, Events, Options],
-
-        options: {/*
-                onRequest: $empty,
-                onComplete: $empty,
-                onCancel: $empty,
-                onSuccess: $empty,
-                onFailure: $empty,
-                onException: $empty,*/
-                url: '',
-                data: '',
-                headers: {
-                        'X-Requested-With': 'XMLHttpRequest',
-                        'Accept': 'text/javascript, text/html, application/xml, text/xml, */*'
-                },
-                async: true,
-                format: false,
-                method: 'post',
-                link: 'ignore',
-                isSuccess: null,
-                emulation: true,
-                urlEncoded: true,
-                encoding: 'utf-8',
-                evalScripts: false,
-                evalResponse: false
-        },
-
-        initialize: function(options){
-                this.xhr = new Browser.Request();
-                this.setOptions(options);
-                this.options.isSuccess = this.options.isSuccess || this.isSuccess;
-                this.headers = new Hash(this.options.headers);
-        },
-
-        onStateChange: function(){
-                if (this.xhr.readyState != 4 || !this.running) return;
-                this.running = false;
-                this.status = 0;
-                $try(function(){
-                        this.status = this.xhr.status;
-                }.bind(this));
-                if (this.options.isSuccess.call(this, this.status)){
-                        this.response = {text: this.xhr.responseText, xml: this.xhr.responseXML};
-                        this.success(this.response.text, this.response.xml);
-                } else {
-                        this.response = {text: null, xml: null};
-                        this.failure();
-                }
-                this.xhr.onreadystatechange = $empty;
-        },
-
-        isSuccess: function(){
-                return ((this.status >= 200) && (this.status < 300));
-        },
-
-        processScripts: function(text){
-                if (this.options.evalResponse || (/(ecma|java)script/).test(this.getHeader('Content-type'))) return $exec(text);
-                return text.stripScripts(this.options.evalScripts);
-        },
-
-        success: function(text, xml){
-                this.onSuccess(this.processScripts(text), xml);
-        },
-
-        onSuccess: function(){
-                this.fireEvent('complete', arguments).fireEvent('success', arguments).callChain();
-        },
-
-        failure: function(){
-                this.onFailure();
-        },
-
-        onFailure: function(){
-                this.fireEvent('complete').fireEvent('failure', this.xhr);
-        },
-
-        setHeader: function(name, value){
-                this.headers.set(name, value);
-                return this;
-        },
-
-        getHeader: function(name){
-                return $try(function(){
-                        return this.xhr.getResponseHeader(name);
-                }.bind(this));
-        },
-
-        check: function(caller){
-                if (!this.running) return true;
-                switch (this.options.link){
-                        case 'cancel': this.cancel(); return true;
-                        case 'chain': this.chain(caller.bind(this, Array.slice(arguments, 1))); return false;
-                }
-                return false;
-        },
-
-        send: function(options){
-                if (!this.check(arguments.callee, options)) return this;
-                this.running = true;
-
-                var type = $type(options);
-                if (type == 'string' || type == 'element') options = {data: options};
-
-                var old = this.options;
-                options = $extend({data: old.data, url: old.url, method: old.method}, options);
-                var data = options.data, url = options.url, method = options.method;
-
-                switch ($type(data)){
-                        case 'element': data = $(data).toQueryString(); break;
-                        case 'object': case 'hash': data = Hash.toQueryString(data);
-                }
-
-                if (this.options.format){
-                        var format = 'format=' + this.options.format;
-                        data = (data) ? format + '&' + data : format;
-                }
-
-                if (this.options.emulation && ['put', 'delete'].contains(method)){
-                        var _method = '_method=' + method;
-                        data = (data) ? _method + '&' + data : _method;
-                        method = 'post';
-                }
-
-                if (this.options.urlEncoded && method == 'post'){
-                        var encoding = (this.options.encoding) ? '; charset=' + this.options.encoding : '';
-                        this.headers.set('Content-type', 'application/x-www-form-urlencoded' + encoding);
-                }
-
-                if (data && method == 'get'){
-                        url = url + (url.contains('?') ? '&' : '?') + data;
-                        data = null;
-                }
-
-                this.xhr.open(method.toUpperCase(), url, this.options.async);
-
-                this.xhr.onreadystatechange = this.onStateChange.bind(this);
-
-                this.headers.each(function(value, key){
-                        try {
-                                this.xhr.setRequestHeader(key, value);
-                        } catch (e){
-                                this.fireEvent('exception', [key, value]);
-                        }
-                }, this);
-
-                this.fireEvent('request');
-                this.xhr.send(data);
-                if (!this.options.async) this.onStateChange();
-                return this;
-        },
-
-        cancel: function(){
-                if (!this.running) return this;
-                this.running = false;
-                this.xhr.abort();
-                this.xhr.onreadystatechange = $empty;
-                this.xhr = new Browser.Request();
-                this.fireEvent('cancel');
-                return this;
-        }
-
-});
-
-(function(){
-
-var methods = {};
-['get', 'post', 'put', 'delete', 'GET', 'POST', 'PUT', 'DELETE'].each(function(method){
-        methods[method] = function(){
-                var params = Array.link(arguments, {url: String.type, data: $defined});
-                return this.send($extend(params, {method: method.toLowerCase()}));
-        };
-});
-
-Request.implement(methods);
-
-})();
-
-Element.Properties.send = {
-
-        set: function(options){
-                var send = this.retrieve('send');
-                if (send) send.cancel();
-                return this.eliminate('send').store('send:options', $extend({
-                        data: this, link: 'cancel', method: this.get('method') || 'post', url: this.get('action')
-                }, options));
-        },
-
-        get: function(options){
-                if (options || !this.retrieve('send')){
-                        if (options || !this.retrieve('send:options')) this.set('send', options);
-                        this.store('send', new Request(this.retrieve('send:options')));
-                }
-                return this.retrieve('send');
-        }
-
-};
-
-Element.implement({
-
-        send: function(url){
-                var sender = this.get('send');
-                sender.send({data: this, url: url || sender.options.url});
-                return this;
-        }
-
-});
-
-
-/*
-Script: Request.HTML.js
-        Extends the basic Request Class with additional methods for interacting with HTML responses.
-
-License:
-        MIT-style license.
-*/
-
-Request.HTML = new Class({
-
-        Extends: Request,
-
-        options: {
-                update: false,
-                evalScripts: true,
-                filter: false
-        },
-
-        processHTML: function(text){
-                var match = text.match(/<body[^>]*>([\s\S]*?)<\/body>/i);
-                text = (match) ? match[1] : text;
-
-                var container = new Element('div');
-
-                return $try(function(){
-                        var root = '<root>' + text + '</root>', doc;
-                        if (Browser.Engine.trident){
-                                doc = new ActiveXObject('Microsoft.XMLDOM');
-                                doc.async = false;
-                                doc.loadXML(root);
-                        } else {
-                                doc = new DOMParser().parseFromString(root, 'text/xml');
-                        }
-                        root = doc.getElementsByTagName('root')[0];
-                        for (var i = 0, k = root.childNodes.length; i < k; i++){
-                                var child = Element.clone(root.childNodes[i], true, true);
-                                if (child) container.grab(child);
-                        }
-                        return container;
-                }) || container.set('html', text);
-        },
-
-        success: function(text){
-                var options = this.options, response = this.response;
-
-                response.html = text.stripScripts(function(script){
-                        response.javascript = script;
-                });
-
-                var temp = this.processHTML(response.html);
-
-                response.tree = temp.childNodes;
-                response.elements = temp.getElements('*');
-
-                if (options.filter) response.tree = response.elements.filter(options.filter);
-                if (options.update) $(options.update).empty().set('html', response.html);
-                if (options.evalScripts) $exec(response.javascript);
-
-                this.onSuccess(response.tree, response.elements, response.html, response.javascript);
-        }
-
-});
-
-Element.Properties.load = {
-
-        set: function(options){
-                var load = this.retrieve('load');
-                if (load) load.cancel();
-                return this.eliminate('load').store('load:options', $extend({data: this, link: 'cancel', update: this, method: 'get'}, options));
-        },
-
-        get: function(options){
-                if (options || ! this.retrieve('load')){
-                        if (options || !this.retrieve('load:options')) this.set('load', options);
-                        this.store('load', new Request.HTML(this.retrieve('load:options')));
-                }
-                return this.retrieve('load');
-        }
-
-};
-
-Element.implement({
-
-        load: function(){
-                this.get('load').send(Array.link(arguments, {data: Object.type, url: String.type}));
-                return this;
-        }
-
-});
-
-
-/*
-Script: Request.JSON.js
-        Extends the basic Request Class with additional methods for sending and receiving JSON data.
-
-License:
-        MIT-style license.
-*/
-
-Request.JSON = new Class({
-
-        Extends: Request,
-
-        options: {
-                secure: true
-        },
-
-        initialize: function(options){
-                this.parent(options);
-                this.headers.extend({'Accept': 'application/json', 'X-Request': 'JSON'});
-        },
-
-        success: function(text){
-                this.response.json = JSON.decode(text, this.options.secure);
-                this.onSuccess(this.response.json, text);
-        }
-
-});
diff --git a/PerformanceTests/Dromaeo/resources/dromaeo/web/lib/prototype-1.7.js b/PerformanceTests/Dromaeo/resources/dromaeo/web/lib/prototype-1.7.js
new file mode 100644 (file)
index 0000000..42c3d75
--- /dev/null
@@ -0,0 +1,6082 @@
+/*  Prototype JavaScript framework, version 1.7
+ *  (c) 2005-2010 Sam Stephenson
+ *
+ *  Prototype is freely distributable under the terms of an MIT-style license.
+ *  For details, see the Prototype web site: http://www.prototypejs.org/
+ *
+ *--------------------------------------------------------------------------*/
+
+var Prototype = {
+
+  Version: '1.7',
+
+  Browser: (function(){
+    var ua = navigator.userAgent;
+    var isOpera = Object.prototype.toString.call(window.opera) == '[object Opera]';
+    return {
+      IE:             !!window.attachEvent && !isOpera,
+      Opera:          isOpera,
+      WebKit:         ua.indexOf('AppleWebKit/') > -1,
+      Gecko:          ua.indexOf('Gecko') > -1 && ua.indexOf('KHTML') === -1,
+      MobileSafari:   /Apple.*Mobile/.test(ua)
+    }
+  })(),
+
+  BrowserFeatures: {
+    XPath: !!document.evaluate,
+
+    SelectorsAPI: !!document.querySelector,
+
+    ElementExtensions: (function() {
+      var constructor = window.Element || window.HTMLElement;
+      return !!(constructor && constructor.prototype);
+    })(),
+    SpecificElementExtensions: (function() {
+      if (typeof window.HTMLDivElement !== 'undefined')
+        return true;
+
+      var div = document.createElement('div'),
+          form = document.createElement('form'),
+          isSupported = false;
+
+      if (div['__proto__'] && (div['__proto__'] !== form['__proto__'])) {
+        isSupported = true;
+      }
+
+      div = form = null;
+
+      return isSupported;
+    })()
+  },
+
+  ScriptFragment: '<script[^>]*>([\\S\\s]*?)<\/script>',
+  JSONFilter: /^\/\*-secure-([\s\S]*)\*\/\s*$/,
+
+  emptyFunction: function() { },
+
+  K: function(x) { return x }
+};
+
+if (Prototype.Browser.MobileSafari)
+  Prototype.BrowserFeatures.SpecificElementExtensions = false;
+
+
+var Abstract = { };
+
+
+var Try = {
+  these: function() {
+    var returnValue;
+
+    for (var i = 0, length = arguments.length; i < length; i++) {
+      var lambda = arguments[i];
+      try {
+        returnValue = lambda();
+        break;
+      } catch (e) { }
+    }
+
+    return returnValue;
+  }
+};
+
+/* Based on Alex Arnell's inheritance implementation. */
+
+var Class = (function() {
+
+  var IS_DONTENUM_BUGGY = (function(){
+    for (var p in { toString: 1 }) {
+      if (p === 'toString') return false;
+    }
+    return true;
+  })();
+
+  function subclass() {};
+  function create() {
+    var parent = null, properties = $A(arguments);
+    if (Object.isFunction(properties[0]))
+      parent = properties.shift();
+
+    function klass() {
+      this.initialize.apply(this, arguments);
+    }
+
+    Object.extend(klass, Class.Methods);
+    klass.superclass = parent;
+    klass.subclasses = [];
+
+    if (parent) {
+      subclass.prototype = parent.prototype;
+      klass.prototype = new subclass;
+      parent.subclasses.push(klass);
+    }
+
+    for (var i = 0, length = properties.length; i < length; i++)
+      klass.addMethods(properties[i]);
+
+    if (!klass.prototype.initialize)
+      klass.prototype.initialize = Prototype.emptyFunction;
+
+    klass.prototype.constructor = klass;
+    return klass;
+  }
+
+  function addMethods(source) {
+    var ancestor   = this.superclass && this.superclass.prototype,
+        properties = Object.keys(source);
+
+    if (IS_DONTENUM_BUGGY) {
+      if (source.toString != Object.prototype.toString)
+        properties.push("toString");
+      if (source.valueOf != Object.prototype.valueOf)
+        properties.push("valueOf");
+    }
+
+    for (var i = 0, length = properties.length; i < length; i++) {
+      var property = properties[i], value = source[property];
+      if (ancestor && Object.isFunction(value) &&
+          value.argumentNames()[0] == "$super") {
+        var method = value;
+        value = (function(m) {
+          return function() { return ancestor[m].apply(this, arguments); };
+        })(property).wrap(method);
+
+        value.valueOf = method.valueOf.bind(method);
+        value.toString = method.toString.bind(method);
+      }
+      this.prototype[property] = value;
+    }
+
+    return this;
+  }
+
+  return {
+    create: create,
+    Methods: {
+      addMethods: addMethods
+    }
+  };
+})();
+(function() {
+
+  var _toString = Object.prototype.toString,
+      NULL_TYPE = 'Null',
+      UNDEFINED_TYPE = 'Undefined',
+      BOOLEAN_TYPE = 'Boolean',
+      NUMBER_TYPE = 'Number',
+      STRING_TYPE = 'String',
+      OBJECT_TYPE = 'Object',
+      FUNCTION_CLASS = '[object Function]',
+      BOOLEAN_CLASS = '[object Boolean]',
+      NUMBER_CLASS = '[object Number]',
+      STRING_CLASS = '[object String]',
+      ARRAY_CLASS = '[object Array]',
+      DATE_CLASS = '[object Date]',
+      NATIVE_JSON_STRINGIFY_SUPPORT = window.JSON &&
+        typeof JSON.stringify === 'function' &&
+        JSON.stringify(0) === '0' &&
+        typeof JSON.stringify(Prototype.K) === 'undefined';
+
+  function Type(o) {
+    switch(o) {
+      case null: return NULL_TYPE;
+      case (void 0): return UNDEFINED_TYPE;
+    }
+    var type = typeof o;
+    switch(type) {
+      case 'boolean': return BOOLEAN_TYPE;
+      case 'number':  return NUMBER_TYPE;
+      case 'string':  return STRING_TYPE;
+    }
+    return OBJECT_TYPE;
+  }
+
+  function extend(destination, source) {
+    for (var property in source)
+      destination[property] = source[property];
+    return destination;
+  }
+
+  function inspect(object) {
+    try {
+      if (isUndefined(object)) return 'undefined';
+      if (object === null) return 'null';
+      return object.inspect ? object.inspect() : String(object);
+    } catch (e) {
+      if (e instanceof RangeError) return '...';
+      throw e;
+    }
+  }
+
+  function toJSON(value) {
+    return Str('', { '': value }, []);
+  }
+
+  function Str(key, holder, stack) {
+    var value = holder[key],
+        type = typeof value;
+
+    if (Type(value) === OBJECT_TYPE && typeof value.toJSON === 'function') {
+      value = value.toJSON(key);
+    }
+
+    var _class = _toString.call(value);
+
+    switch (_class) {
+      case NUMBER_CLASS:
+      case BOOLEAN_CLASS:
+      case STRING_CLASS:
+        value = value.valueOf();
+    }
+
+    switch (value) {
+      case null: return 'null';
+      case true: return 'true';
+      case false: return 'false';
+    }
+
+    type = typeof value;
+    switch (type) {
+      case 'string':
+        return value.inspect(true);
+      case 'number':
+        return isFinite(value) ? String(value) : 'null';
+      case 'object':
+
+        for (var i = 0, length = stack.length; i < length; i++) {
+          if (stack[i] === value) { throw new TypeError(); }
+        }
+        stack.push(value);
+
+        var partial = [];
+        if (_class === ARRAY_CLASS) {
+          for (var i = 0, length = value.length; i < length; i++) {
+            var str = Str(i, value, stack);
+            partial.push(typeof str === 'undefined' ? 'null' : str);
+          }
+          partial = '[' + partial.join(',') + ']';
+        } else {
+          var keys = Object.keys(value);
+          for (var i = 0, length = keys.length; i < length; i++) {
+            var key = keys[i], str = Str(key, value, stack);
+            if (typeof str !== "undefined") {
+               partial.push(key.inspect(true)+ ':' + str);
+             }
+          }
+          partial = '{' + partial.join(',') + '}';
+        }
+        stack.pop();
+        return partial;
+    }
+  }
+
+  function stringify(object) {
+    return JSON.stringify(object);
+  }
+
+  function toQueryString(object) {
+    return $H(object).toQueryString();
+  }
+
+  function toHTML(object) {
+    return object && object.toHTML ? object.toHTML() : String.interpret(object);
+  }
+
+  function keys(object) {
+    if (Type(object) !== OBJECT_TYPE) { throw new TypeError(); }
+    var results = [];
+    for (var property in object) {
+      if (object.hasOwnProperty(property)) {
+        results.push(property);
+      }
+    }
+    return results;
+  }
+
+  function values(object) {
+    var results = [];
+    for (var property in object)
+      results.push(object[property]);
+    return results;
+  }
+
+  function clone(object) {
+    return extend({ }, object);
+  }
+
+  function isElement(object) {
+    return !!(object && object.nodeType == 1);
+  }
+
+  function isArray(object) {
+    return _toString.call(object) === ARRAY_CLASS;
+  }
+
+  var hasNativeIsArray = (typeof Array.isArray == 'function')
+    && Array.isArray([]) && !Array.isArray({});
+
+  if (hasNativeIsArray) {
+    isArray = Array.isArray;
+  }
+
+  function isHash(object) {
+    return object instanceof Hash;
+  }
+
+  function isFunction(object) {
+    return _toString.call(object) === FUNCTION_CLASS;
+  }
+
+  function isString(object) {
+    return _toString.call(object) === STRING_CLASS;
+  }
+
+  function isNumber(object) {
+    return _toString.call(object) === NUMBER_CLASS;
+  }
+
+  function isDate(object) {
+    return _toString.call(object) === DATE_CLASS;
+  }
+
+  function isUndefined(object) {
+    return typeof object === "undefined";
+  }
+
+  extend(Object, {
+    extend:        extend,
+    inspect:       inspect,
+    toJSON:        NATIVE_JSON_STRINGIFY_SUPPORT ? stringify : toJSON,
+    toQueryString: toQueryString,
+    toHTML:        toHTML,
+    keys:          Object.keys || keys,
+    values:        values,
+    clone:         clone,
+    isElement:     isElement,
+    isArray:       isArray,
+    isHash:        isHash,
+    isFunction:    isFunction,
+    isString:      isString,
+    isNumber:      isNumber,
+    isDate:        isDate,
+    isUndefined:   isUndefined
+  });
+})();
+Object.extend(Function.prototype, (function() {
+  var slice = Array.prototype.slice;
+
+  function update(array, args) {
+    var arrayLength = array.length, length = args.length;
+    while (length--) array[arrayLength + length] = args[length];
+    return array;
+  }
+
+  function merge(array, args) {
+    array = slice.call(array, 0);
+    return update(array, args);
+  }
+
+  function argumentNames() {
+    var names = this.toString().match(/^[\s\(]*function[^(]*\(([^)]*)\)/)[1]
+      .replace(/\/\/.*?[\r\n]|\/\*(?:.|[\r\n])*?\*\//g, '')
+      .replace(/\s+/g, '').split(',');
+    return names.length == 1 && !names[0] ? [] : names;
+  }
+
+  function bind(context) {
+    if (arguments.length < 2 && Object.isUndefined(arguments[0])) return this;
+    var __method = this, args = slice.call(arguments, 1);
+    return function() {
+      var a = merge(args, arguments);
+      return __method.apply(context, a);
+    }
+  }
+
+  function bindAsEventListener(context) {
+    var __method = this, args = slice.call(arguments, 1);
+    return function(event) {
+      var a = update([event || window.event], args);
+      return __method.apply(context, a);
+    }
+  }
+
+  function curry() {
+    if (!arguments.length) return this;
+    var __method = this, args = slice.call(arguments, 0);
+    return function() {
+      var a = merge(args, arguments);
+      return __method.apply(this, a);
+    }
+  }
+
+  function delay(timeout) {
+    var __method = this, args = slice.call(arguments, 1);
+    timeout = timeout * 1000;
+    return window.setTimeout(function() {
+      return __method.apply(__method, args);
+    }, timeout);
+  }
+
+  function defer() {
+    var args = update([0.01], arguments);
+    return this.delay.apply(this, args);
+  }
+
+  function wrap(wrapper) {
+    var __method = this;
+    return function() {
+      var a = update([__method.bind(this)], arguments);
+      return wrapper.apply(this, a);
+    }
+  }
+
+  function methodize() {
+    if (this._methodized) return this._methodized;
+    var __method = this;
+    return this._methodized = function() {
+      var a = update([this], arguments);
+      return __method.apply(null, a);
+    };
+  }
+
+  return {
+    argumentNames:       argumentNames,
+    bind:                bind,
+    bindAsEventListener: bindAsEventListener,
+    curry:               curry,
+    delay:               delay,
+    defer:               defer,
+    wrap:                wrap,
+    methodize:           methodize
+  }
+})());
+
+
+
+(function(proto) {
+
+
+  function toISOString() {
+    return this.getUTCFullYear() + '-' +
+      (this.getUTCMonth() + 1).toPaddedString(2) + '-' +
+      this.getUTCDate().toPaddedString(2) + 'T' +
+      this.getUTCHours().toPaddedString(2) + ':' +
+      this.getUTCMinutes().toPaddedString(2) + ':' +
+      this.getUTCSeconds().toPaddedString(2) + 'Z';
+  }
+
+
+  function toJSON() {
+    return this.toISOString();
+  }
+
+  if (!proto.toISOString) proto.toISOString = toISOString;
+  if (!proto.toJSON) proto.toJSON = toJSON;
+
+})(Date.prototype);
+
+
+RegExp.prototype.match = RegExp.prototype.test;
+
+RegExp.escape = function(str) {
+  return String(str).replace(/([.*+?^=!:${}()|[\]\/\\])/g, '\\$1');
+};
+var PeriodicalExecuter = Class.create({
+  initialize: function(callback, frequency) {
+    this.callback = callback;
+    this.frequency = frequency;
+    this.currentlyExecuting = false;
+
+    this.registerCallback();
+  },
+
+  registerCallback: function() {
+    this.timer = setInterval(this.onTimerEvent.bind(this), this.frequency * 1000);
+  },
+
+  execute: function() {
+    this.callback(this);
+  },
+
+  stop: function() {
+    if (!this.timer) return;
+    clearInterval(this.timer);
+    this.timer = null;
+  },
+
+  onTimerEvent: function() {
+    if (!this.currentlyExecuting) {
+      try {
+        this.currentlyExecuting = true;
+        this.execute();
+        this.currentlyExecuting = false;
+      } catch(e) {
+        this.currentlyExecuting = false;
+        throw e;
+      }
+    }
+  }
+});
+Object.extend(String, {
+  interpret: function(value) {
+    return value == null ? '' : String(value);
+  },
+  specialChar: {
+    '\b': '\\b',
+    '\t': '\\t',
+    '\n': '\\n',
+    '\f': '\\f',
+    '\r': '\\r',
+    '\\': '\\\\'
+  }
+});
+
+Object.extend(String.prototype, (function() {
+  var NATIVE_JSON_PARSE_SUPPORT = window.JSON &&
+    typeof JSON.parse === 'function' &&
+    JSON.parse('{"test": true}').test;
+
+  function prepareReplacement(replacement) {
+    if (Object.isFunction(replacement)) return replacement;
+    var template = new Template(replacement);
+    return function(match) { return template.evaluate(match) };
+  }
+
+  function gsub(pattern, replacement) {
+    var result = '', source = this, match;
+    replacement = prepareReplacement(replacement);
+
+    if (Object.isString(pattern))
+      pattern = RegExp.escape(pattern);
+
+    if (!(pattern.length || pattern.source)) {
+      replacement = replacement('');
+      return replacement + source.split('').join(replacement) + replacement;
+    }
+
+    while (source.length > 0) {
+      if (match = source.match(pattern)) {
+        result += source.slice(0, match.index);
+        result += String.interpret(replacement(match));
+        source  = source.slice(match.index + match[0].length);
+      } else {
+        result += source, source = '';
+      }
+    }
+    return result;
+  }
+
+  function sub(pattern, replacement, count) {
+    replacement = prepareReplacement(replacement);
+    count = Object.isUndefined(count) ? 1 : count;
+
+    return this.gsub(pattern, function(match) {
+      if (--count < 0) return match[0];
+      return replacement(match);
+    });
+  }
+
+  function scan(pattern, iterator) {
+    this.gsub(pattern, iterator);
+    return String(this);
+  }
+
+  function truncate(length, truncation) {
+    length = length || 30;
+    truncation = Object.isUndefined(truncation) ? '...' : truncation;
+    return this.length > length ?
+      this.slice(0, length - truncation.length) + truncation : String(this);
+  }
+
+  function strip() {
+    return this.replace(/^\s+/, '').replace(/\s+$/, '');
+  }
+
+  function stripTags() {
+    return this.replace(/<\w+(\s+("[^"]*"|'[^']*'|[^>])+)?>|<\/\w+>/gi, '');
+  }
+
+  function stripScripts() {
+    return this.replace(new RegExp(Prototype.ScriptFragment, 'img'), '');
+  }
+
+  function extractScripts() {
+    var matchAll = new RegExp(Prototype.ScriptFragment, 'img'),
+        matchOne = new RegExp(Prototype.ScriptFragment, 'im');
+    return (this.match(matchAll) || []).map(function(scriptTag) {
+      return (scriptTag.match(matchOne) || ['', ''])[1];
+    });
+  }
+
+  function evalScripts() {
+    return this.extractScripts().map(function(script) { return eval(script) });
+  }
+
+  function escapeHTML() {
+    return this.replace(/&/g,'&amp;').replace(/</g,'&lt;').replace(/>/g,'&gt;');
+  }
+
+  function unescapeHTML() {
+    return this.stripTags().replace(/&lt;/g,'<').replace(/&gt;/g,'>').replace(/&amp;/g,'&');
+  }
+
+
+  function toQueryParams(separator) {
+    var match = this.strip().match(/([^?#]*)(#.*)?$/);
+    if (!match) return { };
+
+    return match[1].split(separator || '&').inject({ }, function(hash, pair) {
+      if ((pair = pair.split('='))[0]) {
+        var key = decodeURIComponent(pair.shift()),
+            value = pair.length > 1 ? pair.join('=') : pair[0];
+
+        if (value != undefined) value = decodeURIComponent(value);
+
+        if (key in hash) {
+          if (!Object.isArray(hash[key])) hash[key] = [hash[key]];
+          hash[key].push(value);
+        }
+        else hash[key] = value;
+      }
+      return hash;
+    });
+  }
+
+  function toArray() {
+    return this.split('');
+  }
+
+  function succ() {
+    return this.slice(0, this.length - 1) +
+      String.fromCharCode(this.charCodeAt(this.length - 1) + 1);
+  }
+
+  function times(count) {
+    return count < 1 ? '' : new Array(count + 1).join(this);
+  }
+
+  function camelize() {
+    return this.replace(/-+(.)?/g, function(match, chr) {
+      return chr ? chr.toUpperCase() : '';
+    });
+  }
+
+  function capitalize() {
+    return this.charAt(0).toUpperCase() + this.substring(1).toLowerCase();
+  }
+
+  function underscore() {
+    return this.replace(/::/g, '/')
+               .replace(/([A-Z]+)([A-Z][a-z])/g, '$1_$2')
+               .replace(/([a-z\d])([A-Z])/g, '$1_$2')
+               .replace(/-/g, '_')
+               .toLowerCase();
+  }
+
+  function dasherize() {
+    return this.replace(/_/g, '-');
+  }
+
+  function inspect(useDoubleQuotes) {
+    var escapedString = this.replace(/[\x00-\x1f\\]/g, function(character) {
+      if (character in String.specialChar) {
+        return String.specialChar[character];
+      }
+      return '\\u00' + character.charCodeAt().toPaddedString(2, 16);
+    });
+    if (useDoubleQuotes) return '"' + escapedString.replace(/"/g, '\\"') + '"';
+    return "'" + escapedString.replace(/'/g, '\\\'') + "'";
+  }
+
+  function unfilterJSON(filter) {
+    return this.replace(filter || Prototype.JSONFilter, '$1');
+  }
+
+  function isJSON() {
+    var str = this;
+    if (str.blank()) return false;
+    str = str.replace(/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g, '@');
+    str = str.replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g, ']');
+    str = str.replace(/(?:^|:|,)(?:\s*\[)+/g, '');
+    return (/^[\],:{}\s]*$/).test(str);
+  }
+
+  function evalJSON(sanitize) {
+    var json = this.unfilterJSON(),
+        cx = /[\u0000\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g;
+    if (cx.test(json)) {
+      json = json.replace(cx, function (a) {
+        return '\\u' + ('0000' + a.charCodeAt(0).toString(16)).slice(-4);
+      });
+    }
+    try {
+      if (!sanitize || json.isJSON()) return eval('(' + json + ')');
+    } catch (e) { }
+    throw new SyntaxError('Badly formed JSON string: ' + this.inspect());
+  }
+
+  function parseJSON() {
+    var json = this.unfilterJSON();
+    return JSON.parse(json);
+  }
+
+  function include(pattern) {
+    return this.indexOf(pattern) > -1;
+  }
+
+  function startsWith(pattern) {
+    return this.lastIndexOf(pattern, 0) === 0;
+  }
+
+  function endsWith(pattern) {
+    var d = this.length - pattern.length;
+    return d >= 0 && this.indexOf(pattern, d) === d;
+  }
+
+  function empty() {
+    return this == '';
+  }
+
+  function blank() {
+    return /^\s*$/.test(this);
+  }
+
+  function interpolate(object, pattern) {
+    return new Template(this, pattern).evaluate(object);
+  }
+
+  return {
+    gsub:           gsub,
+    sub:            sub,
+    scan:           scan,
+    truncate:       truncate,
+    strip:          String.prototype.trim || strip,
+    stripTags:      stripTags,
+    stripScripts:   stripScripts,
+    extractScripts: extractScripts,
+    evalScripts:    evalScripts,
+    escapeHTML:     escapeHTML,
+    unescapeHTML:   unescapeHTML,
+    toQueryParams:  toQueryParams,
+    parseQuery:     toQueryParams,
+    toArray:        toArray,
+    succ:           succ,
+    times:          times,
+    camelize:       camelize,
+    capitalize:     capitalize,
+    underscore:     underscore,
+    dasherize:      dasherize,
+    inspect:        inspect,
+    unfilterJSON:   unfilterJSON,
+    isJSON:         isJSON,
+    evalJSON:       NATIVE_JSON_PARSE_SUPPORT ? parseJSON : evalJSON,
+    include:        include,
+    startsWith:     startsWith,
+    endsWith:       endsWith,
+    empty:          empty,
+    blank:          blank,
+    interpolate:    interpolate
+  };
+})());
+
+var Template = Class.create({
+  initialize: function(template, pattern) {
+    this.template = template.toString();
+    this.pattern = pattern || Template.Pattern;
+  },
+
+  evaluate: function(object) {
+    if (object && Object.isFunction(object.toTemplateReplacements))
+      object = object.toTemplateReplacements();
+
+    return this.template.gsub(this.pattern, function(match) {
+      if (object == null) return (match[1] + '');
+
+      var before = match[1] || '';
+      if (before == '\\') return match[2];
+
+      var ctx = object, expr = match[3],
+          pattern = /^([^.[]+|\[((?:.*?[^\\])?)\])(\.|\[|$)/;
+
+      match = pattern.exec(expr);
+      if (match == null) return before;
+
+      while (match != null) {
+        var comp = match[1].startsWith('[') ? match[2].replace(/\\\\]/g, ']') : match[1];
+        ctx = ctx[comp];
+        if (null == ctx || '' == match[3]) break;
+        expr = expr.substring('[' == match[3] ? match[1].length : match[0].length);
+        match = pattern.exec(expr);
+      }
+
+      return before + String.interpret(ctx);
+    });
+  }
+});
+Template.Pattern = /(^|.|\r|\n)(#\{(.*?)\})/;
+
+var $break = { };
+
+var Enumerable = (function() {
+  function each(iterator, context) {
+    var index = 0;
+    try {
+      this._each(function(value) {
+        iterator.call(context, value, index++);
+      });
+    } catch (e) {
+      if (e != $break) throw e;
+    }
+    return this;
+  }
+
+  function eachSlice(number, iterator, context) {
+    var index = -number, slices = [], array = this.toArray();
+    if (number < 1) return array;
+    while ((index += number) < array.length)
+      slices.push(array.slice(index, index+number));
+    return slices.collect(iterator, context);
+  }
+
+  function all(iterator, context) {
+    iterator = iterator || Prototype.K;
+    var result = true;
+    this.each(function(value, index) {
+      result = result && !!iterator.call(context, value, index);
+      if (!result) throw $break;
+    });
+    return result;
+  }
+
+  function any(iterator, context) {
+    iterator = iterator || Prototype.K;
+    var result = false;
+    this.each(function(value, index) {
+      if (result = !!iterator.call(context, value, index))
+        throw $break;
+    });
+    return result;
+  }
+
+  function collect(iterator, context) {
+    iterator = iterator || Prototype.K;
+    var results = [];
+    this.each(function(value, index) {
+      results.push(iterator.call(context, value, index));
+    });
+    return results;
+  }
+
+  function detect(iterator, context) {
+    var result;
+    this.each(function(value, index) {
+      if (iterator.call(context, value, index)) {
+        result = value;
+        throw $break;
+      }
+    });
+    return result;
+  }
+
+  function findAll(iterator, context) {
+    var results = [];
+    this.each(function(value, index) {
+      if (iterator.call(context, value, index))
+        results.push(value);
+    });
+    return results;
+  }
+
+  function grep(filter, iterator, context) {
+    iterator = iterator || Prototype.K;
+    var results = [];
+
+    if (Object.isString(filter))
+      filter = new RegExp(RegExp.escape(filter));
+
+    this.each(function(value, index) {
+      if (filter.match(value))
+        results.push(iterator.call(context, value, index));
+    });
+    return results;
+  }
+
+  function include(object) {
+    if (Object.isFunction(this.indexOf))
+      if (this.indexOf(object) != -1) return true;
+
+    var found = false;
+    this.each(function(value) {
+      if (value == object) {
+        found = true;
+        throw $break;
+      }
+    });
+    return found;
+  }
+
+  function inGroupsOf(number, fillWith) {
+    fillWith = Object.isUndefined(fillWith) ? null : fillWith;
+    return this.eachSlice(number, function(slice) {
+      while(slice.length < number) slice.push(fillWith);
+      return slice;
+    });
+  }
+
+  function inject(memo, iterator, context) {
+    this.each(function(value, index) {
+      memo = iterator.call(context, memo, value, index);
+    });
+    return memo;
+  }
+
+  function invoke(method) {
+    var args = $A(arguments).slice(1);
+    return this.map(function(value) {
+      return value[method].apply(value, args);
+    });
+  }
+
+  function max(iterator, context) {
+    iterator = iterator || Prototype.K;
+    var result;
+    this.each(function(value, index) {
+      value = iterator.call(context, value, index);
+      if (result == null || value >= result)
+        result = value;
+    });
+    return result;
+  }
+
+  function min(iterator, context) {
+    iterator = iterator || Prototype.K;
+    var result;
+    this.each(function(value, index) {
+      value = iterator.call(context, value, index);
+      if (result == null || value < result)
+        result = value;
+    });
+    return result;
+  }
+
+  function partition(iterator, context) {
+    iterator = iterator || Prototype.K;
+    var trues = [], falses = [];
+    this.each(function(value, index) {
+      (iterator.call(context, value, index) ?
+        trues : falses).push(value);
+    });
+    return [trues, falses];
+  }
+
+  function pluck(property) {
+    var results = [];
+    this.each(function(value) {
+      results.push(value[property]);
+    });
+    return results;
+  }
+
+  function reject(iterator, context) {
+    var results = [];
+    this.each(function(value, index) {
+      if (!iterator.call(context, value, index))
+        results.push(value);
+    });
+    return results;
+  }
+
+  function sortBy(iterator, context) {
+    return this.map(function(value, index) {
+      return {
+        value: value,
+        criteria: iterator.call(context, value, index)
+      };
+    }).sort(function(left, right) {
+      var a = left.criteria, b = right.criteria;
+      return a < b ? -1 : a > b ? 1 : 0;
+    }).pluck('value');
+  }
+
+  function toArray() {
+    return this.map();
+  }
+
+  function zip() {
+    var iterator = Prototype.K, args = $A(arguments);
+    if (Object.isFunction(args.last()))
+      iterator = args.pop();
+
+    var collections = [this].concat(args).map($A);
+    return this.map(function(value, index) {
+      return iterator(collections.pluck(index));
+    });
+  }
+
+  function size() {
+    return this.toArray().length;
+  }
+
+  function inspect() {
+    return '#<Enumerable:' + this.toArray().inspect() + '>';
+  }
+
+
+
+
+
+
+
+
+
+  return {
+    each:       each,
+    eachSlice:  eachSlice,
+    all:        all,
+    every:      all,
+    any:        any,
+    some:       any,
+    collect:    collect,
+    map:        collect,
+    detect:     detect,
+    findAll:    findAll,
+    select:     findAll,
+    filter:     findAll,
+    grep:       grep,
+    include:    include,
+    member:     include,
+    inGroupsOf: inGroupsOf,
+    inject:     inject,
+    invoke:     invoke,
+    max:        max,
+    min:        min,
+    partition:  partition,
+    pluck:      pluck,
+    reject:     reject,
+    sortBy:     sortBy,
+    toArray:    toArray,
+    entries:    toArray,
+    zip:        zip,
+    size:       size,
+    inspect:    inspect,
+    find:       detect
+  };
+})();
+
+function $A(iterable) {
+  if (!iterable) return [];
+  if ('toArray' in Object(iterable)) return iterable.toArray();
+  var length = iterable.length || 0, results = new Array(length);
+  while (length--) results[length] = iterable[length];
+  return results;
+}
+
+
+function $w(string) {
+  if (!Object.isString(string)) return [];
+  string = string.strip();
+  return string ? string.split(/\s+/) : [];
+}
+
+Array.from = $A;
+
+
+(function() {
+  var arrayProto = Array.prototype,
+      slice = arrayProto.slice,
+      _each = arrayProto.forEach; // use native browser JS 1.6 implementation if available
+
+  function each(iterator, context) {
+    for (var i = 0, length = this.length >>> 0; i < length; i++) {
+      if (i in this) iterator.call(context, this[i], i, this);
+    }
+  }
+  if (!_each) _each = each;
+
+  function clear() {
+    this.length = 0;
+    return this;
+  }
+
+  function first() {
+    return this[0];
+  }
+
+  function last() {
+    return this[this.length - 1];
+  }
+
+  function compact() {
+    return this.select(function(value) {
+      return value != null;
+    });
+  }
+
+  function flatten() {
+    return this.inject([], function(array, value) {
+      if (Object.isArray(value))
+        return array.concat(value.flatten());
+      array.push(value);
+      return array;
+    });
+  }
+
+  function without() {
+    var values = slice.call(arguments, 0);
+    return this.select(function(value) {
+      return !values.include(value);
+    });
+  }
+
+  function reverse(inline) {
+    return (inline === false ? this.toArray() : this)._reverse();
+  }
+
+  function uniq(sorted) {
+    return this.inject([], function(array, value, index) {
+      if (0 == index || (sorted ? array.last() != value : !array.include(value)))
+        array.push(value);
+      return array;
+    });
+  }
+
+  function intersect(array) {
+    return this.uniq().findAll(function(item) {
+      return array.detect(function(value) { return item === value });
+    });
+  }
+
+
+  function clone() {
+    return slice.call(this, 0);
+  }
+
+  function size() {
+    return this.length;
+  }
+
+  function inspect() {
+    return '[' + this.map(Object.inspect).join(', ') + ']';
+  }
+
+  function indexOf(item, i) {
+    i || (i = 0);
+    var length = this.length;
+    if (i < 0) i = length + i;
+    for (; i < length; i++)
+      if (this[i] === item) return i;
+    return -1;
+  }
+
+  function lastIndexOf(item, i) {
+    i = isNaN(i) ? this.length : (i < 0 ? this.length + i : i) + 1;
+    var n = this.slice(0, i).reverse().indexOf(item);
+    return (n < 0) ? n : i - n - 1;
+  }
+
+  function concat() {
+    var array = slice.call(this, 0), item;
+    for (var i = 0, length = arguments.length; i < length; i++) {
+      item = arguments[i];
+      if (Object.isArray(item) && !('callee' in item)) {
+        for (var j = 0, arrayLength = item.length; j < arrayLength; j++)
+          array.push(item[j]);
+      } else {
+        array.push(item);
+      }
+    }
+    return array;
+  }
+
+  Object.extend(arrayProto, Enumerable);
+
+  if (!arrayProto._reverse)
+    arrayProto._reverse = arrayProto.reverse;
+
+  Object.extend(arrayProto, {
+    _each:     _each,
+    clear:     clear,
+    first:     first,
+    last:      last,
+    compact:   compact,
+    flatten:   flatten,
+    without:   without,
+    reverse:   reverse,
+    uniq:      uniq,
+    intersect: intersect,
+    clone:     clone,
+    toArray:   clone,
+    size:      size,
+    inspect:   inspect
+  });
+
+  var CONCAT_ARGUMENTS_BUGGY = (function() {
+    return [].concat(arguments)[0][0] !== 1;
+  })(1,2)
+
+  if (CONCAT_ARGUMENTS_BUGGY) arrayProto.concat = concat;
+
+  if (!arrayProto.indexOf) arrayProto.indexOf = indexOf;
+  if (!arrayProto.lastIndexOf) arrayProto.lastIndexOf = lastIndexOf;
+})();
+function $H(object) {
+  return new Hash(object);
+};
+
+var Hash = Class.create(Enumerable, (function() {
+  function initialize(object) {
+    this._object = Object.isHash(object) ? object.toObject() : Object.clone(object);
+  }
+
+
+  function _each(iterator) {
+    for (var key in this._object) {
+      var value = this._object[key], pair = [key, value];
+      pair.key = key;
+      pair.value = value;
+      iterator(pair);
+    }
+  }
+
+  function set(key, value) {
+    return this._object[key] = value;
+  }
+
+  function get(key) {
+    if (this._object[key] !== Object.prototype[key])
+      return this._object[key];
+  }
+
+  function unset(key) {
+    var value = this._object[key];
+    delete this._object[key];
+    return value;
+  }
+
+  function toObject() {
+    return Object.clone(this._object);
+  }
+
+
+
+  function keys() {
+    return this.pluck('key');
+  }
+
+  function values() {
+    return this.pluck('value');
+  }
+
+  function index(value) {
+    var match = this.detect(function(pair) {
+      return pair.value === value;
+    });
+    return match && match.key;
+  }
+
+  function merge(object) {
+    return this.clone().update(object);
+  }
+
+  function update(object) {
+    return new Hash(object).inject(this, function(result, pair) {
+      result.set(pair.key, pair.value);
+      return result;
+    });
+  }
+
+  function toQueryPair(key, value) {
+    if (Object.isUndefined(value)) return key;
+    return key + '=' + encodeURIComponent(String.interpret(value));
+  }
+
+  function toQueryString() {
+    return this.inject([], function(results, pair) {
+      var key = encodeURIComponent(pair.key), values = pair.value;
+
+      if (values && typeof values == 'object') {
+        if (Object.isArray(values)) {
+          var queryValues = [];
+          for (var i = 0, len = values.length, value; i < len; i++) {
+            value = values[i];
+            queryValues.push(toQueryPair(key, value));
+          }
+          return results.concat(queryValues);
+        }
+      } else results.push(toQueryPair(key, values));
+      return results;
+    }).join('&');
+  }
+
+  function inspect() {
+    return '#<Hash:{' + this.map(function(pair) {
+      return pair.map(Object.inspect).join(': ');
+    }).join(', ') + '}>';
+  }
+
+  function clone() {
+    return new Hash(this);
+  }
+
+  return {
+    initialize:             initialize,
+    _each:                  _each,
+    set:                    set,
+    get:                    get,
+    unset:                  unset,
+    toObject:               toObject,
+    toTemplateReplacements: toObject,
+    keys:                   keys,
+    values:                 values,
+    index:                  index,
+    merge:                  merge,
+    update:                 update,
+    toQueryString:          toQueryString,
+    inspect:                inspect,
+    toJSON:                 toObject,
+    clone:                  clone
+  };
+})());
+
+Hash.from = $H;
+Object.extend(Number.prototype, (function() {
+  function toColorPart() {
+    return this.toPaddedString(2, 16);
+  }
+
+  function succ() {
+    return this + 1;
+  }
+
+  function times(iterator, context) {
+    $R(0, this, true).each(iterator, context);
+    return this;
+  }
+
+  function toPaddedString(length, radix) {
+    var string = this.toString(radix || 10);
+    return '0'.times(length - string.length) + string;
+  }
+
+  function abs() {
+    return Math.abs(this);
+  }
+
+  function round() {
+    return Math.round(this);
+  }
+
+  function ceil() {
+    return Math.ceil(this);
+  }
+
+  function floor() {
+    return Math.floor(this);
+  }
+
+  return {
+    toColorPart:    toColorPart,
+    succ:           succ,
+    times:          times,
+    toPaddedString: toPaddedString,
+    abs:            abs,
+    round:          round,
+    ceil:           ceil,
+    floor:          floor
+  };
+})());
+
+function $R(start, end, exclusive) {
+  return new ObjectRange(start, end, exclusive);
+}
+
+var ObjectRange = Class.create(Enumerable, (function() {
+  function initialize(start, end, exclusive) {
+    this.start = start;
+    this.end = end;
+    this.exclusive = exclusive;
+  }
+
+  function _each(iterator) {
+    var value = this.start;
+    while (this.include(value)) {
+      iterator(value);
+      value = value.succ();
+    }
+  }
+
+  function include(value) {
+    if (value < this.start)
+      return false;
+    if (this.exclusive)
+      return value < this.end;
+    return value <= this.end;
+  }
+
+  return {
+    initialize: initialize,
+    _each:      _each,
+    include:    include
+  };
+})());
+
+
+
+var Ajax = {
+  getTransport: function() {
+    return Try.these(
+      function() {return new XMLHttpRequest()},
+      function() {return new ActiveXObject('Msxml2.XMLHTTP')},
+      function() {return new ActiveXObject('Microsoft.XMLHTTP')}
+    ) || false;
+  },
+
+  activeRequestCount: 0
+};
+
+Ajax.Responders = {
+  responders: [],
+
+  _each: function(iterator) {
+    this.responders._each(iterator);
+  },
+
+  register: function(responder) {
+    if (!this.include(responder))
+      this.responders.push(responder);
+  },
+
+  unregister: function(responder) {
+    this.responders = this.responders.without(responder);
+  },
+
+  dispatch: function(callback, request, transport, json) {
+    this.each(function(responder) {
+      if (Object.isFunction(responder[callback])) {
+        try {
+          responder[callback].apply(responder, [request, transport, json]);
+        } catch (e) { }
+      }
+    });
+  }
+};
+
+Object.extend(Ajax.Responders, Enumerable);
+
+Ajax.Responders.register({
+  onCreate:   function() { Ajax.activeRequestCount++ },
+  onComplete: function() { Ajax.activeRequestCount-- }
+});
+Ajax.Base = Class.create({
+  initialize: function(options) {
+    this.options = {
+      method:       'post',
+      asynchronous: true,
+      contentType:  'application/x-www-form-urlencoded',
+      encoding:     'UTF-8',
+      parameters:   '',
+      evalJSON:     true,
+      evalJS:       true
+    };
+    Object.extend(this.options, options || { });
+
+    this.options.method = this.options.method.toLowerCase();
+
+    if (Object.isHash(this.options.parameters))
+      this.options.parameters = this.options.parameters.toObject();
+  }
+});
+Ajax.Request = Class.create(Ajax.Base, {
+  _complete: false,
+
+  initialize: function($super, url, options) {
+    $super(options);
+    this.transport = Ajax.getTransport();
+    this.request(url);
+  },
+
+  request: function(url) {
+    this.url = url;
+    this.method = this.options.method;
+    var params = Object.isString(this.options.parameters) ?
+          this.options.parameters :
+          Object.toQueryString(this.options.parameters);
+
+    if (!['get', 'post'].include(this.method)) {
+      params += (params ? '&' : '') + "_method=" + this.method;
+      this.method = 'post';
+    }
+
+    if (params && this.method === 'get') {
+      this.url += (this.url.include('?') ? '&' : '?') + params;
+    }
+
+    this.parameters = params.toQueryParams();
+
+    try {
+      var response = new Ajax.Response(this);
+      if (this.options.onCreate) this.options.onCreate(response);
+      Ajax.Responders.dispatch('onCreate', this, response);
+
+      this.transport.open(this.method.toUpperCase(), this.url,
+        this.options.asynchronous);
+
+      if (this.options.asynchronous) this.respondToReadyState.bind(this).defer(1);
+
+      this.transport.onreadystatechange = this.onStateChange.bind(this);
+      this.setRequestHeaders();
+
+      this.body = this.method == 'post' ? (this.options.postBody || params) : null;
+      this.transport.send(this.body);
+
+      /* Force Firefox to handle ready state 4 for synchronous requests */
+      if (!this.options.asynchronous && this.transport.overrideMimeType)
+        this.onStateChange();
+
+    }
+    catch (e) {
+      this.dispatchException(e);
+    }
+  },
+
+  onStateChange: function() {
+    var readyState = this.transport.readyState;
+    if (readyState > 1 && !((readyState == 4) && this._complete))
+      this.respondToReadyState(this.transport.readyState);
+  },
+
+  setRequestHeaders: function() {
+    var headers = {
+      'X-Requested-With': 'XMLHttpRequest',
+      'X-Prototype-Version': Prototype.Version,
+      'Accept': 'text/javascript, text/html, application/xml, text/xml, */*'
+    };
+
+    if (this.method == 'post') {
+      headers['Content-type'] = this.options.contentType +
+        (this.options.encoding ? '; charset=' + this.options.encoding : '');
+
+      /* Force "Connection: close" for older Mozilla browsers to work
+       * around a bug where XMLHttpRequest sends an incorrect
+       * Content-length header. See Mozilla Bugzilla #246651.
+       */
+      if (this.transport.overrideMimeType &&
+          (navigator.userAgent.match(/Gecko\/(\d{4})/) || [0,2005])[1] < 2005)
+            headers['Connection'] = 'close';
+    }
+
+    if (typeof this.options.requestHeaders == 'object') {
+      var extras = this.options.requestHeaders;
+
+      if (Object.isFunction(extras.push))
+        for (var i = 0, length = extras.length; i < length; i += 2)
+          headers[extras[i]] = extras[i+1];
+      else
+        $H(extras).each(function(pair) { headers[pair.key] = pair.value });
+    }
+
+    for (var name in headers)
+      this.transport.setRequestHeader(name, headers[name]);
+  },
+
+  success: function() {
+    var status = this.getStatus();
+    return !status || (status >= 200 && status < 300) || status == 304;
+  },
+
+  getStatus: function() {
+    try {
+      if (this.transport.status === 1223) return 204;
+      return this.transport.status || 0;
+    } catch (e) { return 0 }
+  },
+
+  respondToReadyState: function(readyState) {
+    var state = Ajax.Request.Events[readyState], response = new Ajax.Response(this);
+
+    if (state == 'Complete') {
+      try {
+        this._complete = true;
+        (this.options['on' + response.status]
+         || this.options['on' + (this.success() ? 'Success' : 'Failure')]
+         || Prototype.emptyFunction)(response, response.headerJSON);
+      } catch (e) {
+        this.dispatchException(e);
+      }
+
+      var contentType = response.getHeader('Content-type');
+      if (this.options.evalJS == 'force'
+          || (this.options.evalJS && this.isSameOrigin() && contentType
+          && contentType.match(/^\s*(text|application)\/(x-)?(java|ecma)script(;.*)?\s*$/i)))
+        this.evalResponse();
+    }
+
+    try {
+      (this.options['on' + state] || Prototype.emptyFunction)(response, response.headerJSON);
+      Ajax.Responders.dispatch('on' + state, this, response, response.headerJSON);
+    } catch (e) {
+      this.dispatchException(e);
+    }
+
+    if (state == 'Complete') {
+      this.transport.onreadystatechange = Prototype.emptyFunction;
+    }
+  },
+
+  isSameOrigin: function() {
+    var m = this.url.match(/^\s*https?:\/\/[^\/]*/);
+    return !m || (m[0] == '#{protocol}//#{domain}#{port}'.interpolate({
+      protocol: location.protocol,
+      domain: document.domain,
+      port: location.port ? ':' + location.port : ''
+    }));
+  },
+
+  getHeader: function(name) {
+    try {
+      return this.transport.getResponseHeader(name) || null;
+    } catch (e) { return null; }
+  },
+
+  evalResponse: function() {
+    try {
+      return eval((this.transport.responseText || '').unfilterJSON());
+    } catch (e) {
+      this.dispatchException(e);
+    }
+  },
+
+  dispatchException: function(exception) {
+    (this.options.onException || Prototype.emptyFunction)(this, exception);
+    Ajax.Responders.dispatch('onException', this, exception);
+  }
+});
+
+Ajax.Request.Events =
+  ['Uninitialized', 'Loading', 'Loaded', 'Interactive', 'Complete'];
+
+
+
+
+
+
+
+
+Ajax.Response = Class.create({
+  initialize: function(request){
+    this.request = request;
+    var transport  = this.transport  = request.transport,
+        readyState = this.readyState = transport.readyState;
+
+    if ((readyState > 2 && !Prototype.Browser.IE) || readyState == 4) {
+      this.status       = this.getStatus();
+      this.statusText   = this.getStatusText();
+      this.responseText = String.interpret(transport.responseText);
+      this.headerJSON   = this._getHeaderJSON();
+    }
+
+    if (readyState == 4) {
+      var xml = transport.responseXML;
+      this.responseXML  = Object.isUndefined(xml) ? null : xml;
+      this.responseJSON = this._getResponseJSON();
+    }
+  },
+
+  status:      0,
+
+  statusText: '',
+
+  getStatus: Ajax.Request.prototype.getStatus,
+
+  getStatusText: function() {
+    try {
+      return this.transport.statusText || '';
+    } catch (e) { return '' }
+  },
+
+  getHeader: Ajax.Request.prototype.getHeader,
+
+  getAllHeaders: function() {
+    try {
+      return this.getAllResponseHeaders();
+    } catch (e) { return null }
+  },
+
+  getResponseHeader: function(name) {
+    return this.transport.getResponseHeader(name);
+  },
+
+  getAllResponseHeaders: function() {
+    return this.transport.getAllResponseHeaders();
+  },
+
+  _getHeaderJSON: function() {
+    var json = this.getHeader('X-JSON');
+    if (!json) return null;
+    json = decodeURIComponent(escape(json));
+    try {
+      return json.evalJSON(this.request.options.sanitizeJSON ||
+        !this.request.isSameOrigin());
+    } catch (e) {
+      this.request.dispatchException(e);
+    }
+  },
+
+  _getResponseJSON: function() {
+    var options = this.request.options;
+    if (!options.evalJSON || (options.evalJSON != 'force' &&
+      !(this.getHeader('Content-type') || '').include('application/json')) ||
+        this.responseText.blank())
+          return null;
+    try {
+      return this.responseText.evalJSON(options.sanitizeJSON ||
+        !this.request.isSameOrigin());
+    } catch (e) {
+      this.request.dispatchException(e);
+    }
+  }
+});
+
+Ajax.Updater = Class.create(Ajax.Request, {
+  initialize: function($super, container, url, options) {
+    this.container = {
+      success: (container.success || container),
+      failure: (container.failure || (container.success ? null : container))
+    };
+
+    options = Object.clone(options);
+    var onComplete = options.onComplete;
+    options.onComplete = (function(response, json) {
+      this.updateContent(response.responseText);
+      if (Object.isFunction(onComplete)) onComplete(response, json);
+    }).bind(this);
+
+    $super(url, options);
+  },
+
+  updateContent: function(responseText) {
+    var receiver = this.container[this.success() ? 'success' : 'failure'],
+        options = this.options;
+
+    if (!options.evalScripts) responseText = responseText.stripScripts();
+
+    if (receiver = $(receiver)) {
+      if (options.insertion) {
+        if (Object.isString(options.insertion)) {
+          var insertion = { }; insertion[options.insertion] = responseText;
+          receiver.insert(insertion);
+        }
+        else options.insertion(receiver, responseText);
+      }
+      else receiver.update(responseText);
+    }
+  }
+});
+
+Ajax.PeriodicalUpdater = Class.create(Ajax.Base, {
+  initialize: function($super, container, url, options) {
+    $super(options);
+    this.onComplete = this.options.onComplete;
+
+    this.frequency = (this.options.frequency || 2);
+    this.decay = (this.options.decay || 1);
+
+    this.updater = { };
+    this.container = container;
+    this.url = url;
+
+    this.start();
+  },
+
+  start: function() {
+    this.options.onComplete = this.updateComplete.bind(this);
+    this.onTimerEvent();
+  },
+
+  stop: function() {
+    this.updater.options.onComplete = undefined;
+    clearTimeout(this.timer);
+    (this.onComplete || Prototype.emptyFunction).apply(this, arguments);
+  },
+
+  updateComplete: function(response) {
+    if (this.options.decay) {
+      this.decay = (response.responseText == this.lastText ?
+        this.decay * this.options.decay : 1);
+
+      this.lastText = response.responseText;
+    }
+    this.timer = this.onTimerEvent.bind(this).delay(this.decay * this.frequency);
+  },
+
+  onTimerEvent: function() {
+    this.updater = new Ajax.Updater(this.container, this.url, this.options);
+  }
+});
+
+
+function $(element) {
+  if (arguments.length > 1) {
+    for (var i = 0, elements = [], length = arguments.length; i < length; i++)
+      elements.push($(arguments[i]));
+    return elements;
+  }
+  if (Object.isString(element))
+    element = document.getElementById(element);
+  return Element.extend(element);
+}
+
+if (Prototype.BrowserFeatures.XPath) {
+  document._getElementsByXPath = function(expression, parentElement) {
+    var results = [];
+    var query = document.evaluate(expression, $(parentElement) || document,
+      null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null);
+    for (var i = 0, length = query.snapshotLength; i < length; i++)
+      results.push(Element.extend(query.snapshotItem(i)));
+    return results;
+  };
+}
+
+/*--------------------------------------------------------------------------*/
+
+if (!Node) var Node = { };
+
+if (!Node.ELEMENT_NODE) {
+  Object.extend(Node, {
+    ELEMENT_NODE: 1,
+    ATTRIBUTE_NODE: 2,
+    TEXT_NODE: 3,
+    CDATA_SECTION_NODE: 4,
+    ENTITY_REFERENCE_NODE: 5,
+    ENTITY_NODE: 6,
+    PROCESSING_INSTRUCTION_NODE: 7,
+    COMMENT_NODE: 8,
+    DOCUMENT_NODE: 9,
+    DOCUMENT_TYPE_NODE: 10,
+    DOCUMENT_FRAGMENT_NODE: 11,
+    NOTATION_NODE: 12
+  });
+}
+
+
+
+(function(global) {
+  function shouldUseCache(tagName, attributes) {
+    if (tagName === 'select') return false;
+    if ('type' in attributes) return false;
+    return true;
+  }
+
+  var HAS_EXTENDED_CREATE_ELEMENT_SYNTAX = (function(){
+    try {
+      var el = document.createElement('<input name="x">');
+      return el.tagName.toLowerCase() === 'input' && el.name === 'x';
+    }
+    catch(err) {
+      return false;
+    }
+  })();
+
+  var element = global.Element;
+
+  global.Element = function(tagName, attributes) {
+    attributes = attributes || { };
+    tagName = tagName.toLowerCase();
+    var cache = Element.cache;
+
+    if (HAS_EXTENDED_CREATE_ELEMENT_SYNTAX && attributes.name) {
+      tagName = '<' + tagName + ' name="' + attributes.name + '">';
+      delete attributes.name;
+      return Element.writeAttribute(document.createElement(tagName), attributes);
+    }
+
+    if (!cache[tagName]) cache[tagName] = Element.extend(document.createElement(tagName));
+
+    var node = shouldUseCache(tagName, attributes) ?
+     cache[tagName].cloneNode(false) : document.createElement(tagName);
+
+    return Element.writeAttribute(node, attributes);
+  };
+
+  Object.extend(global.Element, element || { });
+  if (element) global.Element.prototype = element.prototype;
+
+})(this);
+
+Element.idCounter = 1;
+Element.cache = { };
+
+Element._purgeElement = function(element) {
+  var uid = element._prototypeUID;
+  if (uid) {
+    Element.stopObserving(element);
+    element._prototypeUID = void 0;
+    delete Element.Storage[uid];
+  }
+}
+
+Element.Methods = {
+  visible: function(element) {
+    return $(element).style.display != 'none';
+  },
+
+  toggle: function(element) {
+    element = $(element);
+    Element[Element.visible(element) ? 'hide' : 'show'](element);
+    return element;
+  },
+
+  hide: function(element) {
+    element = $(element);
+    element.style.display = 'none';
+    return element;
+  },
+
+  show: function(element) {
+    element = $(element);
+    element.style.display = '';
+    return element;
+  },
+
+  remove: function(element) {
+    element = $(element);
+    element.parentNode.removeChild(element);
+    return element;
+  },
+
+  update: (function(){
+
+    var SELECT_ELEMENT_INNERHTML_BUGGY = (function(){
+      var el = document.createElement("select"),
+          isBuggy = true;
+      el.innerHTML = "<option value=\"test\">test</option>";
+      if (el.options && el.options[0]) {
+        isBuggy = el.options[0].nodeName.toUpperCase() !== "OPTION";
+      }
+      el = null;
+      return isBuggy;
+    })();
+
+    var TABLE_ELEMENT_INNERHTML_BUGGY = (function(){
+      try {
+        var el = document.createElement("table");
+        if (el && el.tBodies) {
+          el.innerHTML = "<tbody><tr><td>test</td></tr></tbody>";
+          var isBuggy = typeof el.tBodies[0] == "undefined";
+          el = null;
+          return isBuggy;
+        }
+      } catch (e) {
+        return true;
+      }
+    })();
+
+    var LINK_ELEMENT_INNERHTML_BUGGY = (function() {
+      try {
+        var el = document.createElement('div');
+        el.innerHTML = "<link>";
+        var isBuggy = (el.childNodes.length === 0);
+        el = null;
+        return isBuggy;
+      } catch(e) {
+        return true;
+      }
+    })();
+
+    var ANY_INNERHTML_BUGGY = SELECT_ELEMENT_INNERHTML_BUGGY ||
+     TABLE_ELEMENT_INNERHTML_BUGGY || LINK_ELEMENT_INNERHTML_BUGGY;
+
+    var SCRIPT_ELEMENT_REJECTS_TEXTNODE_APPENDING = (function () {
+      var s = document.createElement("script"),
+          isBuggy = false;
+      try {
+        s.appendChild(document.createTextNode(""));
+        isBuggy = !s.firstChild ||
+          s.firstChild && s.firstChild.nodeType !== 3;
+      } catch (e) {
+        isBuggy = true;
+      }
+      s = null;
+      return isBuggy;
+    })();
+
+
+    function update(element, content) {
+      element = $(element);
+      var purgeElement = Element._purgeElement;
+
+      var descendants = element.getElementsByTagName('*'),
+       i = descendants.length;
+      while (i--) purgeElement(descendants[i]);
+
+      if (content && content.toElement)
+        content = content.toElement();
+
+      if (Object.isElement(content))
+        return element.update().insert(content);
+
+      content = Object.toHTML(content);
+
+      var tagName = element.tagName.toUpperCase();
+
+      if (tagName === 'SCRIPT' && SCRIPT_ELEMENT_REJECTS_TEXTNODE_APPENDING) {
+        element.text = content;
+        return element;
+      }
+
+      if (ANY_INNERHTML_BUGGY) {
+        if (tagName in Element._insertionTranslations.tags) {
+          while (element.firstChild) {
+            element.removeChild(element.firstChild);
+          }
+          Element._getContentFromAnonymousElement(tagName, content.stripScripts())
+            .each(function(node) {
+              element.appendChild(node)
+            });
+        } else if (LINK_ELEMENT_INNERHTML_BUGGY && Object.isString(content) && content.indexOf('<link') > -1) {
+          while (element.firstChild) {
+            element.removeChild(element.firstChild);
+          }
+          var nodes = Element._getContentFromAnonymousElement(tagName, content.stripScripts(), true);
+          nodes.each(function(node) { element.appendChild(node) });
+        }
+        else {
+          element.innerHTML = content.stripScripts();
+        }
+      }
+      else {
+        element.innerHTML = content.stripScripts();
+      }
+
+      content.evalScripts.bind(content).defer();
+      return element;
+    }
+
+    return update;
+  })(),
+
+  replace: function(element, content) {
+    element = $(element);
+    if (content && content.toElement) content = content.toElement();
+    else if (!Object.isElement(content)) {
+      content = Object.toHTML(content);
+      var range = element.ownerDocument.createRange();
+      range.selectNode(element);
+      content.evalScripts.bind(content).defer();
+      content = range.createContextualFragment(content.stripScripts());
+    }
+    element.parentNode.replaceChild(content, element);
+    return element;
+  },
+
+  insert: function(element, insertions) {
+    element = $(element);
+
+    if (Object.isString(insertions) || Object.isNumber(insertions) ||
+        Object.isElement(insertions) || (insertions && (insertions.toElement || insertions.toHTML)))
+          insertions = {bottom:insertions};
+
+    var content, insert, tagName, childNodes;
+
+    for (var position in insertions) {
+      content  = insertions[position];
+      position = position.toLowerCase();
+      insert = Element._insertionTranslations[position];
+
+      if (content && content.toElement) content = content.toElement();
+      if (Object.isElement(content)) {
+        insert(element, content);
+        continue;
+      }
+
+      content = Object.toHTML(content);
+
+      tagName = ((position == 'before' || position == 'after')
+        ? element.parentNode : element).tagName.toUpperCase();
+
+      childNodes = Element._getContentFromAnonymousElement(tagName, content.stripScripts());
+
+      if (position == 'top' || position == 'after') childNodes.reverse();
+      childNodes.each(insert.curry(element));
+
+      content.evalScripts.bind(content).defer();
+    }
+
+    return element;
+  },
+
+  wrap: function(element, wrapper, attributes) {
+    element = $(element);
+    if (Object.isElement(wrapper))
+      $(wrapper).writeAttribute(attributes || { });
+    else if (Object.isString(wrapper)) wrapper = new Element(wrapper, attributes);
+    else wrapper = new Element('div', wrapper);
+    if (element.parentNode)
+      element.parentNode.replaceChild(wrapper, element);
+    wrapper.appendChild(element);
+    return wrapper;
+  },
+
+  inspect: function(element) {
+    element = $(element);
+    var result = '<' + element.tagName.toLowerCase();
+    $H({'id': 'id', 'className': 'class'}).each(function(pair) {
+      var property = pair.first(),
+          attribute = pair.last(),
+          value = (element[property] || '').toString();
+      if (value) result += ' ' + attribute + '=' + value.inspect(true);
+    });
+    return result + '>';
+  },
+
+  recursivelyCollect: function(element, property, maximumLength) {
+    element = $(element);
+    maximumLength = maximumLength || -1;
+    var elements = [];
+
+    while (element = element[property]) {
+      if (element.nodeType == 1)
+        elements.push(Element.extend(element));
+      if (elements.length == maximumLength)
+        break;
+    }
+
+    return elements;
+  },
+
+  ancestors: function(element) {
+    return Element.recursivelyCollect(element, 'parentNode');
+  },
+
+  descendants: function(element) {
+    return Element.select(element, "*");
+  },
+
+  firstDescendant: function(element) {
+    element = $(element).firstChild;
+    while (element && element.nodeType != 1) element = element.nextSibling;
+    return $(element);
+  },
+
+  immediateDescendants: function(element) {
+    var results = [], child = $(element).firstChild;
+    while (child) {
+      if (child.nodeType === 1) {
+        results.push(Element.extend(child));
+      }
+      child = child.nextSibling;
+    }
+    return results;
+  },
+
+  previousSiblings: function(element, maximumLength) {
+    return Element.recursivelyCollect(element, 'previousSibling');
+  },
+
+  nextSiblings: function(element) {
+    return Element.recursivelyCollect(element, 'nextSibling');
+  },
+
+  siblings: function(element) {
+    element = $(element);
+    return Element.previousSiblings(element).reverse()
+      .concat(Element.nextSiblings(element));
+  },
+
+  match: function(element, selector) {
+    element = $(element);
+    if (Object.isString(selector))
+      return Prototype.Selector.match(element, selector);
+    return selector.match(element);
+  },
+
+  up: function(element, expression, index) {
+    element = $(element);
+    if (arguments.length == 1) return $(element.parentNode);
+    var ancestors = Element.ancestors(element);
+    return Object.isNumber(expression) ? ancestors[expression] :
+      Prototype.Selector.find(ancestors, expression, index);
+  },
+
+  down: function(element, expression, index) {
+    element = $(element);
+    if (arguments.length == 1) return Element.firstDescendant(element);
+    return Object.isNumber(expression) ? Element.descendants(element)[expression] :
+      Element.select(element, expression)[index || 0];
+  },
+
+  previous: function(element, expression, index) {
+    element = $(element);
+    if (Object.isNumber(expression)) index = expression, expression = false;
+    if (!Object.isNumber(index)) index = 0;
+
+    if (expression) {
+      return Prototype.Selector.find(element.previousSiblings(), expression, index);
+    } else {
+      return element.recursivelyCollect("previousSibling", index + 1)[index];
+    }
+  },
+
+  next: function(element, expression, index) {
+    element = $(element);
+    if (Object.isNumber(expression)) index = expression, expression = false;
+    if (!Object.isNumber(index)) index = 0;
+
+    if (expression) {
+      return Prototype.Selector.find(element.nextSiblings(), expression, index);
+    } else {
+      var maximumLength = Object.isNumber(index) ? index + 1 : 1;
+      return element.recursivelyCollect("nextSibling", index + 1)[index];
+    }
+  },
+
+
+  select: function(element) {
+    element = $(element);
+    var expressions = Array.prototype.slice.call(arguments, 1).join(', ');
+    return Prototype.Selector.select(expressions, element);
+  },
+
+  adjacent: function(element) {
+    element = $(element);
+    var expressions = Array.prototype.slice.call(arguments, 1).join(', ');
+    return Prototype.Selector.select(expressions, element.parentNode).without(element);
+  },
+
+  identify: function(element) {
+    element = $(element);
+    var id = Element.readAttribute(element, 'id');
+    if (id) return id;
+    do { id = 'anonymous_element_' + Element.idCounter++ } while ($(id));
+    Element.writeAttribute(element, 'id', id);
+    return id;
+  },
+
+  readAttribute: function(element, name) {
+    element = $(element);
+    if (Prototype.Browser.IE) {
+      var t = Element._attributeTranslations.read;
+      if (t.values[name]) return t.values[name](element, name);
+      if (t.names[name]) name = t.names[name];
+      if (name.include(':')) {
+        return (!element.attributes || !element.attributes[name]) ? null :
+         element.attributes[name].value;
+      }
+    }
+    return element.getAttribute(name);
+  },
+
+  writeAttribute: function(element, name, value) {
+    element = $(element);
+    var attributes = { }, t = Element._attributeTranslations.write;
+
+    if (typeof name == 'object') attributes = name;
+    else attributes[name] = Object.isUndefined(value) ? true : value;
+
+    for (var attr in attributes) {
+      name = t.names[attr] || attr;
+      value = attributes[attr];
+      if (t.values[attr]) name = t.values[attr](element, value);
+      if (value === false || value === null)
+        element.removeAttribute(name);
+      else if (value === true)
+        element.setAttribute(name, name);
+      else element.setAttribute(name, value);
+    }
+    return element;
+  },
+
+  getHeight: function(element) {
+    return Element.getDimensions(element).height;
+  },
+
+  getWidth: function(element) {
+    return Element.getDimensions(element).width;
+  },
+
+  classNames: function(element) {
+    return new Element.ClassNames(element);
+  },
+
+  hasClassName: function(element, className) {
+    if (!(element = $(element))) return;
+    var elementClassName = element.className;
+    return (elementClassName.length > 0 && (elementClassName == className ||
+      new RegExp("(^|\\s)" + className + "(\\s|$)").test(elementClassName)));
+  },
+
+  addClassName: function(element, className) {
+    if (!(element = $(element))) return;
+    if (!Element.hasClassName(element, className))
+      element.className += (element.className ? ' ' : '') + className;
+    return element;
+  },
+
+  removeClassName: function(element, className) {
+    if (!(element = $(element))) return;
+    element.className = element.className.replace(
+      new RegExp("(^|\\s+)" + className + "(\\s+|$)"), ' ').strip();
+    return element;
+  },
+
+  toggleClassName: function(element, className) {
+    if (!(element = $(element))) return;
+    return Element[Element.hasClassName(element, className) ?
+      'removeClassName' : 'addClassName'](element, className);
+  },
+
+  cleanWhitespace: function(element) {
+    element = $(element);
+    var node = element.firstChild;
+    while (node) {
+      var nextNode = node.nextSibling;
+      if (node.nodeType == 3 && !/\S/.test(node.nodeValue))
+        element.removeChild(node);
+      node = nextNode;
+    }
+    return element;
+  },
+
+  empty: function(element) {
+    return $(element).innerHTML.blank();
+  },
+
+  descendantOf: function(element, ancestor) {
+    element = $(element), ancestor = $(ancestor);
+
+    if (element.compareDocumentPosition)
+      return (element.compareDocumentPosition(ancestor) & 8) === 8;
+
+    if (ancestor.contains)
+      return ancestor.contains(element) && ancestor !== element;
+
+    while (element = element.parentNode)
+      if (element == ancestor) return true;
+
+    return false;
+  },
+
+  scrollTo: function(element) {
+    element = $(element);
+    var pos = Element.cumulativeOffset(element);
+    window.scrollTo(pos[0], pos[1]);
+    return element;
+  },
+
+  getStyle: function(element, style) {
+    element = $(element);
+    style = style == 'float' ? 'cssFloat' : style.camelize();
+    var value = element.style[style];
+    if (!value || value == 'auto') {
+      var css = document.defaultView.getComputedStyle(element, null);
+      value = css ? css[style] : null;
+    }
+    if (style == 'opacity') return value ? parseFloat(value) : 1.0;
+    return value == 'auto' ? null : value;
+  },
+
+  getOpacity: function(element) {
+    return $(element).getStyle('opacity');
+  },
+
+  setStyle: function(element, styles) {
+    element = $(element);
+    var elementStyle = element.style, match;
+    if (Object.isString(styles)) {
+      element.style.cssText += ';' + styles;
+      return styles.include('opacity') ?
+        element.setOpacity(styles.match(/opacity:\s*(\d?\.?\d*)/)[1]) : element;
+    }
+    for (var property in styles)
+      if (property == 'opacity') element.setOpacity(styles[property]);
+      else
+        elementStyle[(property == 'float' || property == 'cssFloat') ?
+          (Object.isUndefined(elementStyle.styleFloat) ? 'cssFloat' : 'styleFloat') :
+            property] = styles[property];
+
+    return element;
+  },
+
+  setOpacity: function(element, value) {
+    element = $(element);
+    element.style.opacity = (value == 1 || value === '') ? '' :
+      (value < 0.00001) ? 0 : value;
+    return element;
+  },
+
+  makePositioned: function(element) {
+    element = $(element);
+    var pos = Element.getStyle(element, 'position');
+    if (pos == 'static' || !pos) {
+      element._madePositioned = true;
+      element.style.position = 'relative';
+      if (Prototype.Browser.Opera) {
+        element.style.top = 0;
+        element.style.left = 0;
+      }
+    }
+    return element;
+  },
+
+  undoPositioned: function(element) {
+    element = $(element);
+    if (element._madePositioned) {
+      element._madePositioned = undefined;
+      element.style.position =
+        element.style.top =
+        element.style.left =
+        element.style.bottom =
+        element.style.right = '';
+    }
+    return element;
+  },
+
+  makeClipping: function(element) {
+    element = $(element);
+    if (element._overflow) return element;
+    element._overflow = Element.getStyle(element, 'overflow') || 'auto';
+    if (element._overflow !== 'hidden')
+      element.style.overflow = 'hidden';
+    return element;
+  },
+
+  undoClipping: function(element) {
+    element = $(element);
+    if (!element._overflow) return element;
+    element.style.overflow = element._overflow == 'auto' ? '' : element._overflow;
+    element._overflow = null;
+    return element;
+  },
+
+  clonePosition: function(element, source) {
+    var options = Object.extend({
+      setLeft:    true,
+      setTop:     true,
+      setWidth:   true,
+      setHeight:  true,
+      offsetTop:  0,
+      offsetLeft: 0
+    }, arguments[2] || { });
+
+    source = $(source);
+    var p = Element.viewportOffset(source), delta = [0, 0], parent = null;
+
+    element = $(element);
+
+    if (Element.getStyle(element, 'position') == 'absolute') {
+      parent = Element.getOffsetParent(element);
+      delta = Element.viewportOffset(parent);
+    }
+
+    if (parent == document.body) {
+      delta[0] -= document.body.offsetLeft;
+      delta[1] -= document.body.offsetTop;
+    }
+
+    if (options.setLeft)   element.style.left  = (p[0] - delta[0] + options.offsetLeft) + 'px';
+    if (options.setTop)    element.style.top   = (p[1] - delta[1] + options.offsetTop) + 'px';
+    if (options.setWidth)  element.style.width = source.offsetWidth + 'px';
+    if (options.setHeight) element.style.height = source.offsetHeight + 'px';
+    return element;
+  }
+};
+
+Object.extend(Element.Methods, {
+  getElementsBySelector: Element.Methods.select,
+
+  childElements: Element.Methods.immediateDescendants
+});
+
+Element._attributeTranslations = {
+  write: {
+    names: {
+      className: 'class',
+      htmlFor:   'for'
+    },
+    values: { }
+  }
+};
+
+if (Prototype.Browser.Opera) {
+  Element.Methods.getStyle = Element.Methods.getStyle.wrap(
+    function(proceed, element, style) {
+      switch (style) {
+        case 'height': case 'width':
+          if (!Element.visible(element)) return null;
+
+          var dim = parseInt(proceed(element, style), 10);
+
+          if (dim !== element['offset' + style.capitalize()])
+            return dim + 'px';
+
+          var properties;
+          if (style === 'height') {
+            properties = ['border-top-width', 'padding-top',
+             'padding-bottom', 'border-bottom-width'];
+          }
+          else {
+            properties = ['border-left-width', 'padding-left',
+             'padding-right', 'border-right-width'];
+          }
+          return properties.inject(dim, function(memo, property) {
+            var val = proceed(element, property);
+            return val === null ? memo : memo - parseInt(val, 10);
+          }) + 'px';
+        default: return proceed(element, style);
+      }
+    }
+  );
+
+  Element.Methods.readAttribute = Element.Methods.readAttribute.wrap(
+    function(proceed, element, attribute) {
+      if (attribute === 'title') return element.title;
+      return proceed(element, attribute);
+    }
+  );
+}
+
+else if (Prototype.Browser.IE) {
+  Element.Methods.getStyle = function(element, style) {
+    element = $(element);
+    style = (style == 'float' || style == 'cssFloat') ? 'styleFloat' : style.camelize();
+    var value = element.style[style];
+    if (!value && element.currentStyle) value = element.currentStyle[style];
+
+    if (style == 'opacity') {
+      if (value = (element.getStyle('filter') || '').match(/alpha\(opacity=(.*)\)/))
+        if (value[1]) return parseFloat(value[1]) / 100;
+      return 1.0;
+    }
+
+    if (value == 'auto') {
+      if ((style == 'width' || style == 'height') && (element.getStyle('display') != 'none'))
+        return element['offset' + style.capitalize()] + 'px';
+      return null;
+    }
+    return value;
+  };
+
+  Element.Methods.setOpacity = function(element, value) {
+    function stripAlpha(filter){
+      return filter.replace(/alpha\([^\)]*\)/gi,'');
+    }
+    element = $(element);
+    var currentStyle = element.currentStyle;
+    if ((currentStyle && !currentStyle.hasLayout) ||
+      (!currentStyle && element.style.zoom == 'normal'))
+        element.style.zoom = 1;
+
+    var filter = element.getStyle('filter'), style = element.style;
+    if (value == 1 || value === '') {
+      (filter = stripAlpha(filter)) ?
+        style.filter = filter : style.removeAttribute('filter');
+      return element;
+    } else if (value < 0.00001) value = 0;
+    style.filter = stripAlpha(filter) +
+      'alpha(opacity=' + (value * 100) + ')';
+    return element;
+  };
+
+  Element._attributeTranslations = (function(){
+
+    var classProp = 'className',
+        forProp = 'for',
+        el = document.createElement('div');
+
+    el.setAttribute(classProp, 'x');
+
+    if (el.className !== 'x') {
+      el.setAttribute('class', 'x');
+      if (el.className === 'x') {
+        classProp = 'class';
+      }
+    }
+    el = null;
+
+    el = document.createElement('label');
+    el.setAttribute(forProp, 'x');
+    if (el.htmlFor !== 'x') {
+      el.setAttribute('htmlFor', 'x');
+      if (el.htmlFor === 'x') {
+        forProp = 'htmlFor';
+      }
+    }
+    el = null;
+
+    return {
+      read: {
+        names: {
+          'class':      classProp,
+          'className':  classProp,
+          'for':        forProp,
+          'htmlFor':    forProp
+        },
+        values: {
+          _getAttr: function(element, attribute) {
+            return element.getAttribute(attribute);
+          },
+          _getAttr2: function(element, attribute) {
+            return element.getAttribute(attribute, 2);
+          },
+          _getAttrNode: function(element, attribute) {
+            var node = element.getAttributeNode(attribute);
+            return node ? node.value : "";
+          },
+          _getEv: (function(){
+
+            var el = document.createElement('div'), f;
+            el.onclick = Prototype.emptyFunction;
+            var value = el.getAttribute('onclick');
+
+            if (String(value).indexOf('{') > -1) {
+              f = function(element, attribute) {
+                attribute = element.getAttribute(attribute);
+                if (!attribute) return null;
+                attribute = attribute.toString();
+                attribute = attribute.split('{')[1];
+                attribute = attribute.split('}')[0];
+                return attribute.strip();
+              };
+            }
+            else if (value === '') {
+              f = function(element, attribute) {
+                attribute = element.getAttribute(attribute);
+                if (!attribute) return null;
+                return attribute.strip();
+              };
+            }
+            el = null;
+            return f;
+          })(),
+          _flag: function(element, attribute) {
+            return $(element).hasAttribute(attribute) ? attribute : null;
+          },
+          style: function(element) {
+            return element.style.cssText.toLowerCase();
+          },
+          title: function(element) {
+            return element.title;
+          }
+        }
+      }
+    }
+  })();
+
+  Element._attributeTranslations.write = {
+    names: Object.extend({
+      cellpadding: 'cellPadding',
+      cellspacing: 'cellSpacing'
+    }, Element._attributeTranslations.read.names),
+    values: {
+      checked: function(element, value) {
+        element.checked = !!value;
+      },
+
+      style: function(element, value) {
+        element.style.cssText = value ? value : '';
+      }
+    }
+  };
+
+  Element._attributeTranslations.has = {};
+
+  $w('colSpan rowSpan vAlign dateTime accessKey tabIndex ' +
+      'encType maxLength readOnly longDesc frameBorder').each(function(attr) {
+    Element._attributeTranslations.write.names[attr.toLowerCase()] = attr;
+    Element._attributeTranslations.has[attr.toLowerCase()] = attr;
+  });
+
+  (function(v) {
+    Object.extend(v, {
+      href:        v._getAttr2,
+      src:         v._getAttr2,
+      type:        v._getAttr,
+      action:      v._getAttrNode,
+      disabled:    v._flag,
+      checked:     v._flag,
+      readonly:    v._flag,
+      multiple:    v._flag,
+      onload:      v._getEv,
+      onunload:    v._getEv,
+      onclick:     v._getEv,
+      ondblclick:  v._getEv,
+      onmousedown: v._getEv,
+      onmouseup:   v._getEv,
+      onmouseover: v._getEv,
+      onmousemove: v._getEv,
+      onmouseout:  v._getEv,
+      onfocus:     v._getEv,
+      onblur:      v._getEv,
+      onkeypress:  v._getEv,
+      onkeydown:   v._getEv,
+      onkeyup:     v._getEv,
+      onsubmit:    v._getEv,
+      onreset:     v._getEv,
+      onselect:    v._getEv,
+      onchange:    v._getEv
+    });
+  })(Element._attributeTranslations.read.values);
+
+  if (Prototype.BrowserFeatures.ElementExtensions) {
+    (function() {
+      function _descendants(element) {
+        var nodes = element.getElementsByTagName('*'), results = [];
+        for (var i = 0, node; node = nodes[i]; i++)
+          if (node.tagName !== "!") // Filter out comment nodes.
+            results.push(node);
+        return results;
+      }
+
+      Element.Methods.down = function(element, expression, index) {
+        element = $(element);
+        if (arguments.length == 1) return element.firstDescendant();
+        return Object.isNumber(expression) ? _descendants(element)[expression] :
+          Element.select(element, expression)[index || 0];
+      }
+    })();
+  }
+
+}
+
+else if (Prototype.Browser.Gecko && /rv:1\.8\.0/.test(navigator.userAgent)) {
+  Element.Methods.setOpacity = function(element, value) {
+    element = $(element);
+    element.style.opacity = (value == 1) ? 0.999999 :
+      (value === '') ? '' : (value < 0.00001) ? 0 : value;
+    return element;
+  };
+}
+
+else if (Prototype.Browser.WebKit) {
+  Element.Methods.setOpacity = function(element, value) {
+    element = $(element);
+    element.style.opacity = (value == 1 || value === '') ? '' :
+      (value < 0.00001) ? 0 : value;
+
+    if (value == 1)
+      if (element.tagName.toUpperCase() == 'IMG' && element.width) {
+        element.width++; element.width--;
+      } else try {
+        var n = document.createTextNode(' ');
+        element.appendChild(n);
+        element.removeChild(n);
+      } catch (e) { }
+
+    return element;
+  };
+}
+
+if ('outerHTML' in document.documentElement) {
+  Element.Methods.replace = function(element, content) {
+    element = $(element);
+
+    if (content && content.toElement) content = content.toElement();
+    if (Object.isElement(content)) {
+      element.parentNode.replaceChild(content, element);
+      return element;
+    }
+
+    content = Object.toHTML(content);
+    var parent = element.parentNode, tagName = parent.tagName.toUpperCase();
+
+    if (Element._insertionTranslations.tags[tagName]) {
+      var nextSibling = element.next(),
+          fragments = Element._getContentFromAnonymousElement(tagName, content.stripScripts());
+      parent.removeChild(element);
+      if (nextSibling)
+        fragments.each(function(node) { parent.insertBefore(node, nextSibling) });
+      else
+        fragments.each(function(node) { parent.appendChild(node) });
+    }
+    else element.outerHTML = content.stripScripts();
+
+    content.evalScripts.bind(content).defer();
+    return element;
+  };
+}
+
+Element._returnOffset = function(l, t) {
+  var result = [l, t];
+  result.left = l;
+  result.top = t;
+  return result;
+};
+
+Element._getContentFromAnonymousElement = function(tagName, html, force) {
+  var div = new Element('div'),
+      t = Element._insertionTranslations.tags[tagName];
+
+  var workaround = false;
+  if (t) workaround = true;
+  else if (force) {
+    workaround = true;
+    t = ['', '', 0];
+  }
+
+  if (workaround) {
+    div.innerHTML = '&nbsp;' + t[0] + html + t[1];
+    div.removeChild(div.firstChild);
+    for (var i = t[2]; i--; ) {
+      div = div.firstChild;
+    }
+  }
+  else {
+    div.innerHTML = html;
+  }
+  return $A(div.childNodes);
+};
+
+Element._insertionTranslations = {
+  before: function(element, node) {
+    element.parentNode.insertBefore(node, element);
+  },
+  top: function(element, node) {
+    element.insertBefore(node, element.firstChild);
+  },
+  bottom: function(element, node) {
+    element.appendChild(node);
+  },
+  after: function(element, node) {
+    element.parentNode.insertBefore(node, element.nextSibling);
+  },
+  tags: {
+    TABLE:  ['<table>',                '</table>',                   1],
+    TBODY:  ['<table><tbody>',         '</tbody></table>',           2],
+    TR:     ['<table><tbody><tr>',     '</tr></tbody></table>',      3],
+    TD:     ['<table><tbody><tr><td>', '</td></tr></tbody></table>', 4],
+    SELECT: ['<select>',               '</select>',                  1]
+  }
+};
+
+(function() {
+  var tags = Element._insertionTranslations.tags;
+  Object.extend(tags, {
+    THEAD: tags.TBODY,
+    TFOOT: tags.TBODY,
+    TH:    tags.TD
+  });
+})();
+
+Element.Methods.Simulated = {
+  hasAttribute: function(element, attribute) {
+    attribute = Element._attributeTranslations.has[attribute] || attribute;
+    var node = $(element).getAttributeNode(attribute);
+    return !!(node && node.specified);
+  }
+};
+
+Element.Methods.ByTag = { };
+
+Object.extend(Element, Element.Methods);
+
+(function(div) {
+
+  if (!Prototype.BrowserFeatures.ElementExtensions && div['__proto__']) {
+    window.HTMLElement = { };
+    window.HTMLElement.prototype = div['__proto__'];
+    Prototype.BrowserFeatures.ElementExtensions = true;
+  }
+
+  div = null;
+
+})(document.createElement('div'));
+
+Element.extend = (function() {
+
+  function checkDeficiency(tagName) {
+    if (typeof window.Element != 'undefined') {
+      var proto = window.Element.prototype;
+      if (proto) {
+        var id = '_' + (Math.random()+'').slice(2),
+            el = document.createElement(tagName);
+        proto[id] = 'x';
+        var isBuggy = (el[id] !== 'x');
+        delete proto[id];
+        el = null;
+        return isBuggy;
+      }
+    }
+    return false;
+  }
+
+  function extendElementWith(element, methods) {
+    for (var property in methods) {
+      var value = methods[property];
+      if (Object.isFunction(value) && !(property in element))
+        element[property] = value.methodize();
+    }
+  }
+
+  var HTMLOBJECTELEMENT_PROTOTYPE_BUGGY = checkDeficiency('object');
+
+  if (Prototype.BrowserFeatures.SpecificElementExtensions) {
+    if (HTMLOBJECTELEMENT_PROTOTYPE_BUGGY) {
+      return function(element) {
+        if (element && typeof element._extendedByPrototype == 'undefined') {
+          var t = element.tagName;
+          if (t && (/^(?:object|applet|embed)$/i.test(t))) {
+            extendElementWith(element, Element.Methods);
+            extendElementWith(element, Element.Methods.Simulated);
+            extendElementWith(element, Element.Methods.ByTag[t.toUpperCase()]);
+          }
+        }
+        return element;
+      }
+    }
+    return Prototype.K;
+  }
+
+  var Methods = { }, ByTag = Element.Methods.ByTag;
+
+  var extend = Object.extend(function(element) {
+    if (!element || typeof element._extendedByPrototype != 'undefined' ||
+        element.nodeType != 1 || element == window) return element;
+
+    var methods = Object.clone(Methods),
+        tagName = element.tagName.toUpperCase();
+
+    if (ByTag[tagName]) Object.extend(methods, ByTag[tagName]);
+
+    extendElementWith(element, methods);
+
+    element._extendedByPrototype = Prototype.emptyFunction;
+    return element;
+
+  }, {
+    refresh: function() {
+      if (!Prototype.BrowserFeatures.ElementExtensions) {
+        Object.extend(Methods, Element.Methods);
+        Object.extend(Methods, Element.Methods.Simulated);
+      }
+    }
+  });
+
+  extend.refresh();
+  return extend;
+})();
+
+if (document.documentElement.hasAttribute) {
+  Element.hasAttribute = function(element, attribute) {
+    return element.hasAttribute(attribute);
+  };
+}
+else {
+  Element.hasAttribute = Element.Methods.Simulated.hasAttribute;
+}
+
+Element.addMethods = function(methods) {
+  var F = Prototype.BrowserFeatures, T = Element.Methods.ByTag;
+
+  if (!methods) {
+    Object.extend(Form, Form.Methods);
+    Object.extend(Form.Element, Form.Element.Methods);
+    Object.extend(Element.Methods.ByTag, {
+      "FORM":     Object.clone(Form.Methods),
+      "INPUT":    Object.clone(Form.Element.Methods),
+      "SELECT":   Object.clone(Form.Element.Methods),
+      "TEXTAREA": Object.clone(Form.Element.Methods),
+      "BUTTON":   Object.clone(Form.Element.Methods)
+    });
+  }
+
+  if (arguments.length == 2) {
+    var tagName = methods;
+    methods = arguments[1];
+  }
+
+  if (!tagName) Object.extend(Element.Methods, methods || { });
+  else {
+    if (Object.isArray(tagName)) tagName.each(extend);
+    else extend(tagName);
+  }
+
+  function extend(tagName) {
+    tagName = tagName.toUpperCase();
+    if (!Element.Methods.ByTag[tagName])
+      Element.Methods.ByTag[tagName] = { };
+    Object.extend(Element.Methods.ByTag[tagName], methods);
+  }
+
+  function copy(methods, destination, onlyIfAbsent) {
+    onlyIfAbsent = onlyIfAbsent || false;
+    for (var property in methods) {
+      var value = methods[property];
+      if (!Object.isFunction(value)) continue;
+      if (!onlyIfAbsent || !(property in destination))
+        destination[property] = value.methodize();
+    }
+  }
+
+  function findDOMClass(tagName) {
+    var klass;
+    var trans = {
+      "OPTGROUP": "OptGroup", "TEXTAREA": "TextArea", "P": "Paragraph",
+      "FIELDSET": "FieldSet", "UL": "UList", "OL": "OList", "DL": "DList",
+      "DIR": "Directory", "H1": "Heading", "H2": "Heading", "H3": "Heading",
+      "H4": "Heading", "H5": "Heading", "H6": "Heading", "Q": "Quote",
+      "INS": "Mod", "DEL": "Mod", "A": "Anchor", "IMG": "Image", "CAPTION":
+      "TableCaption", "COL": "TableCol", "COLGROUP": "TableCol", "THEAD":
+      "TableSection", "TFOOT": "TableSection", "TBODY": "TableSection", "TR":
+      "TableRow", "TH": "TableCell", "TD": "TableCell", "FRAMESET":
+      "FrameSet", "IFRAME": "IFrame"
+    };
+    if (trans[tagName]) klass = 'HTML' + trans[tagName] + 'Element';
+    if (window[klass]) return window[klass];
+    klass = 'HTML' + tagName + 'Element';
+    if (window[klass]) return window[klass];
+    klass = 'HTML' + tagName.capitalize() + 'Element';
+    if (window[klass]) return window[klass];
+
+    var element = document.createElement(tagName),
+        proto = element['__proto__'] || element.constructor.prototype;
+
+    element = null;
+    return proto;
+  }
+
+  var elementPrototype = window.HTMLElement ? HTMLElement.prototype :
+   Element.prototype;
+
+  if (F.ElementExtensions) {
+    copy(Element.Methods, elementPrototype);
+    copy(Element.Methods.Simulated, elementPrototype, true);
+  }
+
+  if (F.SpecificElementExtensions) {
+    for (var tag in Element.Methods.ByTag) {
+      var klass = findDOMClass(tag);
+      if (Object.isUndefined(klass)) continue;
+      copy(T[tag], klass.prototype);
+    }
+  }
+
+  Object.extend(Element, Element.Methods);
+  delete Element.ByTag;
+
+  if (Element.extend.refresh) Element.extend.refresh();
+  Element.cache = { };
+};
+
+
+document.viewport = {
+
+  getDimensions: function() {
+    return { width: this.getWidth(), height: this.getHeight() };
+  },
+
+  getScrollOffsets: function() {
+    return Element._returnOffset(
+      window.pageXOffset || document.documentElement.scrollLeft || document.body.scrollLeft,
+      window.pageYOffset || document.documentElement.scrollTop  || document.body.scrollTop);
+  }
+};
+
+(function(viewport) {
+  var B = Prototype.Browser, doc = document, element, property = {};
+
+  function getRootElement() {
+    if (B.WebKit && !doc.evaluate)
+      return document;
+
+    if (B.Opera && window.parseFloat(window.opera.version()) < 9.5)
+      return document.body;
+
+    return document.documentElement;
+  }
+
+  function define(D) {
+    if (!element) element = getRootElement();
+
+    property[D] = 'client' + D;
+
+    viewport['get' + D] = function() { return element[property[D]] };
+    return viewport['get' + D]();
+  }
+
+  viewport.getWidth  = define.curry('Width');
+
+  viewport.getHeight = define.curry('Height');
+})(document.viewport);
+
+
+Element.Storage = {
+  UID: 1
+};
+
+Element.addMethods({
+  getStorage: function(element) {
+    if (!(element = $(element))) return;
+
+    var uid;
+    if (element === window) {
+      uid = 0;
+    } else {
+      if (typeof element._prototypeUID === "undefined")
+        element._prototypeUID = Element.Storage.UID++;
+      uid = element._prototypeUID;
+    }
+
+    if (!Element.Storage[uid])
+      Element.Storage[uid] = $H();
+
+    return Element.Storage[uid];
+  },
+
+  store: function(element, key, value) {
+    if (!(element = $(element))) return;
+
+    if (arguments.length === 2) {
+      Element.getStorage(element).update(key);
+    } else {
+      Element.getStorage(element).set(key, value);
+    }
+
+    return element;
+  },
+
+  retrieve: function(element, key, defaultValue) {
+    if (!(element = $(element))) return;
+    var hash = Element.getStorage(element), value = hash.get(key);
+
+    if (Object.isUndefined(value)) {
+      hash.set(key, defaultValue);
+      value = defaultValue;
+    }
+
+    return value;
+  },
+
+  clone: function(element, deep) {
+    if (!(element = $(element))) return;
+    var clone = element.cloneNode(deep);
+    clone._prototypeUID = void 0;
+    if (deep) {
+      var descendants = Element.select(clone, '*'),
+          i = descendants.length;
+      while (i--) {
+        descendants[i]._prototypeUID = void 0;
+      }
+    }
+    return Element.extend(clone);
+  },
+
+  purge: function(element) {
+    if (!(element = $(element))) return;
+    var purgeElement = Element._purgeElement;
+
+    purgeElement(element);
+
+    var descendants = element.getElementsByTagName('*'),
+     i = descendants.length;
+
+    while (i--) purgeElement(descendants[i]);
+
+    return null;
+  }
+});
+
+(function() {
+
+  function toDecimal(pctString) {
+    var match = pctString.match(/^(\d+)%?$/i);
+    if (!match) return null;
+    return (Number(match[1]) / 100);
+  }
+
+  function getPixelValue(value, property, context) {
+    var element = null;
+    if (Object.isElement(value)) {
+      element = value;
+      value = element.getStyle(property);
+    }
+
+    if (value === null) {
+      return null;
+    }
+
+    if ((/^(?:-)?\d+(\.\d+)?(px)?$/i).test(value)) {
+      return window.parseFloat(value);
+    }
+
+    var isPercentage = value.include('%'), isViewport = (context === document.viewport);
+
+    if (/\d/.test(value) && element && element.runtimeStyle && !(isPercentage && isViewport)) {
+      var style = element.style.left, rStyle = element.runtimeStyle.left;
+      element.runtimeStyle.left = element.currentStyle.left;
+      element.style.left = value || 0;
+      value = element.style.pixelLeft;
+      element.style.left = style;
+      element.runtimeStyle.left = rStyle;
+
+      return value;
+    }
+
+    if (element && isPercentage) {
+      context = context || element.parentNode;
+      var decimal = toDecimal(value);
+      var whole = null;
+      var position = element.getStyle('position');
+
+      var isHorizontal = property.include('left') || property.include('right') ||
+       property.include('width');
+
+      var isVertical =  property.include('top') || property.include('bottom') ||
+        property.include('height');
+
+      if (context === document.viewport) {
+        if (isHorizontal) {
+          whole = document.viewport.getWidth();
+        } else if (isVertical) {
+          whole = document.viewport.getHeight();
+        }
+      } else {
+        if (isHorizontal) {
+          whole = $(context).measure('width');
+        } else if (isVertical) {
+          whole = $(context).measure('height');
+        }
+      }
+
+      return (whole === null) ? 0 : whole * decimal;
+    }
+
+    return 0;
+  }
+
+  function toCSSPixels(number) {
+    if (Object.isString(number) && number.endsWith('px')) {
+      return number;
+    }
+    return number + 'px';
+  }
+
+  function isDisplayed(element) {
+    var originalElement = element;
+    while (element && element.parentNode) {
+      var display = element.getStyle('display');
+      if (display === 'none') {
+        return false;
+      }
+      element = $(element.parentNode);
+    }
+    return true;
+  }
+
+  var hasLayout = Prototype.K;
+  if ('currentStyle' in document.documentElement) {
+    hasLayout = function(element) {
+      if (!element.currentStyle.hasLayout) {
+        element.style.zoom = 1;
+      }
+      return element;
+    };
+  }
+
+  function cssNameFor(key) {
+    if (key.include('border')) key = key + '-width';
+    return key.camelize();
+  }
+
+  Element.Layout = Class.create(Hash, {
+    initialize: function($super, element, preCompute) {
+      $super();
+      this.element = $(element);
+
+      Element.Layout.PROPERTIES.each( function(property) {
+        this._set(property, null);
+      }, this);
+
+      if (preCompute) {
+        this._preComputing = true;
+        this._begin();
+        Element.Layout.PROPERTIES.each( this._compute, this );
+        this._end();
+        this._preComputing = false;
+      }
+    },
+
+    _set: function(property, value) {
+      return Hash.prototype.set.call(this, property, value);
+    },
+
+    set: function(property, value) {
+      throw "Properties of Element.Layout are read-only.";
+    },
+
+    get: function($super, property) {
+      var value = $super(property);
+      return value === null ? this._compute(property) : value;
+    },
+
+    _begin: function() {
+      if (this._prepared) return;
+
+      var element = this.element;
+      if (isDisplayed(element)) {
+        this._prepared = true;
+        return;
+      }
+
+      var originalStyles = {
+        position:   element.style.position   || '',
+        width:      element.style.width      || '',
+        visibility: element.style.visibility || '',
+        display:    element.style.display    || ''
+      };
+
+      element.store('prototype_original_styles', originalStyles);
+
+      var position = element.getStyle('position'),
+       width = element.getStyle('width');
+
+      if (width === "0px" || width === null) {
+        element.style.display = 'block';
+        width = element.getStyle('width');
+      }
+
+      var context = (position === 'fixed') ? document.viewport :
+       element.parentNode;
+
+      element.setStyle({
+        position:   'absolute',
+        visibility: 'hidden',
+        display:    'block'
+      });
+
+      var positionedWidth = element.getStyle('width');
+
+      var newWidth;
+      if (width && (positionedWidth === width)) {
+        newWidth = getPixelValue(element, 'width', context);
+      } else if (position === 'absolute' || position === 'fixed') {
+        newWidth = getPixelValue(element, 'width', context);
+      } else {
+        var parent = element.parentNode, pLayout = $(parent).getLayout();
+
+        newWidth = pLayout.get('width') -
+         this.get('margin-left') -
+         this.get('border-left') -
+         this.get('padding-left') -
+         this.get('padding-right') -
+         this.get('border-right') -
+         this.get('margin-right');
+      }
+
+      element.setStyle({ width: newWidth + 'px' });
+
+      this._prepared = true;
+    },
+
+    _end: function() {
+      var element = this.element;
+      var originalStyles = element.retrieve('prototype_original_styles');
+      element.store('prototype_original_styles', null);
+      element.setStyle(originalStyles);
+      this._prepared = false;
+    },
+
+    _compute: function(property) {
+      var COMPUTATIONS = Element.Layout.COMPUTATIONS;
+      if (!(property in COMPUTATIONS)) {
+        throw "Property not found.";
+      }
+
+      return this._set(property, COMPUTATIONS[property].call(this, this.element));
+    },
+
+    toObject: function() {
+      var args = $A(arguments);
+      var keys = (args.length === 0) ? Element.Layout.PROPERTIES :
+       args.join(' ').split(' ');
+      var obj = {};
+      keys.each( function(key) {
+        if (!Element.Layout.PROPERTIES.include(key)) return;
+        var value = this.get(key);
+        if (value != null) obj[key] = value;
+      }, this);
+      return obj;
+    },
+
+    toHash: function() {
+      var obj = this.toObject.apply(this, arguments);
+      return new Hash(obj);
+    },
+
+    toCSS: function() {
+      var args = $A(arguments);
+      var keys = (args.length === 0) ? Element.Layout.PROPERTIES :
+       args.join(' ').split(' ');
+      var css = {};
+
+      keys.each( function(key) {
+        if (!Element.Layout.PROPERTIES.include(key)) return;
+        if (Element.Layout.COMPOSITE_PROPERTIES.include(key)) return;
+
+        var value = this.get(key);
+        if (value != null) css[cssNameFor(key)] = value + 'px';
+      }, this);
+      return css;
+    },
+
+    inspect: function() {
+      return "#<Element.Layout>";
+    }
+  });
+
+  Object.extend(Element.Layout, {
+    PROPERTIES: $w('height width top left right bottom border-left border-right border-top border-bottom padding-left padding-right padding-top padding-bottom margin-top margin-bottom margin-left margin-right padding-box-width padding-box-height border-box-width border-box-height margin-box-width margin-box-height'),
+
+    COMPOSITE_PROPERTIES: $w('padding-box-width padding-box-height margin-box-width margin-box-height border-box-width border-box-height'),
+
+    COMPUTATIONS: {
+      'height': function(element) {
+        if (!this._preComputing) this._begin();
+
+        var bHeight = this.get('border-box-height');
+        if (bHeight <= 0) {
+          if (!this._preComputing) this._end();
+          return 0;
+        }
+
+        var bTop = this.get('border-top'),
+         bBottom = this.get('border-bottom');
+
+        var pTop = this.get('padding-top'),
+         pBottom = this.get('padding-bottom');
+
+        if (!this._preComputing) this._end();
+
+        return bHeight - bTop - bBottom - pTop - pBottom;
+      },
+
+      'width': function(element) {
+        if (!this._preComputing) this._begin();
+
+        var bWidth = this.get('border-box-width');
+        if (bWidth <= 0) {
+          if (!this._preComputing) this._end();
+          return 0;
+        }
+
+        var bLeft = this.get('border-left'),
+         bRight = this.get('border-right');
+
+        var pLeft = this.get('padding-left'),
+         pRight = this.get('padding-right');
+
+        if (!this._preComputing) this._end();
+
+        return bWidth - bLeft - bRight - pLeft - pRight;
+      },
+
+      'padding-box-height': function(element) {
+        var height = this.get('height'),
+         pTop = this.get('padding-top'),
+         pBottom = this.get('padding-bottom');
+
+        return height + pTop + pBottom;
+      },
+
+      'padding-box-width': function(element) {
+        var width = this.get('width'),
+         pLeft = this.get('padding-left'),
+         pRight = this.get('padding-right');
+
+        return width + pLeft + pRight;
+      },
+
+      'border-box-height': function(element) {
+        if (!this._preComputing) this._begin();
+        var height = element.offsetHeight;
+        if (!this._preComputing) this._end();
+        return height;
+      },
+
+      'border-box-width': function(element) {
+        if (!this._preComputing) this._begin();
+        var width = element.offsetWidth;
+        if (!this._preComputing) this._end();
+        return width;
+      },
+
+      'margin-box-height': function(element) {
+        var bHeight = this.get('border-box-height'),
+         mTop = this.get('margin-top'),
+         mBottom = this.get('margin-bottom');
+
+        if (bHeight <= 0) return 0;
+
+        return bHeight + mTop + mBottom;
+      },
+
+      'margin-box-width': function(element) {
+        var bWidth = this.get('border-box-width'),
+         mLeft = this.get('margin-left'),
+         mRight = this.get('margin-right');
+
+        if (bWidth <= 0) return 0;
+
+        return bWidth + mLeft + mRight;
+      },
+
+      'top': function(element) {
+        var offset = element.positionedOffset();
+        return offset.top;
+      },
+
+      'bottom': function(element) {
+        var offset = element.positionedOffset(),
+         parent = element.getOffsetParent(),
+         pHeight = parent.measure('height');
+
+        var mHeight = this.get('border-box-height');
+
+        return pHeight - mHeight - offset.top;
+      },
+
+      'left': function(element) {
+        var offset = element.positionedOffset();
+        return offset.left;
+      },
+
+      'right': function(element) {
+        var offset = element.positionedOffset(),
+         parent = element.getOffsetParent(),
+         pWidth = parent.measure('width');
+
+        var mWidth = this.get('border-box-width');
+
+        return pWidth - mWidth - offset.left;
+      },
+
+      'padding-top': function(element) {
+        return getPixelValue(element, 'paddingTop');
+      },
+
+      'padding-bottom': function(element) {
+        return getPixelValue(element, 'paddingBottom');
+      },
+
+      'padding-left': function(element) {
+        return getPixelValue(element, 'paddingLeft');
+      },
+
+      'padding-right': function(element) {
+        return getPixelValue(element, 'paddingRight');
+      },
+
+      'border-top': function(element) {
+        return getPixelValue(element, 'borderTopWidth');
+      },
+
+      'border-bottom': function(element) {
+        return getPixelValue(element, 'borderBottomWidth');
+      },
+
+      'border-left': function(element) {
+        return getPixelValue(element, 'borderLeftWidth');
+      },
+
+      'border-right': function(element) {
+        return getPixelValue(element, 'borderRightWidth');
+      },
+
+      'margin-top': function(element) {
+        return getPixelValue(element, 'marginTop');
+      },
+
+      'margin-bottom': function(element) {
+        return getPixelValue(element, 'marginBottom');
+      },
+
+      'margin-left': function(element) {
+        return getPixelValue(element, 'marginLeft');
+      },
+
+      'margin-right': function(element) {
+        return getPixelValue(element, 'marginRight');
+      }
+    }
+  });
+
+  if ('getBoundingClientRect' in document.documentElement) {
+    Object.extend(Element.Layout.COMPUTATIONS, {
+      'right': function(element) {
+        var parent = hasLayout(element.getOffsetParent());
+        var rect = element.getBoundingClientRect(),
+         pRect = parent.getBoundingClientRect();
+
+        return (pRect.right - rect.right).round();
+      },
+
+      'bottom': function(element) {
+        var parent = hasLayout(element.getOffsetParent());
+        var rect = element.getBoundingClientRect(),
+         pRect = parent.getBoundingClientRect();
+
+        return (pRect.bottom - rect.bottom).round();
+      }
+    });
+  }
+
+  Element.Offset = Class.create({
+    initialize: function(left, top) {
+      this.left = left.round();
+      this.top  = top.round();
+
+      this[0] = this.left;
+      this[1] = this.top;
+    },
+
+    relativeTo: function(offset) {
+      return new Element.Offset(
+        this.left - offset.left,
+        this.top  - offset.top
+      );
+    },
+
+    inspect: function() {
+      return "#<Element.Offset left: #{left} top: #{top}>".interpolate(this);
+    },
+
+    toString: function() {
+      return "[#{left}, #{top}]".interpolate(this);
+    },
+
+    toArray: function() {
+      return [this.left, this.top];
+    }
+  });
+
+  function getLayout(element, preCompute) {
+    return new Element.Layout(element, preCompute);
+  }
+
+  function measure(element, property) {
+    return $(element).getLayout().get(property);
+  }
+
+  function getDimensions(element) {
+    element = $(element);
+    var display = Element.getStyle(element, 'display');
+
+    if (display && display !== 'none') {
+      return { width: element.offsetWidth, height: element.offsetHeight };
+    }
+
+    var style = element.style;
+    var originalStyles = {
+      visibility: style.visibility,
+      position:   style.position,
+      display:    style.display
+    };
+
+    var newStyles = {
+      visibility: 'hidden',
+      display:    'block'
+    };
+
+    if (originalStyles.position !== 'fixed')
+      newStyles.position = 'absolute';
+
+    Element.setStyle(element, newStyles);
+
+    var dimensions = {
+      width:  element.offsetWidth,
+      height: element.offsetHeight
+    };
+
+    Element.setStyle(element, originalStyles);
+
+    return dimensions;
+  }
+
+  function getOffsetParent(element) {
+    element = $(element);
+
+    if (isDocument(element) || isDetached(element) || isBody(element) || isHtml(element))
+      return $(document.body);
+
+    var isInline = (Element.getStyle(element, 'display') === 'inline');
+    if (!isInline && element.offsetParent) return $(element.offsetParent);
+
+    while ((element = element.parentNode) && element !== document.body) {
+      if (Element.getStyle(element, 'position') !== 'static') {
+        return isHtml(element) ? $(document.body) : $(element);
+      }
+    }
+
+    return $(document.body);
+  }
+
+
+  function cumulativeOffset(element) {
+    element = $(element);
+    var valueT = 0, valueL = 0;
+    if (element.parentNode) {
+      do {
+        valueT += element.offsetTop  || 0;
+        valueL += element.offsetLeft || 0;
+        element = element.offsetParent;
+      } while (element);
+    }
+    return new Element.Offset(valueL, valueT);
+  }
+
+  function positionedOffset(element) {
+    element = $(element);
+
+    var layout = element.getLayout();
+
+    var valueT = 0, valueL = 0;
+    do {
+      valueT += element.offsetTop  || 0;
+      valueL += element.offsetLeft || 0;
+      element = element.offsetParent;
+      if (element) {
+        if (isBody(element)) break;
+        var p = Element.getStyle(element, 'position');
+        if (p !== 'static') break;
+      }
+    } while (element);
+
+    valueL -= layout.get('margin-top');
+    valueT -= layout.get('margin-left');
+
+    return new Element.Offset(valueL, valueT);
+  }
+
+  function cumulativeScrollOffset(element) {
+    var valueT = 0, valueL = 0;
+    do {
+      valueT += element.scrollTop  || 0;
+      valueL += element.scrollLeft || 0;
+      element = element.parentNode;
+    } while (element);
+    return new Element.Offset(valueL, valueT);
+  }
+
+  function viewportOffset(forElement) {
+    element = $(element);
+    var valueT = 0, valueL = 0, docBody = document.body;
+
+    var element = forElement;
+    do {
+      valueT += element.offsetTop  || 0;
+      valueL += element.offsetLeft || 0;
+      if (element.offsetParent == docBody &&
+        Element.getStyle(element, 'position') == 'absolute') break;
+    } while (element = element.offsetParent);
+
+    element = forElement;
+    do {
+      if (element != docBody) {
+        valueT -= element.scrollTop  || 0;
+        valueL -= element.scrollLeft || 0;
+      }
+    } while (element = element.parentNode);
+    return new Element.Offset(valueL, valueT);
+  }
+
+  function absolutize(element) {
+    element = $(element);
+
+    if (Element.getStyle(element, 'position') === 'absolute') {
+      return element;
+    }
+
+    var offsetParent = getOffsetParent(element);
+    var eOffset = element.viewportOffset(),
+     pOffset = offsetParent.viewportOffset();
+
+    var offset = eOffset.relativeTo(pOffset);
+    var layout = element.getLayout();
+
+    element.store('prototype_absolutize_original_styles', {
+      left:   element.getStyle('left'),
+      top:    element.getStyle('top'),
+      width:  element.getStyle('width'),
+      height: element.getStyle('height')
+    });
+
+    element.setStyle({
+      position: 'absolute',
+      top:    offset.top + 'px',
+      left:   offset.left + 'px',
+      width:  layout.get('width') + 'px',
+      height: layout.get('height') + 'px'
+    });
+
+    return element;
+  }
+
+  function relativize(element) {
+    element = $(element);
+    if (Element.getStyle(element, 'position') === 'relative') {
+      return element;
+    }
+
+    var originalStyles =
+     element.retrieve('prototype_absolutize_original_styles');
+
+    if (originalStyles) element.setStyle(originalStyles);
+    return element;
+  }
+
+  if (Prototype.Browser.IE) {
+    getOffsetParent = getOffsetParent.wrap(
+      function(proceed, element) {
+        element = $(element);
+
+        if (isDocument(element) || isDetached(element) || isBody(element) || isHtml(element))
+          return $(document.body);
+
+        var position = element.getStyle('position');
+        if (position !== 'static') return proceed(element);
+
+        element.setStyle({ position: 'relative' });
+        var value = proceed(element);
+        element.setStyle({ position: position });
+        return value;
+      }
+    );
+
+    positionedOffset = positionedOffset.wrap(function(proceed, element) {
+      element = $(element);
+      if (!element.parentNode) return new Element.Offset(0, 0);
+      var position = element.getStyle('position');
+      if (position !== 'static') return proceed(element);
+
+      var offsetParent = element.getOffsetParent();
+      if (offsetParent && offsetParent.getStyle('position') === 'fixed')
+        hasLayout(offsetParent);
+
+      element.setStyle({ position: 'relative' });
+      var value = proceed(element);
+      element.setStyle({ position: position });
+      return value;
+    });
+  } else if (Prototype.Browser.Webkit) {
+    cumulativeOffset = function(element) {
+      element = $(element);
+      var valueT = 0, valueL = 0;
+      do {
+        valueT += element.offsetTop  || 0;
+        valueL += element.offsetLeft || 0;
+        if (element.offsetParent == document.body)
+          if (Element.getStyle(element, 'position') == 'absolute') break;
+
+        element = element.offsetParent;
+      } while (element);
+
+      return new Element.Offset(valueL, valueT);
+    };
+  }
+
+
+  Element.addMethods({
+    getLayout:              getLayout,
+    measure:                measure,
+    getDimensions:          getDimensions,
+    getOffsetParent:        getOffsetParent,
+    cumulativeOffset:       cumulativeOffset,
+    positionedOffset:       positionedOffset,
+    cumulativeScrollOffset: cumulativeScrollOffset,
+    viewportOffset:         viewportOffset,
+    absolutize:             absolutize,
+    relativize:             relativize
+  });
+
+  function isBody(element) {
+    return element.nodeName.toUpperCase() === 'BODY';
+  }
+
+  function isHtml(element) {
+    return element.nodeName.toUpperCase() === 'HTML';
+  }
+
+  function isDocument(element) {
+    return element.nodeType === Node.DOCUMENT_NODE;
+  }
+
+  function isDetached(element) {
+    return element !== document.body &&
+     !Element.descendantOf(element, document.body);
+  }
+
+  if ('getBoundingClientRect' in document.documentElement) {
+    Element.addMethods({
+      viewportOffset: function(element) {
+        element = $(element);
+        if (isDetached(element)) return new Element.Offset(0, 0);
+
+        var rect = element.getBoundingClientRect(),
+         docEl = document.documentElement;
+        return new Element.Offset(rect.left - docEl.clientLeft,
+         rect.top - docEl.clientTop);
+      }
+    });
+  }
+})();
+window.$$ = function() {
+  var expression = $A(arguments).join(', ');
+  return Prototype.Selector.select(expression, document);
+};
+
+Prototype.Selector = (function() {
+
+  function select() {
+    throw new Error('Method "Prototype.Selector.select" must be defined.');
+  }
+
+  function match() {
+    throw new Error('Method "Prototype.Selector.match" must be defined.');
+  }
+
+  function find(elements, expression, index) {
+    index = index || 0;
+    var match = Prototype.Selector.match, length = elements.length, matchIndex = 0, i;
+
+    for (i = 0; i < length; i++) {
+      if (match(elements[i], expression) && index == matchIndex++) {
+        return Element.extend(elements[i]);
+      }
+    }
+  }
+
+  function extendElements(elements) {
+    for (var i = 0, length = elements.length; i < length; i++) {
+      Element.extend(elements[i]);
+    }
+    return elements;
+  }
+
+
+  var K = Prototype.K;
+
+  return {
+    select: select,
+    match: match,
+    find: find,
+    extendElements: (Element.extend === K) ? K : extendElements,
+    extendElement: Element.extend
+  };
+})();
+Prototype._original_property = window.Sizzle;
+/*!
+ * Sizzle CSS Selector Engine - v1.0
+ *  Copyright 2009, The Dojo Foundation
+ *  Released under the MIT, BSD, and GPL Licenses.
+ *  More information: http://sizzlejs.com/
+ */
+(function(){
+
+var chunker = /((?:\((?:\([^()]+\)|[^()]+)+\)|\[(?:\[[^[\]]*\]|['"][^'"]*['"]|[^[\]'"]+)+\]|\\.|[^ >+~,(\[\\]+)+|[>+~])(\s*,\s*)?((?:.|\r|\n)*)/g,
+        done = 0,
+        toString = Object.prototype.toString,
+        hasDuplicate = false,
+        baseHasDuplicate = true;
+
+[0, 0].sort(function(){
+        baseHasDuplicate = false;
+        return 0;
+});
+
+var Sizzle = function(selector, context, results, seed) {
+        results = results || [];
+        var origContext = context = context || document;
+
+        if ( context.nodeType !== 1 && context.nodeType !== 9 ) {
+                return [];
+        }
+
+        if ( !selector || typeof selector !== "string" ) {
+                return results;
+        }
+
+        var parts = [], m, set, checkSet, check, mode, extra, prune = true, contextXML = isXML(context),
+                soFar = selector;
+
+        while ( (chunker.exec(""), m = chunker.exec(soFar)) !== null ) {
+                soFar = m[3];
+
+                parts.push( m[1] );
+
+                if ( m[2] ) {
+                        extra = m[3];
+                        break;
+                }
+        }
+
+        if ( parts.length > 1 && origPOS.exec( selector ) ) {
+                if ( parts.length === 2 && Expr.relative[ parts[0] ] ) {
+                        set = posProcess( parts[0] + parts[1], context );
+                } else {
+                        set = Expr.relative[ parts[0] ] ?
+                                [ context ] :
+                                Sizzle( parts.shift(), context );
+
+                        while ( parts.length ) {
+                                selector = parts.shift();
+
+                                if ( Expr.relative[ selector ] )
+                                        selector += parts.shift();
+
+                                set = posProcess( selector, set );
+                        }
+                }
+        } else {
+                if ( !seed && parts.length > 1 && context.nodeType === 9 && !contextXML &&
+                                Expr.match.ID.test(parts[0]) && !Expr.match.ID.test(parts[parts.length - 1]) ) {
+                        var ret = Sizzle.find( parts.shift(), context, contextXML );
+                        context = ret.expr ? Sizzle.filter( ret.expr, ret.set )[0] : ret.set[0];
+                }
+
+                if ( context ) {
+                        var ret = seed ?
+                                { expr: parts.pop(), set: makeArray(seed) } :
+                                Sizzle.find( parts.pop(), parts.length === 1 && (parts[0] === "~" || parts[0] === "+") && context.parentNode ? context.parentNode : context, contextXML );
+                        set = ret.expr ? Sizzle.filter( ret.expr, ret.set ) : ret.set;
+
+                        if ( parts.length > 0 ) {
+                                checkSet = makeArray(set);
+                        } else {
+                                prune = false;
+                        }
+
+                        while ( parts.length ) {
+                                var cur = parts.pop(), pop = cur;
+
+                                if ( !Expr.relative[ cur ] ) {
+                                        cur = "";
+                                } else {
+                                        pop = parts.pop();
+                                }
+
+                                if ( pop == null ) {
+                                        pop = context;
+                                }
+
+                                Expr.relative[ cur ]( checkSet, pop, contextXML );
+                        }
+                } else {
+                        checkSet = parts = [];
+                }
+        }
+
+        if ( !checkSet ) {
+                checkSet = set;
+        }
+
+        if ( !checkSet ) {
+                throw "Syntax error, unrecognized expression: " + (cur || selector);
+        }
+
+        if ( toString.call(checkSet) === "[object Array]" ) {
+                if ( !prune ) {
+                        results.push.apply( results, checkSet );
+                } else if ( context && context.nodeType === 1 ) {
+                        for ( var i = 0; checkSet[i] != null; i++ ) {
+                                if ( checkSet[i] && (checkSet[i] === true || checkSet[i].nodeType === 1 && contains(context, checkSet[i])) ) {
+                                        results.push( set[i] );
+                                }
+                        }
+                } else {
+                        for ( var i = 0; checkSet[i] != null; i++ ) {
+                                if ( checkSet[i] && checkSet[i].nodeType === 1 ) {
+                                        results.push( set[i] );
+                                }
+                        }
+                }
+        } else {
+                makeArray( checkSet, results );
+        }
+
+        if ( extra ) {
+                Sizzle( extra, origContext, results, seed );
+                Sizzle.uniqueSort( results );
+        }
+
+        return results;
+};
+
+Sizzle.uniqueSort = function(results){
+        if ( sortOrder ) {
+                hasDuplicate = baseHasDuplicate;
+                results.sort(sortOrder);
+
+                if ( hasDuplicate ) {
+                        for ( var i = 1; i < results.length; i++ ) {
+                                if ( results[i] === results[i-1] ) {
+                                        results.splice(i--, 1);
+                                }
+                        }
+                }
+        }
+
+        return results;
+};
+
+Sizzle.matches = function(expr, set){
+        return Sizzle(expr, null, null, set);
+};
+
+Sizzle.find = function(expr, context, isXML){
+        var set, match;
+
+        if ( !expr ) {
+                return [];
+        }
+
+        for ( var i = 0, l = Expr.order.length; i < l; i++ ) {
+                var type = Expr.order[i], match;
+
+                if ( (match = Expr.leftMatch[ type ].exec( expr )) ) {
+                        var left = match[1];
+                        match.splice(1,1);
+
+                        if ( left.substr( left.length - 1 ) !== "\\" ) {
+                                match[1] = (match[1] || "").replace(/\\/g, "");
+                                set = Expr.find[ type ]( match, context, isXML );
+                                if ( set != null ) {
+                                        expr = expr.replace( Expr.match[ type ], "" );
+                                        break;
+                                }
+                        }
+                }
+        }
+
+        if ( !set ) {
+                set = context.getElementsByTagName("*");
+        }
+
+        return {set: set, expr: expr};
+};
+
+Sizzle.filter = function(expr, set, inplace, not){
+        var old = expr, result = [], curLoop = set, match, anyFound,
+                isXMLFilter = set && set[0] && isXML(set[0]);
+
+        while ( expr && set.length ) {
+                for ( var type in Expr.filter ) {
+                        if ( (match = Expr.match[ type ].exec( expr )) != null ) {
+                                var filter = Expr.filter[ type ], found, item;
+                                anyFound = false;
+
+                                if ( curLoop == result ) {
+                                        result = [];
+                                }
+
+                                if ( Expr.preFilter[ type ] ) {
+                                        match = Expr.preFilter[ type ]( match, curLoop, inplace, result, not, isXMLFilter );
+
+                                        if ( !match ) {
+                                                anyFound = found = true;
+                                        } else if ( match === true ) {
+                                                continue;
+                                        }
+                                }
+
+                                if ( match ) {
+                                        for ( var i = 0; (item = curLoop[i]) != null; i++ ) {
+                                                if ( item ) {
+                                                        found = filter( item, match, i, curLoop );
+                                                        var pass = not ^ !!found;
+
+                                                        if ( inplace && found != null ) {
+                                                                if ( pass ) {
+                                                                        anyFound = true;
+                                                                } else {
+                                                                        curLoop[i] = false;
+                                                                }
+                                                        } else if ( pass ) {
+                                                                result.push( item );
+                                                                anyFound = true;
+                                                        }
+                                                }
+                                        }
+                                }
+
+                                if ( found !== undefined ) {
+                                        if ( !inplace ) {
+                                                curLoop = result;
+                                        }
+
+                                        expr = expr.replace( Expr.match[ type ], "" );
+
+                                        if ( !anyFound ) {
+                                                return [];
+                                        }
+
+                                        break;
+                                }
+                        }
+                }
+
+                if ( expr == old ) {
+                        if ( anyFound == null ) {
+                                throw "Syntax error, unrecognized expression: " + expr;
+                        } else {
+                                break;
+                        }
+                }
+
+                old = expr;
+        }
+
+        return curLoop;
+};
+
+var Expr = Sizzle.selectors = {
+        order: [ "ID", "NAME", "TAG" ],
+        match: {
+                ID: /#((?:[\w\u00c0-\uFFFF-]|\\.)+)/,
+                CLASS: /\.((?:[\w\u00c0-\uFFFF-]|\\.)+)/,
+                NAME: /\[name=['"]*((?:[\w\u00c0-\uFFFF-]|\\.)+)['"]*\]/,
+                ATTR: /\[\s*((?:[\w\u00c0-\uFFFF-]|\\.)+)\s*(?:(\S?=)\s*(['"]*)(.*?)\3|)\s*\]/,
+                TAG: /^((?:[\w\u00c0-\uFFFF\*-]|\\.)+)/,
+                CHILD: /:(only|nth|last|first)-child(?:\((even|odd|[\dn+-]*)\))?/,
+                POS: /:(nth|eq|gt|lt|first|last|even|odd)(?:\((\d*)\))?(?=[^-]|$)/,
+                PSEUDO: /:((?:[\w\u00c0-\uFFFF-]|\\.)+)(?:\((['"]*)((?:\([^\)]+\)|[^\2\(\)]*)+)\2\))?/
+        },
+        leftMatch: {},
+        attrMap: {
+                "class": "className",
+                "for": "htmlFor"
+        },
+        attrHandle: {
+                href: function(elem){
+                        return elem.getAttribute("href");
+                }
+        },
+        relative: {
+                "+": function(checkSet, part, isXML){
+                        var isPartStr = typeof part === "string",
+                                isTag = isPartStr && !/\W/.test(part),
+                                isPartStrNotTag = isPartStr && !isTag;
+
+                        if ( isTag && !isXML ) {
+                                part = part.toUpperCase();
+                        }
+
+                        for ( var i = 0, l = checkSet.length, elem; i < l; i++ ) {
+                                if ( (elem = checkSet[i]) ) {
+                                        while ( (elem = elem.previousSibling) && elem.nodeType !== 1 ) {}
+
+                                        checkSet[i] = isPartStrNotTag || elem && elem.nodeName === part ?
+                                                elem || false :
+                                                elem === part;
+                                }
+                        }
+
+                        if ( isPartStrNotTag ) {
+                                Sizzle.filter( part, checkSet, true );
+                        }
+                },
+                ">": function(checkSet, part, isXML){
+                        var isPartStr = typeof part === "string";
+
+                        if ( isPartStr && !/\W/.test(part) ) {
+                                part = isXML ? part : part.toUpperCase();
+
+                                for ( var i = 0, l = checkSet.length; i < l; i++ ) {
+                                        var elem = checkSet[i];
+                                        if ( elem ) {
+                                                var parent = elem.parentNode;
+                                                checkSet[i] = parent.nodeName === part ? parent : false;
+                                        }
+                                }
+                        } else {
+                                for ( var i = 0, l = checkSet.length; i < l; i++ ) {
+                                        var elem = checkSet[i];
+                                        if ( elem ) {
+                                                checkSet[i] = isPartStr ?
+                                                        elem.parentNode :
+                                                        elem.parentNode === part;
+                                        }
+                                }
+
+                                if ( isPartStr ) {
+                                        Sizzle.filter( part, checkSet, true );
+                                }
+                        }
+                },
+                "": function(checkSet, part, isXML){
+                        var doneName = done++, checkFn = dirCheck;
+
+                        if ( !/\W/.test(part) ) {
+                                var nodeCheck = part = isXML ? part : part.toUpperCase();
+                                checkFn = dirNodeCheck;
+                        }
+
+                        checkFn("parentNode", part, doneName, checkSet, nodeCheck, isXML);
+                },
+                "~": function(checkSet, part, isXML){
+                        var doneName = done++, checkFn = dirCheck;
+
+                        if ( typeof part === "string" && !/\W/.test(part) ) {
+                                var nodeCheck = part = isXML ? part : part.toUpperCase();
+                                checkFn = dirNodeCheck;
+                        }
+
+                        checkFn("previousSibling", part, doneName, checkSet, nodeCheck, isXML);
+                }
+        },
+        find: {
+                ID: function(match, context, isXML){
+                        if ( typeof context.getElementById !== "undefined" && !isXML ) {
+                                var m = context.getElementById(match[1]);
+                                return m ? [m] : [];
+                        }
+                },
+                NAME: function(match, context, isXML){
+                        if ( typeof context.getElementsByName !== "undefined" ) {
+                                var ret = [], results = context.getElementsByName(match[1]);
+
+                                for ( var i = 0, l = results.length; i < l; i++ ) {
+                                        if ( results[i].getAttribute("name") === match[1] ) {
+                                                ret.push( results[i] );
+                                        }
+                                }
+
+                                return ret.length === 0 ? null : ret;
+                        }
+                },
+                TAG: function(match, context){
+                        return context.getElementsByTagName(match[1]);
+                }
+        },
+        preFilter: {
+                CLASS: function(match, curLoop, inplace, result, not, isXML){
+                        match = " " + match[1].replace(/\\/g, "") + " ";
+
+                        if ( isXML ) {
+                                return match;
+                        }
+
+                        for ( var i = 0, elem; (elem = curLoop[i]) != null; i++ ) {
+                                if ( elem ) {
+                                        if ( not ^ (elem.className && (" " + elem.className + " ").indexOf(match) >= 0) ) {
+                                                if ( !inplace )
+                                                        result.push( elem );
+                                        } else if ( inplace ) {
+                                                curLoop[i] = false;
+                                        }
+                                }
+                        }
+
+                        return false;
+                },
+                ID: function(match){
+                        return match[1].replace(/\\/g, "");
+                },
+                TAG: function(match, curLoop){
+                        for ( var i = 0; curLoop[i] === false; i++ ){}
+                        return curLoop[i] && isXML(curLoop[i]) ? match[1] : match[1].toUpperCase();
+                },
+                CHILD: function(match){
+                        if ( match[1] == "nth" ) {
+                                var test = /(-?)(\d*)n((?:\+|-)?\d*)/.exec(
+                                        match[2] == "even" && "2n" || match[2] == "odd" && "2n+1" ||
+                                        !/\D/.test( match[2] ) && "0n+" + match[2] || match[2]);
+
+                                match[2] = (test[1] + (test[2] || 1)) - 0;
+                                match[3] = test[3] - 0;
+                        }
+
+                        match[0] = done++;
+
+                        return match;
+                },
+                ATTR: function(match, curLoop, inplace, result, not, isXML){
+                        var name = match[1].replace(/\\/g, "");
+
+                        if ( !isXML && Expr.attrMap[name] ) {
+                                match[1] = Expr.attrMap[name];
+                        }
+
+                        if ( match[2] === "~=" ) {
+                                match[4] = " " + match[4] + " ";
+                        }
+
+                        return match;
+                },
+                PSEUDO: function(match, curLoop, inplace, result, not){
+                        if ( match[1] === "not" ) {
+                                if ( ( chunker.exec(match[3]) || "" ).length > 1 || /^\w/.test(match[3]) ) {
+                                        match[3] = Sizzle(match[3], null, null, curLoop);
+                                } else {
+                                        var ret = Sizzle.filter(match[3], curLoop, inplace, true ^ not);
+                                        if ( !inplace ) {
+                                                result.push.apply( result, ret );
+                                        }
+                                        return false;
+                                }
+                        } else if ( Expr.match.POS.test( match[0] ) || Expr.match.CHILD.test( match[0] ) ) {
+                                return true;
+                        }
+
+                        return match;
+                },
+                POS: function(match){
+                        match.unshift( true );
+                        return match;
+                }
+        },
+        filters: {
+                enabled: function(elem){
+                        return elem.disabled === false && elem.type !== "hidden";
+                },
+                disabled: function(elem){
+                        return elem.disabled === true;
+                },
+                checked: function(elem){
+                        return elem.checked === true;
+                },
+                selected: function(elem){
+                        elem.parentNode.selectedIndex;
+                        return elem.selected === true;
+                },
+                parent: function(elem){
+                        return !!elem.firstChild;
+                },
+                empty: function(elem){
+                        return !elem.firstChild;
+                },
+                has: function(elem, i, match){
+                        return !!Sizzle( match[3], elem ).length;
+                },
+                header: function(elem){
+                        return /h\d/i.test( elem.nodeName );
+                },
+                text: function(elem){
+                        return "text" === elem.type;
+                },
+                radio: function(elem){
+                        return "radio" === elem.type;
+                },
+                checkbox: function(elem){
+                        return "checkbox" === elem.type;
+                },
+                file: function(elem){
+                        return "file" === elem.type;
+                },
+                password: function(elem){
+                        return "password" === elem.type;
+                },
+                submit: function(elem){
+                        return "submit" === elem.type;
+                },
+                image: function(elem){
+                        return "image" === elem.type;
+                },
+                reset: function(elem){
+                        return "reset" === elem.type;
+                },
+                button: function(elem){
+                        return "button" === elem.type || elem.nodeName.toUpperCase() === "BUTTON";
+                },
+                input: function(elem){
+                        return /input|select|textarea|button/i.test(elem.nodeName);
+                }
+        },
+        setFilters: {
+                first: function(elem, i){
+                        return i === 0;
+                },
+                last: function(elem, i, match, array){
+                        return i === array.length - 1;
+                },
+                even: function(elem, i){
+                        return i % 2 === 0;
+                },
+                odd: function(elem, i){
+                        return i % 2 === 1;
+                },
+                lt: function(elem, i, match){
+                        return i < match[3] - 0;
+                },
+                gt: function(elem, i, match){
+                        return i > match[3] - 0;
+                },
+                nth: function(elem, i, match){
+                        return match[3] - 0 == i;
+                },
+                eq: function(elem, i, match){
+                        return match[3] - 0 == i;
+                }
+        },
+        filter: {
+                PSEUDO: function(elem, match, i, array){
+                        var name = match[1], filter = Expr.filters[ name ];
+
+                        if ( filter ) {
+                                return filter( elem, i, match, array );
+                        } else if ( name === "contains" ) {
+                                return (elem.textContent || elem.innerText || "").indexOf(match[3]) >= 0;
+                        } else if ( name === "not" ) {
+                                var not = match[3];
+
+                                for ( var i = 0, l = not.length; i < l; i++ ) {
+                                        if ( not[i] === elem ) {
+                                                return false;
+                                        }
+                                }
+
+                                return true;
+                        }
+                },
+                CHILD: function(elem, match){
+                        var type = match[1], node = elem;
+                        switch (type) {
+                                case 'only':
+                                case 'first':
+                                        while ( (node = node.previousSibling) )  {
+                                                if ( node.nodeType === 1 ) return false;
+                                        }
+                                        if ( type == 'first') return true;
+                                        node = elem;
+                                case 'last':
+                                        while ( (node = node.nextSibling) )  {
+                                                if ( node.nodeType === 1 ) return false;
+                                        }
+                                        return true;
+                                case 'nth':
+                                        var first = match[2], last = match[3];
+
+                                        if ( first == 1 && last == 0 ) {
+                                                return true;
+                                        }
+
+                                        var doneName = match[0],
+                                                parent = elem.parentNode;
+
+                                        if ( parent && (parent.sizcache !== doneName || !elem.nodeIndex) ) {
+                                                var count = 0;
+                                                for ( node = parent.firstChild; node; node = node.nextSibling ) {
+                                                        if ( node.nodeType === 1 ) {
+                                                                node.nodeIndex = ++count;
+                                                        }
+                                                }
+                                                parent.sizcache = doneName;
+                                        }
+
+                                        var diff = elem.nodeIndex - last;
+                                        if ( first == 0 ) {
+                                                return diff == 0;
+                                        } else {
+                                                return ( diff % first == 0 && diff / first >= 0 );
+                                        }
+                        }
+                },
+                ID: function(elem, match){
+                        return elem.nodeType === 1 && elem.getAttribute("id") === match;
+                },
+                TAG: function(elem, match){
+                        return (match === "*" && elem.nodeType === 1) || elem.nodeName === match;
+                },
+                CLASS: function(elem, match){
+                        return (" " + (elem.className || elem.getAttribute("class")) + " ")
+                                .indexOf( match ) > -1;
+                },
+                ATTR: function(elem, match){
+                        var name = match[1],
+                                result = Expr.attrHandle[ name ] ?
+                                        Expr.attrHandle[ name ]( elem ) :
+                                        elem[ name ] != null ?
+                                                elem[ name ] :
+                                                elem.getAttribute( name ),
+                                value = result + "",
+                                type = match[2],
+                                check = match[4];
+
+                        return result == null ?
+                                type === "!=" :
+                                type === "=" ?
+                                value === check :
+                                type === "*=" ?
+                                value.indexOf(check) >= 0 :
+                                type === "~=" ?
+                                (" " + value + " ").indexOf(check) >= 0 :
+                                !check ?
+                                value && result !== false :
+                                type === "!=" ?
+                                value != check :
+                                type === "^=" ?
+                                value.indexOf(check) === 0 :
+                                type === "$=" ?
+                                value.substr(value.length - check.length) === check :
+                                type === "|=" ?
+                                value === check || value.substr(0, check.length + 1) === check + "-" :
+                                false;
+                },
+                POS: function(elem, match, i, array){
+                        var name = match[2], filter = Expr.setFilters[ name ];
+
+                        if ( filter ) {
+                                return filter( elem, i, match, array );
+                        }
+                }
+        }
+};
+
+var origPOS = Expr.match.POS;
+
+for ( var type in Expr.match ) {
+        Expr.match[ type ] = new RegExp( Expr.match[ type ].source + /(?![^\[]*\])(?![^\(]*\))/.source );
+        Expr.leftMatch[ type ] = new RegExp( /(^(?:.|\r|\n)*?)/.source + Expr.match[ type ].source );
+}
+
+var makeArray = function(array, results) {
+        array = Array.prototype.slice.call( array, 0 );
+
+        if ( results ) {
+                results.push.apply( results, array );
+                return results;
+        }
+
+        return array;
+};
+
+try {
+        Array.prototype.slice.call( document.documentElement.childNodes, 0 );
+
+} catch(e){
+        makeArray = function(array, results) {
+                var ret = results || [];
+
+                if ( toString.call(array) === "[object Array]" ) {
+                        Array.prototype.push.apply( ret, array );
+                } else {
+                        if ( typeof array.length === "number" ) {
+                                for ( var i = 0, l = array.length; i < l; i++ ) {
+                                        ret.push( array[i] );
+                                }
+                        } else {
+                                for ( var i = 0; array[i]; i++ ) {
+                                        ret.push( array[i] );
+                                }
+                        }
+                }
+
+                return ret;
+        };
+}
+
+var sortOrder;
+
+if ( document.documentElement.compareDocumentPosition ) {
+        sortOrder = function( a, b ) {
+                if ( !a.compareDocumentPosition || !b.compareDocumentPosition ) {
+                        if ( a == b ) {
+                                hasDuplicate = true;
+                        }
+                        return 0;
+                }
+
+                var ret = a.compareDocumentPosition(b) & 4 ? -1 : a === b ? 0 : 1;
+                if ( ret === 0 ) {
+                        hasDuplicate = true;
+                }
+                return ret;
+        };
+} else if ( "sourceIndex" in document.documentElement ) {
+        sortOrder = function( a, b ) {
+                if ( !a.sourceIndex || !b.sourceIndex ) {
+                        if ( a == b ) {
+                                hasDuplicate = true;
+                        }
+                        return 0;
+                }
+
+                var ret = a.sourceIndex - b.sourceIndex;
+                if ( ret === 0 ) {
+                        hasDuplicate = true;
+                }
+                return ret;
+        };
+} else if ( document.createRange ) {
+        sortOrder = function( a, b ) {
+                if ( !a.ownerDocument || !b.ownerDocument ) {
+                        if ( a == b ) {
+                                hasDuplicate = true;
+                        }
+                        return 0;
+                }
+
+                var aRange = a.ownerDocument.createRange(), bRange = b.ownerDocument.createRange();
+                aRange.setStart(a, 0);
+                aRange.setEnd(a, 0);
+                bRange.setStart(b, 0);
+                bRange.setEnd(b, 0);
+                var ret = aRange.compareBoundaryPoints(Range.START_TO_END, bRange);
+                if ( ret === 0 ) {
+                        hasDuplicate = true;
+                }
+                return ret;
+        };
+}
+
+(function(){
+        var form = document.createElement("div"),
+                id = "script" + (new Date).getTime();
+        form.innerHTML = "<a name='" + id + "'/>";
+
+        var root = document.documentElement;
+        root.insertBefore( form, root.firstChild );
+
+        if ( !!document.getElementById( id ) ) {
+                Expr.find.ID = function(match, context, isXML){
+                        if ( typeof context.getElementById !== "undefined" && !isXML ) {
+                                var m = context.getElementById(match[1]);
+                                return m ? m.id === match[1] || typeof m.getAttributeNode !== "undefined" && m.getAttributeNode("id").nodeValue === match[1] ? [m] : undefined : [];
+                        }
+                };
+
+                Expr.filter.ID = function(elem, match){
+                        var node = typeof elem.getAttributeNode !== "undefined" && elem.getAttributeNode("id");
+                        return elem.nodeType === 1 && node && node.nodeValue === match;
+                };
+        }
+
+        root.removeChild( form );
+        root = form = null; // release memory in IE
+})();
+
+(function(){
+
+        var div = document.createElement("div");
+        div.appendChild( document.createComment("") );
+
+        if ( div.getElementsByTagName("*").length > 0 ) {
+                Expr.find.TAG = function(match, context){
+                        var results = context.getElementsByTagName(match[1]);
+
+                        if ( match[1] === "*" ) {
+                                var tmp = [];
+
+                                for ( var i = 0; results[i]; i++ ) {
+                                        if ( results[i].nodeType === 1 ) {
+                                                tmp.push( results[i] );
+                                        }
+                                }
+
+                                results = tmp;
+                        }
+
+                        return results;
+                };
+        }
+
+        div.innerHTML = "<a href='#'></a>";
+        if ( div.firstChild && typeof div.firstChild.getAttribute !== "undefined" &&
+                        div.firstChild.getAttribute("href") !== "#" ) {
+                Expr.attrHandle.href = function(elem){
+                        return elem.getAttribute("href", 2);
+                };
+        }
+
+        div = null; // release memory in IE
+})();
+
+if ( document.querySelectorAll ) (function(){
+        var oldSizzle = Sizzle, div = document.createElement("div");
+        div.innerHTML = "<p class='TEST'></p>";
+
+        if ( div.querySelectorAll && div.querySelectorAll(".TEST").length === 0 ) {
+                return;
+        }
+
+        Sizzle = function(query, context, extra, seed){
+                context = context || document;
+
+                if ( !seed && context.nodeType === 9 && !isXML(context) ) {
+                        try {
+                                return makeArray( context.querySelectorAll(query), extra );
+                        } catch(e){}
+                }
+
+                return oldSizzle(query, context, extra, seed);
+        };
+
+        for ( var prop in oldSizzle ) {
+                Sizzle[ prop ] = oldSizzle[ prop ];
+        }
+
+        div = null; // release memory in IE
+})();
+
+if ( document.getElementsByClassName && document.documentElement.getElementsByClassName ) (function(){
+        var div = document.createElement("div");
+        div.innerHTML = "<div class='test e'></div><div class='test'></div>";
+
+        if ( div.getElementsByClassName("e").length === 0 )
+                return;
+
+        div.lastChild.className = "e";
+
+        if ( div.getElementsByClassName("e").length === 1 )
+                return;
+
+        Expr.order.splice(1, 0, "CLASS");
+        Expr.find.CLASS = function(match, context, isXML) {
+                if ( typeof context.getElementsByClassName !== "undefined" && !isXML ) {
+                        return context.getElementsByClassName(match[1]);
+                }
+        };
+
+        div = null; // release memory in IE
+})();
+
+function dirNodeCheck( dir, cur, doneName, checkSet, nodeCheck, isXML ) {
+        var sibDir = dir == "previousSibling" && !isXML;
+        for ( var i = 0, l = checkSet.length; i < l; i++ ) {
+                var elem = checkSet[i];
+                if ( elem ) {
+                        if ( sibDir && elem.nodeType === 1 ){
+                                elem.sizcache = doneName;
+                                elem.sizset = i;
+                        }
+                        elem = elem[dir];
+                        var match = false;
+
+                        while ( elem ) {
+                                if ( elem.sizcache === doneName ) {
+                                        match = checkSet[elem.sizset];
+                                        break;
+                                }
+
+                                if ( elem.nodeType === 1 && !isXML ){
+                                        elem.sizcache = doneName;
+                                        elem.sizset = i;
+                                }
+
+                                if ( elem.nodeName === cur ) {
+                                        match = elem;
+                                        break;
+                                }
+
+                                elem = elem[dir];
+                        }
+
+                        checkSet[i] = match;
+                }
+        }
+}
+
+function dirCheck( dir, cur, doneName, checkSet, nodeCheck, isXML ) {
+        var sibDir = dir == "previousSibling" && !isXML;
+        for ( var i = 0, l = checkSet.length; i < l; i++ ) {
+                var elem = checkSet[i];
+                if ( elem ) {
+                        if ( sibDir && elem.nodeType === 1 ) {
+                                elem.sizcache = doneName;
+                                elem.sizset = i;
+                        }
+                        elem = elem[dir];
+                        var match = false;
+
+                        while ( elem ) {
+                                if ( elem.sizcache === doneName ) {
+                                        match = checkSet[elem.sizset];
+                                        break;
+                                }
+
+                                if ( elem.nodeType === 1 ) {
+                                        if ( !isXML ) {
+                                                elem.sizcache = doneName;
+                                                elem.sizset = i;
+                                        }
+                                        if ( typeof cur !== "string" ) {
+                                                if ( elem === cur ) {
+                                                        match = true;
+                                                        break;
+                                                }
+
+                                        } else if ( Sizzle.filter( cur, [elem] ).length > 0 ) {
+                                                match = elem;
+                                                break;
+                                        }
+                                }
+
+                                elem = elem[dir];
+                        }
+
+                        checkSet[i] = match;
+                }
+        }
+}
+
+var contains = document.compareDocumentPosition ?  function(a, b){
+        return a.compareDocumentPosition(b) & 16;
+} : function(a, b){
+        return a !== b && (a.contains ? a.contains(b) : true);
+};
+
+var isXML = function(elem){
+        return elem.nodeType === 9 && elem.documentElement.nodeName !== "HTML" ||
+                !!elem.ownerDocument && elem.ownerDocument.documentElement.nodeName !== "HTML";
+};
+
+var posProcess = function(selector, context){
+        var tmpSet = [], later = "", match,
+                root = context.nodeType ? [context] : context;
+
+        while ( (match = Expr.match.PSEUDO.exec( selector )) ) {
+                later += match[0];
+                selector = selector.replace( Expr.match.PSEUDO, "" );
+        }
+
+        selector = Expr.relative[selector] ? selector + "*" : selector;
+
+        for ( var i = 0, l = root.length; i < l; i++ ) {
+                Sizzle( selector, root[i], tmpSet );
+        }
+
+        return Sizzle.filter( later, tmpSet );
+};
+
+
+window.Sizzle = Sizzle;
+
+})();
+
+;(function(engine) {
+  var extendElements = Prototype.Selector.extendElements;
+
+  function select(selector, scope) {
+    return extendElements(engine(selector, scope || document));
+  }
+
+  function match(element, selector) {
+    return engine.matches(selector, [element]).length == 1;
+  }
+
+  Prototype.Selector.engine = engine;
+  Prototype.Selector.select = select;
+  Prototype.Selector.match = match;
+})(Sizzle);
+
+window.Sizzle = Prototype._original_property;
+delete Prototype._original_property;
+
+var Form = {
+  reset: function(form) {
+    form = $(form);
+    form.reset();
+    return form;
+  },
+
+  serializeElements: function(elements, options) {
+    if (typeof options != 'object') options = { hash: !!options };
+    else if (Object.isUndefined(options.hash)) options.hash = true;
+    var key, value, submitted = false, submit = options.submit, accumulator, initial;
+
+    if (options.hash) {
+      initial = {};
+      accumulator = function(result, key, value) {
+        if (key in result) {
+          if (!Object.isArray(result[key])) result[key] = [result[key]];
+          result[key].push(value);
+        } else result[key] = value;
+        return result;
+      };
+    } else {
+      initial = '';
+      accumulator = function(result, key, value) {
+        return result + (result ? '&' : '') + encodeURIComponent(key) + '=' + encodeURIComponent(value);
+      }
+    }
+
+    return elements.inject(initial, function(result, element) {
+      if (!element.disabled && element.name) {
+        key = element.name; value = $(element).getValue();
+        if (value != null && element.type != 'file' && (element.type != 'submit' || (!submitted &&
+            submit !== false && (!submit || key == submit) && (submitted = true)))) {
+          result = accumulator(result, key, value);
+        }
+      }
+      return result;
+    });
+  }
+};
+
+Form.Methods = {
+  serialize: function(form, options) {
+    return Form.serializeElements(Form.getElements(form), options);
+  },
+
+  getElements: function(form) {
+    var elements = $(form).getElementsByTagName('*'),
+        element,
+        arr = [ ],
+        serializers = Form.Element.Serializers;
+    for (var i = 0; element = elements[i]; i++) {
+      arr.push(element);
+    }
+    return arr.inject([], function(elements, child) {
+      if (serializers[child.tagName.toLowerCase()])
+        elements.push(Element.extend(child));
+      return elements;
+    })
+  },
+
+  getInputs: function(form, typeName, name) {
+    form = $(form);
+    var inputs = form.getElementsByTagName('input');
+
+    if (!typeName && !name) return $A(inputs).map(Element.extend);
+
+    for (var i = 0, matchingInputs = [], length = inputs.length; i < length; i++) {
+      var input = inputs[i];
+      if ((typeName && input.type != typeName) || (name && input.name != name))
+        continue;
+      matchingInputs.push(Element.extend(input));
+    }
+
+    return matchingInputs;
+  },
+
+  disable: function(form) {
+    form = $(form);
+    Form.getElements(form).invoke('disable');
+    return form;
+  },
+
+  enable: function(form) {
+    form = $(form);
+    Form.getElements(form).invoke('enable');
+    return form;
+  },
+
+  findFirstElement: function(form) {
+    var elements = $(form).getElements().findAll(function(element) {
+      return 'hidden' != element.type && !element.disabled;
+    });
+    var firstByIndex = elements.findAll(function(element) {
+      return element.hasAttribute('tabIndex') && element.tabIndex >= 0;
+    }).sortBy(function(element) { return element.tabIndex }).first();
+
+    return firstByIndex ? firstByIndex : elements.find(function(element) {
+      return /^(?:input|select|textarea)$/i.test(element.tagName);
+    });
+  },
+
+  focusFirstElement: function(form) {
+    form = $(form);
+    var element = form.findFirstElement();
+    if (element) element.activate();
+    return form;
+  },
+
+  request: function(form, options) {
+    form = $(form), options = Object.clone(options || { });
+
+    var params = options.parameters, action = form.readAttribute('action') || '';
+    if (action.blank()) action = window.location.href;
+    options.parameters = form.serialize(true);
+
+    if (params) {
+      if (Object.isString(params)) params = params.toQueryParams();
+      Object.extend(options.parameters, params);
+    }
+
+    if (form.hasAttribute('method') && !options.method)
+      options.method = form.method;
+
+    return new Ajax.Request(action, options);
+  }
+};
+
+/*--------------------------------------------------------------------------*/
+
+
+Form.Element = {
+  focus: function(element) {
+    $(element).focus();
+    return element;
+  },
+
+  select: function(element) {
+    $(element).select();
+    return element;
+  }
+};
+
+Form.Element.Methods = {
+
+  serialize: function(element) {
+    element = $(element);
+    if (!element.disabled && element.name) {
+      var value = element.getValue();
+      if (value != undefined) {
+        var pair = { };
+        pair[element.name] = value;
+        return Object.toQueryString(pair);
+      }
+    }
+    return '';
+  },
+
+  getValue: function(element) {
+    element = $(element);
+    var method = element.tagName.toLowerCase();
+    return Form.Element.Serializers[method](element);
+  },
+
+  setValue: function(element, value) {
+    element = $(element);
+    var method = element.tagName.toLowerCase();
+    Form.Element.Serializers[method](element, value);
+    return element;
+  },
+
+  clear: function(element) {
+    $(element).value = '';
+    return element;
+  },
+
+  present: function(element) {
+    return $(element).value != '';
+  },
+
+  activate: function(element) {
+    element = $(element);
+    try {
+      element.focus();
+      if (element.select && (element.tagName.toLowerCase() != 'input' ||
+          !(/^(?:button|reset|submit)$/i.test(element.type))))
+        element.select();
+    } catch (e) { }
+    return element;
+  },
+
+  disable: function(element) {
+    element = $(element);
+    element.disabled = true;
+    return element;
+  },
+
+  enable: function(element) {
+    element = $(element);
+    element.disabled = false;
+    return element;
+  }
+};
+
+/*--------------------------------------------------------------------------*/
+
+var Field = Form.Element;
+
+var $F = Form.Element.Methods.getValue;
+
+/*--------------------------------------------------------------------------*/
+
+Form.Element.Serializers = (function() {
+  function input(element, value) {
+    switch (element.type.toLowerCase()) {
+      case 'checkbox':
+      case 'radio':
+        return inputSelector(element, value);
+      default:
+        return valueSelector(element, value);
+    }
+  }
+
+  function inputSelector(element, value) {
+    if (Object.isUndefined(value))
+      return element.checked ? element.value : null;
+    else element.checked = !!value;
+  }
+
+  function valueSelector(element, value) {
+    if (Object.isUndefined(value)) return element.value;
+    else element.value = value;
+  }
+
+  function select(element, value) {
+    if (Object.isUndefined(value))
+      return (element.type === 'select-one' ? selectOne : selectMany)(element);
+
+    var opt, currentValue, single = !Object.isArray(value);
+    for (var i = 0, length = element.length; i < length; i++) {
+      opt = element.options[i];
+      currentValue = this.optionValue(opt);
+      if (single) {
+        if (currentValue == value) {
+          opt.selected = true;
+          return;
+        }
+      }
+      else opt.selected = value.include(currentValue);
+    }
+  }
+
+  function selectOne(element) {
+    var index = element.selectedIndex;
+    return index >= 0 ? optionValue(element.options[index]) : null;
+  }
+
+  function selectMany(element) {
+    var values, length = element.length;
+    if (!length) return null;
+
+    for (var i = 0, values = []; i < length; i++) {
+      var opt = element.options[i];
+      if (opt.selected) values.push(optionValue(opt));
+    }
+    return values;
+  }
+
+  function optionValue(opt) {
+    return Element.hasAttribute(opt, 'value') ? opt.value : opt.text;
+  }
+
+  return {
+    input:         input,
+    inputSelector: inputSelector,
+    textarea:      valueSelector,
+    select:        select,
+    selectOne:     selectOne,
+    selectMany:    selectMany,
+    optionValue:   optionValue,
+    button:        valueSelector
+  };
+})();
+
+/*--------------------------------------------------------------------------*/
+
+
+Abstract.TimedObserver = Class.create(PeriodicalExecuter, {
+  initialize: function($super, element, frequency, callback) {
+    $super(callback, frequency);
+    this.element   = $(element);
+    this.lastValue = this.getValue();
+  },
+
+  execute: function() {
+    var value = this.getValue();
+    if (Object.isString(this.lastValue) && Object.isString(value) ?
+        this.lastValue != value : String(this.lastValue) != String(value)) {
+      this.callback(this.element, value);
+      this.lastValue = value;
+    }
+  }
+});
+
+Form.Element.Observer = Class.create(Abstract.TimedObserver, {
+  getValue: function() {
+    return Form.Element.getValue(this.element);
+  }
+});
+
+Form.Observer = Class.create(Abstract.TimedObserver, {
+  getValue: function() {
+    return Form.serialize(this.element);
+  }
+});
+
+/*--------------------------------------------------------------------------*/
+
+Abstract.EventObserver = Class.create({
+  initialize: function(element, callback) {
+    this.element  = $(element);
+    this.callback = callback;
+
+    this.lastValue = this.getValue();
+    if (this.element.tagName.toLowerCase() == 'form')
+      this.registerFormCallbacks();
+    else
+      this.registerCallback(this.element);
+  },
+
+  onElementEvent: function() {
+    var value = this.getValue();
+    if (this.lastValue != value) {
+      this.callback(this.element, value);
+      this.lastValue = value;
+    }
+  },
+
+  registerFormCallbacks: function() {
+    Form.getElements(this.element).each(this.registerCallback, this);
+  },
+
+  registerCallback: function(element) {
+    if (element.type) {
+      switch (element.type.toLowerCase()) {
+        case 'checkbox':
+        case 'radio':
+          Event.observe(element, 'click', this.onElementEvent.bind(this));
+          break;
+        default:
+          Event.observe(element, 'change', this.onElementEvent.bind(this));
+          break;
+      }
+    }
+  }
+});
+
+Form.Element.EventObserver = Class.create(Abstract.EventObserver, {
+  getValue: function() {
+    return Form.Element.getValue(this.element);
+  }
+});
+
+Form.EventObserver = Class.create(Abstract.EventObserver, {
+  getValue: function() {
+    return Form.serialize(this.element);
+  }
+});
+(function() {
+
+  var Event = {
+    KEY_BACKSPACE: 8,
+    KEY_TAB:       9,
+    KEY_RETURN:   13,
+    KEY_ESC:      27,
+    KEY_LEFT:     37,
+    KEY_UP:       38,
+    KEY_RIGHT:    39,
+    KEY_DOWN:     40,
+    KEY_DELETE:   46,
+    KEY_HOME:     36,
+    KEY_END:      35,
+    KEY_PAGEUP:   33,
+    KEY_PAGEDOWN: 34,
+    KEY_INSERT:   45,
+
+    cache: {}
+  };
+
+  var docEl = document.documentElement;
+  var MOUSEENTER_MOUSELEAVE_EVENTS_SUPPORTED = 'onmouseenter' in docEl
+    && 'onmouseleave' in docEl;
+
+
+
+  var isIELegacyEvent = function(event) { return false; };
+
+  if (window.attachEvent) {
+    if (window.addEventListener) {
+      isIELegacyEvent = function(event) {
+        return !(event instanceof window.Event);
+      };
+    } else {
+      isIELegacyEvent = function(event) { return true; };
+    }
+  }
+
+  var _isButton;
+
+  function _isButtonForDOMEvents(event, code) {
+    return event.which ? (event.which === code + 1) : (event.button === code);
+  }
+
+  var legacyButtonMap = { 0: 1, 1: 4, 2: 2 };
+  function _isButtonForLegacyEvents(event, code) {
+    return event.button === legacyButtonMap[code];
+  }
+
+  function _isButtonForWebKit(event, code) {
+    switch (code) {
+      case 0: return event.which == 1 && !event.metaKey;
+      case 1: return event.which == 2 || (event.which == 1 && event.metaKey);
+      case 2: return event.which == 3;
+      default: return false;
+    }
+  }
+
+  if (window.attachEvent) {
+    if (!window.addEventListener) {
+      _isButton = _isButtonForLegacyEvents;
+    } else {
+      _isButton = function(event, code) {
+        return isIELegacyEvent(event) ? _isButtonForLegacyEvents(event, code) :
+         _isButtonForDOMEvents(event, code);
+      }
+    }
+  } else if (Prototype.Browser.WebKit) {
+    _isButton = _isButtonForWebKit;
+  } else {
+    _isButton = _isButtonForDOMEvents;
+  }
+
+  function isLeftClick(event)   { return _isButton(event, 0) }
+
+  function isMiddleClick(event) { return _isButton(event, 1) }
+
+  function isRightClick(event)  { return _isButton(event, 2) }
+
+  function element(event) {
+    event = Event.extend(event);
+
+    var node = event.target, type = event.type,
+     currentTarget = event.currentTarget;
+
+    if (currentTarget && currentTarget.tagName) {
+      if (type === 'load' || type === 'error' ||
+        (type === 'click' && currentTarget.tagName.toLowerCase() === 'input'
+          && currentTarget.type === 'radio'))
+            node = currentTarget;
+    }
+
+    if (node.nodeType == Node.TEXT_NODE)
+      node = node.parentNode;
+
+    return Element.extend(node);
+  }
+
+  function findElement(event, expression) {
+    var element = Event.element(event);
+
+    if (!expression) return element;
+    while (element) {
+      if (Object.isElement(element) && Prototype.Selector.match(element, expression)) {
+        return Element.extend(element);
+      }
+      element = element.parentNode;
+    }
+  }
+
+  function pointer(event) {
+    return { x: pointerX(event), y: pointerY(event) };
+  }
+
+  function pointerX(event) {
+    var docElement = document.documentElement,
+     body = document.body || { scrollLeft: 0 };
+
+    return event.pageX || (event.clientX +
+      (docElement.scrollLeft || body.scrollLeft) -
+      (docElement.clientLeft || 0));
+  }
+
+  function pointerY(event) {
+    var docElement = document.documentElement,
+     body = document.body || { scrollTop: 0 };
+
+    return  event.pageY || (event.clientY +
+       (docElement.scrollTop || body.scrollTop) -
+       (docElement.clientTop || 0));
+  }
+
+
+  function stop(event) {
+    Event.extend(event);
+    event.preventDefault();
+    event.stopPropagation();
+
+    event.stopped = true;
+  }
+
+
+  Event.Methods = {
+    isLeftClick:   isLeftClick,
+    isMiddleClick: isMiddleClick,
+    isRightClick:  isRightClick,
+
+    element:     element,
+    findElement: findElement,
+
+    pointer:  pointer,
+    pointerX: pointerX,
+    pointerY: pointerY,
+
+    stop: stop
+  };
+
+  var methods = Object.keys(Event.Methods).inject({ }, function(m, name) {
+    m[name] = Event.Methods[name].methodize();
+    return m;
+  });
+
+  if (window.attachEvent) {
+    function _relatedTarget(event) {
+      var element;
+      switch (event.type) {
+        case 'mouseover':
+        case 'mouseenter':
+          element = event.fromElement;
+          break;
+        case 'mouseout':
+        case 'mouseleave':
+          element = event.toElement;
+          break;
+        default:
+          return null;
+      }
+      return Element.extend(element);
+    }
+
+    var additionalMethods = {
+      stopPropagation: function() { this.cancelBubble = true },
+      preventDefault:  function() { this.returnValue = false },
+      inspect: function() { return '[object Event]' }
+    };
+
+    Event.extend = function(event, element) {
+      if (!event) return false;
+
+      if (!isIELegacyEvent(event)) return event;
+
+      if (event._extendedByPrototype) return event;
+      event._extendedByPrototype = Prototype.emptyFunction;
+
+      var pointer = Event.pointer(event);
+
+      Object.extend(event, {
+        target: event.srcElement || element,
+        relatedTarget: _relatedTarget(event),
+        pageX:  pointer.x,
+        pageY:  pointer.y
+      });
+
+      Object.extend(event, methods);
+      Object.extend(event, additionalMethods);
+
+      return event;
+    };
+  } else {
+    Event.extend = Prototype.K;
+  }
+
+  if (window.addEventListener) {
+    Event.prototype = window.Event.prototype || document.createEvent('HTMLEvents').__proto__;
+    Object.extend(Event.prototype, methods);
+  }
+
+  function _createResponder(element, eventName, handler) {
+    var registry = Element.retrieve(element, 'prototype_event_registry');
+
+    if (Object.isUndefined(registry)) {
+      CACHE.push(element);
+      registry = Element.retrieve(element, 'prototype_event_registry', $H());
+    }
+
+    var respondersForEvent = registry.get(eventName);
+    if (Object.isUndefined(respondersForEvent)) {
+      respondersForEvent = [];
+      registry.set(eventName, respondersForEvent);
+    }
+
+    if (respondersForEvent.pluck('handler').include(handler)) return false;
+
+    var responder;
+    if (eventName.include(":")) {
+      responder = function(event) {
+        if (Object.isUndefined(event.eventName))
+          return false;
+
+        if (event.eventName !== eventName)
+          return false;
+
+        Event.extend(event, element);
+        handler.call(element, event);
+      };
+    } else {
+      if (!MOUSEENTER_MOUSELEAVE_EVENTS_SUPPORTED &&
+       (eventName === "mouseenter" || eventName === "mouseleave")) {
+        if (eventName === "mouseenter" || eventName === "mouseleave") {
+          responder = function(event) {
+            Event.extend(event, element);
+
+            var parent = event.relatedTarget;
+            while (parent && parent !== element) {
+              try { parent = parent.parentNode; }
+              catch(e) { parent = element; }
+            }
+
+            if (parent === element) return;
+
+            handler.call(element, event);
+          };
+        }
+      } else {
+        responder = function(event) {
+          Event.extend(event, element);
+          handler.call(element, event);
+        };
+      }
+    }
+
+    responder.handler = handler;
+    respondersForEvent.push(responder);
+    return responder;
+  }
+
+  function _destroyCache() {
+    for (var i = 0, length = CACHE.length; i < length; i++) {
+      Event.stopObserving(CACHE[i]);
+      CACHE[i] = null;
+    }
+  }
+
+  var CACHE = [];
+
+  if (Prototype.Browser.IE)
+    window.attachEvent('onunload', _destroyCache);
+
+  if (Prototype.Browser.WebKit)
+    window.addEventListener('unload', Prototype.emptyFunction, false);
+
+
+  var _getDOMEventName = Prototype.K,
+      translations = { mouseenter: "mouseover", mouseleave: "mouseout" };
+
+  if (!MOUSEENTER_MOUSELEAVE_EVENTS_SUPPORTED) {
+    _getDOMEventName = function(eventName) {
+      return (translations[eventName] || eventName);
+    };
+  }
+
+  function observe(element, eventName, handler) {
+    element = $(element);
+
+    var responder = _createResponder(element, eventName, handler);
+
+    if (!responder) return element;
+
+    if (eventName.include(':')) {
+      if (element.addEventListener)
+        element.addEventListener("dataavailable", responder, false);
+      else {
+        element.attachEvent("ondataavailable", responder);
+        element.attachEvent("onlosecapture", responder);
+      }
+    } else {
+      var actualEventName = _getDOMEventName(eventName);
+
+      if (element.addEventListener)
+        element.addEventListener(actualEventName, responder, false);
+      else
+        element.attachEvent("on" + actualEventName, responder);
+    }
+
+    return element;
+  }
+
+  function stopObserving(element, eventName, handler) {
+    element = $(element);
+
+    var registry = Element.retrieve(element, 'prototype_event_registry');
+    if (!registry) return element;
+
+    if (!eventName) {
+      registry.each( function(pair) {
+        var eventName = pair.key;
+        stopObserving(element, eventName);
+      });
+      return element;
+    }
+
+    var responders = registry.get(eventName);
+    if (!responders) return element;
+
+    if (!handler) {
+      responders.each(function(r) {
+        stopObserving(element, eventName, r.handler);
+      });
+      return element;
+    }
+
+    var i = responders.length, responder;
+    while (i--) {
+      if (responders[i].handler === handler) {
+        responder = responders[i];
+        break;
+      }
+    }
+    if (!responder) return element;
+
+    if (eventName.include(':')) {
+      if (element.removeEventListener)
+        element.removeEventListener("dataavailable", responder, false);
+      else {
+        element.detachEvent("ondataavailable", responder);
+        element.detachEvent("onlosecapture", responder);
+      }
+    } else {
+      var actualEventName = _getDOMEventName(eventName);
+      if (element.removeEventListener)
+        element.removeEventListener(actualEventName, responder, false);
+      else
+        element.detachEvent('on' + actualEventName, responder);
+    }
+
+    registry.set(eventName, responders.without(responder));
+
+    return element;
+  }
+
+  function fire(element, eventName, memo, bubble) {
+    element = $(element);
+
+    if (Object.isUndefined(bubble))
+      bubble = true;
+
+    if (element == document && document.createEvent && !element.dispatchEvent)
+      element = document.documentElement;
+
+    var event;
+    if (document.createEvent) {
+      event = document.createEvent('HTMLEvents');
+      event.initEvent('dataavailable', bubble, true);
+    } else {
+      event = document.createEventObject();
+      event.eventType = bubble ? 'ondataavailable' : 'onlosecapture';
+    }
+
+    event.eventName = eventName;
+    event.memo = memo || { };
+
+    if (document.createEvent)
+      element.dispatchEvent(event);
+    else
+      element.fireEvent(event.eventType, event);
+
+    return Event.extend(event);
+  }
+
+  Event.Handler = Class.create({
+    initialize: function(element, eventName, selector, callback) {
+      this.element   = $(element);
+      this.eventName = eventName;
+      this.selector  = selector;
+      this.callback  = callback;
+      this.handler   = this.handleEvent.bind(this);
+    },
+
+    start: function() {
+      Event.observe(this.element, this.eventName, this.handler);
+      return this;
+    },
+
+    stop: function() {
+      Event.stopObserving(this.element, this.eventName, this.handler);
+      return this;
+    },
+
+    handleEvent: function(event) {
+      var element = Event.findElement(event, this.selector);
+      if (element) this.callback.call(this.element, event, element);
+    }
+  });
+
+  function on(element, eventName, selector, callback) {
+    element = $(element);
+    if (Object.isFunction(selector) && Object.isUndefined(callback)) {
+      callback = selector, selector = null;
+    }
+
+    return new Event.Handler(element, eventName, selector, callback).start();
+  }
+
+  Object.extend(Event, Event.Methods);
+
+  Object.extend(Event, {
+    fire:          fire,
+    observe:       observe,
+    stopObserving: stopObserving,
+    on:            on
+  });
+
+  Element.addMethods({
+    fire:          fire,
+
+    observe:       observe,
+
+    stopObserving: stopObserving,
+
+    on:            on
+  });
+
+  Object.extend(document, {
+    fire:          fire.methodize(),
+
+    observe:       observe.methodize(),
+
+    stopObserving: stopObserving.methodize(),
+
+    on:            on.methodize(),
+
+    loaded:        false
+  });
+
+  if (window.Event) Object.extend(window.Event, Event);
+  else window.Event = Event;
+})();
+
+(function() {
+  /* Support for the DOMContentLoaded event is based on work by Dan Webb,
+     Matthias Miller, Dean Edwards, John Resig, and Diego Perini. */
+
+  var timer;
+
+  function fireContentLoadedEvent() {
+    if (document.loaded) return;
+    if (timer) window.clearTimeout(timer);
+    document.loaded = true;
+    document.fire('dom:loaded');
+  }
+
+  function checkReadyState() {
+    if (document.readyState === 'complete') {
+      document.stopObserving('readystatechange', checkReadyState);
+      fireContentLoadedEvent();
+    }
+  }
+
+  function pollDoScroll() {
+    try { document.documentElement.doScroll('left'); }
+    catch(e) {
+      timer = pollDoScroll.defer();
+      return;
+    }
+    fireContentLoadedEvent();
+  }
+
+  if (document.addEventListener) {
+    document.addEventListener('DOMContentLoaded', fireContentLoadedEvent, false);
+  } else {
+    document.observe('readystatechange', checkReadyState);
+    if (window == top)
+      timer = pollDoScroll.defer();
+  }
+
+  Event.observe(window, 'load', fireContentLoadedEvent);
+})();
+
+Element.addMethods();
+
+/*------------------------------- DEPRECATED -------------------------------*/
+
+Hash.toQueryString = Object.toQueryString;
+
+var Toggle = { display: Element.toggle };
+
+Element.Methods.childOf = Element.Methods.descendantOf;
+
+var Insertion = {
+  Before: function(element, content) {
+    return Element.insert(element, {before:content});
+  },
+
+  Top: function(element, content) {
+    return Element.insert(element, {top:content});
+  },
+
+  Bottom: function(element, content) {
+    return Element.insert(element, {bottom:content});
+  },
+
+  After: function(element, content) {
+    return Element.insert(element, {after:content});
+  }
+};
+
+var $continue = new Error('"throw $continue" is deprecated, use "return" instead');
+
+var Position = {
+  includeScrollOffsets: false,
+
+  prepare: function() {
+    this.deltaX =  window.pageXOffset
+                || document.documentElement.scrollLeft
+                || document.body.scrollLeft
+                || 0;
+    this.deltaY =  window.pageYOffset
+                || document.documentElement.scrollTop
+                || document.body.scrollTop
+                || 0;
+  },
+
+  within: function(element, x, y) {
+    if (this.includeScrollOffsets)
+      return this.withinIncludingScrolloffsets(element, x, y);
+    this.xcomp = x;
+    this.ycomp = y;
+    this.offset = Element.cumulativeOffset(element);
+
+    return (y >= this.offset[1] &&
+            y <  this.offset[1] + element.offsetHeight &&
+            x >= this.offset[0] &&
+            x <  this.offset[0] + element.offsetWidth);
+  },
+
+  withinIncludingScrolloffsets: function(element, x, y) {
+    var offsetcache = Element.cumulativeScrollOffset(element);
+
+    this.xcomp = x + offsetcache[0] - this.deltaX;
+    this.ycomp = y + offsetcache[1] - this.deltaY;
+    this.offset = Element.cumulativeOffset(element);
+
+    return (this.ycomp >= this.offset[1] &&
+            this.ycomp <  this.offset[1] + element.offsetHeight &&
+            this.xcomp >= this.offset[0] &&
+            this.xcomp <  this.offset[0] + element.offsetWidth);
+  },
+
+  overlap: function(mode, element) {
+    if (!mode) return 0;
+    if (mode == 'vertical')
+      return ((this.offset[1] + element.offsetHeight) - this.ycomp) /
+        element.offsetHeight;
+    if (mode == 'horizontal')
+      return ((this.offset[0] + element.offsetWidth) - this.xcomp) /
+        element.offsetWidth;
+  },
+
+
+  cumulativeOffset: Element.Methods.cumulativeOffset,
+
+  positionedOffset: Element.Methods.positionedOffset,
+
+  absolutize: function(element) {
+    Position.prepare();
+    return Element.absolutize(element);
+  },
+
+  relativize: function(element) {
+    Position.prepare();
+    return Element.relativize(element);
+  },
+
+  realOffset: Element.Methods.cumulativeScrollOffset,
+
+  offsetParent: Element.Methods.getOffsetParent,
+
+  page: Element.Methods.viewportOffset,
+
+  clone: function(source, target, options) {
+    options = options || { };
+    return Element.clonePosition(target, source, options);
+  }
+};
+
+/*--------------------------------------------------------------------------*/
+
+if (!document.getElementsByClassName) document.getElementsByClassName = function(instanceMethods){
+  function iter(name) {
+    return name.blank() ? null : "[contains(concat(' ', @class, ' '), ' " + name + " ')]";
+  }
+
+  instanceMethods.getElementsByClassName = Prototype.BrowserFeatures.XPath ?
+  function(element, className) {
+    className = className.toString().strip();
+    var cond = /\s/.test(className) ? $w(className).map(iter).join('') : iter(className);
+    return cond ? document._getElementsByXPath('.//*' + cond, element) : [];
+  } : function(element, className) {
+    className = className.toString().strip();
+    var elements = [], classNames = (/\s/.test(className) ? $w(className) : null);
+    if (!classNames && !className) return elements;
+
+    var nodes = $(element).getElementsByTagName('*');
+    className = ' ' + className + ' ';
+
+    for (var i = 0, child, cn; child = nodes[i]; i++) {
+      if (child.className && (cn = ' ' + child.className + ' ') && (cn.include(className) ||
+          (classNames && classNames.all(function(name) {
+            return !name.toString().blank() && cn.include(' ' + name + ' ');
+          }))))
+        elements.push(Element.extend(child));
+    }
+    return elements;
+  };
+
+  return function(className, parentElement) {
+    return $(parentElement || document.body).getElementsByClassName(className);
+  };
+}(Element.Methods);
+
+/*--------------------------------------------------------------------------*/
+
+Element.ClassNames = Class.create();
+Element.ClassNames.prototype = {
+  initialize: function(element) {
+    this.element = $(element);
+  },
+
+  _each: function(iterator) {
+    this.element.className.split(/\s+/).select(function(name) {
+      return name.length > 0;
+    })._each(iterator);
+  },
+
+  set: function(className) {
+    this.element.className = className;
+  },
+
+  add: function(classNameToAdd) {
+    if (this.include(classNameToAdd)) return;
+    this.set($A(this).concat(classNameToAdd).join(' '));
+  },
+
+  remove: function(classNameToRemove) {
+    if (!this.include(classNameToRemove)) return;
+    this.set($A(this).without(classNameToRemove).join(' '));
+  },
+
+  toString: function() {
+    return $A(this).join(' ');
+  }
+};
+
+Object.extend(Element.ClassNames.prototype, Enumerable);
+
+/*--------------------------------------------------------------------------*/
+
+(function() {
+  window.Selector = Class.create({
+    initialize: function(expression) {
+      this.expression = expression.strip();
+    },
+
+    findElements: function(rootElement) {
+      return Prototype.Selector.select(this.expression, rootElement);
+    },
+
+    match: function(element) {
+      return Prototype.Selector.match(element, this.expression);
+    },
+
+    toString: function() {
+      return this.expression;
+    },
+
+    inspect: function() {
+      return "#<Selector: " + this.expression + ">";
+    }
+  });
+
+  Object.extend(Selector, {
+    matchElements: function(elements, expression) {
+      var match = Prototype.Selector.match,
+          results = [];
+
+      for (var i = 0, length = elements.length; i < length; i++) {
+        var element = elements[i];
+        if (match(element, expression)) {
+          results.push(Element.extend(element));
+        }
+      }
+      return results;
+    },
+
+    findElement: function(elements, expression, index) {
+      index = index || 0;
+      var matchIndex = 0, element;
+      for (var i = 0, length = elements.length; i < length; i++) {
+        element = elements[i];
+        if (Prototype.Selector.match(element, expression) && index === matchIndex++) {
+          return Element.extend(element);
+        }
+      }
+    },
+
+    findChildElements: function(element, expressions) {
+      var selector = expressions.toArray().join(', ');
+      return Prototype.Selector.select(selector, element || document);
+    }
+  });
+})();
diff --git a/PerformanceTests/Dromaeo/resources/dromaeo/web/lib/prototype.js b/PerformanceTests/Dromaeo/resources/dromaeo/web/lib/prototype.js
deleted file mode 100644 (file)
index dfe8ab4..0000000
+++ /dev/null
@@ -1,4320 +0,0 @@
-/*  Prototype JavaScript framework, version 1.6.0.3
- *  (c) 2005-2008 Sam Stephenson
- *
- *  Prototype is freely distributable under the terms of an MIT-style license.
- *  For details, see the Prototype web site: http://www.prototypejs.org/
- *
- *--------------------------------------------------------------------------*/
-
-var Prototype = {
-  Version: '1.6.0.3',
-
-  Browser: {
-    IE:     !!(window.attachEvent &&
-      navigator.userAgent.indexOf('Opera') === -1),
-    Opera:  navigator.userAgent.indexOf('Opera') > -1,
-    WebKit: navigator.userAgent.indexOf('AppleWebKit/') > -1,
-    Gecko:  navigator.userAgent.indexOf('Gecko') > -1 &&
-      navigator.userAgent.indexOf('KHTML') === -1,
-    MobileSafari: !!navigator.userAgent.match(/Apple.*Mobile.*Safari/)
-  },
-
-  BrowserFeatures: {
-    XPath: !!document.evaluate,
-    SelectorsAPI: !!document.querySelector,
-    ElementExtensions: !!window.HTMLElement,
-    SpecificElementExtensions:
-      document.createElement('div')['__proto__'] &&
-      document.createElement('div')['__proto__'] !==
-        document.createElement('form')['__proto__']
-  },
-
-  ScriptFragment: '<script[^>]*>([\\S\\s]*?)<\/script>',
-  JSONFilter: /^\/\*-secure-([\s\S]*)\*\/\s*$/,
-
-  emptyFunction: function() { },
-  K: function(x) { return x }
-};
-
-if (Prototype.Browser.MobileSafari)
-  Prototype.BrowserFeatures.SpecificElementExtensions = false;
-
-
-/* Based on Alex Arnell's inheritance implementation. */
-var Class = {
-  create: function() {
-    var parent = null, properties = $A(arguments);
-    if (Object.isFunction(properties[0]))
-      parent = properties.shift();
-
-    function klass() {
-      this.initialize.apply(this, arguments);
-    }
-
-    Object.extend(klass, Class.Methods);
-    klass.superclass = parent;
-    klass.subclasses = [];
-
-    if (parent) {
-      var subclass = function() { };
-      subclass.prototype = parent.prototype;
-      klass.prototype = new subclass;
-      parent.subclasses.push(klass);
-    }
-
-    for (var i = 0; i < properties.length; i++)
-      klass.addMethods(properties[i]);
-
-    if (!klass.prototype.initialize)
-      klass.prototype.initialize = Prototype.emptyFunction;
-
-    klass.prototype.constructor = klass;
-
-    return klass;
-  }
-};
-
-Class.Methods = {
-  addMethods: function(source) {
-    var ancestor   = this.superclass && this.superclass.prototype;
-    var properties = Object.keys(source);
-
-    if (!Object.keys({ toString: true }).length)
-      properties.push("toString", "valueOf");
-
-    for (var i = 0, length = properties.length; i < length; i++) {
-      var property = properties[i], value = source[property];
-      if (ancestor && Object.isFunction(value) &&
-          value.argumentNames().first() == "$super") {
-        var method = value;
-        value = (function(m) {
-          return function() { return ancestor[m].apply(this, arguments) };
-        })(property).wrap(method);
-
-        value.valueOf = method.valueOf.bind(method);
-        value.toString = method.toString.bind(method);
-      }
-      this.prototype[property] = value;
-    }
-
-    return this;
-  }
-};
-
-var Abstract = { };
-
-Object.extend = function(destination, source) {
-  for (var property in source)
-    destination[property] = source[property];
-  return destination;
-};
-
-Object.extend(Object, {
-  inspect: function(object) {
-    try {
-      if (Object.isUndefined(object)) return 'undefined';
-      if (object === null) return 'null';
-      return object.inspect ? object.inspect() : String(object);
-    } catch (e) {
-      if (e instanceof RangeError) return '...';
-      throw e;
-    }
-  },
-
-  toJSON: function(object) {
-    var type = typeof object;
-    switch (type) {
-      case 'undefined':
-      case 'function':
-      case 'unknown': return;
-      case 'boolean': return object.toString();
-    }
-
-    if (object === null) return 'null';
-    if (object.toJSON) return object.toJSON();
-    if (Object.isElement(object)) return;
-
-    var results = [];
-    for (var property in object) {
-      var value = Object.toJSON(object[property]);
-      if (!Object.isUndefined(value))
-        results.push(property.toJSON() + ': ' + value);
-    }
-
-    return '{' + results.join(', ') + '}';
-  },
-
-  toQueryString: function(object) {
-    return $H(object).toQueryString();
-  },
-
-  toHTML: function(object) {
-    return object && object.toHTML ? object.toHTML() : String.interpret(object);
-  },
-
-  keys: function(object) {
-    var keys = [];
-    for (var property in object)
-      keys.push(property);
-    return keys;
-  },
-
-  values: function(object) {
-    var values = [];
-    for (var property in object)
-      values.push(object[property]);
-    return values;
-  },
-
-  clone: function(object) {
-    return Object.extend({ }, object);
-  },
-
-  isElement: function(object) {
-    return !!(object && object.nodeType == 1);
-  },
-
-  isArray: function(object) {
-    return object != null && typeof object == "object" &&
-      'splice' in object && 'join' in object;
-  },
-
-  isHash: function(object) {
-    return object instanceof Hash;
-  },
-
-  isFunction: function(object) {
-    return typeof object == "function";
-  },
-
-  isString: function(object) {
-    return typeof object == "string";
-  },
-
-  isNumber: function(object) {
-    return typeof object == "number";
-  },
-
-  isUndefined: function(object) {
-    return typeof object == "undefined";
-  }
-});
-
-Object.extend(Function.prototype, {
-  argumentNames: function() {
-    var names = this.toString().match(/^[\s\(]*function[^(]*\(([^\)]*)\)/)[1]
-      .replace(/\s+/g, '').split(',');
-    return names.length == 1 && !names[0] ? [] : names;
-  },
-
-  bind: function() {
-    if (arguments.length < 2 && Object.isUndefined(arguments[0])) return this;
-    var __method = this, args = $A(arguments), object = args.shift();
-    return function() {
-      return __method.apply(object, args.concat($A(arguments)));
-    }
-  },
-
-  bindAsEventListener: function() {
-    var __method = this, args = $A(arguments), object = args.shift();
-    return function(event) {
-      return __method.apply(object, [event || window.event].concat(args));
-    }
-  },
-
-  curry: function() {
-    if (!arguments.length) return this;
-    var __method = this, args = $A(arguments);
-    return function() {
-      return __method.apply(this, args.concat($A(arguments)));
-    }
-  },
-
-  delay: function() {
-    var __method = this, args = $A(arguments), timeout = args.shift() * 1000;
-    return window.setTimeout(function() {
-      return __method.apply(__method, args);
-    }, timeout);
-  },
-
-  defer: function() {
-    var args = [0.01].concat($A(arguments));
-    return this.delay.apply(this, args);
-  },
-
-  wrap: function(wrapper) {
-    var __method = this;
-    return function() {
-      return wrapper.apply(this, [__method.bind(this)].concat($A(arguments)));
-    }
-  },
-
-  methodize: function() {
-    if (this._methodized) return this._methodized;
-    var __method = this;
-    return this._methodized = function() {
-      return __method.apply(null, [this].concat($A(arguments)));
-    };
-  }
-});
-
-Date.prototype.toJSON = function() {
-  return '"' + this.getUTCFullYear() + '-' +
-    (this.getUTCMonth() + 1).toPaddedString(2) + '-' +
-    this.getUTCDate().toPaddedString(2) + 'T' +
-    this.getUTCHours().toPaddedString(2) + ':' +
-    this.getUTCMinutes().toPaddedString(2) + ':' +
-    this.getUTCSeconds().toPaddedString(2) + 'Z"';
-};
-
-var Try = {
-  these: function() {
-    var returnValue;
-
-    for (var i = 0, length = arguments.length; i < length; i++) {
-      var lambda = arguments[i];
-      try {
-        returnValue = lambda();
-        break;
-      } catch (e) { }
-    }
-
-    return returnValue;
-  }
-};
-
-RegExp.prototype.match = RegExp.prototype.test;
-
-RegExp.escape = function(str) {
-  return String(str).replace(/([.*+?^=!:${}()|[\]\/\\])/g, '\\$1');
-};
-
-/*--------------------------------------------------------------------------*/
-
-var PeriodicalExecuter = Class.create({
-  initialize: function(callback, frequency) {
-    this.callback = callback;
-    this.frequency = frequency;
-    this.currentlyExecuting = false;
-
-    this.registerCallback();
-  },
-
-  registerCallback: function() {
-    this.timer = setInterval(this.onTimerEvent.bind(this), this.frequency * 1000);
-  },
-
-  execute: function() {
-    this.callback(this);
-  },
-
-  stop: function() {
-    if (!this.timer) return;
-    clearInterval(this.timer);
-    this.timer = null;
-  },
-
-  onTimerEvent: function() {
-    if (!this.currentlyExecuting) {
-      try {
-        this.currentlyExecuting = true;
-        this.execute();
-      } finally {
-        this.currentlyExecuting = false;
-      }
-    }
-  }
-});
-Object.extend(String, {
-  interpret: function(value) {
-    return value == null ? '' : String(value);
-  },
-  specialChar: {
-    '\b': '\\b',
-    '\t': '\\t',
-    '\n': '\\n',
-    '\f': '\\f',
-    '\r': '\\r',
-    '\\': '\\\\'
-  }
-});
-
-Object.extend(String.prototype, {
-  gsub: function(pattern, replacement) {
-    var result = '', source = this, match;
-    replacement = arguments.callee.prepareReplacement(replacement);
-
-    while (source.length > 0) {
-      if (match = source.match(pattern)) {
-        result += source.slice(0, match.index);
-        result += String.interpret(replacement(match));
-        source  = source.slice(match.index + match[0].length);
-      } else {
-        result += source, source = '';
-      }
-    }
-    return result;
-  },
-
-  sub: function(pattern, replacement, count) {
-    replacement = this.gsub.prepareReplacement(replacement);
-    count = Object.isUndefined(count) ? 1 : count;
-
-    return this.gsub(pattern, function(match) {
-      if (--count < 0) return match[0];
-      return replacement(match);
-    });
-  },
-
-  scan: function(pattern, iterator) {
-    this.gsub(pattern, iterator);
-    return String(this);
-  },
-
-  truncate: function(length, truncation) {
-    length = length || 30;
-    truncation = Object.isUndefined(truncation) ? '...' : truncation;
-    return this.length > length ?
-      this.slice(0, length - truncation.length) + truncation : String(this);
-  },
-
-  strip: function() {
-    return this.replace(/^\s+/, '').replace(/\s+$/, '');
-  },
-
-  stripTags: function() {
-    return this.replace(/<\/?[^>]+>/gi, '');
-  },
-
-  stripScripts: function() {
-    return this.replace(new RegExp(Prototype.ScriptFragment, 'img'), '');
-  },
-
-  extractScripts: function() {
-    var matchAll = new RegExp(Prototype.ScriptFragment, 'img');
-    var matchOne = new RegExp(Prototype.ScriptFragment, 'im');
-    return (this.match(matchAll) || []).map(function(scriptTag) {
-      return (scriptTag.match(matchOne) || ['', ''])[1];
-    });
-  },
-
-  evalScripts: function() {
-    return this.extractScripts().map(function(script) { return eval(script) });
-  },
-
-  escapeHTML: function() {
-    var self = arguments.callee;
-    self.text.data = this;
-    return self.div.innerHTML;
-  },
-
-  unescapeHTML: function() {
-    var div = new Element('div');
-    div.innerHTML = this.stripTags();
-    return div.childNodes[0] ? (div.childNodes.length > 1 ?
-      $A(div.childNodes).inject('', function(memo, node) { return memo+node.nodeValue }) :
-      div.childNodes[0].nodeValue) : '';
-  },
-
-  toQueryParams: function(separator) {
-    var match = this.strip().match(/([^?#]*)(#.*)?$/);
-    if (!match) return { };
-
-    return match[1].split(separator || '&').inject({ }, function(hash, pair) {
-      if ((pair = pair.split('='))[0]) {
-        var key = decodeURIComponent(pair.shift());
-        var value = pair.length > 1 ? pair.join('=') : pair[0];
-        if (value != undefined) value = decodeURIComponent(value);
-
-        if (key in hash) {
-          if (!Object.isArray(hash[key])) hash[key] = [hash[key]];
-          hash[key].push(value);
-        }
-        else hash[key] = value;
-      }
-      return hash;
-    });
-  },
-
-  toArray: function() {
-    return this.split('');
-  },
-
-  succ: function() {
-    return this.slice(0, this.length - 1) +
-      String.fromCharCode(this.charCodeAt(this.length - 1) + 1);
-  },
-
-  times: function(count) {
-    return count < 1 ? '' : new Array(count + 1).join(this);
-  },
-
-  camelize: function() {
-    var parts = this.split('-'), len = parts.length;
-    if (len == 1) return parts[0];
-
-    var camelized = this.charAt(0) == '-'
-      ? parts[0].charAt(0).toUpperCase() + parts[0].substring(1)
-      : parts[0];
-
-    for (var i = 1; i < len; i++)
-      camelized += parts[i].charAt(0).toUpperCase() + parts[i].substring(1);
-
-    return camelized;
-  },
-
-  capitalize: function() {
-    return this.charAt(0).toUpperCase() + this.substring(1).toLowerCase();
-  },
-
-  underscore: function() {
-    return this.gsub(/::/, '/').gsub(/([A-Z]+)([A-Z][a-z])/,'#{1}_#{2}').gsub(/([a-z\d])([A-Z])/,'#{1}_#{2}').gsub(/-/,'_').toLowerCase();
-  },
-
-  dasherize: function() {
-    return this.gsub(/_/,'-');
-  },
-
-  inspect: function(useDoubleQuotes) {
-    var escapedString = this.gsub(/[\x00-\x1f\\]/, function(match) {
-      var character = String.specialChar[match[0]];
-      return character ? character : '\\u00' + match[0].charCodeAt().toPaddedString(2, 16);
-    });
-    if (useDoubleQuotes) return '"' + escapedString.replace(/"/g, '\\"') + '"';
-    return "'" + escapedString.replace(/'/g, '\\\'') + "'";
-  },
-
-  toJSON: function() {
-    return this.inspect(true);
-  },
-
-  unfilterJSON: function(filter) {
-    return this.sub(filter || Prototype.JSONFilter, '#{1}');
-  },
-
-  isJSON: function() {
-    var str = this;
-    if (str.blank()) return false;
-    str = this.replace(/\\./g, '@').replace(/"[^"\\\n\r]*"/g, '');
-    return (/^[,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t]*$/).test(str);
-  },
-
-  evalJSON: function(sanitize) {
-    var json = this.unfilterJSON();
-    try {
-      if (!sanitize || json.isJSON()) return eval('(' + json + ')');
-    } catch (e) { }
-    throw new SyntaxError('Badly formed JSON string: ' + this.inspect());
-  },
-
-  include: function(pattern) {
-    return this.indexOf(pattern) > -1;
-  },
-
-  startsWith: function(pattern) {
-    return this.indexOf(pattern) === 0;
-  },
-
-  endsWith: function(pattern) {
-    var d = this.length - pattern.length;
-    return d >= 0 && this.lastIndexOf(pattern) === d;
-  },
-
-  empty: function() {
-    return this == '';
-  },
-
-  blank: function() {
-    return /^\s*$/.test(this);
-  },
-
-  interpolate: function(object, pattern) {
-    return new Template(this, pattern).evaluate(object);
-  }
-});
-
-if (Prototype.Browser.WebKit || Prototype.Browser.IE) Object.extend(String.prototype, {
-  escapeHTML: function() {
-    return this.replace(/&/g,'&amp;').replace(/</g,'&lt;').replace(/>/g,'&gt;');
-  },
-  unescapeHTML: function() {
-    return this.stripTags().replace(/&amp;/g,'&').replace(/&lt;/g,'<').replace(/&gt;/g,'>');
-  }
-});
-
-String.prototype.gsub.prepareReplacement = function(replacement) {
-  if (Object.isFunction(replacement)) return replacement;
-  var template = new Template(replacement);
-  return function(match) { return template.evaluate(match) };
-};
-
-String.prototype.parseQuery = String.prototype.toQueryParams;
-
-Object.extend(String.prototype.escapeHTML, {
-  div:  document.createElement('div'),
-  text: document.createTextNode('')
-});
-
-String.prototype.escapeHTML.div.appendChild(String.prototype.escapeHTML.text);
-
-var Template = Class.create({
-  initialize: function(template, pattern) {
-    this.template = template.toString();
-    this.pattern = pattern || Template.Pattern;
-  },
-
-  evaluate: function(object) {
-    if (Object.isFunction(object.toTemplateReplacements))
-      object = object.toTemplateReplacements();
-
-    return this.template.gsub(this.pattern, function(match) {
-      if (object == null) return '';
-
-      var before = match[1] || '';
-      if (before == '\\') return match[2];
-
-      var ctx = object, expr = match[3];
-      var pattern = /^([^.[]+|\[((?:.*?[^\\])?)\])(\.|\[|$)/;
-      match = pattern.exec(expr);
-      if (match == null) return before;
-
-      while (match != null) {
-        var comp = match[1].startsWith('[') ? match[2].gsub('\\\\]', ']') : match[1];
-        ctx = ctx[comp];
-        if (null == ctx || '' == match[3]) break;
-        expr = expr.substring('[' == match[3] ? match[1].length : match[0].length);
-        match = pattern.exec(expr);
-      }
-
-      return before + String.interpret(ctx);
-    });
-  }
-});
-Template.Pattern = /(^|.|\r|\n)(#\{(.*?)\})/;
-
-var $break = { };
-
-var Enumerable = {
-  each: function(iterator, context) {
-    var index = 0;
-    try {
-      this._each(function(value) {
-        iterator.call(context, value, index++);
-      });
-    } catch (e) {
-      if (e != $break) throw e;
-    }
-    return this;
-  },
-
-  eachSlice: function(number, iterator, context) {
-    var index = -number, slices = [], array = this.toArray();
-    if (number < 1) return array;
-    while ((index += number) < array.length)
-      slices.push(array.slice(index, index+number));
-    return slices.collect(iterator, context);
-  },
-
-  all: function(iterator, context) {
-    iterator = iterator || Prototype.K;
-    var result = true;
-    this.each(function(value, index) {
-      result = result && !!iterator.call(context, value, index);
-      if (!result) throw $break;
-    });
-    return result;
-  },
-
-  any: function(iterator, context) {
-    iterator = iterator || Prototype.K;
-    var result = false;
-    this.each(function(value, index) {
-      if (result = !!iterator.call(context, value, index))
-        throw $break;
-    });
-    return result;
-  },
-
-  collect: function(iterator, context) {
-    iterator = iterator || Prototype.K;
-    var results = [];
-    this.each(function(value, index) {
-      results.push(iterator.call(context, value, index));
-    });
-    return results;
-  },
-
-  detect: function(iterator, context) {
-    var result;
-    this.each(function(value, index) {
-      if (iterator.call(context, value, index)) {
-        result = value;
-        throw $break;
-      }
-    });
-    return result;
-  },
-
-  findAll: function(iterator, context) {
-    var results = [];
-    this.each(function(value, index) {
-      if (iterator.call(context, value, index))
-        results.push(value);
-    });
-    return results;
-  },
-
-  grep: function(filter, iterator, context) {
-    iterator = iterator || Prototype.K;
-    var results = [];
-
-    if (Object.isString(filter))
-      filter = new RegExp(filter);
-
-    this.each(function(value, index) {
-      if (filter.match(value))
-        results.push(iterator.call(context, value, index));
-    });
-    return results;
-  },
-
-  include: function(object) {
-    if (Object.isFunction(this.indexOf))
-      if (this.indexOf(object) != -1) return true;
-
-    var found = false;
-    this.each(function(value) {
-      if (value == object) {
-        found = true;
-        throw $break;
-      }
-    });
-    return found;
-  },
-
-  inGroupsOf: function(number, fillWith) {
-    fillWith = Object.isUndefined(fillWith) ? null : fillWith;
-    return this.eachSlice(number, function(slice) {
-      while(slice.length < number) slice.push(fillWith);
-      return slice;
-    });
-  },
-
-  inject: function(memo, iterator, context) {
-    this.each(function(value, index) {
-      memo = iterator.call(context, memo, value, index);
-    });
-    return memo;
-  },
-
-  invoke: function(method) {
-    var args = $A(arguments).slice(1);
-    return this.map(function(value) {
-      return value[method].apply(value, args);
-    });
-  },
-
-  max: function(iterator, context) {
-    iterator = iterator || Prototype.K;
-    var result;
-    this.each(function(value, index) {
-      value = iterator.call(context, value, index);
-      if (result == null || value >= result)
-        result = value;
-    });
-    return result;
-  },
-
-  min: function(iterator, context) {
-    iterator = iterator || Prototype.K;
-    var result;
-    this.each(function(value, index) {
-      value = iterator.call(context, value, index);
-      if (result == null || value < result)
-        result = value;
-    });
-    return result;
-  },
-
-  partition: function(iterator, context) {
-    iterator = iterator || Prototype.K;
-    var trues = [], falses = [];
-    this.each(function(value, index) {
-      (iterator.call(context, value, index) ?
-        trues : falses).push(value);
-    });
-    return [trues, falses];
-  },
-
-  pluck: function(property) {
-    var results = [];
-    this.each(function(value) {
-      results.push(value[property]);
-    });
-    return results;
-  },
-
-  reject: function(iterator, context) {
-    var results = [];
-    this.each(function(value, index) {
-      if (!iterator.call(context, value, index))
-        results.push(value);
-    });
-    return results;
-  },
-
-  sortBy: function(iterator, context) {
-    return this.map(function(value, index) {
-      return {
-        value: value,
-        criteria: iterator.call(context, value, index)
-      };
-    }).sort(function(left, right) {
-      var a = left.criteria, b = right.criteria;
-      return a < b ? -1 : a > b ? 1 : 0;
-    }).pluck('value');
-  },
-
-  toArray: function() {
-    return this.map();
-  },
-
-  zip: function() {
-    var iterator = Prototype.K, args = $A(arguments);
-    if (Object.isFunction(args.last()))
-      iterator = args.pop();
-
-    var collections = [this].concat(args).map($A);
-    return this.map(function(value, index) {
-      return iterator(collections.pluck(index));
-    });
-  },
-
-  size: function() {
-    return this.toArray().length;
-  },
-
-  inspect: function() {
-    return '#<Enumerable:' + this.toArray().inspect() + '>';
-  }
-};
-
-Object.extend(Enumerable, {
-  map:     Enumerable.collect,
-  find:    Enumerable.detect,
-  select:  Enumerable.findAll,
-  filter:  Enumerable.findAll,
-  member:  Enumerable.include,
-  entries: Enumerable.toArray,
-  every:   Enumerable.all,
-  some:    Enumerable.any
-});
-function $A(iterable) {
-  if (!iterable) return [];
-  if (iterable.toArray) return iterable.toArray();
-  var length = iterable.length || 0, results = new Array(length);
-  while (length--) results[length] = iterable[length];
-  return results;
-}
-
-if (Prototype.Browser.WebKit) {
-  $A = function(iterable) {
-    if (!iterable) return [];
-    // In Safari, only use the `toArray` method if it's not a NodeList.
-    // A NodeList is a function, has an function `item` property, and a numeric
-    // `length` property. Adapted from Google Doctype.
-    if (!(typeof iterable === 'function' && typeof iterable.length ===
-        'number' && typeof iterable.item === 'function') && iterable.toArray)
-      return iterable.toArray();
-    var length = iterable.length || 0, results = new Array(length);
-    while (length--) results[length] = iterable[length];
-    return results;
-  };
-}
-
-Array.from = $A;
-
-Object.extend(Array.prototype, Enumerable);
-
-if (!Array.prototype._reverse) Array.prototype._reverse = Array.prototype.reverse;
-
-Object.extend(Array.prototype, {
-  _each: function(iterator) {
-    for (var i = 0, length = this.length; i < length; i++)
-      iterator(this[i]);
-  },
-
-  clear: function() {
-    this.length = 0;
-    return this;
-  },
-
-  first: function() {
-    return this[0];
-  },
-
-  last: function() {
-    return this[this.length - 1];
-  },
-
-  compact: function() {
-    return this.select(function(value) {
-      return value != null;
-    });
-  },
-
-  flatten: function() {
-    return this.inject([], function(array, value) {
-      return array.concat(Object.isArray(value) ?
-        value.flatten() : [value]);
-    });
-  },
-
-  without: function() {
-    var values = $A(arguments);
-    return this.select(function(value) {
-      return !values.include(value);
-    });
-  },
-
-  reverse: function(inline) {
-    return (inline !== false ? this : this.toArray())._reverse();
-  },
-
-  reduce: function() {
-    return this.length > 1 ? this : this[0];
-  },
-
-  uniq: function(sorted) {
-    return this.inject([], function(array, value, index) {
-      if (0 == index || (sorted ? array.last() != value : !array.include(value)))
-        array.push(value);
-      return array;
-    });
-  },
-
-  intersect: function(array) {
-    return this.uniq().findAll(function(item) {
-      return array.detect(function(value) { return item === value });
-    });
-  },
-
-  clone: function() {
-    return [].concat(this);
-  },
-
-  size: function() {
-    return this.length;
-  },
-
-  inspect: function() {
-    return '[' + this.map(Object.inspect).join(', ') + ']';
-  },
-
-  toJSON: function() {
-    var results = [];
-    this.each(function(object) {
-      var value = Object.toJSON(object);
-      if (!Object.isUndefined(value)) results.push(value);
-    });
-    return '[' + results.join(', ') + ']';
-  }
-});
-
-// use native browser JS 1.6 implementation if available
-if (Object.isFunction(Array.prototype.forEach))
-  Array.prototype._each = Array.prototype.forEach;
-
-if (!Array.prototype.indexOf) Array.prototype.indexOf = function(item, i) {
-  i || (i = 0);
-  var length = this.length;
-  if (i < 0) i = length + i;
-  for (; i < length; i++)
-    if (this[i] === item) return i;
-  return -1;
-};
-
-if (!Array.prototype.lastIndexOf) Array.prototype.lastIndexOf = function(item, i) {
-  i = isNaN(i) ? this.length : (i < 0 ? this.length + i : i) + 1;
-  var n = this.slice(0, i).reverse().indexOf(item);
-  return (n < 0) ? n : i - n - 1;
-};
-
-Array.prototype.toArray = Array.prototype.clone;
-
-function $w(string) {
-  if (!Object.isString(string)) return [];
-  string = string.strip();
-  return string ? string.split(/\s+/) : [];
-}
-
-if (Prototype.Browser.Opera){
-  Array.prototype.concat = function() {
-    var array = [];
-    for (var i = 0, length = this.length; i < length; i++) array.push(this[i]);
-    for (var i = 0, length = arguments.length; i < length; i++) {
-      if (Object.isArray(arguments[i])) {
-        for (var j = 0, arrayLength = arguments[i].length; j < arrayLength; j++)
-          array.push(arguments[i][j]);
-      } else {
-        array.push(arguments[i]);
-      }
-    }
-    return array;
-  };
-}
-Object.extend(Number.prototype, {
-  toColorPart: function() {
-    return this.toPaddedString(2, 16);
-  },
-
-  succ: function() {
-    return this + 1;
-  },
-
-  times: function(iterator, context) {
-    $R(0, this, true).each(iterator, context);
-    return this;
-  },
-
-  toPaddedString: function(length, radix) {
-    var string = this.toString(radix || 10);
-    return '0'.times(length - string.length) + string;
-  },
-
-  toJSON: function() {
-    return isFinite(this) ? this.toString() : 'null';
-  }
-});
-
-$w('abs round ceil floor').each(function(method){
-  Number.prototype[method] = Math[method].methodize();
-});
-function $H(object) {
-  return new Hash(object);
-};
-
-var Hash = Class.create(Enumerable, (function() {
-
-  function toQueryPair(key, value) {
-    if (Object.isUndefined(value)) return key;
-    return key + '=' + encodeURIComponent(String.interpret(value));
-  }
-
-  return {
-    initialize: function(object) {
-      this._object = Object.isHash(object) ? object.toObject() : Object.clone(object);
-    },
-
-    _each: function(iterator) {
-      for (var key in this._object) {
-        var value = this._object[key], pair = [key, value];
-        pair.key = key;
-        pair.value = value;
-        iterator(pair);
-      }
-    },
-
-    set: function(key, value) {
-      return this._object[key] = value;
-    },
-
-    get: function(key) {
-      // simulating poorly supported hasOwnProperty
-      if (this._object[key] !== Object.prototype[key])
-        return this._object[key];
-    },
-
-    unset: function(key) {
-      var value = this._object[key];
-      delete this._object[key];
-      return value;
-    },
-
-    toObject: function() {
-      return Object.clone(this._object);
-    },
-
-    keys: function() {
-      return this.pluck('key');
-    },
-
-    values: function() {
-      return this.pluck('value');
-    },
-
-    index: function(value) {
-      var match = this.detect(function(pair) {
-        return pair.value === value;
-      });
-      return match && match.key;
-    },
-
-    merge: function(object) {
-      return this.clone().update(object);
-    },
-
-    update: function(object) {
-      return new Hash(object).inject(this, function(result, pair) {
-        result.set(pair.key, pair.value);
-        return result;
-      });
-    },
-
-    toQueryString: function() {
-      return this.inject([], function(results, pair) {
-        var key = encodeURIComponent(pair.key), values = pair.value;
-
-        if (values && typeof values == 'object') {
-          if (Object.isArray(values))
-            return results.concat(values.map(toQueryPair.curry(key)));
-        } else results.push(toQueryPair(key, values));
-        return results;
-      }).join('&');
-    },
-
-    inspect: function() {
-      return '#<Hash:{' + this.map(function(pair) {
-        return pair.map(Object.inspect).join(': ');
-      }).join(', ') + '}>';
-    },
-
-    toJSON: function() {
-      return Object.toJSON(this.toObject());
-    },
-
-    clone: function() {
-      return new Hash(this);
-    }
-  }
-})());
-
-Hash.prototype.toTemplateReplacements = Hash.prototype.toObject;
-Hash.from = $H;
-var ObjectRange = Class.create(Enumerable, {
-  initialize: function(start, end, exclusive) {
-    this.start = start;
-    this.end = end;
-    this.exclusive = exclusive;
-  },
-
-  _each: function(iterator) {
-    var value = this.start;
-    while (this.include(value)) {
-      iterator(value);
-      value = value.succ();
-    }
-  },
-
-  include: function(value) {
-    if (value < this.start)
-      return false;
-    if (this.exclusive)
-      return value < this.end;
-    return value <= this.end;
-  }
-});
-
-var $R = function(start, end, exclusive) {
-  return new ObjectRange(start, end, exclusive);
-};
-
-var Ajax = {
-  getTransport: function() {
-    return Try.these(
-      function() {return new XMLHttpRequest()},
-      function() {return new ActiveXObject('Msxml2.XMLHTTP')},
-      function() {return new ActiveXObject('Microsoft.XMLHTTP')}
-    ) || false;
-  },
-
-  activeRequestCount: 0
-};
-
-Ajax.Responders = {
-  responders: [],
-
-  _each: function(iterator) {
-    this.responders._each(iterator);
-  },
-
-  register: function(responder) {
-    if (!this.include(responder))
-      this.responders.push(responder);
-  },
-
-  unregister: function(responder) {
-    this.responders = this.responders.without(responder);
-  },
-
-  dispatch: function(callback, request, transport, json) {
-    this.each(function(responder) {
-      if (Object.isFunction(responder[callback])) {
-        try {
-          responder[callback].apply(responder, [request, transport, json]);
-        } catch (e) { }
-      }
-    });
-  }
-};
-
-Object.extend(Ajax.Responders, Enumerable);
-
-Ajax.Responders.register({
-  onCreate:   function() { Ajax.activeRequestCount++ },
-  onComplete: function() { Ajax.activeRequestCount-- }
-});
-
-Ajax.Base = Class.create({
-  initialize: function(options) {
-    this.options = {
-      method:       'post',
-      asynchronous: true,
-      contentType:  'application/x-www-form-urlencoded',
-      encoding:     'UTF-8',
-      parameters:   '',
-      evalJSON:     true,
-      evalJS:       true
-    };
-    Object.extend(this.options, options || { });
-
-    this.options.method = this.options.method.toLowerCase();
-
-    if (Object.isString(this.options.parameters))
-      this.options.parameters = this.options.parameters.toQueryParams();
-    else if (Object.isHash(this.options.parameters))
-      this.options.parameters = this.options.parameters.toObject();
-  }
-});
-
-Ajax.Request = Class.create(Ajax.Base, {
-  _complete: false,
-
-  initialize: function($super, url, options) {
-    $super(options);
-    this.transport = Ajax.getTransport();
-    this.request(url);
-  },
-
-  request: function(url) {
-    this.url = url;
-    this.method = this.options.method;
-    var params = Object.clone(this.options.parameters);
-
-    if (!['get', 'post'].include(this.method)) {
-      // simulate other verbs over post
-      params['_method'] = this.method;
-      this.method = 'post';
-    }
-
-    this.parameters = params;
-
-    if (params = Object.toQueryString(params)) {
-      // when GET, append parameters to URL
-      if (this.method == 'get')
-        this.url += (this.url.include('?') ? '&' : '?') + params;
-      else if (/Konqueror|Safari|KHTML/.test(navigator.userAgent))
-        params += '&_=';
-    }
-
-    try {
-      var response = new Ajax.Response(this);
-      if (this.options.onCreate) this.options.onCreate(response);
-      Ajax.Responders.dispatch('onCreate', this, response);
-
-      this.transport.open(this.method.toUpperCase(), this.url,
-        this.options.asynchronous);
-
-      if (this.options.asynchronous) this.respondToReadyState.bind(this).defer(1);
-
-      this.transport.onreadystatechange = this.onStateChange.bind(this);
-      this.setRequestHeaders();
-
-      this.body = this.method == 'post' ? (this.options.postBody || params) : null;
-      this.transport.send(this.body);
-
-      /* Force Firefox to handle ready state 4 for synchronous requests */
-      if (!this.options.asynchronous && this.transport.overrideMimeType)
-        this.onStateChange();
-
-    }
-    catch (e) {
-      this.dispatchException(e);
-    }
-  },
-
-  onStateChange: function() {
-    var readyState = this.transport.readyState;
-    if (readyState > 1 && !((readyState == 4) && this._complete))
-      this.respondToReadyState(this.transport.readyState);
-  },
-
-  setRequestHeaders: function() {
-    var headers = {
-      'X-Requested-With': 'XMLHttpRequest',
-      'X-Prototype-Version': Prototype.Version,
-      'Accept': 'text/javascript, text/html, application/xml, text/xml, */*'
-    };
-
-    if (this.method == 'post') {
-      headers['Content-type'] = this.options.contentType +
-        (this.options.encoding ? '; charset=' + this.options.encoding : '');
-
-      /* Force "Connection: close" for older Mozilla browsers to work
-       * around a bug where XMLHttpRequest sends an incorrect
-       * Content-length header. See Mozilla Bugzilla #246651.
-       */
-      if (this.transport.overrideMimeType &&
-          (navigator.userAgent.match(/Gecko\/(\d{4})/) || [0,2005])[1] < 2005)
-            headers['Connection'] = 'close';
-    }
-
-    // user-defined headers
-    if (typeof this.options.requestHeaders == 'object') {
-      var extras = this.options.requestHeaders;
-
-      if (Object.isFunction(extras.push))
-        for (var i = 0, length = extras.length; i < length; i += 2)
-          headers[extras[i]] = extras[i+1];
-      else
-        $H(extras).each(function(pair) { headers[pair.key] = pair.value });
-    }
-
-    for (var name in headers)
-      this.transport.setRequestHeader(name, headers[name]);
-  },
-
-  success: function() {
-    var status = this.getStatus();
-    return !status || (status >= 200 && status < 300);
-  },
-
-  getStatus: function() {
-    try {
-      return this.transport.status || 0;
-    } catch (e) { return 0 }
-  },
-
-  respondToReadyState: function(readyState) {
-    var state = Ajax.Request.Events[readyState], response = new Ajax.Response(this);
-
-    if (state == 'Complete') {
-      try {
-        this._complete = true;
-        (this.options['on' + response.status]
-         || this.options['on' + (this.success() ? 'Success' : 'Failure')]
-         || Prototype.emptyFunction)(response, response.headerJSON);
-      } catch (e) {
-        this.dispatchException(e);
-      }
-
-      var contentType = response.getHeader('Content-type');
-      if (this.options.evalJS == 'force'
-          || (this.options.evalJS && this.isSameOrigin() && contentType
-          && contentType.match(/^\s*(text|application)\/(x-)?(java|ecma)script(;.*)?\s*$/i)))
-        this.evalResponse();
-    }
-
-    try {
-      (this.options['on' + state] || Prototype.emptyFunction)(response, response.headerJSON);
-      Ajax.Responders.dispatch('on' + state, this, response, response.headerJSON);
-    } catch (e) {
-      this.dispatchException(e);
-    }
-
-    if (state == 'Complete') {
-      // avoid memory leak in MSIE: clean up
-      this.transport.onreadystatechange = Prototype.emptyFunction;
-    }
-  },
-
-  isSameOrigin: function() {
-    var m = this.url.match(/^\s*https?:\/\/[^\/]*/);
-    return !m || (m[0] == '#{protocol}//#{domain}#{port}'.interpolate({
-      protocol: location.protocol,
-      domain: document.domain,
-      port: location.port ? ':' + location.port : ''
-    }));
-  },
-
-  getHeader: function(name) {
-    try {
-      return this.transport.getResponseHeader(name) || null;
-    } catch (e) { return null }
-  },
-
-  evalResponse: function() {
-    try {
-      return eval((this.transport.responseText || '').unfilterJSON());
-    } catch (e) {
-      this.dispatchException(e);
-    }
-  },
-
-  dispatchException: function(exception) {
-    (this.options.onException || Prototype.emptyFunction)(this, exception);
-    Ajax.Responders.dispatch('onException', this, exception);
-  }
-});
-
-Ajax.Request.Events =
-  ['Uninitialized', 'Loading', 'Loaded', 'Interactive', 'Complete'];
-
-Ajax.Response = Class.create({
-  initialize: function(request){
-    this.request = request;
-    var transport  = this.transport  = request.transport,
-        readyState = this.readyState = transport.readyState;
-
-    if((readyState > 2 && !Prototype.Browser.IE) || readyState == 4) {
-      this.status       = this.getStatus();
-      this.statusText   = this.getStatusText();
-      this.responseText = String.interpret(transport.responseText);
-      this.headerJSON   = this._getHeaderJSON();
-    }
-
-    if(readyState == 4) {
-      var xml = transport.responseXML;
-      this.responseXML  = Object.isUndefined(xml) ? null : xml;
-      this.responseJSON = this._getResponseJSON();
-    }
-  },
-
-  status:      0,
-  statusText: '',
-
-  getStatus: Ajax.Request.prototype.getStatus,
-
-  getStatusText: function() {
-    try {
-      return this.transport.statusText || '';
-    } catch (e) { return '' }
-  },
-
-  getHeader: Ajax.Request.prototype.getHeader,
-
-  getAllHeaders: function() {
-    try {
-      return this.getAllResponseHeaders();
-    } catch (e) { return null }
-  },
-
-  getResponseHeader: function(name) {
-    return this.transport.getResponseHeader(name);
-  },
-
-  getAllResponseHeaders: function() {
-    return this.transport.getAllResponseHeaders();
-  },
-
-  _getHeaderJSON: function() {
-    var json = this.getHeader('X-JSON');
-    if (!json) return null;
-    json = decodeURIComponent(escape(json));
-    try {
-      return json.evalJSON(this.request.options.sanitizeJSON ||
-        !this.request.isSameOrigin());
-    } catch (e) {
-      this.request.dispatchException(e);
-    }
-  },
-
-  _getResponseJSON: function() {
-    var options = this.request.options;
-    if (!options.evalJSON || (options.evalJSON != 'force' &&
-      !(this.getHeader('Content-type') || '').include('application/json')) ||
-        this.responseText.blank())
-          return null;
-    try {
-      return this.responseText.evalJSON(options.sanitizeJSON ||
-        !this.request.isSameOrigin());
-    } catch (e) {
-      this.request.dispatchException(e);
-    }
-  }
-});
-
-Ajax.Updater = Class.create(Ajax.Request, {
-  initialize: function($super, container, url, options) {
-    this.container = {
-      success: (container.success || container),
-      failure: (container.failure || (container.success ? null : container))
-    };
-
-    options = Object.clone(options);
-    var onComplete = options.onComplete;
-    options.onComplete = (function(response, json) {
-      this.updateContent(response.responseText);
-      if (Object.isFunction(onComplete)) onComplete(response, json);
-    }).bind(this);
-
-    $super(url, options);
-  },
-
-  updateContent: function(responseText) {
-    var receiver = this.container[this.success() ? 'success' : 'failure'],
-        options = this.options;
-
-    if (!options.evalScripts) responseText = responseText.stripScripts();
-
-    if (receiver = $(receiver)) {
-      if (options.insertion) {
-        if (Object.isString(options.insertion)) {
-          var insertion = { }; insertion[options.insertion] = responseText;
-          receiver.insert(insertion);
-        }
-        else options.insertion(receiver, responseText);
-      }
-      else receiver.update(responseText);
-    }
-  }
-});
-
-Ajax.PeriodicalUpdater = Class.create(Ajax.Base, {
-  initialize: function($super, container, url, options) {
-    $super(options);
-    this.onComplete = this.options.onComplete;
-
-    this.frequency = (this.options.frequency || 2);
-    this.decay = (this.options.decay || 1);
-
-    this.updater = { };
-    this.container = container;
-    this.url = url;
-
-    this.start();
-  },
-
-  start: function() {
-    this.options.onComplete = this.updateComplete.bind(this);
-    this.onTimerEvent();
-  },
-
-  stop: function() {
-    this.updater.options.onComplete = undefined;
-    clearTimeout(this.timer);
-    (this.onComplete || Prototype.emptyFunction).apply(this, arguments);
-  },
-
-  updateComplete: function(response) {
-    if (this.options.decay) {
-      this.decay = (response.responseText == this.lastText ?
-        this.decay * this.options.decay : 1);
-
-      this.lastText = response.responseText;
-    }
-    this.timer = this.onTimerEvent.bind(this).delay(this.decay * this.frequency);
-  },
-
-  onTimerEvent: function() {
-    this.updater = new Ajax.Updater(this.container, this.url, this.options);
-  }
-});
-function $(element) {
-  if (arguments.length > 1) {
-    for (var i = 0, elements = [], length = arguments.length; i < length; i++)
-      elements.push($(arguments[i]));
-    return elements;
-  }
-  if (Object.isString(element))
-    element = document.getElementById(element);
-  return Element.extend(element);
-}
-
-if (Prototype.BrowserFeatures.XPath) {
-  document._getElementsByXPath = function(expression, parentElement) {
-    var results = [];
-    var query = document.evaluate(expression, $(parentElement) || document,
-      null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null);
-    for (var i = 0, length = query.snapshotLength; i < length; i++)
-      results.push(Element.extend(query.snapshotItem(i)));
-    return results;
-  };
-}
-
-/*--------------------------------------------------------------------------*/
-
-if (!window.Node) var Node = { };
-
-if (!Node.ELEMENT_NODE) {
-  // DOM level 2 ECMAScript Language Binding
-  Object.extend(Node, {
-    ELEMENT_NODE: 1,
-    ATTRIBUTE_NODE: 2,
-    TEXT_NODE: 3,
-    CDATA_SECTION_NODE: 4,
-    ENTITY_REFERENCE_NODE: 5,
-    ENTITY_NODE: 6,
-    PROCESSING_INSTRUCTION_NODE: 7,
-    COMMENT_NODE: 8,
-    DOCUMENT_NODE: 9,
-    DOCUMENT_TYPE_NODE: 10,
-    DOCUMENT_FRAGMENT_NODE: 11,
-    NOTATION_NODE: 12
-  });
-}
-
-(function() {
-  var element = this.Element;
-  this.Element = function(tagName, attributes) {
-    attributes = attributes || { };
-    tagName = tagName.toLowerCase();
-    var cache = Element.cache;
-    if (Prototype.Browser.IE && attributes.name) {
-      tagName = '<' + tagName + ' name="' + attributes.name + '">';
-      delete attributes.name;
-      return Element.writeAttribute(document.createElement(tagName), attributes);
-    }
-    if (!cache[tagName]) cache[tagName] = Element.extend(document.createElement(tagName));
-    return Element.writeAttribute(cache[tagName].cloneNode(false), attributes);
-  };
-  Object.extend(this.Element, element || { });
-  if (element) this.Element.prototype = element.prototype;
-}).call(window);
-
-Element.cache = { };
-
-Element.Methods = {
-  visible: function(element) {
-    return $(element).style.display != 'none';
-  },
-
-  toggle: function(element) {
-    element = $(element);
-    Element[Element.visible(element) ? 'hide' : 'show'](element);
-    return element;
-  },
-
-  hide: function(element) {
-    element = $(element);
-    element.style.display = 'none';
-    return element;
-  },
-
-  show: function(element) {
-    element = $(element);
-    element.style.display = '';
-    return element;
-  },
-
-  remove: function(element) {
-    element = $(element);
-    element.parentNode.removeChild(element);
-    return element;
-  },
-
-  update: function(element, content) {
-    element = $(element);
-    if (content && content.toElement) content = content.toElement();
-    if (Object.isElement(content)) return element.update().insert(content);
-    content = Object.toHTML(content);
-    element.innerHTML = content.stripScripts();
-    content.evalScripts.bind(content).defer();
-    return element;
-  },
-
-  replace: function(element, content) {
-    element = $(element);
-    if (content && content.toElement) content = content.toElement();
-    else if (!Object.isElement(content)) {
-      content = Object.toHTML(content);
-      var range = element.ownerDocument.createRange();
-      range.selectNode(element);
-      content.evalScripts.bind(content).defer();
-      content = range.createContextualFragment(content.stripScripts());
-    }
-    element.parentNode.replaceChild(content, element);
-    return element;
-  },
-
-  insert: function(element, insertions) {
-    element = $(element);
-
-    if (Object.isString(insertions) || Object.isNumber(insertions) ||
-        Object.isElement(insertions) || (insertions && (insertions.toElement || insertions.toHTML)))
-          insertions = {bottom:insertions};
-
-    var content, insert, tagName, childNodes;
-
-    for (var position in insertions) {
-      content  = insertions[position];
-      position = position.toLowerCase();
-      insert = Element._insertionTranslations[position];
-
-      if (content && content.toElement) content = content.toElement();
-      if (Object.isElement(content)) {
-        insert(element, content);
-        continue;
-      }
-
-      content = Object.toHTML(content);
-
-      tagName = ((position == 'before' || position == 'after')
-        ? element.parentNode : element).tagName.toUpperCase();
-
-      childNodes = Element._getContentFromAnonymousElement(tagName, content.stripScripts());
-
-      if (position == 'top' || position == 'after') childNodes.reverse();
-      childNodes.each(insert.curry(element));
-
-      content.evalScripts.bind(content).defer();
-    }
-
-    return element;
-  },
-
-  wrap: function(element, wrapper, attributes) {
-    element = $(element);
-    if (Object.isElement(wrapper))
-      $(wrapper).writeAttribute(attributes || { });
-    else if (Object.isString(wrapper)) wrapper = new Element(wrapper, attributes);
-    else wrapper = new Element('div', wrapper);
-    if (element.parentNode)
-      element.parentNode.replaceChild(wrapper, element);
-    wrapper.appendChild(element);
-    return wrapper;
-  },
-
-  inspect: function(element) {
-    element = $(element);
-    var result = '<' + element.tagName.toLowerCase();
-    $H({'id': 'id', 'className': 'class'}).each(function(pair) {
-      var property = pair.first(), attribute = pair.last();
-      var value = (element[property] || '').toString();
-      if (value) result += ' ' + attribute + '=' + value.inspect(true);
-    });
-    return result + '>';
-  },
-
-  recursivelyCollect: function(element, property) {
-    element = $(element);
-    var elements = [];
-    while (element = element[property])
-      if (element.nodeType == 1)
-        elements.push(Element.extend(element));
-    return elements;
-  },
-
-  ancestors: function(element) {
-    return $(element).recursivelyCollect('parentNode');
-  },
-
-  descendants: function(element) {
-    return $(element).select("*");
-  },
-
-  firstDescendant: function(element) {
-    element = $(element).firstChild;
-    while (element && element.nodeType != 1) element = element.nextSibling;
-    return $(element);
-  },
-
-  immediateDescendants: function(element) {
-    if (!(element = $(element).firstChild)) return [];
-    while (element && element.nodeType != 1) element = element.nextSibling;
-    if (element) return [element].concat($(element).nextSiblings());
-    return [];
-  },
-
-  previousSiblings: function(element) {
-    return $(element).recursivelyCollect('previousSibling');
-  },
-
-  nextSiblings: function(element) {
-    return $(element).recursivelyCollect('nextSibling');
-  },
-
-  siblings: function(element) {
-    element = $(element);
-    return element.previousSiblings().reverse().concat(element.nextSiblings());
-  },
-
-  match: function(element, selector) {
-    if (Object.isString(selector))
-      selector = new Selector(selector);
-    return selector.match($(element));
-  },
-
-  up: function(element, expression, index) {
-    element = $(element);
-    if (arguments.length == 1) return $(element.parentNode);
-    var ancestors = element.ancestors();
-    return Object.isNumber(expression) ? ancestors[expression] :
-      Selector.findElement(ancestors, expression, index);
-  },
-
-  down: function(element, expression, index) {
-    element = $(element);
-    if (arguments.length == 1) return element.firstDescendant();
-    return Object.isNumber(expression) ? element.descendants()[expression] :
-      Element.select(element, expression)[index || 0];
-  },
-
-  previous: function(element, expression, index) {
-    element = $(element);
-    if (arguments.length == 1) return $(Selector.handlers.previousElementSibling(element));
-    var previousSiblings = element.previousSiblings();
-    return Object.isNumber(expression) ? previousSiblings[expression] :
-      Selector.findElement(previousSiblings, expression, index);
-  },
-
-  next: function(element, expression, index) {
-    element = $(element);
-    if (arguments.length == 1) return $(Selector.handlers.nextElementSibling(element));
-    var nextSiblings = element.nextSiblings();
-    return Object.isNumber(expression) ? nextSiblings[expression] :
-      Selector.findElement(nextSiblings, expression, index);
-  },
-
-  select: function() {
-    var args = $A(arguments), element = $(args.shift());
-    return Selector.findChildElements(element, args);
-  },
-
-  adjacent: function() {
-    var args = $A(arguments), element = $(args.shift());
-    return Selector.findChildElements(element.parentNode, args).without(element);
-  },
-
-  identify: function(element) {
-    element = $(element);
-    var id = element.readAttribute('id'), self = arguments.callee;
-    if (id) return id;
-    do { id = 'anonymous_element_' + self.counter++ } while ($(id));
-    element.writeAttribute('id', id);
-    return id;
-  },
-
-  readAttribute: function(element, name) {
-    element = $(element);
-    if (Prototype.Browser.IE) {
-      var t = Element._attributeTranslations.read;
-      if (t.values[name]) return t.values[name](element, name);
-      if (t.names[name]) name = t.names[name];
-      if (name.include(':')) {
-        return (!element.attributes || !element.attributes[name]) ? null :
-         element.attributes[name].value;
-      }
-    }
-    return element.getAttribute(name);
-  },
-
-  writeAttribute: function(element, name, value) {
-    element = $(element);
-    var attributes = { }, t = Element._attributeTranslations.write;
-
-    if (typeof name == 'object') attributes = name;
-    else attributes[name] = Object.isUndefined(value) ? true : value;
-
-    for (var attr in attributes) {
-      name = t.names[attr] || attr;
-      value = attributes[attr];
-      if (t.values[attr]) name = t.values[attr](element, value);
-      if (value === false || value === null)
-        element.removeAttribute(name);
-      else if (value === true)
-        element.setAttribute(name, name);
-      else element.setAttribute(name, value);
-    }
-    return element;
-  },
-
-  getHeight: function(element) {
-    return $(element).getDimensions().height;
-  },
-
-  getWidth: function(element) {
-    return $(element).getDimensions().width;
-  },
-
-  classNames: function(element) {
-    return new Element.ClassNames(element);
-  },
-
-  hasClassName: function(element, className) {
-    if (!(element = $(element))) return;
-    var elementClassName = element.className;
-    return (elementClassName.length > 0 && (elementClassName == className ||
-      new RegExp("(^|\\s)" + className + "(\\s|$)").test(elementClassName)));
-  },
-
-  addClassName: function(element, className) {
-    if (!(element = $(element))) return;
-    if (!element.hasClassName(className))
-      element.className += (element.className ? ' ' : '') + className;
-    return element;
-  },
-
-  removeClassName: function(element, className) {
-    if (!(element = $(element))) return;
-    element.className = element.className.replace(
-      new RegExp("(^|\\s+)" + className + "(\\s+|$)"), ' ').strip();
-    return element;
-  },
-
-  toggleClassName: function(element, className) {
-    if (!(element = $(element))) return;
-    return element[element.hasClassName(className) ?
-      'removeClassName' : 'addClassName'](className);
-  },
-
-  // removes whitespace-only text node children
-  cleanWhitespace: function(element) {
-    element = $(element);
-    var node = element.firstChild;
-    while (node) {
-      var nextNode = node.nextSibling;
-      if (node.nodeType == 3 && !/\S/.test(node.nodeValue))
-        element.removeChild(node);
-      node = nextNode;
-    }
-    return element;
-  },
-
-  empty: function(element) {
-    return $(element).innerHTML.blank();
-  },
-
-  descendantOf: function(element, ancestor) {
-    element = $(element), ancestor = $(ancestor);
-
-    if (element.compareDocumentPosition)
-      return (element.compareDocumentPosition(ancestor) & 8) === 8;
-
-    if (ancestor.contains)
-      return ancestor.contains(element) && ancestor !== element;
-
-    while (element = element.parentNode)
-      if (element == ancestor) return true;
-
-    return false;
-  },
-
-  scrollTo: function(element) {
-    element = $(element);
-    var pos = element.cumulativeOffset();
-    window.scrollTo(pos[0], pos[1]);
-    return element;
-  },
-
-  getStyle: function(element, style) {
-    element = $(element);
-    style = style == 'float' ? 'cssFloat' : style.camelize();
-    var value = element.style[style];
-    if (!value || value == 'auto') {
-      var css = document.defaultView.getComputedStyle(element, null);
-      value = css ? css[style] : null;
-    }
-    if (style == 'opacity') return value ? parseFloat(value) : 1.0;
-    return value == 'auto' ? null : value;
-  },
-
-  getOpacity: function(element) {
-    return $(element).getStyle('opacity');
-  },
-
-  setStyle: function(element, styles) {
-    element = $(element);
-    var elementStyle = element.style, match;
-    if (Object.isString(styles)) {
-      element.style.cssText += ';' + styles;
-      return styles.include('opacity') ?
-        element.setOpacity(styles.match(/opacity:\s*(\d?\.?\d*)/)[1]) : element;
-    }
-    for (var property in styles)
-      if (property == 'opacity') element.setOpacity(styles[property]);
-      else
-        elementStyle[(property == 'float' || property == 'cssFloat') ?
-          (Object.isUndefined(elementStyle.styleFloat) ? 'cssFloat' : 'styleFloat') :
-            property] = styles[property];
-
-    return element;
-  },
-
-  setOpacity: function(element, value) {
-    element = $(element);
-    element.style.opacity = (value == 1 || value === '') ? '' :
-      (value < 0.00001) ? 0 : value;
-    return element;
-  },
-
-  getDimensions: function(element) {
-    element = $(element);
-    var display = element.getStyle('display');
-    if (display != 'none' && display != null) // Safari bug
-      return {width: element.offsetWidth, height: element.offsetHeight};
-
-    // All *Width and *Height properties give 0 on elements with display none,
-    // so enable the element temporarily
-    var els = element.style;
-    var originalVisibility = els.visibility;
-    var originalPosition = els.position;
-    var originalDisplay = els.display;
-    els.visibility = 'hidden';
-    els.position = 'absolute';
-    els.display = 'block';
-    var originalWidth = element.clientWidth;
-    var originalHeight = element.clientHeight;
-    els.display = originalDisplay;
-    els.position = originalPosition;
-    els.visibility = originalVisibility;
-    return {width: originalWidth, height: originalHeight};
-  },
-
-  makePositioned: function(element) {
-    element = $(element);
-    var pos = Element.getStyle(element, 'position');
-    if (pos == 'static' || !pos) {
-      element._madePositioned = true;
-      element.style.position = 'relative';
-      // Opera returns the offset relative to the positioning context, when an
-      // element is position relative but top and left have not been defined
-      if (Prototype.Browser.Opera) {
-        element.style.top = 0;
-        element.style.left = 0;
-      }
-    }
-    return element;
-  },
-
-  undoPositioned: function(element) {
-    element = $(element);
-    if (element._madePositioned) {
-      element._madePositioned = undefined;
-      element.style.position =
-        element.style.top =
-        element.style.left =
-        element.style.bottom =
-        element.style.right = '';
-    }
-    return element;
-  },
-
-  makeClipping: function(element) {
-    element = $(element);
-    if (element._overflow) return element;
-    element._overflow = Element.getStyle(element, 'overflow') || 'auto';
-    if (element._overflow !== 'hidden')
-      element.style.overflow = 'hidden';
-    return element;
-  },
-
-  undoClipping: function(element) {
-    element = $(element);
-    if (!element._overflow) return element;
-    element.style.overflow = element._overflow == 'auto' ? '' : element._overflow;
-    element._overflow = null;
-    return element;
-  },
-
-  cumulativeOffset: function(element) {
-    var valueT = 0, valueL = 0;
-    do {
-      valueT += element.offsetTop  || 0;
-      valueL += element.offsetLeft || 0;
-      element = element.offsetParent;
-    } while (element);
-    return Element._returnOffset(valueL, valueT);
-  },
-
-  positionedOffset: function(element) {
-    var valueT = 0, valueL = 0;
-    do {
-      valueT += element.offsetTop  || 0;
-      valueL += element.offsetLeft || 0;
-      element = element.offsetParent;
-      if (element) {
-        if (element.tagName.toUpperCase() == 'BODY') break;
-        var p = Element.getStyle(element, 'position');
-        if (p !== 'static') break;
-      }
-    } while (element);
-    return Element._returnOffset(valueL, valueT);
-  },
-
-  absolutize: function(element) {
-    element = $(element);
-    if (element.getStyle('position') == 'absolute') return element;
-    // Position.prepare(); // To be done manually by Scripty when it needs it.
-
-    var offsets = element.positionedOffset();
-    var top     = offsets[1];
-    var left    = offsets[0];
-    var width   = element.clientWidth;
-    var height  = element.clientHeight;
-
-    element._originalLeft   = left - parseFloat(element.style.left  || 0);
-    element._originalTop    = top  - parseFloat(element.style.top || 0);
-    element._originalWidth  = element.style.width;
-    element._originalHeight = element.style.height;
-
-    element.style.position = 'absolute';
-    element.style.top    = top + 'px';
-    element.style.left   = left + 'px';
-    element.style.width  = width + 'px';
-    element.style.height = height + 'px';
-    return element;
-  },
-
-  relativize: function(element) {
-    element = $(element);
-    if (element.getStyle('position') == 'relative') return element;
-    // Position.prepare(); // To be done manually by Scripty when it needs it.
-
-    element.style.position = 'relative';
-    var top  = parseFloat(element.style.top  || 0) - (element._originalTop || 0);
-    var left = parseFloat(element.style.left || 0) - (element._originalLeft || 0);
-
-    element.style.top    = top + 'px';
-    element.style.left   = left + 'px';
-    element.style.height = element._originalHeight;
-    element.style.width  = element._originalWidth;
-    return element;
-  },
-
-  cumulativeScrollOffset: function(element) {
-    var valueT = 0, valueL = 0;
-    do {
-      valueT += element.scrollTop  || 0;
-      valueL += element.scrollLeft || 0;
-      element = element.parentNode;
-    } while (element);
-    return Element._returnOffset(valueL, valueT);
-  },
-
-  getOffsetParent: function(element) {
-    if (element.offsetParent) return $(element.offsetParent);
-    if (element == document.body) return $(element);
-
-    while ((element = element.parentNode) && element != document.body)
-      if (Element.getStyle(element, 'position') != 'static')
-        return $(element);
-
-    return $(document.body);
-  },
-
-  viewportOffset: function(forElement) {
-    var valueT = 0, valueL = 0;
-
-    var element = forElement;
-    do {
-      valueT += element.offsetTop  || 0;
-      valueL += element.offsetLeft || 0;
-
-      // Safari fix
-      if (element.offsetParent == document.body &&
-        Element.getStyle(element, 'position') == 'absolute') break;
-
-    } while (element = element.offsetParent);
-
-    element = forElement;
-    do {
-      if (!Prototype.Browser.Opera || (element.tagName && (element.tagName.toUpperCase() == 'BODY'))) {
-        valueT -= element.scrollTop  || 0;
-        valueL -= element.scrollLeft || 0;
-      }
-    } while (element = element.parentNode);
-
-    return Element._returnOffset(valueL, valueT);
-  },
-
-  clonePosition: function(element, source) {
-    var options = Object.extend({
-      setLeft:    true,
-      setTop:     true,
-      setWidth:   true,
-      setHeight:  true,
-      offsetTop:  0,
-      offsetLeft: 0
-    }, arguments[2] || { });
-
-    // find page position of source
-    source = $(source);
-    var p = source.viewportOffset();
-
-    // find coordinate system to use
-    element = $(element);
-    var delta = [0, 0];
-    var parent = null;
-    // delta [0,0] will do fine with position: fixed elements,
-    // position:absolute needs offsetParent deltas
-    if (Element.getStyle(element, 'position') == 'absolute') {
-      parent = element.getOffsetParent();
-      delta = parent.viewportOffset();
-    }
-
-    // correct by body offsets (fixes Safari)
-    if (parent == document.body) {
-      delta[0] -= document.body.offsetLeft;
-      delta[1] -= document.body.offsetTop;
-    }
-
-    // set position
-    if (options.setLeft)   element.style.left  = (p[0] - delta[0] + options.offsetLeft) + 'px';
-    if (options.setTop)    element.style.top   = (p[1] - delta[1] + options.offsetTop) + 'px';
-    if (options.setWidth)  element.style.width = source.offsetWidth + 'px';
-    if (options.setHeight) element.style.height = source.offsetHeight + 'px';
-    return element;
-  }
-};
-
-Element.Methods.identify.counter = 1;
-
-Object.extend(Element.Methods, {
-  getElementsBySelector: Element.Methods.select,
-  childElements: Element.Methods.immediateDescendants
-});
-
-Element._attributeTranslations = {
-  write: {
-    names: {
-      className: 'class',
-      htmlFor:   'for'
-    },
-    values: { }
-  }
-};
-
-if (Prototype.Browser.Opera) {
-  Element.Methods.getStyle = Element.Methods.getStyle.wrap(
-    function(proceed, element, style) {
-      switch (style) {
-        case 'left': case 'top': case 'right': case 'bottom':
-          if (proceed(element, 'position') === 'static') return null;
-        case 'height': case 'width':
-          // returns '0px' for hidden elements; we want it to return null
-          if (!Element.visible(element)) return null;
-
-          // returns the border-box dimensions rather than the content-box
-          // dimensions, so we subtract padding and borders from the value
-          var dim = parseInt(proceed(element, style), 10);
-
-          if (dim !== element['offset' + style.capitalize()])
-            return dim + 'px';
-
-          var properties;
-          if (style === 'height') {
-            properties = ['border-top-width', 'padding-top',
-             'padding-bottom', 'border-bottom-width'];
-          }
-          else {
-            properties = ['border-left-width', 'padding-left',
-             'padding-right', 'border-right-width'];
-          }
-          return properties.inject(dim, function(memo, property) {
-            var val = proceed(element, property);
-            return val === null ? memo : memo - parseInt(val, 10);
-          }) + 'px';
-        default: return proceed(element, style);
-      }
-    }
-  );
-
-  Element.Methods.readAttribute = Element.Methods.readAttribute.wrap(
-    function(proceed, element, attribute) {
-      if (attribute === 'title') return element.title;
-      return proceed(element, attribute);
-    }
-  );
-}
-
-else if (Prototype.Browser.IE) {
-  // IE doesn't report offsets correctly for static elements, so we change them
-  // to "relative" to get the values, then change them back.
-  Element.Methods.getOffsetParent = Element.Methods.getOffsetParent.wrap(
-    function(proceed, element) {
-      element = $(element);
-      // IE throws an error if element is not in document
-      try { element.offsetParent }
-      catch(e) { return $(document.body) }
-      var position = element.getStyle('position');
-      if (position !== 'static') return proceed(element);
-      element.setStyle({ position: 'relative' });
-      var value = proceed(element);
-      element.setStyle({ position: position });
-      return value;
-    }
-  );
-
-  $w('positionedOffset viewportOffset').each(function(method) {
-    Element.Methods[method] = Element.Methods[method].wrap(
-      function(proceed, element) {
-        element = $(element);
-        try { element.offsetParent }
-        catch(e) { return Element._returnOffset(0,0) }
-        var position = element.getStyle('position');
-        if (position !== 'static') return proceed(element);
-        // Trigger hasLayout on the offset parent so that IE6 reports
-        // accurate offsetTop and offsetLeft values for position: fixed.
-        var offsetParent = element.getOffsetParent();
-        if (offsetParent && offsetParent.getStyle('position') === 'fixed')
-          offsetParent.setStyle({ zoom: 1 });
-        element.setStyle({ position: 'relative' });
-        var value = proceed(element);
-        element.setStyle({ position: position });
-        return value;
-      }
-    );
-  });
-
-  Element.Methods.cumulativeOffset = Element.Methods.cumulativeOffset.wrap(
-    function(proceed, element) {
-      try { element.offsetParent }
-      catch(e) { return Element._returnOffset(0,0) }
-      return proceed(element);
-    }
-  );
-
-  Element.Methods.getStyle = function(element, style) {
-    element = $(element);
-    style = (style == 'float' || style == 'cssFloat') ? 'styleFloat' : style.camelize();
-    var value = element.style[style];
-    if (!value && element.currentStyle) value = element.currentStyle[style];
-
-    if (style == 'opacity') {
-      if (value = (element.getStyle('filter') || '').match(/alpha\(opacity=(.*)\)/))
-        if (value[1]) return parseFloat(value[1]) / 100;
-      return 1.0;
-    }
-
-    if (value == 'auto') {
-      if ((style == 'width' || style == 'height') && (element.getStyle('display') != 'none'))
-        return element['offset' + style.capitalize()] + 'px';
-      return null;
-    }
-    return value;
-  };
-
-  Element.Methods.setOpacity = function(element, value) {
-    function stripAlpha(filter){
-      return filter.replace(/alpha\([^\)]*\)/gi,'');
-    }
-    element = $(element);
-    var currentStyle = element.currentStyle;
-    if ((currentStyle && !currentStyle.hasLayout) ||
-      (!currentStyle && element.style.zoom == 'normal'))
-        element.style.zoom = 1;
-
-    var filter = element.getStyle('filter'), style = element.style;
-    if (value == 1 || value === '') {
-      (filter = stripAlpha(filter)) ?
-        style.filter = filter : style.removeAttribute('filter');
-      return element;
-    } else if (value < 0.00001) value = 0;
-    style.filter = stripAlpha(filter) +
-      'alpha(opacity=' + (value * 100) + ')';
-    return element;
-  };
-
-  Element._attributeTranslations = {
-    read: {
-      names: {
-        'class': 'className',
-        'for':   'htmlFor'
-      },
-      values: {
-        _getAttr: function(element, attribute) {
-          return element.getAttribute(attribute, 2);
-        },
-        _getAttrNode: function(element, attribute) {
-          var node = element.getAttributeNode(attribute);
-          return node ? node.value : "";
-        },
-        _getEv: function(element, attribute) {
-          attribute = element.getAttribute(attribute);
-          return attribute ? attribute.toString().slice(23, -2) : null;
-        },
-        _flag: function(element, attribute) {
-          return $(element).hasAttribute(attribute) ? attribute : null;
-        },
-        style: function(element) {
-          return element.style.cssText.toLowerCase();
-        },
-        title: function(element) {
-          return element.title;
-        }
-      }
-    }
-  };
-
-  Element._attributeTranslations.write = {
-    names: Object.extend({
-      cellpadding: 'cellPadding',
-      cellspacing: 'cellSpacing'
-    }, Element._attributeTranslations.read.names),
-    values: {
-      checked: function(element, value) {
-        element.checked = !!value;
-      },
-
-      style: function(element, value) {
-        element.style.cssText = value ? value : '';
-      }
-    }
-  };
-
-  Element._attributeTranslations.has = {};
-
-  $w('colSpan rowSpan vAlign dateTime accessKey tabIndex ' +
-      'encType maxLength readOnly longDesc frameBorder').each(function(attr) {
-    Element._attributeTranslations.write.names[attr.toLowerCase()] = attr;
-    Element._attributeTranslations.has[attr.toLowerCase()] = attr;
-  });
-
-  (function(v) {
-    Object.extend(v, {
-      href:        v._getAttr,
-      src:         v._getAttr,
-      type:        v._getAttr,
-      action:      v._getAttrNode,
-      disabled:    v._flag,
-      checked:     v._flag,
-      readonly:    v._flag,
-      multiple:    v._flag,
-      onload:      v._getEv,
-      onunload:    v._getEv,
-      onclick:     v._getEv,
-      ondblclick:  v._getEv,
-      onmousedown: v._getEv,
-      onmouseup:   v._getEv,
-      onmouseover: v._getEv,
-      onmousemove: v._getEv,
-      onmouseout:  v._getEv,
-      onfocus:     v._getEv,
-      onblur:      v._getEv,
-      onkeypress:  v._getEv,
-      onkeydown:   v._getEv,
-      onkeyup:     v._getEv,
-      onsubmit:    v._getEv,
-      onreset:     v._getEv,
-      onselect:    v._getEv,
-      onchange:    v._getEv
-    });
-  })(Element._attributeTranslations.read.values);
-}
-
-else if (Prototype.Browser.Gecko && /rv:1\.8\.0/.test(navigator.userAgent)) {
-  Element.Methods.setOpacity = function(element, value) {
-    element = $(element);
-    element.style.opacity = (value == 1) ? 0.999999 :
-      (value === '') ? '' : (value < 0.00001) ? 0 : value;
-    return element;
-  };
-}
-
-else if (Prototype.Browser.WebKit) {
-  Element.Methods.setOpacity = function(element, value) {
-    element = $(element);
-    element.style.opacity = (value == 1 || value === '') ? '' :
-      (value < 0.00001) ? 0 : value;
-
-    if (value == 1)
-      if(element.tagName.toUpperCase() == 'IMG' && element.width) {
-        element.width++; element.width--;
-      } else try {
-        var n = document.createTextNode(' ');
-        element.appendChild(n);
-        element.removeChild(n);
-      } catch (e) { }
-
-    return element;
-  };
-
-  // Safari returns margins on body which is incorrect if the child is absolutely
-  // positioned.  For performance reasons, redefine Element#cumulativeOffset for
-  // KHTML/WebKit only.
-  Element.Methods.cumulativeOffset = function(element) {
-    var valueT = 0, valueL = 0;
-    do {
-      valueT += element.offsetTop  || 0;
-      valueL += element.offsetLeft || 0;
-      if (element.offsetParent == document.body)
-        if (Element.getStyle(element, 'position') == 'absolute') break;
-
-      element = element.offsetParent;
-    } while (element);
-
-    return Element._returnOffset(valueL, valueT);
-  };
-}
-
-if (Prototype.Browser.IE || Prototype.Browser.Opera) {
-  // IE and Opera are missing .innerHTML support for TABLE-related and SELECT elements
-  Element.Methods.update = function(element, content) {
-    element = $(element);
-
-    if (content && content.toElement) content = content.toElement();
-    if (Object.isElement(content)) return element.update().insert(content);
-
-    content = Object.toHTML(content);
-    var tagName = element.tagName.toUpperCase();
-
-    if (tagName in Element._insertionTranslations.tags) {
-      $A(element.childNodes).each(function(node) { element.removeChild(node) });
-      Element._getContentFromAnonymousElement(tagName, content.stripScripts())
-        .each(function(node) { element.appendChild(node) });
-    }
-    else element.innerHTML = content.stripScripts();
-
-    content.evalScripts.bind(content).defer();
-    return element;
-  };
-}
-
-if ('outerHTML' in document.createElement('div')) {
-  Element.Methods.replace = function(element, content) {
-    element = $(element);
-
-    if (content && content.toElement) content = content.toElement();
-    if (Object.isElement(content)) {
-      element.parentNode.replaceChild(content, element);
-      return element;
-    }
-
-    content = Object.toHTML(content);
-    var parent = element.parentNode, tagName = parent.tagName.toUpperCase();
-
-    if (Element._insertionTranslations.tags[tagName]) {
-      var nextSibling = element.next();
-      var fragments = Element._getContentFromAnonymousElement(tagName, content.stripScripts());
-      parent.removeChild(element);
-      if (nextSibling)
-        fragments.each(function(node) { parent.insertBefore(node, nextSibling) });
-      else
-        fragments.each(function(node) { parent.appendChild(node) });
-    }
-    else element.outerHTML = content.stripScripts();
-
-    content.evalScripts.bind(content).defer();
-    return element;
-  };
-}
-
-Element._returnOffset = function(l, t) {
-  var result = [l, t];
-  result.left = l;
-  result.top = t;
-  return result;
-};
-
-Element._getContentFromAnonymousElement = function(tagName, html) {
-  var div = new Element('div'), t = Element._insertionTranslations.tags[tagName];
-  if (t) {
-    div.innerHTML = t[0] + html + t[1];
-    t[2].times(function() { div = div.firstChild });
-  } else div.innerHTML = html;
-  return $A(div.childNodes);
-};
-
-Element._insertionTranslations = {
-  before: function(element, node) {
-    element.parentNode.insertBefore(node, element);
-  },
-  top: function(element, node) {
-    element.insertBefore(node, element.firstChild);
-  },
-  bottom: function(element, node) {
-    element.appendChild(node);
-  },
-  after: function(element, node) {
-    element.parentNode.insertBefore(node, element.nextSibling);
-  },
-  tags: {
-    TABLE:  ['<table>',                '</table>',                   1],
-    TBODY:  ['<table><tbody>',         '</tbody></table>',           2],
-    TR:     ['<table><tbody><tr>',     '</tr></tbody></table>',      3],
-    TD:     ['<table><tbody><tr><td>', '</td></tr></tbody></table>', 4],
-    SELECT: ['<select>',               '</select>',                  1]
-  }
-};
-
-(function() {
-  Object.extend(this.tags, {
-    THEAD: this.tags.TBODY,
-    TFOOT: this.tags.TBODY,
-    TH:    this.tags.TD
-  });
-}).call(Element._insertionTranslations);
-
-Element.Methods.Simulated = {
-  hasAttribute: function(element, attribute) {
-    attribute = Element._attributeTranslations.has[attribute] || attribute;
-    var node = $(element).getAttributeNode(attribute);
-    return !!(node && node.specified);
-  }
-};
-
-Element.Methods.ByTag = { };
-
-Object.extend(Element, Element.Methods);
-
-if (!Prototype.BrowserFeatures.ElementExtensions &&
-    document.createElement('div')['__proto__']) {
-  window.HTMLElement = { };
-  window.HTMLElement.prototype = document.createElement('div')['__proto__'];
-  Prototype.BrowserFeatures.ElementExtensions = true;
-}
-
-Element.extend = (function() {
-  if (Prototype.BrowserFeatures.SpecificElementExtensions)
-    return Prototype.K;
-
-  var Methods = { }, ByTag = Element.Methods.ByTag;
-
-  var extend = Object.extend(function(element) {
-    if (!element || element._extendedByPrototype ||
-        element.nodeType != 1 || element == window) return element;
-
-    var methods = Object.clone(Methods),
-      tagName = element.tagName.toUpperCase(), property, value;
-
-    // extend methods for specific tags
-    if (ByTag[tagName]) Object.extend(methods, ByTag[tagName]);
-
-    for (property in methods) {
-      value = methods[property];
-      if (Object.isFunction(value) && !(property in element))
-        element[property] = value.methodize();
-    }
-
-    element._extendedByPrototype = Prototype.emptyFunction;
-    return element;
-
-  }, {
-    refresh: function() {
-      // extend methods for all tags (Safari doesn't need this)
-      if (!Prototype.BrowserFeatures.ElementExtensions) {
-        Object.extend(Methods, Element.Methods);
-        Object.extend(Methods, Element.Methods.Simulated);
-      }
-    }
-  });
-
-  extend.refresh();
-  return extend;
-})();
-
-Element.hasAttribute = function(element, attribute) {
-  if (element.hasAttribute) return element.hasAttribute(attribute);
-  return Element.Methods.Simulated.hasAttribute(element, attribute);
-};
-
-Element.addMethods = function(methods) {
-  var F = Prototype.BrowserFeatures, T = Element.Methods.ByTag;
-
-  if (!methods) {
-    Object.extend(Form, Form.Methods);
-    Object.extend(Form.Element, Form.Element.Methods);
-    Object.extend(Element.Methods.ByTag, {
-      "FORM":     Object.clone(Form.Methods),
-      "INPUT":    Object.clone(Form.Element.Methods),
-      "SELECT":   Object.clone(Form.Element.Methods),
-      "TEXTAREA": Object.clone(Form.Element.Methods)
-    });
-  }
-
-  if (arguments.length == 2) {
-    var tagName = methods;
-    methods = arguments[1];
-  }
-
-  if (!tagName) Object.extend(Element.Methods, methods || { });
-  else {
-    if (Object.isArray(tagName)) tagName.each(extend);
-    else extend(tagName);
-  }
-
-  function extend(tagName) {
-    tagName = tagName.toUpperCase();
-    if (!Element.Methods.ByTag[tagName])
-      Element.Methods.ByTag[tagName] = { };
-    Object.extend(Element.Methods.ByTag[tagName], methods);
-  }
-
-  function copy(methods, destination, onlyIfAbsent) {
-    onlyIfAbsent = onlyIfAbsent || false;
-    for (var property in methods) {
-      var value = methods[property];
-      if (!Object.isFunction(value)) continue;
-      if (!onlyIfAbsent || !(property in destination))
-        destination[property] = value.methodize();
-    }
-  }
-
-  function findDOMClass(tagName) {
-    var klass;
-    var trans = {
-      "OPTGROUP": "OptGroup", "TEXTAREA": "TextArea", "P": "Paragraph",
-      "FIELDSET": "FieldSet", "UL": "UList", "OL": "OList", "DL": "DList",
-      "DIR": "Directory", "H1": "Heading", "H2": "Heading", "H3": "Heading",
-      "H4": "Heading", "H5": "Heading", "H6": "Heading", "Q": "Quote",
-      "INS": "Mod", "DEL": "Mod", "A": "Anchor", "IMG": "Image", "CAPTION":
-      "TableCaption", "COL": "TableCol", "COLGROUP": "TableCol", "THEAD":
-      "TableSection", "TFOOT": "TableSection", "TBODY": "TableSection", "TR":
-      "TableRow", "TH": "TableCell", "TD": "TableCell", "FRAMESET":
-      "FrameSet", "IFRAME": "IFrame"
-    };
-    if (trans[tagName]) klass = 'HTML' + trans[tagName] + 'Element';
-    if (window[klass]) return window[klass];
-    klass = 'HTML' + tagName + 'Element';
-    if (window[klass]) return window[klass];
-    klass = 'HTML' + tagName.capitalize() + 'Element';
-    if (window[klass]) return window[klass];
-
-    window[klass] = { };
-    window[klass].prototype = document.createElement(tagName)['__proto__'];
-    return window[klass];
-  }
-
-  if (F.ElementExtensions) {
-    copy(Element.Methods, HTMLElement.prototype);
-    copy(Element.Methods.Simulated, HTMLElement.prototype, true);
-  }
-
-  if (F.SpecificElementExtensions) {
-    for (var tag in Element.Methods.ByTag) {
-      var klass = findDOMClass(tag);
-      if (Object.isUndefined(klass)) continue;
-      copy(T[tag], klass.prototype);
-    }
-  }
-
-  Object.extend(Element, Element.Methods);
-  delete Element.ByTag;
-
-  if (Element.extend.refresh) Element.extend.refresh();
-  Element.cache = { };
-};
-
-document.viewport = {
-  getDimensions: function() {
-    var dimensions = { }, B = Prototype.Browser;
-    $w('width height').each(function(d) {
-      var D = d.capitalize();
-      if (B.WebKit && !document.evaluate) {
-        // Safari <3.0 needs self.innerWidth/Height
-        dimensions[d] = self['inner' + D];
-      } else if (B.Opera && parseFloat(window.opera.version()) < 9.5) {
-        // Opera <9.5 needs document.body.clientWidth/Height
-        dimensions[d] = document.body['client' + D]
-      } else {
-        dimensions[d] = document.documentElement['client' + D];
-      }
-    });
-    return dimensions;
-  },
-
-  getWidth: function() {
-    return this.getDimensions().width;
-  },
-
-  getHeight: function() {
-    return this.getDimensions().height;
-  },
-
-  getScrollOffsets: function() {
-    return Element._returnOffset(
-      window.pageXOffset || document.documentElement.scrollLeft || document.body.scrollLeft,
-      window.pageYOffset || document.documentElement.scrollTop || document.body.scrollTop);
-  }
-};
-/* Portions of the Selector class are derived from Jack Slocum's DomQuery,
- * part of YUI-Ext version 0.40, distributed under the terms of an MIT-style
- * license.  Please see http://www.yui-ext.com/ for more information. */
-
-var Selector = Class.create({
-  initialize: function(expression) {
-    this.expression = expression.strip();
-
-    if (this.shouldUseSelectorsAPI()) {
-      this.mode = 'selectorsAPI';
-    } else if (this.shouldUseXPath()) {
-      this.mode = 'xpath';
-      this.compileXPathMatcher();
-    } else {
-      this.mode = "normal";
-      this.compileMatcher();
-    }
-
-  },
-
-  shouldUseXPath: function() {
-    if (!Prototype.BrowserFeatures.XPath) return false;
-
-    var e = this.expression;
-
-    // Safari 3 chokes on :*-of-type and :empty
-    if (Prototype.Browser.WebKit &&
-     (e.include("-of-type") || e.include(":empty")))
-      return false;
-
-    // XPath can't do namespaced attributes, nor can it read
-    // the "checked" property from DOM nodes
-    if ((/(\[[\w-]*?:|:checked)/).test(e))
-      return false;
-
-    return true;
-  },
-
-  shouldUseSelectorsAPI: function() {
-    if (!Prototype.BrowserFeatures.SelectorsAPI) return false;
-
-    if (!Selector._div) Selector._div = new Element('div');
-
-    // Make sure the browser treats the selector as valid. Test on an
-    // isolated element to minimize cost of this check.
-    try {
-      Selector._div.querySelector(this.expression);
-    } catch(e) {
-      return false;
-    }
-
-    return true;
-  },
-
-  compileMatcher: function() {
-    var e = this.expression, ps = Selector.patterns, h = Selector.handlers,
-        c = Selector.criteria, le, p, m;
-
-    if (Selector._cache[e]) {
-      this.matcher = Selector._cache[e];
-      return;
-    }
-
-    this.matcher = ["this.matcher = function(root) {",
-                    "var r = root, h = Selector.handlers, c = false, n;"];
-
-    while (e && le != e && (/\S/).test(e)) {
-      le = e;
-      for (var i in ps) {
-        p = ps[i];
-        if (m = e.match(p)) {
-          this.matcher.push(Object.isFunction(c[i]) ? c[i](m) :
-            new Template(c[i]).evaluate(m));
-          e = e.replace(m[0], '');
-          break;
-        }
-      }
-    }
-
-    this.matcher.push("return h.unique(n);\n}");
-    eval(this.matcher.join('\n'));
-    Selector._cache[this.expression] = this.matcher;
-  },
-
-  compileXPathMatcher: function() {
-    var e = this.expression, ps = Selector.patterns,
-        x = Selector.xpath, le, m;
-
-    if (Selector._cache[e]) {
-      this.xpath = Selector._cache[e]; return;
-    }
-
-    this.matcher = ['.//*'];
-    while (e && le != e && (/\S/).test(e)) {
-      le = e;
-      for (var i in ps) {
-        if (m = e.match(ps[i])) {
-          this.matcher.push(Object.isFunction(x[i]) ? x[i](m) :
-            new Template(x[i]).evaluate(m));
-          e = e.replace(m[0], '');
-          break;
-        }
-      }
-    }
-
-    this.xpath = this.matcher.join('');
-    Selector._cache[this.expression] = this.xpath;
-  },
-
-  findElements: function(root) {
-    root = root || document;
-    var e = this.expression, results;
-
-    switch (this.mode) {
-      case 'selectorsAPI':
-        // querySelectorAll queries document-wide, then filters to descendants
-        // of the context element. That's not what we want.
-        // Add an explicit context to the selector if necessary.
-        if (root !== document) {
-          var oldId = root.id, id = $(root).identify();
-          e = "#" + id + " " + e;
-        }
-
-        results = $A(root.querySelectorAll(e)).map(Element.extend);
-        root.id = oldId;
-
-        return results;
-      case 'xpath':
-        return document._getElementsByXPath(this.xpath, root);
-      default:
-       return this.matcher(root);
-    }
-  },
-
-  match: function(element) {
-    this.tokens = [];
-
-    var e = this.expression, ps = Selector.patterns, as = Selector.assertions;
-    var le, p, m;
-
-    while (e && le !== e && (/\S/).test(e)) {
-      le = e;
-      for (var i in ps) {
-        p = ps[i];
-        if (m = e.match(p)) {
-          // use the Selector.assertions methods unless the selector
-          // is too complex.
-          if (as[i]) {
-            this.tokens.push([i, Object.clone(m)]);
-            e = e.replace(m[0], '');
-          } else {
-            // reluctantly do a document-wide search
-            // and look for a match in the array
-            return this.findElements(document).include(element);
-          }
-        }
-      }
-    }
-
-    var match = true, name, matches;
-    for (var i = 0, token; token = this.tokens[i]; i++) {
-      name = token[0], matches = token[1];
-      if (!Selector.assertions[name](element, matches)) {
-        match = false; break;
-      }
-    }
-
-    return match;
-  },
-
-  toString: function() {
-    return this.expression;
-  },
-
-  inspect: function() {
-    return "#<Selector:" + this.expression.inspect() + ">";
-  }
-});
-
-Object.extend(Selector, {
-  _cache: { },
-
-  xpath: {
-    descendant:   "//*",
-    child:        "/*",
-    adjacent:     "/following-sibling::*[1]",
-    laterSibling: '/following-sibling::*',
-    tagName:      function(m) {
-      if (m[1] == '*') return '';
-      return "[local-name()='" + m[1].toLowerCase() +
-             "' or local-name()='" + m[1].toUpperCase() + "']";
-    },
-    className:    "[contains(concat(' ', @class, ' '), ' #{1} ')]",
-    id:           "[@id='#{1}']",
-    attrPresence: function(m) {
-      m[1] = m[1].toLowerCase();
-      return new Template("[@#{1}]").evaluate(m);
-    },
-    attr: function(m) {
-      m[1] = m[1].toLowerCase();
-      m[3] = m[5] || m[6];
-      return new Template(Selector.xpath.operators[m[2]]).evaluate(m);
-    },
-    pseudo: function(m) {
-      var h = Selector.xpath.pseudos[m[1]];
-      if (!h) return '';
-      if (Object.isFunction(h)) return h(m);
-      return new Template(Selector.xpath.pseudos[m[1]]).evaluate(m);
-    },
-    operators: {
-      '=':  "[@#{1}='#{3}']",
-      '!=': "[@#{1}!='#{3}']",
-      '^=': "[starts-with(@#{1}, '#{3}')]",
-      '$=': "[substring(@#{1}, (string-length(@#{1}) - string-length('#{3}') + 1))='#{3}']",
-      '*=': "[contains(@#{1}, '#{3}')]",
-      '~=': "[contains(concat(' ', @#{1}, ' '), ' #{3} ')]",
-      '|=': "[contains(concat('-', @#{1}, '-'), '-#{3}-')]"
-    },
-    pseudos: {
-      'first-child': '[not(preceding-sibling::*)]',
-      'last-child':  '[not(following-sibling::*)]',
-      'only-child':  '[not(preceding-sibling::* or following-sibling::*)]',
-      'empty':       "[count(*) = 0 and (count(text()) = 0)]",
-      'checked':     "[@checked]",
-      'disabled':    "[(@disabled) and (@type!='hidden')]",
-      'enabled':     "[not(@disabled) and (@type!='hidden')]",
-      'not': function(m) {
-        var e = m[6], p = Selector.patterns,
-            x = Selector.xpath, le, v;
-
-        var exclusion = [];
-        while (e && le != e && (/\S/).test(e)) {
-          le = e;
-          for (var i in p) {
-            if (m = e.match(p[i])) {
-              v = Object.isFunction(x[i]) ? x[i](m) : new Template(x[i]).evaluate(m);
-              exclusion.push("(" + v.substring(1, v.length - 1) + ")");
-              e = e.replace(m[0], '');
-              break;
-            }
-          }
-        }
-        return "[not(" + exclusion.join(" and ") + ")]";
-      },
-      'nth-child':      function(m) {
-        return Selector.xpath.pseudos.nth("(count(./preceding-sibling::*) + 1) ", m);
-      },
-      'nth-last-child': function(m) {
-        return Selector.xpath.pseudos.nth("(count(./following-sibling::*) + 1) ", m);
-      },
-      'nth-of-type':    function(m) {
-        return Selector.xpath.pseudos.nth("position() ", m);
-      },
-      'nth-last-of-type': function(m) {
-        return Selector.xpath.pseudos.nth("(last() + 1 - position()) ", m);
-      },
-      'first-of-type':  function(m) {
-        m[6] = "1"; return Selector.xpath.pseudos['nth-of-type'](m);
-      },
-      'last-of-type':   function(m) {
-        m[6] = "1"; return Selector.xpath.pseudos['nth-last-of-type'](m);
-      },
-      'only-of-type':   function(m) {
-        var p = Selector.xpath.pseudos; return p['first-of-type'](m) + p['last-of-type'](m);
-      },
-      nth: function(fragment, m) {
-        var mm, formula = m[6], predicate;
-        if (formula == 'even') formula = '2n+0';
-        if (formula == 'odd')  formula = '2n+1';
-        if (mm = formula.match(/^(\d+)$/)) // digit only
-          return '[' + fragment + "= " + mm[1] + ']';
-        if (mm = formula.match(/^(-?\d*)?n(([+-])(\d+))?/)) { // an+b
-          if (mm[1] == "-") mm[1] = -1;
-          var a = mm[1] ? Number(mm[1]) : 1;
-          var b = mm[2] ? Number(mm[2]) : 0;
-          predicate = "[((#{fragment} - #{b}) mod #{a} = 0) and " +
-          "((#{fragment} - #{b}) div #{a} >= 0)]";
-          return new Template(predicate).evaluate({
-            fragment: fragment, a: a, b: b });
-        }
-      }
-    }
-  },
-
-  criteria: {
-    tagName:      'n = h.tagName(n, r, "#{1}", c);      c = false;',
-    className:    'n = h.className(n, r, "#{1}", c);    c = false;',
-    id:           'n = h.id(n, r, "#{1}", c);           c = false;',
-    attrPresence: 'n = h.attrPresence(n, r, "#{1}", c); c = false;',
-    attr: function(m) {
-      m[3] = (m[5] || m[6]);
-      return new Template('n = h.attr(n, r, "#{1}", "#{3}", "#{2}", c); c = false;').evaluate(m);
-    },
-    pseudo: function(m) {
-      if (m[6]) m[6] = m[6].replace(/"/g, '\\"');
-      return new Template('n = h.pseudo(n, "#{1}", "#{6}", r, c); c = false;').evaluate(m);
-    },
-    descendant:   'c = "descendant";',
-    child:        'c = "child";',
-    adjacent:     'c = "adjacent";',
-    laterSibling: 'c = "laterSibling";'
-  },
-
-  patterns: {
-    // combinators must be listed first
-    // (and descendant needs to be last combinator)
-    laterSibling: /^\s*~\s*/,
-    child:        /^\s*>\s*/,
-    adjacent:     /^\s*\+\s*/,
-    descendant:   /^\s/,
-
-    // selectors follow
-    tagName:      /^\s*(\*|[\w\-]+)(\b|$)?/,
-    id:           /^#([\w\-\*]+)(\b|$)/,
-    className:    /^\.([\w\-\*]+)(\b|$)/,
-    pseudo:
-/^:((first|last|nth|nth-last|only)(-child|-of-type)|empty|checked|(en|dis)abled|not)(\((.*?)\))?(\b|$|(?=\s|[:+~>]))/,
-    attrPresence: /^\[((?:[\w]+:)?[\w]+)\]/,
-    attr:         /\[((?:[\w-]*:)?[\w-]+)\s*(?:([!^$*~|]?=)\s*((['"])([^\4]*?)\4|([^'"][^\]]*?)))?\]/
-  },
-
-  // for Selector.match and Element#match
-  assertions: {
-    tagName: function(element, matches) {
-      return matches[1].toUpperCase() == element.tagName.toUpperCase();
-    },
-
-    className: function(element, matches) {
-      return Element.hasClassName(element, matches[1]);
-    },
-
-    id: function(element, matches) {
-      return element.id === matches[1];
-    },
-
-    attrPresence: function(element, matches) {
-      return Element.hasAttribute(element, matches[1]);
-    },
-
-    attr: function(element, matches) {
-      var nodeValue = Element.readAttribute(element, matches[1]);
-      return nodeValue && Selector.operators[matches[2]](nodeValue, matches[5] || matches[6]);
-    }
-  },
-
-  handlers: {
-    // UTILITY FUNCTIONS
-    // joins two collections
-    concat: function(a, b) {
-      for (var i = 0, node; node = b[i]; i++)
-        a.push(node);
-      return a;
-    },
-
-    // marks an array of nodes for counting
-    mark: function(nodes) {
-      var _true = Prototype.emptyFunction;
-      for (var i = 0, node; node = nodes[i]; i++)
-        node._countedByPrototype = _true;
-      return nodes;
-    },
-
-    unmark: function(nodes) {
-      for (var i = 0, node; node = nodes[i]; i++)
-        node._countedByPrototype = undefined;
-      return nodes;
-    },
-
-    // mark each child node with its position (for nth calls)
-    // "ofType" flag indicates whether we're indexing for nth-of-type
-    // rather than nth-child
-    index: function(parentNode, reverse, ofType) {
-      parentNode._countedByPrototype = Prototype.emptyFunction;
-      if (reverse) {
-        for (var nodes = parentNode.childNodes, i = nodes.length - 1, j = 1; i >= 0; i--) {
-          var node = nodes[i];
-          if (node.nodeType == 1 && (!ofType || node._countedByPrototype)) node.nodeIndex = j++;
-        }
-      } else {
-        for (var i = 0, j = 1, nodes = parentNode.childNodes; node = nodes[i]; i++)
-          if (node.nodeType == 1 && (!ofType || node._countedByPrototype)) node.nodeIndex = j++;
-      }
-    },
-
-    // filters out duplicates and extends all nodes
-    unique: function(nodes) {
-      if (nodes.length == 0) return nodes;
-      var results = [], n;
-      for (var i = 0, l = nodes.length; i < l; i++)
-        if (!(n = nodes[i])._countedByPrototype) {
-          n._countedByPrototype = Prototype.emptyFunction;
-          results.push(Element.extend(n));
-        }
-      return Selector.handlers.unmark(results);
-    },
-
-    // COMBINATOR FUNCTIONS
-    descendant: function(nodes) {
-      var h = Selector.handlers;
-      for (var i = 0, results = [], node; node = nodes[i]; i++)
-        h.concat(results, node.getElementsByTagName('*'));
-      return results;
-    },
-
-    child: function(nodes) {
-      var h = Selector.handlers;
-      for (var i = 0, results = [], node; node = nodes[i]; i++) {
-        for (var j = 0, child; child = node.childNodes[j]; j++)
-          if (child.nodeType == 1 && child.tagName != '!') results.push(child);
-      }
-      return results;
-    },
-
-    adjacent: function(nodes) {
-      for (var i = 0, results = [], node; node = nodes[i]; i++) {
-        var next = this.nextElementSibling(node);
-        if (next) results.push(next);
-      }
-      return results;
-    },
-
-    laterSibling: function(nodes) {
-      var h = Selector.handlers;
-      for (var i = 0, results = [], node; node = nodes[i]; i++)
-        h.concat(results, Element.nextSiblings(node));
-      return results;
-    },
-
-    nextElementSibling: function(node) {
-      while (node = node.nextSibling)
-        if (node.nodeType == 1) return node;
-      return null;
-    },
-
-    previousElementSibling: function(node) {
-      while (node = node.previousSibling)
-        if (node.nodeType == 1) return node;
-      return null;
-    },
-
-    // TOKEN FUNCTIONS
-    tagName: function(nodes, root, tagName, combinator) {
-      var uTagName = tagName.toUpperCase();
-      var results = [], h = Selector.handlers;
-      if (nodes) {
-        if (combinator) {
-          // fastlane for ordinary descendant combinators
-          if (combinator == "descendant") {
-            for (var i = 0, node; node = nodes[i]; i++)
-              h.concat(results, node.getElementsByTagName(tagName));
-            return results;
-          } else nodes = this[combinator](nodes);
-          if (tagName == "*") return nodes;
-        }
-        for (var i = 0, node; node = nodes[i]; i++)
-          if (node.tagName.toUpperCase() === uTagName) results.push(node);
-        return results;
-      } else return root.getElementsByTagName(tagName);
-    },
-
-    id: function(nodes, root, id, combinator) {
-      var targetNode = $(id), h = Selector.handlers;
-      if (!targetNode) return [];
-      if (!nodes && root == document) return [targetNode];
-      if (nodes) {
-        if (combinator) {
-          if (combinator == 'child') {
-            for (var i = 0, node; node = nodes[i]; i++)
-              if (targetNode.parentNode == node) return [targetNode];
-          } else if (combinator == 'descendant') {
-            for (var i = 0, node; node = nodes[i]; i++)
-              if (Element.descendantOf(targetNode, node)) return [targetNode];
-          } else if (combinator == 'adjacent') {
-            for (var i = 0, node; node = nodes[i]; i++)
-              if (Selector.handlers.previousElementSibling(targetNode) == node)
-                return [targetNode];
-          } else nodes = h[combinator](nodes);
-        }
-        for (var i = 0, node; node = nodes[i]; i++)
-          if (node == targetNode) return [targetNode];
-        return [];
-      }
-      return (targetNode && Element.descendantOf(targetNode, root)) ? [targetNode] : [];
-    },
-
-    className: function(nodes, root, className, combinator) {
-      if (nodes && combinator) nodes = this[combinator](nodes);
-      return Selector.handlers.byClassName(nodes, root, className);
-    },
-
-    byClassName: function(nodes, root, className) {
-      if (!nodes) nodes = Selector.handlers.descendant([root]);
-      var needle = ' ' + className + ' ';
-      for (var i = 0, results = [], node, nodeClassName; node = nodes[i]; i++) {
-        nodeClassName = node.className;
-        if (nodeClassName.length == 0) continue;
-        if (nodeClassName == className || (' ' + nodeClassName + ' ').include(needle))
-          results.push(node);
-      }
-      return results;
-    },
-
-    attrPresence: function(nodes, root, attr, combinator) {
-      if (!nodes) nodes = root.getElementsByTagName("*");
-      if (nodes && combinator) nodes = this[combinator](nodes);
-      var results = [];
-      for (var i = 0, node; node = nodes[i]; i++)
-        if (Element.hasAttribute(node, attr)) results.push(node);
-      return results;
-    },
-
-    attr: function(nodes, root, attr, value, operator, combinator) {
-      if (!nodes) nodes = root.getElementsByTagName("*");
-      if (nodes && combinator) nodes = this[combinator](nodes);
-      var handler = Selector.operators[operator], results = [];
-      for (var i = 0, node; node = nodes[i]; i++) {
-        var nodeValue = Element.readAttribute(node, attr);
-        if (nodeValue === null) continue;
-        if (handler(nodeValue, value)) results.push(node);
-      }
-      return results;
-    },
-
-    pseudo: function(nodes, name, value, root, combinator) {
-      if (nodes && combinator) nodes = this[combinator](nodes);
-      if (!nodes) nodes = root.getElementsByTagName("*");
-      return Selector.pseudos[name](nodes, value, root);
-    }
-  },
-
-  pseudos: {
-    'first-child': function(nodes, value, root) {
-      for (var i = 0, results = [], node; node = nodes[i]; i++) {
-        if (Selector.handlers.previousElementSibling(node)) continue;
-          results.push(node);
-      }
-      return results;
-    },
-    'last-child': function(nodes, value, root) {
-      for (var i = 0, results = [], node; node = nodes[i]; i++) {
-        if (Selector.handlers.nextElementSibling(node)) continue;
-          results.push(node);
-      }
-      return results;
-    },
-    'only-child': function(nodes, value, root) {
-      var h = Selector.handlers;
-      for (var i = 0, results = [], node; node = nodes[i]; i++)
-        if (!h.previousElementSibling(node) && !h.nextElementSibling(node))
-          results.push(node);
-      return results;
-    },
-    'nth-child':        function(nodes, formula, root) {
-      return Selector.pseudos.nth(nodes, formula, root);
-    },
-    'nth-last-child':   function(nodes, formula, root) {
-      return Selector.pseudos.nth(nodes, formula, root, true);
-    },
-    'nth-of-type':      function(nodes, formula, root) {
-      return Selector.pseudos.nth(nodes, formula, root, false, true);
-    },
-    'nth-last-of-type': function(nodes, formula, root) {
-      return Selector.pseudos.nth(nodes, formula, root, true, true);
-    },
-    'first-of-type':    function(nodes, formula, root) {
-      return Selector.pseudos.nth(nodes, "1", root, false, true);
-    },
-    'last-of-type':     function(nodes, formula, root) {
-      return Selector.pseudos.nth(nodes, "1", root, true, true);
-    },
-    'only-of-type':     function(nodes, formula, root) {
-      var p = Selector.pseudos;
-      return p['last-of-type'](p['first-of-type'](nodes, formula, root), formula, root);
-    },
-
-    // handles the an+b logic
-    getIndices: function(a, b, total) {
-      if (a == 0) return b > 0 ? [b] : [];
-      return $R(1, total).inject([], function(memo, i) {
-        if (0 == (i - b) % a && (i - b) / a >= 0) memo.push(i);
-        return memo;
-      });
-    },
-
-    // handles nth(-last)-child, nth(-last)-of-type, and (first|last)-of-type
-    nth: function(nodes, formula, root, reverse, ofType) {
-      if (nodes.length == 0) return [];
-      if (formula == 'even') formula = '2n+0';
-      if (formula == 'odd')  formula = '2n+1';
-      var h = Selector.handlers, results = [], indexed = [], m;
-      h.mark(nodes);
-      for (var i = 0, node; node = nodes[i]; i++) {
-        if (!node.parentNode._countedByPrototype) {
-          h.index(node.parentNode, reverse, ofType);
-          indexed.push(node.parentNode);
-        }
-      }
-      if (formula.match(/^\d+$/)) { // just a number
-        formula = Number(formula);
-        for (var i = 0, node; node = nodes[i]; i++)
-          if (node.nodeIndex == formula) results.push(node);
-      } else if (m = formula.match(/^(-?\d*)?n(([+-])(\d+))?/)) { // an+b
-        if (m[1] == "-") m[1] = -1;
-        var a = m[1] ? Number(m[1]) : 1;
-        var b = m[2] ? Number(m[2]) : 0;
-        var indices = Selector.pseudos.getIndices(a, b, nodes.length);
-        for (var i = 0, node, l = indices.length; node = nodes[i]; i++) {
-          for (var j = 0; j < l; j++)
-            if (node.nodeIndex == indices[j]) results.push(node);
-        }
-      }
-      h.unmark(nodes);
-      h.unmark(indexed);
-      return results;
-    },
-
-    'empty': function(nodes, value, root) {
-      for (var i = 0, results = [], node; node = nodes[i]; i++) {
-        // IE treats comments as element nodes
-        if (node.tagName == '!' || node.firstChild) continue;
-        results.push(node);
-      }
-      return results;
-    },
-
-    'not': function(nodes, selector, root) {
-      var h = Selector.handlers, selectorType, m;
-      var exclusions = new Selector(selector).findElements(root);
-      h.mark(exclusions);
-      for (var i = 0, results = [], node; node = nodes[i]; i++)
-        if (!node._countedByPrototype) results.push(node);
-      h.unmark(exclusions);
-      return results;
-    },
-
-    'enabled': function(nodes, value, root) {
-      for (var i = 0, results = [], node; node = nodes[i]; i++)
-        if (!node.disabled && (!node.type || node.type !== 'hidden'))
-          results.push(node);
-      return results;
-    },
-
-    'disabled': function(nodes, value, root) {
-      for (var i = 0, results = [], node; node = nodes[i]; i++)
-        if (node.disabled) results.push(node);
-      return results;
-    },
-
-    'checked': function(nodes, value, root) {
-      for (var i = 0, results = [], node; node = nodes[i]; i++)
-        if (node.checked) results.push(node);
-      return results;
-    }
-  },
-
-  operators: {
-    '=':  function(nv, v) { return nv == v; },
-    '!=': function(nv, v) { return nv != v; },
-    '^=': function(nv, v) { return nv == v || nv && nv.startsWith(v); },
-    '$=': function(nv, v) { return nv == v || nv && nv.endsWith(v); },
-    '*=': function(nv, v) { return nv == v || nv && nv.include(v); },
-    '$=': function(nv, v) { return nv.endsWith(v); },
-    '*=': function(nv, v) { return nv.include(v); },
-    '~=': function(nv, v) { return (' ' + nv + ' ').include(' ' + v + ' '); },
-    '|=': function(nv, v) { return ('-' + (nv || "").toUpperCase() +
-     '-').include('-' + (v || "").toUpperCase() + '-'); }
-  },
-
-  split: function(expression) {
-    var expressions = [];
-    expression.scan(/(([\w#:.~>+()\s-]+|\*|\[.*?\])+)\s*(,|$)/, function(m) {
-      expressions.push(m[1].strip());
-    });
-    return expressions;
-  },
-
-  matchElements: function(elements, expression) {
-    var matches = $$(expression), h = Selector.handlers;
-    h.mark(matches);
-    for (var i = 0, results = [], element; element = elements[i]; i++)
-      if (element._countedByPrototype) results.push(element);
-    h.unmark(matches);
-    return results;
-  },
-
-  findElement: function(elements, expression, index) {
-    if (Object.isNumber(expression)) {
-      index = expression; expression = false;
-    }
-    return Selector.matchElements(elements, expression || '*')[index || 0];
-  },
-
-  findChildElements: function(element, expressions) {
-    expressions = Selector.split(expressions.join(','));
-    var results = [], h = Selector.handlers;
-    for (var i = 0, l = expressions.length, selector; i < l; i++) {
-      selector = new Selector(expressions[i].strip());
-      h.concat(results, selector.findElements(element));
-    }
-    return (l > 1) ? h.unique(results) : results;
-  }
-});
-
-if (Prototype.Browser.IE) {
-  Object.extend(Selector.handlers, {
-    // IE returns comment nodes on getElementsByTagName("*").
-    // Filter them out.
-    concat: function(a, b) {
-      for (var i = 0, node; node = b[i]; i++)
-        if (node.tagName !== "!") a.push(node);
-      return a;
-    },
-
-    // IE improperly serializes _countedByPrototype in (inner|outer)HTML.
-    unmark: function(nodes) {
-      for (var i = 0, node; node = nodes[i]; i++)
-        node.removeAttribute('_countedByPrototype');
-      return nodes;
-    }
-  });
-}
-
-function $$() {
-  return Selector.findChildElements(document, $A(arguments));
-}
-var Form = {
-  reset: function(form) {
-    $(form).reset();
-    return form;
-  },
-
-  serializeElements: function(elements, options) {
-    if (typeof options != 'object') options = { hash: !!options };
-    else if (Object.isUndefined(options.hash)) options.hash = true;
-    var key, value, submitted = false, submit = options.submit;
-
-    var data = elements.inject({ }, function(result, element) {
-      if (!element.disabled && element.name) {
-        key = element.name; value = $(element).getValue();
-        if (value != null && element.type != 'file' && (element.type != 'submit' || (!submitted &&
-            submit !== false && (!submit || key == submit) && (submitted = true)))) {
-          if (key in result) {
-            // a key is already present; construct an array of values
-            if (!Object.isArray(result[key])) result[key] = [result[key]];
-            result[key].push(value);
-          }
-          else result[key] = value;
-        }
-      }
-      return result;
-    });
-
-    return options.hash ? data : Object.toQueryString(data);
-  }
-};
-
-Form.Methods = {
-  serialize: function(form, options) {
-    return Form.serializeElements(Form.getElements(form), options);
-  },
-
-  getElements: function(form) {
-    return $A($(form).getElementsByTagName('*')).inject([],
-      function(elements, child) {
-        if (Form.Element.Serializers[child.tagName.toLowerCase()])
-          elements.push(Element.extend(child));
-        return elements;
-      }
-    );
-  },
-
-  getInputs: function(form, typeName, name) {
-    form = $(form);
-    var inputs = form.getElementsByTagName('input');
-
-    if (!typeName && !name) return $A(inputs).map(Element.extend);
-
-    for (var i = 0, matchingInputs = [], length = inputs.length; i < length; i++) {
-      var input = inputs[i];
-      if ((typeName && input.type != typeName) || (name && input.name != name))
-        continue;
-      matchingInputs.push(Element.extend(input));
-    }
-
-    return matchingInputs;
-  },
-
-  disable: function(form) {
-    form = $(form);
-    Form.getElements(form).invoke('disable');
-    return form;
-  },
-
-  enable: function(form) {
-    form = $(form);
-    Form.getElements(form).invoke('enable');
-    return form;
-  },
-
-  findFirstElement: function(form) {
-    var elements = $(form).getElements().findAll(function(element) {
-      return 'hidden' != element.type && !element.disabled;
-    });
-    var firstByIndex = elements.findAll(function(element) {
-      return element.hasAttribute('tabIndex') && element.tabIndex >= 0;
-    }).sortBy(function(element) { return element.tabIndex }).first();
-
-    return firstByIndex ? firstByIndex : elements.find(function(element) {
-      return ['input', 'select', 'textarea'].include(element.tagName.toLowerCase());
-    });
-  },
-
-  focusFirstElement: function(form) {
-    form = $(form);
-    form.findFirstElement().activate();
-    return form;
-  },
-
-  request: function(form, options) {
-    form = $(form), options = Object.clone(options || { });
-
-    var params = options.parameters, action = form.readAttribute('action') || '';
-    if (action.blank()) action = window.location.href;
-    options.parameters = form.serialize(true);
-
-    if (params) {
-      if (Object.isString(params)) params = params.toQueryParams();
-      Object.extend(options.parameters, params);
-    }
-
-    if (form.hasAttribute('method') && !options.method)
-      options.method = form.method;
-
-    return new Ajax.Request(action, options);
-  }
-};
-
-/*--------------------------------------------------------------------------*/
-
-Form.Element = {
-  focus: function(element) {
-    $(element).focus();
-    return element;
-  },
-
-  select: function(element) {
-    $(element).select();
-    return element;
-  }
-};
-
-Form.Element.Methods = {
-  serialize: function(element) {
-    element = $(element);
-    if (!element.disabled && element.name) {
-      var value = element.getValue();
-      if (value != undefined) {
-        var pair = { };
-        pair[element.name] = value;
-        return Object.toQueryString(pair);
-      }
-    }
-    return '';
-  },
-
-  getValue: function(element) {
-    element = $(element);
-    var method = element.tagName.toLowerCase();
-    return Form.Element.Serializers[method](element);
-  },
-
-  setValue: function(element, value) {
-    element = $(element);
-    var method = element.tagName.toLowerCase();
-    Form.Element.Serializers[method](element, value);
-    return element;
-  },
-
-  clear: function(element) {
-    $(element).value = '';
-    return element;
-  },
-
-  present: function(element) {
-    return $(element).value != '';
-  },
-
-  activate: function(element) {
-    element = $(element);
-    try {
-      element.focus();
-      if (element.select && (element.tagName.toLowerCase() != 'input' ||
-          !['button', 'reset', 'submit'].include(element.type)))
-        element.select();
-    } catch (e) { }
-    return element;
-  },
-
-  disable: function(element) {
-    element = $(element);
-    element.disabled = true;
-    return element;
-  },
-
-  enable: function(element) {
-    element = $(element);
-    element.disabled = false;
-    return element;
-  }
-};
-
-/*--------------------------------------------------------------------------*/
-
-var Field = Form.Element;
-var $F = Form.Element.Methods.getValue;
-
-/*--------------------------------------------------------------------------*/
-
-Form.Element.Serializers = {
-  input: function(element, value) {
-    switch (element.type.toLowerCase()) {
-      case 'checkbox':
-      case 'radio':
-        return Form.Element.Serializers.inputSelector(element, value);
-      default:
-        return Form.Element.Serializers.textarea(element, value);
-    }
-  },
-
-  inputSelector: function(element, value) {
-    if (Object.isUndefined(value)) return element.checked ? element.value : null;
-    else element.checked = !!value;
-  },
-
-  textarea: function(element, value) {
-    if (Object.isUndefined(value)) return element.value;
-    else element.value = value;
-  },
-
-  select: function(element, value) {
-    if (Object.isUndefined(value))
-      return this[element.type == 'select-one' ?
-        'selectOne' : 'selectMany'](element);
-    else {
-      var opt, currentValue, single = !Object.isArray(value);
-      for (var i = 0, length = element.length; i < length; i++) {
-        opt = element.options[i];
-        currentValue = this.optionValue(opt);
-        if (single) {
-          if (currentValue == value) {
-            opt.selected = true;
-            return;
-          }
-        }
-        else opt.selected = value.include(currentValue);
-      }
-    }
-  },
-
-  selectOne: function(element) {
-    var index = element.selectedIndex;
-    return index >= 0 ? this.optionValue(element.options[index]) : null;
-  },
-
-  selectMany: function(element) {
-    var values, length = element.length;
-    if (!length) return null;
-
-    for (var i = 0, values = []; i < length; i++) {
-      var opt = element.options[i];
-      if (opt.selected) values.push(this.optionValue(opt));
-    }
-    return values;
-  },
-
-  optionValue: function(opt) {
-    // extend element because hasAttribute may not be native
-    return Element.extend(opt).hasAttribute('value') ? opt.value : opt.text;
-  }
-};
-
-/*--------------------------------------------------------------------------*/
-
-Abstract.TimedObserver = Class.create(PeriodicalExecuter, {
-  initialize: function($super, element, frequency, callback) {
-    $super(callback, frequency);
-    this.element   = $(element);
-    this.lastValue = this.getValue();
-  },
-
-  execute: function() {
-    var value = this.getValue();
-    if (Object.isString(this.lastValue) && Object.isString(value) ?
-        this.lastValue != value : String(this.lastValue) != String(value)) {
-      this.callback(this.element, value);
-      this.lastValue = value;
-    }
-  }
-});
-
-Form.Element.Observer = Class.create(Abstract.TimedObserver, {
-  getValue: function() {
-    return Form.Element.getValue(this.element);
-  }
-});
-
-Form.Observer = Class.create(Abstract.TimedObserver, {
-  getValue: function() {
-    return Form.serialize(this.element);
-  }
-});
-
-/*--------------------------------------------------------------------------*/
-
-Abstract.EventObserver = Class.create({
-  initialize: function(element, callback) {
-    this.element  = $(element);
-    this.callback = callback;
-
-    this.lastValue = this.getValue();
-    if (this.element.tagName.toLowerCase() == 'form')
-      this.registerFormCallbacks();
-    else
-      this.registerCallback(this.element);
-  },
-
-  onElementEvent: function() {
-    var value = this.getValue();
-    if (this.lastValue != value) {
-      this.callback(this.element, value);
-      this.lastValue = value;
-    }
-  },
-
-  registerFormCallbacks: function() {
-    Form.getElements(this.element).each(this.registerCallback, this);
-  },
-
-  registerCallback: function(element) {
-    if (element.type) {
-      switch (element.type.toLowerCase()) {
-        case 'checkbox':
-        case 'radio':
-          Event.observe(element, 'click', this.onElementEvent.bind(this));
-          break;
-        default:
-          Event.observe(element, 'change', this.onElementEvent.bind(this));
-          break;
-      }
-    }
-  }
-});
-
-Form.Element.EventObserver = Class.create(Abstract.EventObserver, {
-  getValue: function() {
-    return Form.Element.getValue(this.element);
-  }
-});
-
-Form.EventObserver = Class.create(Abstract.EventObserver, {
-  getValue: function() {
-    return Form.serialize(this.element);
-  }
-});
-if (!window.Event) var Event = { };
-
-Object.extend(Event, {
-  KEY_BACKSPACE: 8,
-  KEY_TAB:       9,
-  KEY_RETURN:   13,
-  KEY_ESC:      27,
-  KEY_LEFT:     37,
-  KEY_UP:       38,
-  KEY_RIGHT:    39,
-  KEY_DOWN:     40,
-  KEY_DELETE:   46,
-  KEY_HOME:     36,
-  KEY_END:      35,
-  KEY_PAGEUP:   33,
-  KEY_PAGEDOWN: 34,
-  KEY_INSERT:   45,
-
-  cache: { },
-
-  relatedTarget: function(event) {
-    var element;
-    switch(event.type) {
-      case 'mouseover': element = event.fromElement; break;
-      case 'mouseout':  element = event.toElement;   break;
-      default: return null;
-    }
-    return Element.extend(element);
-  }
-});
-
-Event.Methods = (function() {
-  var isButton;
-
-  if (Prototype.Browser.IE) {
-    var buttonMap = { 0: 1, 1: 4, 2: 2 };
-    isButton = function(event, code) {
-      return event.button == buttonMap[code];
-    };
-
-  } else if (Prototype.Browser.WebKit) {
-    isButton = function(event, code) {
-      switch (code) {
-        case 0: return event.which == 1 && !event.metaKey;
-        case 1: return event.which == 1 && event.metaKey;
-        default: return false;
-      }
-    };
-
-  } else {
-    isButton = function(event, code) {
-      return event.which ? (event.which === code + 1) : (event.button === code);
-    };
-  }
-
-  return {
-    isLeftClick:   function(event) { return isButton(event, 0) },
-    isMiddleClick: function(event) { return isButton(event, 1) },
-    isRightClick:  function(event) { return isButton(event, 2) },
-
-    element: function(event) {
-      event = Event.extend(event);
-
-      var node          = event.target,
-          type          = event.type,
-          currentTarget = event.currentTarget;
-
-      if (currentTarget && currentTarget.tagName) {
-        // Firefox screws up the "click" event when moving between radio buttons
-        // via arrow keys. It also screws up the "load" and "error" events on images,
-        // reporting the document as the target instead of the original image.
-        if (type === 'load' || type === 'error' ||
-          (type === 'click' && currentTarget.tagName.toLowerCase() === 'input'
-            && currentTarget.type === 'radio'))
-              node = currentTarget;
-      }
-      if (node.nodeType == Node.TEXT_NODE) node = node.parentNode;
-      return Element.extend(node);
-    },
-
-    findElement: function(event, expression) {
-      var element = Event.element(event);
-      if (!expression) return element;
-      var elements = [element].concat(element.ancestors());
-      return Selector.findElement(elements, expression, 0);
-    },
-
-    pointer: function(event) {
-      var docElement = document.documentElement,
-      body = document.body || { scrollLeft: 0, scrollTop: 0 };
-      return {
-        x: event.pageX || (event.clientX +
-          (docElement.scrollLeft || body.scrollLeft) -
-          (docElement.clientLeft || 0)),
-        y: event.pageY || (event.clientY +
-          (docElement.scrollTop || body.scrollTop) -
-          (docElement.clientTop || 0))
-      };
-    },
-
-    pointerX: function(event) { return Event.pointer(event).x },
-    pointerY: function(event) { return Event.pointer(event).y },
-
-    stop: function(event) {
-      Event.extend(event);
-      event.preventDefault();
-      event.stopPropagation();
-      event.stopped = true;
-    }
-  };
-})();
-
-Event.extend = (function() {
-  var methods = Object.keys(Event.Methods).inject({ }, function(m, name) {
-    m[name] = Event.Methods[name].methodize();
-    return m;
-  });
-
-  if (Prototype.Browser.IE) {
-    Object.extend(methods, {
-      stopPropagation: function() { this.cancelBubble = true },
-      preventDefault:  function() { this.returnValue = false },
-      inspect: function() { return "[object Event]" }
-    });
-
-    return function(event) {
-      if (!event) return false;
-      if (event._extendedByPrototype) return event;
-
-      event._extendedByPrototype = Prototype.emptyFunction;
-      var pointer = Event.pointer(event);
-      Object.extend(event, {
-        target: event.srcElement,
-        relatedTarget: Event.relatedTarget(event),
-        pageX:  pointer.x,
-        pageY:  pointer.y
-      });
-      return Object.extend(event, methods);
-    };
-
-  } else {
-    Event.prototype = Event.prototype || document.createEvent("HTMLEvents")['__proto__'];
-    Object.extend(Event.prototype, methods);
-    return Prototype.K;
-  }
-})();
-
-Object.extend(Event, (function() {
-  var cache = Event.cache;
-
-  function getEventID(element) {
-    if (element._prototypeEventID) return element._prototypeEventID[0];
-    arguments.callee.id = arguments.callee.id || 1;
-    return element._prototypeEventID = [++arguments.callee.id];
-  }
-
-  function getDOMEventName(eventName) {
-    if (eventName && eventName.include(':')) return "dataavailable";
-    return eventName;
-  }
-
-  function getCacheForID(id) {
-    return cache[id] = cache[id] || { };
-  }
-
-  function getWrappersForEventName(id, eventName) {
-    var c = getCacheForID(id);
-    return c[eventName] = c[eventName] || [];
-  }
-
-  function createWrapper(element, eventName, handler) {
-    var id = getEventID(element);
-    var c = getWrappersForEventName(id, eventName);
-    if (c.pluck("handler").include(handler)) return false;
-
-    var wrapper = function(event) {
-      if (!Event || !Event.extend ||
-        (event.eventName && event.eventName != eventName))
-          return false;
-
-      Event.extend(event);
-      handler.call(element, event);
-    };
-
-    wrapper.handler = handler;
-    c.push(wrapper);
-    return wrapper;
-  }
-
-  function findWrapper(id, eventName, handler) {
-    var c = getWrappersForEventName(id, eventName);
-    return c.find(function(wrapper) { return wrapper.handler == handler });
-  }
-
-  function destroyWrapper(id, eventName, handler) {
-    var c = getCacheForID(id);
-    if (!c[eventName]) return false;
-    c[eventName] = c[eventName].without(findWrapper(id, eventName, handler));
-  }
-
-  function destroyCache() {
-    for (var id in cache)
-      for (var eventName in cache[id])
-        cache[id][eventName] = null;
-  }
-
-
-  // Internet Explorer needs to remove event handlers on page unload
-  // in order to avoid memory leaks.
-  if (window.attachEvent) {
-    window.attachEvent("onunload", destroyCache);
-  }
-
-  // Safari has a dummy event handler on page unload so that it won't
-  // use its bfcache. Safari <= 3.1 has an issue with restoring the "document"
-  // object when page is returned to via the back button using its bfcache.
-  if (Prototype.Browser.WebKit) {
-    window.addEventListener('unload', Prototype.emptyFunction, false);
-  }
-
-  return {
-    observe: function(element, eventName, handler) {
-      element = $(element);
-      var name = getDOMEventName(eventName);
-
-      var wrapper = createWrapper(element, eventName, handler);
-      if (!wrapper) return element;
-
-      if (element.addEventListener) {
-        element.addEventListener(name, wrapper, false);
-      } else {
-        element.attachEvent("on" + name, wrapper);
-      }
-
-      return element;
-    },
-
-    stopObserving: function(element, eventName, handler) {
-      element = $(element);
-      var id = getEventID(element), name = getDOMEventName(eventName);
-
-      if (!handler && eventName) {
-        getWrappersForEventName(id, eventName).each(function(wrapper) {
-          element.stopObserving(eventName, wrapper.handler);
-        });
-        return element;
-
-      } else if (!eventName) {
-        Object.keys(getCacheForID(id)).each(function(eventName) {
-          element.stopObserving(eventName);
-        });
-        return element;
-      }
-
-      var wrapper = findWrapper(id, eventName, handler);
-      if (!wrapper) return element;
-
-      if (element.removeEventListener) {
-        element.removeEventListener(name, wrapper, false);
-      } else {
-        element.detachEvent("on" + name, wrapper);
-      }
-
-      destroyWrapper(id, eventName, handler);
-
-      return element;
-    },
-
-    fire: function(element, eventName, memo) {
-      element = $(element);
-      if (element == document && document.createEvent && !element.dispatchEvent)
-        element = document.documentElement;
-
-      var event;
-      if (document.createEvent) {
-        event = document.createEvent("HTMLEvents");
-        event.initEvent("dataavailable", true, true);
-      } else {
-        event = document.createEventObject();
-        event.eventType = "ondataavailable";
-      }
-
-      event.eventName = eventName;
-      event.memo = memo || { };
-
-      if (document.createEvent) {
-        element.dispatchEvent(event);
-      } else {
-        element.fireEvent(event.eventType, event);
-      }
-
-      return Event.extend(event);
-    }
-  };
-})());
-
-Object.extend(Event, Event.Methods);
-
-Element.addMethods({
-  fire:          Event.fire,
-  observe:       Event.observe,
-  stopObserving: Event.stopObserving
-});
-
-Object.extend(document, {
-  fire:          Element.Methods.fire.methodize(),
-  observe:       Element.Methods.observe.methodize(),
-  stopObserving: Element.Methods.stopObserving.methodize(),
-  loaded:        false
-});
-
-(function() {
-  /* Support for the DOMContentLoaded event is based on work by Dan Webb,
-     Matthias Miller, Dean Edwards and John Resig. */
-
-  var timer;
-
-  function fireContentLoadedEvent() {
-    if (document.loaded) return;
-    if (timer) window.clearInterval(timer);
-    document.fire("dom:loaded");
-    document.loaded = true;
-  }
-
-  if (document.addEventListener) {
-    if (Prototype.Browser.WebKit) {
-      timer = window.setInterval(function() {
-        if (/loaded|complete/.test(document.readyState))
-          fireContentLoadedEvent();
-      }, 0);
-
-      Event.observe(window, "load", fireContentLoadedEvent);
-
-    } else {
-      document.addEventListener("DOMContentLoaded",
-        fireContentLoadedEvent, false);
-    }
-
-  } else {
-    document.write("<script id=__onDOMContentLoaded defer src=//:><\/script>");
-    $("__onDOMContentLoaded").onreadystatechange = function() {
-      if (this.readyState == "complete") {
-        this.onreadystatechange = null;
-        fireContentLoadedEvent();
-      }
-    };
-  }
-})();
-/*------------------------------- DEPRECATED -------------------------------*/
-
-Hash.toQueryString = Object.toQueryString;
-
-var Toggle = { display: Element.toggle };
-
-Element.Methods.childOf = Element.Methods.descendantOf;
-
-var Insertion = {
-  Before: function(element, content) {
-    return Element.insert(element, {before:content});
-  },
-
-  Top: function(element, content) {
-    return Element.insert(element, {top:content});
-  },
-
-  Bottom: function(element, content) {
-    return Element.insert(element, {bottom:content});
-  },
-
-  After: function(element, content) {
-    return Element.insert(element, {after:content});
-  }
-};
-
-var $continue = new Error('"throw $continue" is deprecated, use "return" instead');
-
-// This should be moved to script.aculo.us; notice the deprecated methods
-// further below, that map to the newer Element methods.
-var Position = {
-  // set to true if needed, warning: firefox performance problems
-  // NOT neeeded for page scrolling, only if draggable contained in
-  // scrollable elements
-  includeScrollOffsets: false,
-
-  // must be called before calling withinIncludingScrolloffset, every time the
-  // page is scrolled
-  prepare: function() {
-    this.deltaX =  window.pageXOffset
-                || document.documentElement.scrollLeft
-                || document.body.scrollLeft
-                || 0;
-    this.deltaY =  window.pageYOffset
-                || document.documentElement.scrollTop
-                || document.body.scrollTop
-                || 0;
-  },
-
-  // caches x/y coordinate pair to use with overlap
-  within: function(element, x, y) {
-    if (this.includeScrollOffsets)
-      return this.withinIncludingScrolloffsets(element, x, y);
-    this.xcomp = x;
-    this.ycomp = y;
-    this.offset = Element.cumulativeOffset(element);
-
-    return (y >= this.offset[1] &&
-            y <  this.offset[1] + element.offsetHeight &&
-            x >= this.offset[0] &&
-            x <  this.offset[0] + element.offsetWidth);
-  },
-
-  withinIncludingScrolloffsets: function(element, x, y) {
-    var offsetcache = Element.cumulativeScrollOffset(element);
-
-    this.xcomp = x + offsetcache[0] - this.deltaX;
-    this.ycomp = y + offsetcache[1] - this.deltaY;
-    this.offset = Element.cumulativeOffset(element);
-
-    return (this.ycomp >= this.offset[1] &&
-            this.ycomp <  this.offset[1] + element.offsetHeight &&
-            this.xcomp >= this.offset[0] &&
-            this.xcomp <  this.offset[0] + element.offsetWidth);
-  },
-
-  // within must be called directly before
-  overlap: function(mode, element) {
-    if (!mode) return 0;
-    if (mode == 'vertical')
-      return ((this.offset[1] + element.offsetHeight) - this.ycomp) /
-        element.offsetHeight;
-    if (mode == 'horizontal')
-      return ((this.offset[0] + element.offsetWidth) - this.xcomp) /
-        element.offsetWidth;
-  },
-
-  // Deprecation layer -- use newer Element methods now (1.5.2).
-
-  cumulativeOffset: Element.Methods.cumulativeOffset,
-
-  positionedOffset: Element.Methods.positionedOffset,
-
-  absolutize: function(element) {
-    Position.prepare();
-    return Element.absolutize(element);
-  },
-
-  relativize: function(element) {
-    Position.prepare();
-    return Element.relativize(element);
-  },
-
-  realOffset: Element.Methods.cumulativeScrollOffset,
-
-  offsetParent: Element.Methods.getOffsetParent,
-
-  page: Element.Methods.viewportOffset,
-
-  clone: function(source, target, options) {
-    options = options || { };
-    return Element.clonePosition(target, source, options);
-  }
-};
-
-/*--------------------------------------------------------------------------*/
-
-if (!document.getElementsByClassName) document.getElementsByClassName = function(instanceMethods){
-  function iter(name) {
-    return name.blank() ? null : "[contains(concat(' ', @class, ' '), ' " + name + " ')]";
-  }
-
-  instanceMethods.getElementsByClassName = Prototype.BrowserFeatures.XPath ?
-  function(element, className) {
-    className = className.toString().strip();
-    var cond = /\s/.test(className) ? $w(className).map(iter).join('') : iter(className);
-    return cond ? document._getElementsByXPath('.//*' + cond, element) : [];
-  } : function(element, className) {
-    className = className.toString().strip();
-    var elements = [], classNames = (/\s/.test(className) ? $w(className) : null);
-    if (!classNames && !className) return elements;
-
-    var nodes = $(element).getElementsByTagName('*');
-    className = ' ' + className + ' ';
-
-    for (var i = 0, child, cn; child = nodes[i]; i++) {
-      if (child.className && (cn = ' ' + child.className + ' ') && (cn.include(className) ||
-          (classNames && classNames.all(function(name) {
-            return !name.toString().blank() && cn.include(' ' + name + ' ');
-          }))))
-        elements.push(Element.extend(child));
-    }
-    return elements;
-  };
-
-  return function(className, parentElement) {
-    return $(parentElement || document.body).getElementsByClassName(className);
-  };
-}(Element.Methods);
-
-/*--------------------------------------------------------------------------*/
-
-Element.ClassNames = Class.create();
-Element.ClassNames.prototype = {
-  initialize: function(element) {
-    this.element = $(element);
-  },
-
-  _each: function(iterator) {
-    this.element.className.split(/\s+/).select(function(name) {
-      return name.length > 0;
-    })._each(iterator);
-  },
-
-  set: function(className) {
-    this.element.className = className;
-  },
-
-  add: function(classNameToAdd) {
-    if (this.include(classNameToAdd)) return;
-    this.set($A(this).concat(classNameToAdd).join(' '));
-  },
-
-  remove: function(classNameToRemove) {
-    if (!this.include(classNameToRemove)) return;
-    this.set($A(this).without(classNameToRemove).join(' '));
-  },
-
-  toString: function() {
-    return $A(this).join(' ');
-  }
-};
-
-Object.extend(Element.ClassNames.prototype, Enumerable);
-
-/*--------------------------------------------------------------------------*/
-
-Element.addMethods();
\ No newline at end of file
index 4434ad9..8cb884b 100644 (file)
@@ -1,7 +1,7 @@
 <html>
 <head>
 <script src="../htmlrunner.js"></script>
-<script src="http://ajax.googleapis.com/ajax/libs/dojo/1.6.1/dojo/dojo.xd.js"></script>
+<script src="../lib/dojo-1.6.1.js"></script>
 <script>
 window.onload = function(){
 startTest("cssquery-dojo", 'a8cfcc7a');
index 60bba7a..357153a 100644 (file)
@@ -1,7 +1,7 @@
 <html>
 <head>
 <script src="../htmlrunner.js"></script>
-<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.6.4/jquery.min.js"></script>
+<script src="../lib/jquery-1.6.4.js"></script>
 <script>
 window.onload = function(){
 startTest("cssquery-jquery", '7704c451');
diff --git a/PerformanceTests/Dromaeo/resources/dromaeo/web/tests/cssquery-mootools.html b/PerformanceTests/Dromaeo/resources/dromaeo/web/tests/cssquery-mootools.html
deleted file mode 100644 (file)
index 4820e7d..0000000
+++ /dev/null
@@ -1,3062 +0,0 @@
-<html>
-<head>
-<script src="../htmlrunner.js"></script>
-<script src="https://ajax.googleapis.com/ajax/libs/mootools/1.4.1/mootools-yui-compressed.js"></script>
-<script>
-window.onload = function(){
-startTest("cssquery-mootools", 'afe5c623');
-
-// Try to force real results
-var ret, tmp;
-
-var html = document.body.innerHTML;
-
-       prep(function(){
-               var div = document.createElement("div");
-               div.innerHTML = html;
-               document.body.appendChild( div );
-       });
-
-       test("Mootools - *", function(){
-               $$("*");
-       });
-
-       test("Mootools - div:only-child", function(){
-               $$("div:only-child");
-       });
-
-       test("Mootools - div:first-child", function(){
-               $$("div:first-child");
-       });
-
-       test("Mootools - div:nth-child(even)", function(){
-               $$("div:nth-child(even)");
-       });
-
-       test("Mootools - div:nth-child(2n)", function(){
-               $$("div:nth-child(2n)");
-       });
-
-       test("Mootools - div:nth-child(odd)", function(){
-               $$("div:nth-child(odd)");
-       });
-
-       test("Mootools - div:nth-child(2n+1)", function(){
-               $$("div:nth-child(2n+1)");
-       });
-
-       test("Mootools - div:nth-child(n)", function(){
-               $$("div:nth-child(n)");
-       });
-
-       test("Mootools - div:last-child", function(){
-               $$("div:last-child");
-       });
-
-       test("Mootools - div > div", function(){
-               $$("div > div");
-       });
-
-       test("Mootools - div + div", function(){
-               $$("div + div");
-       });
-
-       test("Mootools - div ~ div", function(){
-               $$("div ~ div");
-       });
-
-       test("Mootools - body", function(){
-               $$("body");
-       });
-
-       test("Mootools - body div", function(){
-               $$("body div");
-       });
-
-       test("Mootools - div", function(){
-               $$("div");
-       });
-
-       test("Mootools - div div", function(){
-               $$("div div");
-       });
-
-       test("Mootools - div div div", function(){
-               $$("div div div");
-       });
-
-       test("Mootools - div, div, div", function(){
-               $$("div, div, div");
-       });
-
-       test("Mootools - div, a, span", function(){
-               $$("div, a, span");
-       });
-
-       test("Mootools - .dialog", function(){
-               $$(".dialog");
-       });
-
-       test("Mootools - div.dialog", function(){
-               $$("div.dialog");
-       });
-
-       test("Mootools - div .dialog", function(){
-               $$("div .dialog");
-       });
-
-       test("Mootools - div.character, div.dialog", function(){
-               $$("div.character, div.dialog");
-       });
-
-       test("Mootools - #speech5", function(){
-               $$("#speech5");
-       });
-
-       test("Mootools - div#speech5", function(){
-               $$("div#speech5");
-       });
-
-       test("Mootools - div #speech5", function(){
-               $$("div #speech5");
-       });
-
-       test("Mootools - div.scene div.dialog", function(){
-               $$("div.scene div.dialog");
-       });
-
-       test("Mootools - div#scene1 div.dialog div", function(){
-               $$("div#scene1 div.dialog div");
-       });
-
-       test("Mootools - #scene1 #speech1", function(){
-               $$("#scene1 #speech1");
-       });
-
-       test("Mootools - div[class]", function(){
-               $$("div[class]");
-       });
-
-       test("Mootools - div[class=dialog]", function(){
-               $$("div[class=dialog]");
-       });
-
-       test("Mootools - div[class^=dia]", function(){
-               $$("div[class^=dia]");
-       });
-
-       test("Mootools - div[class$=log]", function(){
-               $$("div[class$=log]");
-       });
-
-       test("Mootools - div[class*=sce]", function(){
-               $$("div[class*=sce]");
-       });
-
-       test("Mootools - div[class|=dialog]", function(){
-               $$("div[class|=dialog]");
-       });
-
-       test("Mootools - div[class~=dialog]", function(){
-               $$("div[class~=dialog]");
-       });
-
-endTest();
-};
-</script>
-</head>
-<body>
-  <div class="head">
-   <p><a href="http://www.w3.org/"><img height=48 alt=W3C src="72px.png" width=72></a>
-
-   <h1 id="title">Selectors</h1>
-
-   <h2>W3C Working Draft 15 December 2005</h2>
-
-   <dl>
-
-    <dt>This version:
-
-    <dd><a href="http://www.w3.org/TR/2005/WD-css3-selectors-20051215">
-                 http://www.w3.org/TR/2005/WD-css3-selectors-20051215</a>
-
-    <dt>Latest version:
-
-    <dd><a href="http://www.w3.org/TR/css3-selectors">
-                 http://www.w3.org/TR/css3-selectors</a>
-
-    <dt>Previous version:
-
-    <dd><a href="http://www.w3.org/TR/2001/CR-css3-selectors-20011113">
-                 http://www.w3.org/TR/2001/CR-css3-selectors-20011113</a>
-
-    <dt><a name=editors-list></a>Editors:
-
-    <dd class="vcard"><span class="fn">Daniel Glazman</span> (Invited Expert)</dd>
-
-    <dd class="vcard"><a lang="tr" class="url fn" href="http://www.tantek.com/">Tantek &Ccedil;elik</a> (Invited Expert)
-
-    <dd class="vcard"><a href="mailto:ian@hixie.ch" class="url fn">Ian Hickson</a> (<span
-    class="company"><a href="http://www.google.com/">Google</a></span>)
-
-    <dd class="vcard"><span class="fn">Peter Linss</span> (former editor, <span class="company"><a
-    href="http://www.netscape.com/">Netscape/AOL</a></span>)
-
-    <dd class="vcard"><span class="fn">John Williams</span> (former editor, <span class="company"><a
-    href="http://www.quark.com/">Quark, Inc.</a></span>)
-
-   </dl>
-
-   <p class="copyright"><a
-   href="http://www.w3.org/Consortium/Legal/ipr-notice#Copyright">
-   Copyright</a> &copy; 2005 <a href="http://www.w3.org/"><abbr
-   title="World Wide Web Consortium">W3C</abbr></a><sup>&reg;</sup>
-   (<a href="http://www.csail.mit.edu/"><abbr title="Massachusetts
-   Institute of Technology">MIT</abbr></a>, <a
-   href="http://www.ercim.org/"><acronym title="European Research
-   Consortium for Informatics and Mathematics">ERCIM</acronym></a>, <a
-   href="http://www.keio.ac.jp/">Keio</a>), All Rights Reserved.  W3C
-   <a
-   href="http://www.w3.org/Consortium/Legal/ipr-notice#Legal_Disclaimer">liability</a>,
-   <a
-   href="http://www.w3.org/Consortium/Legal/ipr-notice#W3C_Trademarks">trademark</a>,
-   <a
-   href="http://www.w3.org/Consortium/Legal/copyright-documents">document
-   use</a> rules apply.
-
-   <hr title="Separator for header">
-
-  </div>
-
-  <h2><a name=abstract></a>Abstract</h2>
-
-  <p><em>Selectors</em> are patterns that match against elements in a
-  tree. Selectors have been optimized for use with HTML and XML, and
-  are designed to be usable in performance-critical code.</p>
-
-  <p><acronym title="Cascading Style Sheets">CSS</acronym> (Cascading
-  Style Sheets) is a language for describing the rendering of <acronym
-  title="Hypertext Markup Language">HTML</acronym> and <acronym
-  title="Extensible Markup Language">XML</acronym> documents on
-  screen, on paper, in speech, etc. CSS uses Selectors for binding
-  style properties to elements in the document. This document
-  describes extensions to the selectors defined in CSS level 2. These
-  extended selectors will be used by CSS level 3.
-
-  <p>Selectors define the following function:</p>
-
-  <pre>expression &#x2217; element &rarr; boolean</pre>
-
-  <p>That is, given an element and a selector, this specification
-  defines whether that element matches the selector.</p>
-
-  <p>These expressions can also be used, for instance, to select a set
-  of elements, or a single element from a set of elements, by
-  evaluating the expression across all the elements in a
-  subtree. <acronym title="Simple Tree Transformation
-  Sheets">STTS</acronym> (Simple Tree Transformation Sheets), a
-  language for transforming XML trees, uses this mechanism. <a href="#refsSTTS">[STTS]</a></p>
-
-  <h2><a name=status></a>Status of this document</h2>
-
-  <p><em>This section describes the status of this document at the
-  time of its publication. Other documents may supersede this
-  document. A list of current W3C publications and the latest revision
-  of this technical report can be found in the <a
-  href="http://www.w3.org/TR/">W3C technical reports index at
-  http://www.w3.org/TR/.</a></em></p>
-
-  <p>This document describes the selectors that already exist in <a
-  href="#refsCSS1"><abbr title="CSS level 1">CSS1</abbr></a> and <a
-  href="#refsCSS21"><abbr title="CSS level 2">CSS2</abbr></a>, and
-  also proposes new selectors for <abbr title="CSS level
-  3">CSS3</abbr> and other languages that may need them.</p>
-
-  <p>The CSS Working Group doesn't expect that all implementations of
-  CSS3 will have to implement all selectors. Instead, there will
-  probably be a small number of variants of CSS3, called profiles. For
-  example, it may be that only a profile for interactive user agents
-  will include all of the selectors.</p>
-
-  <p>This specification is a last call working draft for the the <a
-  href="http://www.w3.org/Style/CSS/members">CSS Working Group</a>
-  (<a href="/Style/">Style Activity</a>). This
-  document is a revision of the <a
-  href="http://www.w3.org/TR/2001/CR-css3-selectors-20011113/">Candidate
-  Recommendation dated 2001 November 13</a>, and has incorporated
-  implementation feedback received in the past few years. It is
-  expected that this last call will proceed straight to Proposed
-  Recommendation stage since it is believed that interoperability will
-  be demonstrable.</p>
-
-  <p>All persons are encouraged to review and implement this
-  specification and return comments to the (<a
-  href="http://lists.w3.org/Archives/Public/www-style/">archived</a>)
-  public mailing list <a
-  href="http://www.w3.org/Mail/Lists.html#www-style">www-style</a>
-  (see <a href="http://www.w3.org/Mail/Request">instructions</a>). W3C
-  Members can also send comments directly to the CSS Working
-  Group.
-  The deadline for comments is 14 January 2006.</p>
-
-  <p>This is still a draft document and may be updated, replaced, or
-  obsoleted by other documents at any time. It is inappropriate to
-  cite a W3C Working Draft as other than &quot;work in progress&quot;.
-
-  <p>This document may be available in <a
-  href="http://www.w3.org/Style/css3-selectors-updates/translations">translation</a>.
-  The English version of this specification is the only normative
-  version.
-
-  <div class="subtoc">
-
-   <h2 id="test10"><a name=contents>Table of contents</a></h2>
-
-   <ul class="toc">
-    <li class="tocline2"><a href="#context">1. Introduction</a>
-     <ul>
-      <li><a href="#dependencies">1.1. Dependencies</a> </li>
-      <li><a href="#terminology">1.2. Terminology</a> </li>
-      <li><a href="#changesFromCSS2">1.3. Changes from CSS2</a> </li>
-     </ul>
-    <li class="tocline2"><a href="#selectors">2. Selectors</a>
-    <li class="tocline2"><a href="#casesens">3. Case sensitivity</a>
-    <li class="tocline2"><a href="#selector-syntax">4. Selector syntax</a>
-    <li class="tocline2"><a href="#grouping">5. Groups of selectors</a>
-    <li class="tocline2"><a href="#simple-selectors">6. Simple selectors</a>
-     <ul class="toc">
-      <li class="tocline3"><a href="#type-selectors">6.1. Type selectors</a>
-       <ul class="toc">
-        <li class="tocline4"><a href="#typenmsp">6.1.1. Type selectors and namespaces</a></li>
-       </ul>
-      <li class="tocline3"><a href="#universal-selector">6.2. Universal selector</a>
-       <ul>
-        <li><a href="#univnmsp">6.2.1. Universal selector and namespaces</a></li>
-       </ul>
-      <li class="tocline3"><a href="#attribute-selectors">6.3. Attribute selectors</a>
-       <ul class="toc">
-        <li class="tocline4"><a href="#attribute-representation">6.3.1. Representation of attributes and attributes values</a>
-        <li><a href="#attribute-substrings">6.3.2. Substring matching attribute selectors</a>
-        <li class="tocline4"><a href="#attrnmsp">6.3.3. Attribute selectors and namespaces</a>
-        <li class="tocline4"><a href="#def-values">6.3.4. Default attribute values in DTDs</a></li>
-       </ul>
-      <li class="tocline3"><a href="#class-html">6.4. Class selectors</a>
-      <li class="tocline3"><a href="#id-selectors">6.5. ID selectors</a>
-      <li class="tocline3"><a href="#pseudo-classes">6.6. Pseudo-classes</a>
-       <ul class="toc">
-        <li class="tocline4"><a href="#dynamic-pseudos">6.6.1. Dynamic pseudo-classes</a>
-        <li class="tocline4"><a href="#target-pseudo">6.6.2. The :target pseudo-class</a>
-        <li class="tocline4"><a href="#lang-pseudo">6.6.3. The :lang() pseudo-class</a>
-        <li class="tocline4"><a href="#UIstates">6.6.4. UI element states pseudo-classes</a>
-        <li class="tocline4"><a href="#structural-pseudos">6.6.5. Structural pseudo-classes</a>
-         <ul>
-          <li><a href="#root-pseudo">:root pseudo-class</a>
-          <li><a href="#nth-child-pseudo">:nth-child() pseudo-class</a>
-          <li><a href="#nth-last-child-pseudo">:nth-last-child()</a>
-          <li><a href="#nth-of-type-pseudo">:nth-of-type() pseudo-class</a>
-          <li><a href="#nth-last-of-type-pseudo">:nth-last-of-type()</a>
-          <li><a href="#first-child-pseudo">:first-child pseudo-class</a>
-          <li><a href="#last-child-pseudo">:last-child pseudo-class</a>
-          <li><a href="#first-of-type-pseudo">:first-of-type pseudo-class</a>
-          <li><a href="#last-of-type-pseudo">:last-of-type pseudo-class</a>
-          <li><a href="#only-child-pseudo">:only-child pseudo-class</a>
-          <li><a href="#only-of-type-pseudo">:only-of-type pseudo-class</a>
-          <li><a href="#empty-pseudo">:empty pseudo-class</a></li>
-         </ul>
-        <li class="tocline4"><a href="#negation">6.6.7. The negation pseudo-class</a></li>
-       </ul>
-      </li>
-     </ul>
-    <li><a href="#pseudo-elements">7. Pseudo-elements</a>
-     <ul>
-      <li><a href="#first-line">7.1. The ::first-line pseudo-element</a>
-      <li><a href="#first-letter">7.2. The ::first-letter pseudo-element</a>
-      <li><a href="#UIfragments">7.3. The ::selection pseudo-element</a>
-      <li><a href="#gen-content">7.4. The ::before and ::after pseudo-elements</a></li>
-     </ul>
-    <li class="tocline2"><a href="#combinators">8. Combinators</a>
-     <ul class="toc">
-      <li class="tocline3"><a href="#descendant-combinators">8.1. Descendant combinators</a>
-      <li class="tocline3"><a href="#child-combinators">8.2. Child combinators</a>
-      <li class="tocline3"><a href="#sibling-combinators">8.3. Sibling combinators</a>
-       <ul class="toc">
-        <li class="tocline4"><a href="#adjacent-sibling-combinators">8.3.1. Adjacent sibling combinator</a>
-        <li class="tocline4"><a href="#general-sibling-combinators">8.3.2. General sibling combinator</a></li>
-       </ul>
-      </li>
-     </ul>
-    <li class="tocline2"><a href="#specificity">9. Calculating a selector's specificity</a>
-    <li class="tocline2"><a href="#w3cselgrammar">10. The grammar of Selectors</a>
-     <ul class="toc">
-      <li class="tocline3"><a href="#grammar">10.1. Grammar</a>
-      <li class="tocline3"><a href="#lex">10.2. Lexical scanner</a></li>
-     </ul>
-    <li class="tocline2"><a href="#downlevel">11. Namespaces and down-level clients</a>
-    <li class="tocline2"><a href="#profiling">12. Profiles</a>
-    <li><a href="#Conformance">13. Conformance and requirements</a>
-    <li><a href="#Tests">14. Tests</a>
-    <li><a href="#ACKS">15. Acknowledgements</a>
-    <li class="tocline2"><a href="#references">16. References</a>
-   </ul>
-
-  </div>
-
-  <h2><a name=context>1. Introduction</a></h2>
-
-  <h3><a name=dependencies></a>1.1. Dependencies</h3>
-
-  <p>Some features of this specification are specific to CSS, or have
-  particular limitations or rules specific to CSS. In this
-  specification, these have been described in terms of CSS2.1. <a
-  href="#refsCSS21">[CSS21]</a></p>
-
-  <h3><a name=terminology></a>1.2. Terminology</h3>
-
-  <p>All of the text of this specification is normative except
-  examples, notes, and sections explicitly marked as
-  non-normative.</p>
-
-  <h3><a name=changesFromCSS2></a>1.3. Changes from CSS2</h3>
-
-  <p><em>This section is non-normative.</em></p>
-
-  <p>The main differences between the selectors in CSS2 and those in
-  Selectors are:
-
-  <ul>
-
-   <li>the list of basic definitions (selector, group of selectors,
-   simple selector, etc.) has been changed; in particular, what was
-   referred to in CSS2 as a simple selector is now called a sequence
-   of simple selectors, and the term "simple selector" is now used for
-   the components of this sequence</li>
-
-   <li>an optional namespace component is now allowed in type element
-   selectors, the universal selector and attribute selectors</li>
-
-   <li>a <a href="#general-sibling-combinators">new combinator</a> has been introduced</li>
-
-   <li>new simple selectors including substring matching attribute
-   selectors, and new pseudo-classes</li>
-
-   <li>new pseudo-elements, and introduction of the "::" convention
-   for pseudo-elements</li>
-
-   <li>the grammar has been rewritten</li>
-
-   <li>profiles to be added to specifications integrating Selectors
-   and defining the set of selectors which is actually supported by
-   each specification</li>
-
-   <li>Selectors are now a CSS3 Module and an independent
-   specification; other specifications can now refer to this document
-   independently of CSS</li>
-
-   <li>the specification now has its own test suite</li>
-
-  </ul>
-
-<h2><a name=selectors></a>2. Selectors</h2>
-
-<p><em>This section is non-normative, as it merely summarizes the
-following sections.</em></p>
-
-<p>A Selector represents a structure. This structure can be used as a
-condition (e.g. in a CSS rule) that determines which elements a
-selector matches in the document tree, or as a flat description of the
-HTML or XML fragment corresponding to that structure.</p>
-
-<p>Selectors may range from simple element names to rich contextual
-representations.</p>
-
-<p>The following table summarizes the Selector syntax:</p>
-
-<table class="selectorsReview">
-  <thead>
-  <tr>
-    <th class="pattern">Pattern</th>
-    <th class="meaning">Meaning</th>
-    <th class="described">Described in section</th>
-    <th class="origin">First defined in CSS level</th></tr>
-  <tbody>
-  <tr>
-    <td class="pattern">*</td>
-    <td class="meaning">any element</td>
-    <td class="described"><a
-      href="#universal-selector">Universal
-      selector</a></td>
-    <td class="origin">2</td></tr>
-  <tr>
-    <td class="pattern">E</td>
-    <td class="meaning">an element of type E</td>
-    <td class="described"><a
-      href="#type-selectors">Type selector</a></td>
-    <td class="origin">1</td></tr>
-  <tr>
-    <td class="pattern">E[foo]</td>
-    <td class="meaning">an E element with a "foo" attribute</td>
-    <td class="described"><a
-      href="#attribute-selectors">Attribute
-      selectors</a></td>
-    <td class="origin">2</td></tr>
-  <tr>
-    <td class="pattern">E[foo="bar"]</td>
-    <td class="meaning">an E element whose "foo" attribute value is exactly
-      equal to "bar"</td>
-    <td class="described"><a
-      href="#attribute-selectors">Attribute
-      selectors</a></td>
-    <td class="origin">2</td></tr>
-  <tr>
-    <td class="pattern">E[foo~="bar"]</td>
-    <td class="meaning">an E element whose "foo" attribute value is a list of
-      space-separated values, one of which is exactly equal to "bar"</td>
-    <td class="described"><a
-      href="#attribute-selectors">Attribute
-      selectors</a></td>
-    <td class="origin">2</td></tr>
-  <tr>
-    <td class="pattern">E[foo^="bar"]</td>
-    <td class="meaning">an E element whose "foo" attribute value begins exactly
-      with the string "bar"</td>
-    <td class="described"><a
-      href="#attribute-selectors">Attribute
-      selectors</a></td>
-    <td class="origin">3</td></tr>
-  <tr>
-    <td class="pattern">E[foo$="bar"]</td>
-    <td class="meaning">an E element whose "foo" attribute value ends exactly
-      with the string "bar"</td>
-    <td class="described"><a
-      href="#attribute-selectors">Attribute
-      selectors</a></td>
-    <td class="origin">3</td></tr>
-  <tr>
-    <td class="pattern">E[foo*="bar"]</td>
-    <td class="meaning">an E element whose "foo" attribute value contains the
-      substring "bar"</td>
-    <td class="described"><a
-      href="#attribute-selectors">Attribute
-      selectors</a></td>
-    <td class="origin">3</td></tr>
-  <tr>
-    <td class="pattern">E[hreflang|="en"]</td>
-    <td class="meaning">an E element whose "hreflang" attribute has a hyphen-separated
-      list of values beginning (from the left) with "en"</td>
-    <td class="described"><a
-      href="#attribute-selectors">Attribute
-      selectors</a></td>
-    <td class="origin">2</td></tr>
-  <tr>
-    <td class="pattern">E:root</td>
-    <td class="meaning">an E element, root of the document</td>
-    <td class="described"><a
-      href="#structural-pseudos">Structural
-      pseudo-classes</a></td>
-    <td class="origin">3</td></tr>
-  <tr>
-    <td class="pattern">E:nth-child(n)</td>
-    <td class="meaning">an E element, the n-th child of its parent</td>
-    <td class="described"><a
-      href="#structural-pseudos">Structural
-      pseudo-classes</a></td>
-    <td class="origin">3</td></tr>
-  <tr>
-    <td class="pattern">E:nth-last-child(n)</td>
-    <td class="meaning">an E element, the n-th child of its parent, counting
-      from the last one</td>
-    <td class="described"><a
-      href="#structural-pseudos">Structural
-      pseudo-classes</a></td>
-    <td class="origin">3</td></tr>
-  <tr>
-    <td class="pattern">E:nth-of-type(n)</td>
-    <td class="meaning">an E element, the n-th sibling of its type</td>
-    <td class="described"><a
-      href="#structural-pseudos">Structural
-      pseudo-classes</a></td>
-    <td class="origin">3</td></tr>
-  <tr>
-    <td class="pattern">E:nth-last-of-type(n)</td>
-    <td class="meaning">an E element, the n-th sibling of its type, counting
-      from the last one</td>
-    <td class="described"><a
-      href="#structural-pseudos">Structural
-      pseudo-classes</a></td>
-    <td class="origin">3</td></tr>
-  <tr>
-    <td class="pattern">E:first-child</td>
-    <td class="meaning">an E element, first child of its parent</td>
-    <td class="described"><a
-      href="#structural-pseudos">Structural
-      pseudo-classes</a></td>
-    <td class="origin">2</td></tr>
-  <tr>
-    <td class="pattern">E:last-child</td>
-    <td class="meaning">an E element, last child of its parent</td>
-    <td class="described"><a
-      href="#structural-pseudos">Structural
-      pseudo-classes</a></td>
-    <td class="origin">3</td></tr>
-  <tr>
-    <td class="pattern">E:first-of-type</td>
-    <td class="meaning">an E element, first sibling of its type</td>
-    <td class="described"><a
-      href="#structural-pseudos">Structural
-      pseudo-classes</a></td>
-    <td class="origin">3</td></tr>
-  <tr>
-    <td class="pattern">E:last-of-type</td>
-    <td class="meaning">an E element, last sibling of its type</td>
-    <td class="described"><a
-      href="#structural-pseudos">Structural
-      pseudo-classes</a></td>
-    <td class="origin">3</td></tr>
-  <tr>
-    <td class="pattern">E:only-child</td>
-    <td class="meaning">an E element, only child of its parent</td>
-    <td class="described"><a
-      href="#structural-pseudos">Structural
-      pseudo-classes</a></td>
-    <td class="origin">3</td></tr>
-  <tr>
-    <td class="pattern">E:only-of-type</td>
-    <td class="meaning">an E element, only sibling of its type</td>
-    <td class="described"><a
-      href="#structural-pseudos">Structural
-      pseudo-classes</a></td>
-    <td class="origin">3</td></tr>
-  <tr>
-    <td class="pattern">E:empty</td>
-    <td class="meaning">an E element that has no children (including text
-    nodes)</td>
-    <td class="described"><a
-      href="#structural-pseudos">Structural
-      pseudo-classes</a></td>
-    <td class="origin">3</td></tr>
-  <tr>
-    <td class="pattern">E:link<br>E:visited</td>
-    <td class="meaning">an E element being the source anchor of a hyperlink of
-      which the target is not yet visited (:link) or already visited
-    (:visited)</td>
-    <td class="described"><a
-      href="#link">The link
-      pseudo-classes</a></td>
-    <td class="origin">1</td></tr>
-  <tr>
-    <td class="pattern">E:active<br>E:hover<br>E:focus</td>
-    <td class="meaning">an E element during certain user actions</td>
-    <td class="described"><a
-      href="#useraction-pseudos">The user
-      action pseudo-classes</a></td>
-    <td class="origin">1 and 2</td></tr>
-  <tr>
-    <td class="pattern">E:target</td>
-    <td class="meaning">an E element being the target of the referring URI</td>
-    <td class="described"><a
-      href="#target-pseudo">The target
-      pseudo-class</a></td>
-    <td class="origin">3</td></tr>
-  <tr>
-    <td class="pattern">E:lang(fr)</td>
-    <td class="meaning">an element of type E in language "fr" (the document
-      language specifies how language is determined)</td>
-    <td class="described"><a
-      href="#lang-pseudo">The :lang()
-      pseudo-class</a></td>
-    <td class="origin">2</td></tr>
-  <tr>
-    <td class="pattern">E:enabled<br>E:disabled</td>
-    <td class="meaning">a user interface element E which is enabled or
-    disabled</td>
-    <td class="described"><a
-      href="#UIstates">The UI element states
-      pseudo-classes</a></td>
-    <td class="origin">3</td></tr>
-  <tr>
-    <td class="pattern">E:checked<!--<br>E:indeterminate--></td>
-    <td class="meaning">a user interface element E which is checked<!-- or in an
-      indeterminate state--> (for instance a radio-button or checkbox)</td>
-    <td class="described"><a
-      href="#UIstates">The UI element states
-      pseudo-classes</a></td>
-    <td class="origin">3</td></tr>
-  <tr>
-    <td class="pattern">E::first-line</td>
-    <td class="meaning">the first formatted line of an E element</td>
-    <td class="described"><a
-      href="#first-line">The ::first-line
-      pseudo-element</a></td>
-    <td class="origin">1</td></tr>
-  <tr>
-    <td class="pattern">E::first-letter</td>
-    <td class="meaning">the first formatted letter of an E element</td>
-    <td class="described"><a
-      href="#first-letter">The ::first-letter
-      pseudo-element</a></td>
-    <td class="origin">1</td></tr>
-  <tr>
-    <td class="pattern">E::selection</td>
-    <td class="meaning">the portion of an E element that is currently
-      selected/highlighted by the user</td>
-    <td class="described"><a
-      href="#UIfragments">The UI element
-      fragments pseudo-elements</a></td>
-    <td class="origin">3</td></tr>
-  <tr>
-    <td class="pattern">E::before</td>
-    <td class="meaning">generated content before an E element</td>
-    <td class="described"><a
-      href="#gen-content">The ::before
-      pseudo-element</a></td>
-    <td class="origin">2</td></tr>
-  <tr>
-    <td class="pattern">E::after</td>
-    <td class="meaning">generated content after an E element</td>
-    <td class="described"><a
-      href="#gen-content">The ::after
-      pseudo-element</a></td>
-    <td class="origin">2</td></tr>
-  <tr>
-    <td class="pattern">E.warning</td>
-    <td class="meaning">an E element whose class is
-"warning" (the document language specifies how class is determined).</td>
-    <td class="described"><a
-      href="#class-html">Class
-    selectors</a></td>
-    <td class="origin">1</td></tr>
-  <tr>
-    <td class="pattern">E#myid</td>
-    <td class="meaning">an E element with ID equal to "myid".</td>
-    <td class="described"><a
-      href="#id-selectors">ID
-    selectors</a></td>
-    <td class="origin">1</td></tr>
-  <tr>
-    <td class="pattern">E:not(s)</td>
-    <td class="meaning">an E element that does not match simple selector s</td>
-    <td class="described"><a
-      href="#negation">Negation
-      pseudo-class</a></td>
-    <td class="origin">3</td></tr>
-  <tr>
-    <td class="pattern">E F</td>
-    <td class="meaning">an F element descendant of an E element</td>
-    <td class="described"><a
-      href="#descendant-combinators">Descendant
-      combinator</a></td>
-    <td class="origin">1</td></tr>
-  <tr>
-    <td class="pattern">E &gt; F</td>
-    <td class="meaning">an F element child of an E element</td>
-    <td class="described"><a
-      href="#child-combinators">Child
-      combinator</a></td>
-    <td class="origin">2</td></tr>
-  <tr>
-    <td class="pattern">E + F</td>
-    <td class="meaning">an F element immediately preceded by an E element</td>
-    <td class="described"><a
-      href="#adjacent-sibling-combinators">Adjacent sibling combinator</a></td>
-    <td class="origin">2</td></tr>
-  <tr>
-    <td class="pattern">E ~ F</td>
-    <td class="meaning">an F element preceded by an E element</td>
-    <td class="described"><a
-      href="#general-sibling-combinators">General sibling combinator</a></td>
-    <td class="origin">3</td></tr></tbody></table>
-
-<p>The meaning of each selector is derived from the table above by
-prepending "matches" to the contents of each cell in the "Meaning"
-column.</p>
-
-<h2><a name=casesens>3. Case sensitivity</a></h2>
-
-<p>The case sensitivity of document language element names, attribute
-names, and attribute values in selectors depends on the document
-language. For example, in HTML, element names are case-insensitive,
-but in XML, they are case-sensitive.</p>
-
-<h2><a name=selector-syntax>4. Selector syntax</a></h2>
-
-<p>A <dfn><a name=selector>selector</a></dfn> is a chain of one
-or more <a href="#sequence">sequences of simple selectors</a>
-separated by <a href="#combinators">combinators</a>.</p>
-
-<p>A <dfn><a name=sequence>sequence of simple selectors</a></dfn>
-is a chain of <a href="#simple-selectors-dfn">simple selectors</a>
-that are not separated by a <a href="#combinators">combinator</a>. It
-always begins with a <a href="#type-selectors">type selector</a> or a
-<a href="#universal-selector">universal selector</a>. No other type
-selector or universal selector is allowed in the sequence.</p>
-
-<p>A <dfn><a name=simple-selectors-dfn></a><a
-href="#simple-selectors">simple selector</a></dfn> is either a <a
-href="#type-selectors">type selector</a>, <a
-href="#universal-selector">universal selector</a>, <a
-href="#attribute-selectors">attribute selector</a>, <a
-href="#class-html">class selector</a>, <a
-href="#id-selectors">ID selector</a>, <a
-href="#content-selectors">content selector</a>, or <a
-href="#pseudo-classes">pseudo-class</a>. One <a
-href="#pseudo-elements">pseudo-element</a> may be appended to the last
-sequence of simple selectors.</p>
-
-<p><dfn>Combinators</dfn> are: white space, &quot;greater-than
-sign&quot; (U+003E, <code>&gt;</code>), &quot;plus sign&quot; (U+002B,
-<code>+</code>) and &quot;tilde&quot; (U+007E, <code>~</code>).  White
-space may appear between a combinator and the simple selectors around
-it. <a name=whitespace></a>Only the characters "space" (U+0020), "tab"
-(U+0009), "line feed" (U+000A), "carriage return" (U+000D), and "form
-feed" (U+000C) can occur in white space. Other space-like characters,
-such as "em-space" (U+2003) and "ideographic space" (U+3000), are
-never part of white space.</p>
-
-<p>The elements of a document tree that are represented by a selector
-are the <dfn><a name=subject></a>subjects of the selector</dfn>. A
-selector consisting of a single sequence of simple selectors
-represents any element satisfying its requirements. Prepending another
-sequence of simple selectors and a combinator to a sequence imposes
-additional matching constraints, so the subjects of a selector are
-always a subset of the elements represented by the last sequence of
-simple selectors.</p>
-
-<p>An empty selector, containing no sequence of simple selectors and
-no pseudo-element, is an <a href="#Conformance">invalid
-selector</a>.</p>
-
-<h2><a name=grouping>5. Groups of selectors</a></h2>
-
-<p>When several selectors share the same declarations, they may be
-grouped into a comma-separated list. (A comma is U+002C.)</p>
-
-<div class="example">
-<p>CSS examples:</p>
-<p>In this example, we condense three rules with identical
-declarations into one. Thus,</p>
-<pre>h1 { font-family: sans-serif }
-h2 { font-family: sans-serif }
-h3 { font-family: sans-serif }</pre>
-<p>is equivalent to:</p>
-<pre>h1, h2, h3 { font-family: sans-serif }</pre>
-</div>
-
-<p><strong>Warning</strong>: the equivalence is true in this example
-because all the selectors are valid selectors. If just one of these
-selectors were invalid, the entire group of selectors would be
-invalid. This would invalidate the rule for all three heading
-elements, whereas in the former case only one of the three individual
-heading rules would be invalidated.</p>
-
-
-<h2><a name=simple-selectors>6. Simple selectors</a></h2>
-
-<h3><a name=type-selectors>6.1. Type selector</a></h3>
-
-<p>A <dfn>type selector</dfn> is the name of a document language
-element type. A type selector represents an instance of the element
-type in the document tree.</p>
-
-<div class="example">
- <p>Example:</p>
- <p>The following selector represents an <code>h1</code> element in the document tree:</p>
- <pre>h1</pre>
-</div>
-
-
-<h4><a name=typenmsp>6.1.1. Type selectors and namespaces</a></h4>
-
-<p>Type selectors allow an optional namespace (<a
-href="#refsXMLNAMES">[XMLNAMES]</a>) component. A namespace prefix
-that has been previously declared may be prepended to the element name
-separated by the namespace separator &quot;vertical bar&quot;
-(U+007C, <code>|</code>).</p>
-
-<p>The namespace component may be left empty to indicate that the
-selector is only to represent elements with no declared namespace.</p>
-
-<p>An asterisk may be used for the namespace prefix, indicating that
-the selector represents elements in any namespace (including elements
-with no namespace).</p>
-
-<p>Element type selectors that have no namespace component (no
-namespace separator), represent elements without regard to the
-element's namespace (equivalent to "<code>*|</code>") unless a default
-namespace has been declared. If a default namespace has been declared,
-the selector will represent only elements in the default
-namespace.</p>
-
-<p>A type selector containing a namespace prefix that has not been
-previously declared is an <a href="#Conformance">invalid</a> selector.
-The mechanism for declaring a namespace prefix is left up to the
-language implementing Selectors. In CSS, such a mechanism is defined
-in the General Syntax module.</p>
-
-<p>In a namespace-aware client, element type selectors will only match
-against the <a
-href="http://www.w3.org/TR/REC-xml-names/#NT-LocalPart">local part</a>
-of the element's <a
-href="http://www.w3.org/TR/REC-xml-names/#ns-qualnames">qualified
-name</a>. See <a href="#downlevel">below</a> for notes about matching
-behaviors in down-level clients.</p>
-
-<p>In summary:</p>
-
-<dl>
-  <dt><code>ns|E</code></dt>
-  <dd>elements with name E in namespace ns</dd>
-  <dt><code>*|E</code></dt>
-  <dd>elements with name E in any namespace, including those without any
-  declared namespace</dd>
-  <dt><code>|E</code></dt>
-  <dd>elements with name E without any declared namespace</dd>
-  <dt><code>E</code></dt>
-  <dd>if no default namespace has been specified, this is equivalent to *|E.
-  Otherwise it is equivalent to ns|E where ns is the default namespace.</dd>
-</dl>
-
-<div class="example">
- <p>CSS examples:</p>
-
- <pre>@namespace foo url(http://www.example.com);
- foo|h1 { color: blue }
- foo|* { color: yellow }
- |h1 { color: red }
- *|h1 { color: green }
- h1 { color: green }</pre>
-
- <p>The first rule will match only <code>h1</code> elements in the
- "http://www.example.com" namespace.</p>
-
- <p>The second rule will match all elements in the
- "http://www.example.com" namespace.</p>
-
- <p>The third rule will match only <code>h1</code> elements without
- any declared namespace.</p>
-
- <p>The fourth rule will match <code>h1</code> elements in any
- namespace (including those without any declared namespace).</p>
-
- <p>The last rule is equivalent to the fourth rule because no default
- namespace has been defined.</p>
-
-</div>
-
-<h3><a name=universal-selector>6.2. Universal selector</a> </h3>
-
-<p>The <dfn>universal selector</dfn>, written &quot;asterisk&quot;
-(<code>*</code>), represents the qualified name of any element
-type. It represents any single element in the document tree in any
-namespace (including those without any declared namespace) if no
-default namespace has been specified. If a default namespace has been
-specified, see <a href="#univnmsp">Universal selector and
-Namespaces</a> below.</p>
-
-<p>If the universal selector is not the only component of a sequence
-of simple selectors, the <code>*</code> may be omitted.</p>
-
-<div class="example">
- <p>Examples:</p>
- <ul>
-  <li><code>*[hreflang|=en]</code> and <code>[hreflang|=en]</code> are equivalent,</li>
-  <li><code>*.warning</code> and <code>.warning</code> are equivalent,</li>
-  <li><code>*#myid</code> and <code>#myid</code> are equivalent.</li>
- </ul>
-</div>
-
-<p class="note"><strong>Note:</strong> it is recommended that the
-<code>*</code>, representing the universal selector, not be
-omitted.</p>
-
-<h4><a name=univnmsp>6.2.1. Universal selector and namespaces</a></h4>
-
-<p>The universal selector allows an optional namespace component. It
-is used as follows:</p>
-
-<dl>
- <dt><code>ns|*</code></dt>
- <dd>all elements in namespace ns</dd>
- <dt><code>*|*</code></dt>
- <dd>all elements</dd>
- <dt><code>|*</code></dt>
- <dd>all elements without any declared namespace</dd>
- <dt><code>*</code></dt>
- <dd>if no default namespace has been specified, this is equivalent to *|*.
- Otherwise it is equivalent to ns|* where ns is the default namespace.</dd>
-</dl>
-
-<p>A universal selector containing a namespace prefix that has not
-been previously declared is an <a href="#Conformance">invalid</a>
-selector.  The mechanism for declaring a namespace prefix is left up
-to the language implementing Selectors.  In CSS, such a mechanism is
-defined in the General Syntax module.</p>
-
-
-<h3><a name=attribute-selectors>6.3. Attribute selectors</a></h3>
-
-<p>Selectors allow the representation of an element's attributes. When
-a selector is used as an expression to match against an element,
-attribute selectors must be considered to match an element if that
-element has an attribute that matches the attribute represented by the
-attribute selector.</p>
-
-<h4><a name=attribute-representation>6.3.1. Attribute presence and values
-selectors</a></h4>
-
-<p>CSS2 introduced four attribute selectors:</p>
-
-<dl>
-  <dt><code>[att]</code>
-  <dd>Represents an element with the <code>att</code> attribute, whatever the value of
-  the attribute.</dd>
-  <dt><code>[att=val]</code></dt>
-  <dd>Represents an element with the <code>att</code> attribute whose value is exactly
-  "val".</dd>
-  <dt><code>[att~=val]</code></dt>
-  <dd>Represents an element with the <code>att</code> attribute whose value is a <a
-  href="#whitespace">whitespace</a>-separated list of words, one of
-  which is exactly "val". If "val" contains whitespace, it will never
-  represent anything (since the words are <em>separated</em> by
-  spaces).</dd>
-  <dt><code>[att|=val]</code>
-  <dd>Represents an element with the <code>att</code> attribute, its value either
-  being exactly "val" or beginning with "val" immediately followed by
-  "-" (U+002D).  This is primarily intended to allow language subcode
-  matches (e.g., the <code>hreflang</code> attribute on the
-  <code>link</code> element in HTML) as described in RFC 3066 (<a
-  href="#refsRFC3066">[RFC3066]</a>).  For <code>lang</code> (or
-  <code>xml:lang</code>) language subcode matching, please see <a
-  href="#lang-pseudo">the <code>:lang</code> pseudo-class</a>.</dd>
-</dl>
-
-<p>Attribute values must be identifiers or strings. The
-case-sensitivity of attribute names and values in selectors depends on
-the document language.</p>
-
-<div class="example">
-
-  <p>Examples:</p>
-
-  <p>The following attribute selector represents an <code>h1</code>
-  element that carries the <code>title</code> attribute, whatever its
-  value:</p>
-
-  <pre>h1[title]</pre>
-
-  <p>In the following example, the selector represents a
-  <code>span</code> element whose <code>class</code> attribute has
-  exactly the value "example":</p>
-
-  <pre>span[class="example"]</pre>
-
-  <p>Multiple attribute selectors can be used to represent several
-  attributes of an element, or several conditions on the same
-  attribute. Here, the selector represents a <code>span</code> element
-  whose <code>hello</code> attribute has exactly the value "Cleveland"
-  and whose <code>goodbye</code> attribute has exactly the value
-  "Columbus":</p>
-
-  <pre>span[hello="Cleveland"][goodbye="Columbus"]</pre>
-
-  <p>The following selectors illustrate the differences between "="
-  and "~=".  The first selector will represent, for example, the value
-  "copyright copyleft copyeditor" on a <code>rel</code> attribute. The
-  second selector will only represent an <code>a</code> element with
-  an <code>href</code> attribute having the exact value
-  "http://www.w3.org/".</p>
-
-  <pre>a[rel~="copyright"]
-a[href="http://www.w3.org/"]</pre>
-
-  <p>The following selector represents a <code>link</code> element
-  whose <code>hreflang</code> attribute is exactly "fr".</p>
-
-  <pre>link[hreflang=fr]</pre>
-
-  <p>The following selector represents a <code>link</code> element for
-  which the values of the <code>hreflang</code> attribute begins with
-  "en", including "en", "en-US", and "en-cockney":</p>
-
-  <pre>link[hreflang|="en"]</pre>
-
-  <p>Similarly, the following selectors represents a
-  <code>DIALOGUE</code> element whenever it has one of two different
-  values for an attribute <code>character</code>:</p>
-
-  <pre>DIALOGUE[character=romeo]
-DIALOGUE[character=juliet]</pre>
-
-</div>
-
-<h4><a name=attribute-substrings></a>6.3.2. Substring matching attribute
-selectors</h4>
-
-<p>Three additional attribute selectors are provided for matching
-substrings in the value of an attribute:</p>
-
-<dl>
-  <dt><code>[att^=val]</code></dt>
-  <dd>Represents an element with the <code>att</code> attribute whose value begins
-  with the prefix "val".</dd>
-  <dt><code>[att$=val]</code>
-  <dd>Represents an element with the <code>att</code> attribute whose value ends with
-  the suffix "val".</dd>
-  <dt><code>[att*=val]</code>
-  <dd>Represents an element with the <code>att</code> attribute whose value contains
-  at least one instance of the substring "val".</dd>
-</dl>
-
-<p>Attribute values must be identifiers or strings. The
-case-sensitivity of attribute names in selectors depends on the
-document language.</p>
-
-<div class="example">
- <p>Examples:</p>
- <p>The following selector represents an HTML <code>object</code>, referencing an
- image:</p>
- <pre>object[type^="image/"]</pre>
- <p>The following selector represents an HTML anchor <code>a</code> with an
- <code>href</code> attribute whose value ends with ".html".</p>
- <pre>a[href$=".html"]</pre>
- <p>The following selector represents an HTML paragraph with a <code>title</code>
- attribute whose value contains the substring "hello"</p>
- <pre>p[title*="hello"]</pre>
-</div>
-
-<h4><a name=attrnmsp>6.3.3. Attribute selectors and namespaces</a></h4>
-
-<p>Attribute selectors allow an optional namespace component to the
-attribute name. A namespace prefix that has been previously declared
-may be prepended to the attribute name separated by the namespace
-separator &quot;vertical bar&quot; (<code>|</code>). In keeping with
-the Namespaces in the XML recommendation, default namespaces do not
-apply to attributes, therefore attribute selectors without a namespace
-component apply only to attributes that have no declared namespace
-(equivalent to "<code>|attr</code>"). An asterisk may be used for the
-namespace prefix indicating that the selector is to match all
-attribute names without regard to the attribute's namespace.
-
-<p>An attribute selector with an attribute name containing a namespace
-prefix that has not been previously declared is an <a
-href="#Conformance">invalid</a> selector.  The mechanism for declaring
-a namespace prefix is left up to the language implementing Selectors.
-In CSS, such a mechanism is defined in the General Syntax module.
-
-<div class="example">
-  <p>CSS examples:</p>
-  <pre>@namespace foo "http://www.example.com";
-[foo|att=val] { color: blue }
-[*|att] { color: yellow }
-[|att] { color: green }
-[att] { color: green }</pre>
-
-  <p>The first rule will match only elements with the attribute
-  <code>att</code> in the "http://www.example.com" namespace with the
-  value "val".</p>
-
-  <p>The second rule will match only elements with the attribute
-  <code>att</code> regardless of the namespace of the attribute
-  (including no declared namespace).</p>
-
-  <p>The last two rules are equivalent and will match only elements
-  with the attribute <code>att</code> where the attribute is not
-  declared to be in a namespace.</p>
-
-</div>
-
-<h4><a name=def-values>6.3.4. Default attribute values in DTDs</a></h4>
-
-<p>Attribute selectors represent explicitly set attribute values in
-the document tree. Default attribute values may be defined in a DTD or
-elsewhere, but cannot always be selected by attribute
-selectors. Selectors should be designed so that they work even if the
-default values are not included in the document tree.</p>
-
-<p>More precisely, a UA is <em>not</em> required to read an "external
-subset" of the DTD but <em>is</em> required to look for default
-attribute values in the document's "internal subset." (See <a
-href="#refsXML10">[XML10]</a> for definitions of these subsets.)</p>
-
-<p>A UA that recognizes an XML namespace <a
-href="#refsXMLNAMES">[XMLNAMES]</a> is not required to use its
-knowledge of that namespace to treat default attribute values as if
-they were present in the document. (For example, an XHTML UA is not
-required to use its built-in knowledge of the XHTML DTD.)</p>
-
-<p class="note"><strong>Note:</strong> Typically, implementations
-choose to ignore external subsets.</p>
-
-<div class="example">
-<p>Example:</p>
-
-<p>Consider an element EXAMPLE with an attribute "notation" that has a
-default value of "decimal". The DTD fragment might be</p>
-
-<pre class="dtd-example">&lt;!ATTLIST EXAMPLE notation (decimal,octal) "decimal"></pre>
-
-<p>If the style sheet contains the rules</p>
-
-<pre>EXAMPLE[notation=decimal] { /*... default property settings ...*/ }
-EXAMPLE[notation=octal]   { /*... other settings...*/ }</pre>
-
-<p>the first rule will not match elements whose "notation" attribute
-is set by default, i.e. not set explicitly. To catch all cases, the
-attribute selector for the default value must be dropped:</p>
-
-<pre>EXAMPLE                   { /*... default property settings ...*/ }
-EXAMPLE[notation=octal]   { /*... other settings...*/ }</pre>
-
-<p>Here, because the selector <code>EXAMPLE[notation=octal]</code> is
-more specific than the tag
-selector alone, the style declarations in the second rule will override
-those in the first for elements that have a "notation" attribute value
-of "octal". Care has to be taken that all property declarations that
-are to apply only to the default case are overridden in the non-default
-cases' style rules.</p>
-
-</div>
-
-<h3><a name=class-html>6.4. Class selectors</a></h3>
-
-<p>Working with HTML, authors may use the period (U+002E,
-<code>.</code>) notation as an alternative to the <code>~=</code>
-notation when representing the <code>class</code> attribute. Thus, for
-HTML, <code>div.value</code> and <code>div[class~=value]</code> have
-the same meaning. The attribute value must immediately follow the
-&quot;period&quot; (<code>.</code>).</p>
-
-<p>UAs may apply selectors using the period (.) notation in XML
-documents if the UA has namespace-specific knowledge that allows it to
-determine which attribute is the &quot;class&quot; attribute for the
-respective namespace. One such example of namespace-specific knowledge
-is the prose in the specification for a particular namespace (e.g. SVG
-1.0 <a href="#refsSVG">[SVG]</a> describes the <a
-href="http://www.w3.org/TR/2001/PR-SVG-20010719/styling.html#ClassAttribute">SVG
-&quot;class&quot; attribute</a> and how a UA should interpret it, and
-similarly MathML 1.01 <a href="#refsMATH">[MATH]</a> describes the <a
-href="http://www.w3.org/1999/07/REC-MathML-19990707/chapter2.html#sec2.3.4">MathML
-&quot;class&quot; attribute</a>.)</p>
-
-<div class="example">
- <p>CSS examples:</p>
-
- <p>We can assign style information to all elements with
- <code>class~="pastoral"</code> as follows:</p>
-
-  <pre>*.pastoral { color: green }  /* all elements with class~=pastoral */</pre>
-
-  <p>or just</p>
-
-  <pre>.pastoral { color: green }  /* all elements with class~=pastoral */</pre>
-
-  <p>The following assigns style only to H1 elements with
-  <code>class~="pastoral"</code>:</p>
-
-  <pre>H1.pastoral { color: green }  /* H1 elements with class~=pastoral */</pre>
-
-  <p>Given these rules, the first H1 instance below would not have
-  green text, while the second would:</p>
-
-  <pre>&lt;H1&gt;Not green&lt;/H1&gt;
-&lt;H1 class="pastoral"&gt;Very green&lt;/H1&gt;</pre>
-
-</div>
-
-<p>To represent a subset of "class" values, each value must be preceded
-by a ".", in any order.</P>
-
-<div class="example">
-
-  <p>CSS example:</p>
-
-  <p>The following rule matches any P element whose "class" attribute
-  has been assigned a list of <a
-  href="#whitespace">whitespace</a>-separated values that includes
-  "pastoral" and "marine":</p>
-
-  <pre>p.pastoral.marine { color: green }</pre>
-
-  <p>This rule matches when <code>class="pastoral blue aqua
-  marine"</code> but does not match for <code>class="pastoral
-  blue"</code>.</p>
-
-</div>
-
-<p class="note"><strong>Note:</strong> Because CSS gives considerable
-power to the "class" attribute, authors could conceivably design their
-own "document language" based on elements with almost no associated
-presentation (such as DIV and SPAN in HTML) and assigning style
-information through the "class" attribute.  Authors should avoid this
-practice since the structural elements of a document language often
-have recognized and accepted meanings and author-defined classes may
-not.</p>
-
-<p class="note"><strong>Note:</strong> If an element has multiple
-class attributes, their values must be concatenated with spaces
-between the values before searching for the class. As of this time the
-working group is not aware of any manner in which this situation can
-be reached, however, so this behavior is explicitly non-normative in
-this specification.</p>
-
-<h3><a name=id-selectors>6.5. ID selectors</a></h3>
-
-<p>Document languages may contain attributes that are declared to be
-of type ID. What makes attributes of type ID special is that no two
-such attributes can have the same value in a document, regardless of
-the type of the elements that carry them; whatever the document
-language, an ID typed attribute can be used to uniquely identify its
-element. In HTML all ID attributes are named "id"; XML applications
-may name ID attributes differently, but the same restriction
-applies.</p>
-
-<p>An ID-typed attribute of a document language allows authors to
-assign an identifier to one element instance in the document tree. W3C
-ID selectors represent an element instance based on its identifier. An
-ID selector contains a &quot;number sign&quot; (U+0023,
-<code>#</code>) immediately followed by the ID value, which must be an
-identifier.</p>
-
-<p>Selectors does not specify how a UA knows the ID-typed attribute of
-an element. The UA may, e.g., read a document's DTD, have the
-information hard-coded or ask the user.
-
-<div class="example">
-  <p>Examples:</p>
-  <p>The following ID selector represents an <code>h1</code> element
-  whose ID-typed attribute has the value "chapter1":</p>
-  <pre>h1#chapter1</pre>
-  <p>The following ID selector represents any element whose ID-typed
-  attribute has the value "chapter1":</p>
-  <pre>#chapter1</pre>
-  <p>The following selector represents any element whose ID-typed
-  attribute has the value "z98y".</p>
-  <pre>*#z98y</pre>
-</div>
-
-<p class="note"><strong>Note.</strong> In XML 1.0 <a
-href="#refsXML10">[XML10]</a>, the information about which attribute
-contains an element's IDs is contained in a DTD or a schema. When
-parsing XML, UAs do not always read the DTD, and thus may not know
-what the ID of an element is (though a UA may have namespace-specific
-knowledge that allows it to determine which attribute is the ID
-attribute for that namespace). If a style sheet designer knows or
-suspects that a UA may not know what the ID of an element is, he
-should use normal attribute selectors instead:
-<code>[name=p371]</code> instead of <code>#p371</code>.  Elements in
-XML 1.0 documents without a DTD do not have IDs at all.</p>
-
-<p>If an element has multiple ID attributes, all of them must be
-treated as IDs for that element for the purposes of the ID
-selector. Such a situation could be reached using mixtures of xml:id,
-DOM3 Core, XML DTDs, and namespace-specific knowledge.</p>
-
-<h3><a name=pseudo-classes>6.6. Pseudo-classes</a></h3>
-
-<p>The pseudo-class concept is introduced to permit selection based on
-information that lies outside of the document tree or that cannot be
-expressed using the other simple selectors.</p>
-
-<p>A pseudo-class always consists of a &quot;colon&quot;
-(<code>:</code>) followed by the name of the pseudo-class and
-optionally by a value between parentheses.</p>
-
-<p>Pseudo-classes are allowed in all sequences of simple selectors
-contained in a selector. Pseudo-classes are allowed anywhere in
-sequences of simple selectors, after the leading type selector or
-universal selector (possibly omitted). Pseudo-class names are
-case-insensitive. Some pseudo-classes are mutually exclusive, while
-others can be applied simultaneously to the same
-element. Pseudo-classes may be dynamic, in the sense that an element
-may acquire or lose a pseudo-class while a user interacts with the
-document.</p>
-
-
-<h4><a name=dynamic-pseudos>6.6.1. Dynamic pseudo-classes</a></h4>
-
-<p>Dynamic pseudo-classes classify elements on characteristics other
-than their name, attributes, or content, in principle characteristics
-that cannot be deduced from the document tree.</p>
-
-<p>Dynamic pseudo-classes do not appear in the document source or
-document tree.</p>
-
-
-<h5>The <a name=link>link pseudo-classes: :link and :visited</a></h5>
-
-<p>User agents commonly display unvisited links differently from
-previously visited ones. Selectors
-provides the pseudo-classes <code>:link</code> and
-<code>:visited</code> to distinguish them:</p>
-
-<ul>
-  <li>The <code>:link</code> pseudo-class applies to links that have
-  not yet been visited.</li>
-  <li>The <code>:visited</code> pseudo-class applies once the link has
-  been visited by the user. </li>
-</ul>
-
-<p>After some amount of time, user agents may choose to return a
-visited link to the (unvisited) ':link' state.</p>
-
-<p>The two states are mutually exclusive.</p>
-
-<div class="example">
-
-  <p>Example:</p>
-
-  <p>The following selector represents links carrying class
-  <code>external</code> and already visited:</p>
-
-  <pre>a.external:visited</pre>
-
-</div>
-
-<p class="note"><strong>Note:</strong> It is possible for style sheet
-authors to abuse the :link and :visited pseudo-classes to determine
-which sites a user has visited without the user's consent.
-
-<p>UAs may therefore treat all links as unvisited links, or implement
-other measures to preserve the user's privacy while rendering visited
-and unvisited links differently.</p>
-
-<h5>The <a name=useraction-pseudos>user action pseudo-classes
-:hover, :active, and :focus</a></h5>
-
-<p>Interactive user agents sometimes change the rendering in response
-to user actions. Selectors provides
-three pseudo-classes for the selection of an element the user is
-acting on.</p>
-
-<ul>
-
-  <li>The <code>:hover</code> pseudo-class applies while the user
-  designates an element with a pointing device, but does not activate
-  it. For example, a visual user agent could apply this pseudo-class
-  when the cursor (mouse pointer) hovers over a box generated by the
-  element. User agents not that do not support <a
-  href="http://www.w3.org/TR/REC-CSS2/media.html#interactive-media-group">interactive
-  media</a> do not have to support this pseudo-class. Some conforming
-  user agents that support <a
-  href="http://www.w3.org/TR/REC-CSS2/media.html#interactive-media-group">interactive
-  media</a> may not be able to support this pseudo-class (e.g., a pen
-  device that does not detect hovering).</li>
-
-  <li>The <code>:active</code> pseudo-class applies while an element
-  is being activated by the user. For example, between the times the
-  user presses the mouse button and releases it.</li>
-
-  <li>The <code>:focus</code> pseudo-class applies while an element
-  has the focus (accepts keyboard or mouse events, or other forms of
-  input). </li>
-
-</ul>
-
-<p>There may be document language or implementation specific limits on
-which elements can become <code>:active</code> or acquire
-<code>:focus</code>.</p>
-
-<p>These pseudo-classes are not mutually exclusive. An element may
-match several pseudo-classes at the same time.</p>
-
-<p>Selectors doesn't define if the parent of an element that is
-':active' or ':hover' is also in that state.</p>
-
-<div class="example">
-  <p>Examples:</p>
-  <pre>a:link    /* unvisited links */
-a:visited /* visited links */
-a:hover   /* user hovers */
-a:active  /* active links */</pre>
-  <p>An example of combining dynamic pseudo-classes:</p>
-  <pre>a:focus
-a:focus:hover</pre>
-  <p>The last selector matches <code>a</code> elements that are in
-  the pseudo-class :focus and in the pseudo-class :hover.</p>
-</div>
-
-<p class="note"><strong>Note:</strong> An element can be both ':visited'
-and ':active' (or ':link' and ':active').</p>
-
-<h4><a name=target-pseudo>6.6.2. The target pseudo-class :target</a></h4>
-
-<p>Some URIs refer to a location within a resource. This kind of URI
-ends with a &quot;number sign&quot; (#) followed by an anchor
-identifier (called the fragment identifier).</p>
-
-<p>URIs with fragment identifiers link to a certain element within the
-document, known as the target element. For instance, here is a URI
-pointing to an anchor named <code>section_2</code> in an HTML
-document:</p>
-
-<pre>http://example.com/html/top.html#section_2</pre>
-
-<p>A target element can be represented by the <code>:target</code>
-pseudo-class. If the document's URI has no fragment identifier, then
-the document has no target element.</p>
-
-<div class="example">
- <p>Example:</p>
- <pre>p.note:target</pre>
- <p>This selector represents a <code>p</code> element of class
- <code>note</code> that is the target element of the referring
- URI.</p>
-</div>
-
-<div class="example">
- <p>CSS example:</p>
- <p>Here, the <code>:target</code> pseudo-class is used to make the
- target element red and place an image before it, if there is one:</p>
- <pre>*:target { color : red }
-*:target::before { content : url(target.png) }</pre>
-</div>
-
-<h4><a name=lang-pseudo>6.6.3. The language pseudo-class :lang</a></h4>
-
-<p>If the document language specifies how the human language of an
-element is determined, it is possible to write selectors that
-represent an element based on its language. For example, in HTML <a
-href="#refsHTML4">[HTML4]</a>, the language is determined by a
-combination of the <code>lang</code> attribute, the <code>meta</code>
-element, and possibly by information from the protocol (such as HTTP
-headers). XML uses an attribute called <code>xml:lang</code>, and
-there may be other document language-specific methods for determining
-the language.</p>
-
-<p>The pseudo-class <code>:lang(C)</code> represents an element that
-is in language C. Whether an element is represented by a
-<code>:lang()</code> selector is based solely on the identifier C
-being either equal to, or a hyphen-separated substring of, the
-element's language value, in the same way as if performed by the <a
-href="#attribute-representation">'|='</a> operator in attribute
-selectors. The identifier C does not have to be a valid language
-name.</p>
-
-<p>C must not be empty. (If it is, the selector is invalid.)</p>
-
-<p class="note"><strong>Note:</strong> It is recommended that
-documents and protocols indicate language using codes from RFC 3066 <a
-href="#refsRFC3066">[RFC3066]</a> or its successor, and by means of
-"xml:lang" attributes in the case of XML-based documents <a
-href="#refsXML10">[XML10]</a>. See <a
-href="http://www.w3.org/International/questions/qa-lang-2or3.html">
-"FAQ: Two-letter or three-letter language codes."</a></p>
-
-<div class="example">
-  <p>Examples:</p>
-  <p>The two following selectors represent an HTML document that is in
-  Belgian, French, or German. The two next selectors represent
-  <code>q</code> quotations in an arbitrary element in Belgian, French,
-  or German.</p>
-  <pre>html:lang(fr-be)
-html:lang(de)
-:lang(fr-be) &gt; q
-:lang(de) &gt; q</pre>
-</div>
-
-<h4><a name=UIstates>6.6.4. The UI element states pseudo-classes</a></h4>
-
-<h5><a name=enableddisabled>The :enabled and :disabled pseudo-classes</a></h5>
-
-<p>The <code>:enabled</code> pseudo-class allows authors to customize
-the look of user interface elements that are enabled &mdash; which the
-user can select or activate in some fashion (e.g. clicking on a button
-with a mouse).  There is a need for such a pseudo-class because there
-is no way to programmatically specify the default appearance of say,
-an enabled <code>input</code> element without also specifying what it
-would look like when it was disabled.</p>
-
-<p>Similar to <code>:enabled</code>, <code>:disabled</code> allows the
-author to specify precisely how a disabled or inactive user interface
-element should look.</p>
-
-<p>Most elements will be neither enabled nor disabled.  An element is
-enabled if the user can either activate it or transfer the focus to
-it. An element is disabled if it could be enabled, but the user cannot
-presently activate it or transfer focus to it.</p>
-
-
-<h5><a name=checked>The :checked pseudo-class</a></h5>
-
-<p>Radio and checkbox elements can be toggled by the user. Some menu
-items are "checked" when the user selects them. When such elements are
-toggled "on" the <code>:checked</code> pseudo-class applies. The
-<code>:checked</code> pseudo-class initially applies to such elements
-that have the HTML4 <code>selected</code> and <code>checked</code>
-attributes as described in <a
-href="http://www.w3.org/TR/REC-html40/interact/forms.html#h-17.2.1">Section
-17.2.1 of HTML4</a>, but of course the user can toggle "off" such
-elements in which case the <code>:checked</code> pseudo-class would no
-longer apply. While the <code>:checked</code> pseudo-class is dynamic
-in nature, and is altered by user action, since it can also be based
-on the presence of the semantic HTML4 <code>selected</code> and
-<code>checked</code> attributes, it applies to all media.
-
-
-<h5><a name=indeterminate>The :indeterminate pseudo-class</a></h5>
-
-<div class="note">
-
-<p>Radio and checkbox elements can be toggled by the user, but are
-sometimes in an indeterminate state, neither checked nor unchecked.
-This can be due to an element attribute, or DOM manipulation.</p>
-
-<p>A future version of this specification may introduce an
-<code>:indeterminate</code> pseudo-class that applies to such elements.
-<!--While the <code>:indeterminate</code> pseudo-class is dynamic in
-nature, and is altered by user action, since it can also be based on
-the presence of an element attribute, it applies to all media.</p>
-
-<p>Components of a radio-group initialized with no pre-selected choice
-are an example of :indeterminate state.--></p>
-
-</div>
-
-
-<h4><a name=structural-pseudos>6.6.5. Structural pseudo-classes</a></h4>
-
-<p>Selectors introduces the concept of <dfn>structural
-pseudo-classes</dfn> to permit selection based on extra information that lies in
-the document tree but cannot be represented by other simple selectors or
-combinators.
-
-<p>Note that standalone pieces of PCDATA (text nodes in the DOM) are
-not counted when calculating the position of an element in the list of
-children of its parent. When calculating the position of an element in
-the list of children of its parent, the index numbering starts at 1.
-
-
-<h5><a name=root-pseudo>:root pseudo-class</a></h5>
-
-<p>The <code>:root</code> pseudo-class represents an element that is
-the root of the document. In HTML 4, this is always the
-<code>HTML</code> element.
-
-
-<h5><a name=nth-child-pseudo>:nth-child() pseudo-class</a></h5>
-
-<p>The
-<code>:nth-child(<var>a</var><code>n</code>+<var>b</var>)</code>
-pseudo-class notation represents an element that has
-<var>a</var><code>n</code>+<var>b</var>-1 siblings
-<strong>before</strong> it in the document tree, for a given positive
-integer or zero value of <code>n</code>, and has a parent element. In
-other words, this matches the <var>b</var>th child of an element after
-all the children have been split into groups of <var>a</var> elements
-each. For example, this allows the selectors to address every other
-row in a table, and could be used to alternate the color
-of paragraph text in a cycle of four. The <var>a</var> and
-<var>b</var> values must be zero, negative integers or positive
-integers. The index of the first child of an element is 1.
-
-<p>In addition to this, <code>:nth-child()</code> can take
-'<code>odd</code>' and '<code>even</code>' as arguments instead.
-'<code>odd</code>' has the same signification as <code>2n+1</code>,
-and '<code>even</code>' has the same signification as <code>2n</code>.
-
-
-<div class="example">
-<p>Examples:</p>
-<pre>tr:nth-child(2n+1) /* represents every odd row of an HTML table */
-tr:nth-child(odd)  /* same */
-tr:nth-child(2n)   /* represents every even row of an HTML table */
-tr:nth-child(even) /* same */
-
-/* Alternate paragraph colours in CSS */
-p:nth-child(4n+1) { color: navy; }
-p:nth-child(4n+2) { color: green; }
-p:nth-child(4n+3) { color: maroon; }
-p:nth-child(4n+4) { color: purple; }</pre>
-</div>
-
-<p>When <var>a</var>=0, no repeating is used, so for example
-<code>:nth-child(0n+5)</code> matches only the fifth child. When
-<var>a</var>=0, the <var>a</var><code>n</code> part need not be
-included, so the syntax simplifies to
-<code>:nth-child(<var>b</var>)</code> and the last example simplifies
-to <code>:nth-child(5)</code>.
-
-<div class="example">
-<p>Examples:</p>
-<pre>foo:nth-child(0n+1)   /* represents an element foo, first child of its parent element */
-foo:nth-child(1)      /* same */</pre>
-</div>
-
-<p>When <var>a</var>=1, the number may be omitted from the rule.
-
-<div class="example">
-<p>Examples:</p>
-<p>The following selectors are therefore equivalent:</p>
-<pre>bar:nth-child(1n+0)   /* represents all bar elements, specificity (0,1,1) */
-bar:nth-child(n+0)    /* same */
-bar:nth-child(n)      /* same */
-bar                   /* same but lower specificity (0,0,1) */</pre>
-</div>
-
-<p>If <var>b</var>=0, then every <var>a</var>th element is picked. In
-such a case, the <var>b</var> part may be omitted.
-
-<div class="example">
-<p>Examples:</p>
-<pre>tr:nth-child(2n+0) /* represents every even row of an HTML table */
-tr:nth-child(2n) /* same */</pre>
-</div>
-
-<p>If both <var>a</var> and <var>b</var> are equal to zero, the
-pseudo-class represents no element in the document tree.</p>
-
-<p>The value <var>a</var> can be negative, but only the positive
-values of <var>a</var><code>n</code>+<var>b</var>, for
-<code>n</code>&ge;0, may represent an element in the document
-tree.</p>
-
-<div class="example">
-<p>Example:</p>
-<pre>html|tr:nth-child(-n+6)  /* represents the 6 first rows of XHTML tables */</pre>
-</div>
-
-<p>When the value <var>b</var> is negative, the "+" character in the
-expression must be removed (it is effectively replaced by the "-"
-character indicating the negative value of <var>b</var>).</p>
-
-<div class="example">
-<p>Examples:</p>
-<pre>:nth-child(10n-1)  /* represents the 9th, 19th, 29th, etc, element */
-:nth-child(10n+9)  /* Same */
-:nth-child(10n+-1) /* Syntactically invalid, and would be ignored */</pre>
-</div>
-
-
-<h5><a name=nth-last-child-pseudo>:nth-last-child() pseudo-class</a></h5>
-
-<p>The <code>:nth-last-child(<var>a</var>n+<var>b</var>)</code>
-pseudo-class notation represents an element that has
-<var>a</var><code>n</code>+<var>b</var>-1 siblings
-<strong>after</strong> it in the document tree, for a given positive
-integer or zero value of <code>n</code>, and has a parent element. See
-<code>:nth-child()</code> pseudo-class for the syntax of its argument.
-It also accepts the '<code>even</code>' and '<code>odd</code>' values
-as arguments.
-
-
-<div class="example">
-<p>Examples:</p>
-<pre>tr:nth-last-child(-n+2)    /* represents the two last rows of an HTML table */
-
-foo:nth-last-child(odd)    /* represents all odd foo elements in their parent element,
-                              counting from the last one */</pre>
-</div>
-
-
-<h5><a name=nth-of-type-pseudo>:nth-of-type() pseudo-class</a></h5>
-
-<p>The <code>:nth-of-type(<var>a</var>n+<var>b</var>)</code>
-pseudo-class notation represents an element that has
-<var>a</var><code>n</code>+<var>b</var>-1 siblings with the same
-element name <strong>before</strong> it in the document tree, for a
-given zero or positive integer value of <code>n</code>, and has a
-parent element. In other words, this matches the <var>b</var>th child
-of that type after all the children of that type have been split into
-groups of a elements each. See <code>:nth-child()</code> pseudo-class
-for the syntax of its argument. It also accepts the
-'<code>even</code>' and '<code>odd</code>' values.
-
-
-<div class="example">
-<p>CSS example:</p>
-<p>This allows an author to alternate the position of floated images:</p>
-<pre>img:nth-of-type(2n+1) { float: right; }
-img:nth-of-type(2n) { float: left; }</pre>
-</div>
-
-
-<h5><a name=nth-last-of-type-pseudo>:nth-last-of-type() pseudo-class</a></h5>
-
-<p>The <code>:nth-last-of-type(<var>a</var>n+<var>b</var>)</code>
-pseudo-class notation represents an element that has
-<var>a</var><code>n</code>+<var>b</var>-1 siblings with the same
-element name <strong>after</strong> it in the document tree, for a
-given zero or positive integer value of <code>n</code>, and has a
-parent element. See <code>:nth-child()</code> pseudo-class for the
-syntax of its argument. It also accepts the '<code>even</code>' and '<code>odd</code>' values.
-
-
-<div class="example">
- <p>Example:</p>
- <p>To represent all <code>h2</code> children of an XHTML
- <code>body</code> except the first and last, one could use the
- following selector:</p>
- <pre>body &gt; h2:nth-of-type(n+2):nth-last-of-type(n+2)</pre>
- <p>In this case, one could also use <code>:not()</code>, although the
- selector ends up being just as long:</p>
- <pre>body &gt; h2:not(:first-of-type):not(:last-of-type)</pre>
-</div>
-
-
-<h5><a name=first-child-pseudo>:first-child pseudo-class</a></h5>
-
-<p>Same as <code>:nth-child(1)</code>. The <code>:first-child</code> pseudo-class
-represents an element that is the first child of some other element.
-
-
-<div class="example">
-  <p>Examples:</p>
-  <p>The following selector represents a <code>p</code> element that is
-  the first child of a <code>div</code> element:</p>
-  <pre>div &gt; p:first-child</pre>
-  <p>This selector can represent the <code>p</code> inside the
-  <code>div</code> of the following fragment:</p>
-  <pre>&lt;p&gt; The last P before the note.&lt;/p&gt;
-&lt;div class="note"&gt;
-   &lt;p&gt; The first P inside the note.&lt;/p&gt;
-&lt;/div&gt;</pre>but cannot represent the second <code>p</code> in the following
-fragment:
-  <pre>&lt;p&gt; The last P before the note.&lt;/p&gt;
-&lt;div class="note"&gt;
-   &lt;h2&gt; Note &lt;/h2&gt;
-   &lt;p&gt; The first P inside the note.&lt;/p&gt;
-&lt;/div&gt;</pre>
-  <p>The following two selectors are usually equivalent:</p>
-  <pre>* &gt; a:first-child /* a is first child of any element */
-a:first-child /* Same (assuming a is not the root element) */</pre>
-</div>
-
-<h5><a name=last-child-pseudo>:last-child pseudo-class</a></h5>
-
-<p>Same as <code>:nth-last-child(1)</code>. The <code>:last-child</code> pseudo-class
-represents an element that is the last child of some other element.
-
-<div class="example">
- <p>Example:</p>
- <p>The following selector represents a list item <code>li</code> that
- is the last child of an ordered list <code>ol</code>.
- <pre>ol &gt; li:last-child</pre>
-</div>
-
-<h5><a name=first-of-type-pseudo>:first-of-type pseudo-class</a></h5>
-
-<p>Same as <code>:nth-of-type(1)</code>. The <code>:first-of-type</code> pseudo-class
-represents an element that is the first sibling of its type in the list of
-children of its parent element.
-
-<div class="example">
-<p>Example:</p>
-<p>The following selector represents a definition title
-<code>dt</code> inside a definition list <code>dl</code>, this
-<code>dt</code> being the first of its type in the list of children of
-its parent element.</p>
-<pre>dl dt:first-of-type</pre>
-<p>It is a valid description for the first two <code>dt</code>
-elements in the following example but not for the third one:</p>
-<pre>&lt;dl&gt;
- &lt;dt&gt;gigogne&lt;/dt&gt;
- &lt;dd&gt;
-  &lt;dl&gt;
-   &lt;dt&gt;fus&eacute;e&lt;/dt&gt;
-   &lt;dd&gt;multistage rocket&lt;/dd&gt;
-   &lt;dt&gt;table&lt;/dt&gt;
-   &lt;dd&gt;nest of tables&lt;/dd&gt;
-  &lt;/dl&gt;
- &lt;/dd&gt;
-&lt;/dl&gt;</pre>
-</div>
-
-<h5><a name=last-of-type-pseudo>:last-of-type pseudo-class</a></h5>
-
-<p>Same as <code>:nth-last-of-type(1)</code>. The
-<code>:last-of-type</code> pseudo-class represents an element that is
-the last sibling of its type in the list of children of its parent
-element.</p>
-
-<div class="example">
- <p>Example:</p>
- <p>The following selector represents the last data cell
- <code>td</code> of a table row.</p>
- <pre>tr &gt; td:last-of-type</pre>
-</div>
-
-<h5><a name=only-child-pseudo>:only-child pseudo-class</a></h5>
-
-<p>Represents an element that has a parent element and whose parent
-element has no other element children. Same as
-<code>:first-child:last-child</code> or
-<code>:nth-child(1):nth-last-child(1)</code>, but with a lower
-specificity.</p>
-
-<h5><a name=only-of-type-pseudo>:only-of-type pseudo-class</a></h5>
-
-<p>Represents an element that has a parent element and whose parent
-element has no other element children with the same element name. Same
-as <code>:first-of-type:last-of-type</code> or
-<code>:nth-of-type(1):nth-last-of-type(1)</code>, but with a lower
-specificity.</p>
-
-
-<h5><a name=empty-pseudo></a>:empty pseudo-class</h5>
-
-<p>The <code>:empty</code> pseudo-class represents an element that has
-no children at all. In terms of the DOM, only element nodes and text
-nodes (including CDATA nodes and entity references) whose data has a
-non-zero length must be considered as affecting emptiness; comments,
-PIs, and other nodes must not affect whether an element is considered
-empty or not.</p>
-
-<div class="example">
- <p>Examples:</p>
- <p><code>p:empty</code> is a valid representation of the following fragment:</p>
- <pre>&lt;p&gt;&lt;/p&gt;</pre>
- <p><code>foo:empty</code> is not a valid representation for the
- following fragments:</p>
- <pre>&lt;foo&gt;bar&lt;/foo&gt;</pre>
- <pre>&lt;foo&gt;&lt;bar&gt;bla&lt;/bar&gt;&lt;/foo&gt;</pre>
- <pre>&lt;foo&gt;this is not &lt;bar&gt;:empty&lt;/bar&gt;&lt;/foo&gt;</pre>
-</div>
-
-<h4><a name=content-selectors>6.6.6. Blank</a></h4> <!-- It's the Return of Appendix H!!! Run away! -->
-
-<p>This section intentionally left blank.</p>
-<!-- (used to be :contains()) -->
-
-<h4><a name=negation></a>6.6.7. The negation pseudo-class</h4>
-
-<p>The negation pseudo-class, <code>:not(<var>X</var>)</code>, is a
-functional notation taking a <a href="#simple-selectors-dfn">simple
-selector</a> (excluding the negation pseudo-class itself and
-pseudo-elements) as an argument. It represents an element that is not
-represented by the argument.
-
-<!-- pseudo-elements are not simple selectors, so the above paragraph
-may be a bit confusing -->
-
-<div class="example">
-  <p>Examples:</p>
-  <p>The following CSS selector matches all <code>button</code>
-  elements in an HTML document that are not disabled.</p>
-  <pre>button:not([DISABLED])</pre>
-  <p>The following selector represents all but <code>FOO</code>
-  elements.</p>
-  <pre>*:not(FOO)</pre>
-  <p>The following group of selectors represents all HTML elements
-  except links.</p>
-  <pre>html|*:not(:link):not(:visited)</pre>
-</div>
-
-<p>Default namespace declarations do not affect the argument of the
-negation pseudo-class unless the argument is a universal selector or a
-type selector.</p>
-
-<div class="example">
-  <p>Examples:</p>
-  <p>Assuming that the default namespace is bound to
-  "http://example.com/", the following selector represents all
-  elements that are not in that namespace:</p>
-  <pre>*|*:not(*)</pre>
-  <p>The following CSS selector matches any element being hovered,
-  regardless of its namespace. In particular, it is not limited to
-  only matching elements in the default namespace that are not being
-  hovered, and elements not in the default namespace don't match the
-  rule when they <em>are</em> being hovered.</p>
-  <pre>*|*:not(:hover)</pre>
-</div>
-
-<p class="note"><strong>Note</strong>: the :not() pseudo allows
-useless selectors to be written.  For instance <code>:not(*|*)</code>,
-which represents no element at all, or <code>foo:not(bar)</code>,
-which is equivalent to <code>foo</code> but with a higher
-specificity.</p>
-
-<h3><a name=pseudo-elements>7. Pseudo-elements</a></h3>
-
-<p>Pseudo-elements create abstractions about the document tree beyond
-those specified by the document language. For instance, document
-languages do not offer mechanisms to access the first letter or first
-line of an element's content. Pseudo-elements allow designers to refer
-to this otherwise inaccessible information. Pseudo-elements may also
-provide designers a way to refer to content that does not exist in the
-source document (e.g., the <code>::before</code> and
-<code>::after</code> pseudo-elements give access to generated
-content).</p>
-
-<p>A pseudo-element is made of two colons (<code>::</code>) followed
-by the name of the pseudo-element.</p>
-
-<p>This <code>::</code> notation is introduced by the current document
-in order to establish a discrimination between pseudo-classes and
-pseudo-elements.  For compatibility with existing style sheets, user
-agents must also accept the previous one-colon notation for
-pseudo-elements introduced in CSS levels 1 and 2 (namely,
-<code>:first-line</code>, <code>:first-letter</code>,
-<code>:before</code> and <code>:after</code>). This compatibility is
-not allowed for the new pseudo-elements introduced in CSS level 3.</p>
-
-<p>Only one pseudo-element may appear per selector, and if present it
-must appear after the sequence of simple selectors that represents the
-<a href="#subject">subjects</a> of the selector. <span class="note">A
-future version of this specification may allow multiple
-pesudo-elements per selector.</span></p>
-
-<h4><a name=first-line>7.1. The ::first-line pseudo-element</a></h4>
-
-<p>The <code>::first-line</code> pseudo-element describes the contents
-of the first formatted line of an element.
-
-<div class="example">
-<p>CSS example:</p>
-<pre>p::first-line { text-transform: uppercase }</pre>
-<p>The above rule means "change the letters of the first line of every
-paragraph to uppercase".</p>
-</div>
-
-<p>The selector <code>p::first-line</code> does not match any real
-HTML element. It does match a pseudo-element that conforming user
-agents will insert at the beginning of every paragraph.</p>
-
-<p>Note that the length of the first line depends on a number of
-factors, including the width of the page, the font size, etc.  Thus,
-an ordinary HTML paragraph such as:</p>
-
-<pre>
-&lt;P&gt;This is a somewhat long HTML
-paragraph that will be broken into several
-lines. The first line will be identified
-by a fictional tag sequence. The other lines
-will be treated as ordinary lines in the
-paragraph.&lt;/P&gt;
-</pre>
-
-<p>the lines of which happen to be broken as follows:
-
-<pre>
-THIS IS A SOMEWHAT LONG HTML PARAGRAPH THAT
-will be broken into several lines. The first
-line will be identified by a fictional tag
-sequence. The other lines will be treated as
-ordinary lines in the paragraph.
-</pre>
-
-<p>This paragraph might be "rewritten" by user agents to include the
-<em>fictional tag sequence</em> for <code>::first-line</code>. This
-fictional tag sequence helps to show how properties are inherited.</p>
-
-<pre>
-&lt;P&gt;<b>&lt;P::first-line&gt;</b> This is a somewhat long HTML
-paragraph that <b>&lt;/P::first-line&gt;</b> will be broken into several
-lines. The first line will be identified
-by a fictional tag sequence. The other lines
-will be treated as ordinary lines in the
-paragraph.&lt;/P&gt;
-</pre>
-
-<p>If a pseudo-element breaks up a real element, the desired effect
-can often be described by a fictional tag sequence that closes and
-then re-opens the element. Thus, if we mark up the previous paragraph
-with a <code>span</code> element:</p>
-
-<pre>
-&lt;P&gt;<b>&lt;SPAN class="test"&gt;</b> This is a somewhat long HTML
-paragraph that will be broken into several
-lines.<b>&lt;/SPAN&gt;</b> The first line will be identified
-by a fictional tag sequence. The other lines
-will be treated as ordinary lines in the
-paragraph.&lt;/P&gt;
-</pre>
-
-<p>the user agent could simulate start and end tags for
-<code>span</code> when inserting the fictional tag sequence for
-<code>::first-line</code>.
-
-<pre>
-&lt;P&gt;&lt;P::first-line&gt;<b>&lt;SPAN class="test"&gt;</b> This is a
-somewhat long HTML
-paragraph that will <b>&lt;/SPAN&gt;</b>&lt;/P::first-line&gt;<b>&lt;SPAN class="test"&gt;</b> be
-broken into several
-lines.<b>&lt;/SPAN&gt;</b> The first line will be identified
-by a fictional tag sequence. The other lines
-will be treated as ordinary lines in the
-paragraph.&lt;/P&gt;
-</pre>
-
-<p>In CSS, the <code>::first-line</code> pseudo-element can only be
-attached to a block-level element, an inline-block, a table-caption,
-or a table-cell.</p>
-
-<p><a name="first-formatted-line"></a>The "first formatted line" of an
-element may occur inside a
-block-level descendant in the same flow (i.e., a block-level
-descendant that is not positioned and not a float). E.g., the first
-line of the <code>div</code> in <code>&lt;DIV>&lt;P>This
-line...&lt;/P>&lt/DIV></code> is the first line of the <code>p</code> (assuming
-that both <code>p</code> and <code>div</code> are block-level).
-
-<p>The first line of a table-cell or inline-block cannot be the first
-formatted line of an ancestor element. Thus, in <code>&lt;DIV&gt;&lt;P
-STYLE="display: inline-block">Hello&lt;BR&gt;Goodbye&lt;/P&gt;
-etcetera&lt;/DIV&gt;</code> the first formatted line of the
-<code>div</code> is not the line "Hello".
-
-<p class="note">Note that the first line of the <code>p</code> in this
-fragment: <code>&lt;p&gt&lt;br&gt;First...</code> doesn't contain any
-letters (assuming the default style for <code>br</code> in HTML
-4). The word "First" is not on the first formatted line.
-
-<p>A UA should act as if the fictional start tags of the
-<code>::first-line</code> pseudo-elements were nested just inside the
-innermost enclosing block-level element. (Since CSS1 and CSS2 were
-silent on this case, authors should not rely on this behavior.) Here
-is an example. The fictional tag sequence for</p>
-
-<pre>
-&lt;DIV>
-  &lt;P>First paragraph&lt;/P>
-  &lt;P>Second paragraph&lt;/P>
-&lt;/DIV>
-</pre>
-
-<p>is</p>
-
-<pre>
-&lt;DIV>
-  &lt;P>&lt;DIV::first-line>&lt;P::first-line>First paragraph&lt;/P::first-line>&lt;/DIV::first-line>&lt;/P>
-  &lt;P>&lt;P::first-line>Second paragraph&lt;/P::first-line>&lt;/P>
-&lt;/DIV>
-</pre>
-
-<p>The <code>::first-line</code> pseudo-element is similar to an
-inline-level element, but with certain restrictions. In CSS, the
-following properties apply to a <code>::first-line</code>
-pseudo-element: font properties, color property, background
-properties, 'word-spacing', 'letter-spacing', 'text-decoration',
-'vertical-align', 'text-transform', 'line-height'. UAs may apply other
-properties as well.</p>
-
-
-<h4><a name=first-letter>7.2. The ::first-letter pseudo-element</a></h4>
-
-<p>The <code>::first-letter</code> pseudo-element represents the first
-letter of the first line of a block, if it is not preceded by any
-other content (such as images or inline tables) on its line. The
-::first-letter pseudo-element may be used for "initial caps" and "drop
-caps", which are common typographical effects. This type of initial
-letter is similar to an inline-level element if its 'float' property
-is 'none'; otherwise, it is similar to a floated element.</p>
-
-<p>In CSS, these are the properties that apply to <code>::first-letter</code>
-pseudo-elements: font properties, 'text-decoration', 'text-transform',
-'letter-spacing', 'word-spacing' (when appropriate), 'line-height',
-'float', 'vertical-align' (only if 'float' is 'none'), margin
-properties, padding properties, border properties, color property,
-background properties.  UAs may apply other properties as well.  To
-allow UAs to render a typographically correct drop cap or initial cap,
-the UA may choose a line-height, width and height based on the shape
-of the letter, unlike for normal elements.</p>
-
-<div class="example">
-<p>Example:</p>
-<p>This example shows a possible rendering of an initial cap. Note
-that the 'line-height' that is inherited by the <code>::first-letter</code>
-pseudo-element is 1.1, but the UA in this example has computed the
-height of the first letter differently, so that it doesn't cause any
-unnecessary space between the first two lines. Also note that the
-fictional start tag of the first letter is inside the <span>span</span>, and thus
-the font weight of the first letter is normal, not bold as the <span>span</span>:
-<pre>
-p { line-height: 1.1 }
-p::first-letter { font-size: 3em; font-weight: normal }
-span { font-weight: bold }
-...
-&lt;p>&lt;span>Het hemelsche&lt;/span> gerecht heeft zich ten lange lesten&lt;br>
-Erbarremt over my en mijn benaeuwde vesten&lt;br>
-En arme burgery, en op mijn volcx gebed&lt;br>
-En dagelix geschrey de bange stad ontzet.
-</pre>
-<div class="figure">
-<p><img src="initial-cap.png" alt="Image illustrating the ::first-letter pseudo-element">
-</div>
-</div>
-
-<div class="example">
-<p>The following CSS will make a drop cap initial letter span about two lines:</p>
-
-<pre>
-&lt;!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"&gt;
-&lt;HTML&gt;
- &lt;HEAD&gt;
-  &lt;TITLE&gt;Drop cap initial letter&lt;/TITLE&gt;
-  &lt;STYLE type="text/css"&gt;
-   P               { font-size: 12pt; line-height: 1.2 }
-   P::first-letter { font-size: 200%; font-weight: bold; float: left }
-   SPAN            { text-transform: uppercase }
-  &lt;/STYLE&gt;
- &lt;/HEAD&gt;
- &lt;BODY&gt;
-  &lt;P&gt;&lt;SPAN&gt;The first&lt;/SPAN&gt; few words of an article
-    in The Economist.&lt;/P&gt;
- &lt;/BODY&gt;
-&lt;/HTML&gt;
-</pre>
-
-<p>This example might be formatted as follows:</p>
-
-<div class="figure">
-<P><img src="first-letter.gif" alt="Image illustrating the combined effect of the ::first-letter and ::first-line pseudo-elements"></p>
-</div>
-
-<p>The <span class="index-inst" title="fictional tag
-sequence">fictional tag sequence</span> is:</p>
-
-<pre>
-&lt;P&gt;
-&lt;SPAN&gt;
-&lt;P::first-letter&gt;
-T
-&lt;/P::first-letter&gt;he first
-&lt;/SPAN&gt;
-few words of an article in the Economist.
-&lt;/P&gt;
-</pre>
-
-<p>Note that the <code>::first-letter</code> pseudo-element tags abut
-the content (i.e., the initial character), while the ::first-line
-pseudo-element start tag is inserted right after the start tag of the
-block element.</p> </div>
-
-<p>In order to achieve traditional drop caps formatting, user agents
-may approximate font sizes, for example to align baselines. Also, the
-glyph outline may be taken into account when formatting.</p>
-
-<p>Punctuation (i.e, characters defined in Unicode in the "open" (Ps),
-"close" (Pe), "initial" (Pi). "final" (Pf) and "other" (Po)
-punctuation classes), that precedes or follows the first letter should
-be included. <a href="#refsUNICODE">[UNICODE]</a></p>
-
-<div class="figure">
-<P><img src="first-letter2.gif" alt="Quotes that precede the
-first letter should be included."></p>
-</div>
-
-<p>The <code>::first-letter</code> also applies if the first letter is
-in fact a digit, e.g., the "6" in "67 million dollars is a lot of
-money."</p>
-
-<p>In CSS, the <code>::first-letter</code> pseudo-element applies to
-block, list-item, table-cell, table-caption, and inline-block
-elements. <span class="note">A future version of this specification
-may allow this pesudo-element to apply to more element
-types.</span></p>
-
-<p>The <code>::first-letter</code> pseudo-element can be used with all
-such elements that contain text, or that have a descendant in the same
-flow that contains text. A UA should act as if the fictional start tag
-of the ::first-letter pseudo-element is just before the first text of
-the element, even if that first text is in a descendant.</p>
-
-<div class="example">
-<p>Example:</p>
-<p>The fictional tag sequence for this HTMLfragment:
-<pre>&lt;div>
-&lt;p>The first text.</pre>
-<p>is:
-<pre>&lt;div>
-&lt;p>&lt;div::first-letter>&lt;p::first-letter>T&lt;/...>&lt;/...>he first text.</pre>
-</div>
-
-<p>The first letter of a table-cell or inline-block cannot be the
-first letter of an ancestor element. Thus, in <code>&lt;DIV&gt;&lt;P
-STYLE="display: inline-block">Hello&lt;BR&gt;Goodbye&lt;/P&gt;
-etcetera&lt;/DIV&gt;</code> the first letter of the <code>div</code> is not the
-letter "H". In fact, the <code>div</code> doesn't have a first letter.
-
-<p>The first letter must occur on the <a
-href="#first-formatted-line">first formatted line.</a> For example, in
-this fragment: <code>&lt;p&gt&lt;br&gt;First...</code> the first line
-doesn't contain any letters and <code>::first-letter</code> doesn't
-match anything (assuming the default style for <code>br</code> in HTML
-4). In particular, it does not match the "F" of "First."
-
-<p>In CSS, if an element is a list item ('display: list-item'), the
-<code>::first-letter</code> applies to the first letter in the
-principal box after the marker. UAs may ignore
-<code>::first-letter</code> on list items with 'list-style-position:
-inside'. If an element has <code>::before</code> or
-<code>::after</code> content, the <code>::first-letter</code> applies
-to the first letter of the element <em>including</em> that content.
-
-<div class="example">
-<p>Example:</p>
-<p>After the rule 'p::before {content: "Note: "}', the selector
-'p::first-letter' matches the "N" of "Note".</p>
-</div>
-
-<p>Some languages may have specific rules about how to treat certain
-letter combinations. In Dutch, for example, if the letter combination
-"ij" appears at the beginning of a word, both letters should be
-considered within the <code>::first-letter</code> pseudo-element.
-
-<p>If the letters that would form the ::first-letter are not in the
-same element, such as "'T" in <code>&lt;p>'&lt;em>T...</code>, the UA
-may create a ::first-letter pseudo-element from one of the elements,
-both elements, or simply not create a pseudo-element.</p>
-
-<p>Similarly, if the first letter(s) of the block are not at the start
-of the line (for example due to bidirectional reordering), then the UA
-need not create the pseudo-element(s).
-
-<div class="example">
-<p>Example:</p>
-<p><a name="overlapping-example">The following example</a> illustrates
-how overlapping pseudo-elements may interact.  The first letter of
-each P element will be green with a font size of '24pt'. The rest of
-the first formatted line will be 'blue' while the rest of the
-paragraph will be 'red'.</p>
-
-<pre>p { color: red; font-size: 12pt }
-p::first-letter { color: green; font-size: 200% }
-p::first-line { color: blue }
-
-&lt;P&gt;Some text that ends up on two lines&lt;/P&gt;</pre>
-
-<p>Assuming that a line break will occur before the word "ends", the
-<span class="index-inst" title="fictional tag sequence">fictional tag
-sequence</span> for this fragment might be:</p>
-
-<pre>&lt;P&gt;
-&lt;P::first-line&gt;
-&lt;P::first-letter&gt;
-S
-&lt;/P::first-letter&gt;ome text that
-&lt;/P::first-line&gt;
-ends up on two lines
-&lt;/P&gt;</pre>
-
-<p>Note that the <code>::first-letter</code> element is inside the <code>::first-line</code>
-element.  Properties set on <code>::first-line</code> are inherited by
-<code>::first-letter</code>, but are overridden if the same property is set on
-<code>::first-letter</code>.</p>
-</div>
-
-
-<h4><a name=UIfragments>7.3.</a> <a name=selection>The ::selection pseudo-element</a></h4>
-
-<p>The <code>::selection</code> pseudo-element applies to the portion
-of a document that has been highlighted by the user. This also
-applies, for example, to selected text within an editable text
-field. This pseudo-element should not be confused with the <code><a
-href="#checked">:checked</a></code> pseudo-class (which used to be
-named <code>:selected</code>)
-
-<p>Although the <code>::selection</code> pseudo-element is dynamic in
-nature, and is altered by user action, it is reasonable to expect that
-when a UA re-renders to a static medium (such as a printed page, see
-<a href="#refsCSS21">[CSS21]</a>) which was originally rendered to a
-dynamic medium (like screen), the UA may wish to transfer the current
-<code>::selection</code> state to that other medium, and have all the
-appropriate formatting and rendering take effect as well. This is not
-required &mdash; UAs may omit the <code>::selection</code>
-pseudo-element for static media.
-
-<p>These are the CSS properties that apply to <code>::selection</code>
-pseudo-elements: color, background, cursor (optional), outline
-(optional). The computed value of the 'background-image' property on
-<code>::selection</code> may be ignored.
-
-
-<h4><a name=gen-content>7.4. The ::before and ::after pseudo-elements</a></h4>
-
-<p>The <code>::before</code> and <code>::after</code> pseudo-elements
-can be used to describe generated content before or after an element's
-content. They are explained in CSS 2.1 <a
-href="#refsCSS21">[CSS21]</a>.</p>
-
-<p>When the <code>::first-letter</code> and <code>::first-line</code>
-pseudo-elements are combined with <code>::before</code> and
-<code>::after</code>, they apply to the first letter or line of the
-element including the inserted text.</p>
-
-<h2><a name=combinators>8. Combinators</a></h2>
-
-<h3><a name=descendant-combinators>8.1. Descendant combinator</a></h3>
-
-<p>At times, authors may want selectors to describe an element that is
-the descendant of another element in the document tree (e.g., "an
-<code>EM</code> element that is contained within an <code>H1</code>
-element"). Descendant combinators express such a relationship. A
-descendant combinator is <a href="#whitespace">white space</a> that
-separates two sequences of simple selectors.  A selector of the form
-"<code>A B</code>" represents an element <code>B</code> that is an
-arbitrary descendant of some ancestor element <code>A</code>.
-
-<div class="example">
- <p>Examples:</p>
- <p>For example, consider the following selector:</p>
- <pre>h1 em</pre>
- <p>It represents an <code>em</code> element being the descendant of
- an <code>h1</code> element. It is a correct and valid, but partial,
- description of the following fragment:</p>
- <pre>&lt;h1&gt;This &lt;span class="myclass"&gt;headline
-is &lt;em&gt;very&lt;/em&gt; important&lt;/span&gt;&lt;/h1&gt;</pre>
- <p>The following selector:</p>
- <pre>div * p</pre>
- <p>represents a <code>p</code> element that is a grandchild or later
- descendant of a <code>div</code> element. Note the whitespace on
- either side of the "*" is not part of the universal selector; the
- whitespace is a combinator indicating that the DIV must be the
- ancestor of some element, and that that element must be an ancestor
- of the P.</p>
- <p>The following selector, which combines descendant combinators and
- <a href="#attribute-selectors">attribute selectors</a>, represents an
- element that (1) has the <code>href</code> attribute set and (2) is
- inside a <code>p</code> that is itself inside a <code>div</code>:</p>
- <pre>div p *[href]</pre>
-</div>
-
-<h3><a name=child-combinators>8.2. Child combinators</a></h3>
-
-<p>A <dfn>child combinator</dfn> describes a childhood relationship
-between two elements. A child combinator is made of the
-&quot;greater-than sign&quot; (<code>&gt;</code>) character and
-separates two sequences of simple selectors.
-
-
-<div class="example">
- <p>Examples:</p>
- <p>The following selector represents a <code>p</code> element that is
- child of <code>body</code>:</p>
- <pre>body &gt; p</pre>
- <p>The following example combines descendant combinators and child
- combinators.</p>
- <pre>div ol&gt;li p</pre><!-- LEAVE THOSE SPACES OUT! see below -->
- <p>It represents a <code>p</code> element that is a descendant of an
- <code>li</code> element; the <code>li</code> element must be the
- child of an <code>ol</code> element; the <code>ol</code> element must
- be a descendant of a <code>div</code>. Notice that the optional white
- space around the "&gt;" combinator has been left out.</p>
-</div>
-
-<p>For information on selecting the first child of an element, please
-see the section on the <code><a
-href="#structural-pseudos">:first-child</a></code> pseudo-class
-above.</p>
-
-<h3><a name=sibling-combinators>8.3. Sibling combinators</a></h3>
-
-<p>There are two different sibling combinators: the adjacent sibling
-combinator and the general sibling combinator. In both cases,
-non-element nodes (e.g. text between elements) are ignored when
-considering adjacency of elements.</p>
-
-<h4><a name=adjacent-sibling-combinators>8.3.1. Adjacent sibling combinator</a></h4>
-
-<p>The adjacent sibling combinator is made of the &quot;plus
-sign&quot; (U+002B, <code>+</code>) character that separates two
-sequences of simple selectors. The elements represented by the two
-sequences share the same parent in the document tree and the element
-represented by the first sequence immediately precedes the element
-represented by the second one.</p>
-
-<div class="example">
- <p>Examples:</p>
- <p>The following selector represents a <code>p</code> element
- immediately following a <code>math</code> element:</p>
- <pre>math + p</pre>
- <p>The following selector is conceptually similar to the one in the
- previous example, except that it adds an attribute selector &mdash; it
- adds a constraint to the <code>h1</code> element, that it must have
- <code>class="opener"</code>:</p>
- <pre>h1.opener + h2</pre>
-</div>
-
-
-<h4><a name=general-sibling-combinators>8.3.2. General sibling combinator</a></h4>
-
-<p>The general sibling combinator is made of the &quot;tilde&quot;
-(U+007E, <code>~</code>) character that separates two sequences of
-simple selectors. The elements represented by the two sequences share
-the same parent in the document tree and the element represented by
-the first sequence precedes (not necessarily immediately) the element
-represented by the second one.</p>
-
-<div class="example">
- <p>Example:</p>
- <pre>h1 ~ pre</pre>
- <p>represents a <code>pre</code> element following an <code>h1</code>. It
- is a correct and valid, but partial, description of:</p>
- <pre>&lt;h1&gt;Definition of the function a&lt;/h1&gt;
-&lt;p&gt;Function a(x) has to be applied to all figures in the table.&lt;/p&gt;
-&lt;pre&gt;function a(x) = 12x/13.5&lt;/pre&gt;</pre>
-</div>
-
-<h2><a name=specificity>9. Calculating a selector's specificity</a></h2>
-
-<p>A selector's specificity is calculated as follows:</p>
-
-<ul>
-  <li>count the number of ID selectors in the selector (= a)</li>
-  <li>count the number of class selectors, attributes selectors, and pseudo-classes in the selector (= b)</li>
-  <li>count the number of element names in the selector (= c)</li>
-  <li>ignore pseudo-elements</li>
-</ul>
-
-<p>Selectors inside <a href="#negation">the negation pseudo-class</a>
-are counted like any other, but the negation itself does not count as
-a pseudo-class.</p>
-
-<p>Concatenating the three numbers a-b-c (in a number system with a
-large base) gives the specificity.</p>
-
-<div class="example">
-<p>Examples:</p>
-<pre>*               /* a=0 b=0 c=0 -&gt; specificity =   0 */
-LI              /* a=0 b=0 c=1 -&gt; specificity =   1 */
-UL LI           /* a=0 b=0 c=2 -&gt; specificity =   2 */
-UL OL+LI        /* a=0 b=0 c=3 -&gt; specificity =   3 */
-H1 + *[REL=up]  /* a=0 b=1 c=1 -&gt; specificity =  11 */
-UL OL LI.red    /* a=0 b=1 c=3 -&gt; specificity =  13 */
-LI.red.level    /* a=0 b=2 c=1 -&gt; specificity =  21 */
-#x34y           /* a=1 b=0 c=0 -&gt; specificity = 100 */
-#s12:not(FOO)   /* a=1 b=0 c=1 -&gt; specificity = 101 */
-</pre>
-</div>
-
-<p class="note"><strong>Note:</strong> the specificity of the styles
-specified in an HTML <code>style</code> attribute is described in CSS
-2.1. <a href="#refsCSS21">[CSS21]</a>.</p>
-
-<h2><a name=w3cselgrammar>10. The grammar of Selectors</a></h2>
-
-<h3><a name=grammar>10.1. Grammar</a></h3>
-
-<p>The grammar below defines the syntax of Selectors.  It is globally
-LL(1) and can be locally LL(2) (but note that most UA's should not use
-it directly, since it doesn't express the parsing conventions). The
-format of the productions is optimized for human consumption and some
-shorthand notations beyond Yacc (see <a href="#refsYACC">[YACC]</a>)
-are used:</p>
-
-<ul>
-  <li><b>*</b>: 0 or more
-  <li><b>+</b>: 1 or more
-  <li><b>?</b>: 0 or 1
-  <li><b>|</b>: separates alternatives
-  <li><b>[ ]</b>: grouping </li>
-</ul>
-
-<p>The productions are:</p>
-
-<pre>selectors_group
-  : selector [ COMMA S* selector ]*
-  ;
-
-selector
-  : simple_selector_sequence [ combinator simple_selector_sequence ]*
-  ;
-
-combinator
-  /* combinators can be surrounded by white space */
-  : PLUS S* | GREATER S* | TILDE S* | S+
-  ;
-
-simple_selector_sequence
-  : [ type_selector | universal ]
-    [ HASH | class | attrib | pseudo | negation ]*
-  | [ HASH | class | attrib | pseudo | negation ]+
-  ;
-
-type_selector
-  : [ namespace_prefix ]? element_name
-  ;
-
-namespace_prefix
-  : [ IDENT | '*' ]? '|'
-  ;
-
-element_name
-  : IDENT
-  ;
-
-universal
-  : [ namespace_prefix ]? '*'
-  ;
-
-class
-  : '.' IDENT
-  ;
-
-attrib
-  : '[' S* [ namespace_prefix ]? IDENT S*
-        [ [ PREFIXMATCH |
-            SUFFIXMATCH |
-            SUBSTRINGMATCH |
-            '=' |
-            INCLUDES |
-            DASHMATCH ] S* [ IDENT | STRING ] S*
-        ]? ']'
-  ;
-
-pseudo
-  /* '::' starts a pseudo-element, ':' a pseudo-class */
-  /* Exceptions: :first-line, :first-letter, :before and :after. */
-  /* Note that pseudo-elements are restricted to one per selector and */
-  /* occur only in the last simple_selector_sequence. */
-  : ':' ':'? [ IDENT | functional_pseudo ]
-  ;
-
-functional_pseudo
-  : FUNCTION S* expression ')'
-  ;
-
-expression
-  /* In CSS3, the expressions are identifiers, strings, */
-  /* or of the form "an+b" */
-  : [ [ PLUS | '-' | DIMENSION | NUMBER | STRING | IDENT ] S* ]+
-  ;
-
-negation
-  : NOT S* negation_arg S* ')'
-  ;
-
-negation_arg
-  : type_selector | universal | HASH | class | attrib | pseudo
-  ;</pre>
-
-
-<h3><a name=lex>10.2. Lexical scanner</a></h3>
-
-<p>The following is the <a name=x3>tokenizer</a>, written in Flex (see
-<a href="#refsFLEX">[FLEX]</a>) notation. The tokenizer is
-case-insensitive.</p>
-
-<p>The two occurrences of "\377" represent the highest character
-number that current versions of Flex can deal with (decimal 255). They
-should be read as "\4177777" (decimal 1114111), which is the highest
-possible code point in Unicode/ISO-10646. <a
-href="#refsUNICODE">[UNICODE]</a></p>
-
-<pre>%option case-insensitive
-
-ident     [-]?{nmstart}{nmchar}*
-name      {nmchar}+
-nmstart   [_a-z]|{nonascii}|{escape}
-nonascii  [^\0-\177]
-unicode   \\[0-9a-f]{1,6}(\r\n|[ \n\r\t\f])?
-escape    {unicode}|\\[^\n\r\f0-9a-f]
-nmchar    [_a-z0-9-]|{nonascii}|{escape}
-num       [0-9]+|[0-9]*\.[0-9]+
-string    {string1}|{string2}
-string1   \"([^\n\r\f\\"]|\\{nl}|{nonascii}|{escape})*\"
-string2   \'([^\n\r\f\\']|\\{nl}|{nonascii}|{escape})*\'
-invalid   {invalid1}|{invalid2}
-invalid1  \"([^\n\r\f\\"]|\\{nl}|{nonascii}|{escape})*
-invalid2  \'([^\n\r\f\\']|\\{nl}|{nonascii}|{escape})*
-nl        \n|\r\n|\r|\f
-w         [ \t\r\n\f]*
-
-%%
-
-[ \t\r\n\f]+     return S;
-
-"~="             return INCLUDES;
-"|="             return DASHMATCH;
-"^="             return PREFIXMATCH;
-"$="             return SUFFIXMATCH;
-"*="             return SUBSTRINGMATCH;
-{ident}          return IDENT;
-{string}         return STRING;
-{ident}"("       return FUNCTION;
-{num}            return NUMBER;
-"#"{name}        return HASH;
-{w}"+"           return PLUS;
-{w}"&gt;"           return GREATER;
-{w}","           return COMMA;
-{w}"~"           return TILDE;
-":not("          return NOT;
-@{ident}         return ATKEYWORD;
-{invalid}        return INVALID;
-{num}%           return PERCENTAGE;
-{num}{ident}     return DIMENSION;
-"&lt;!--"           return CDO;
-"--&gt;"            return CDC;
-
-"url("{w}{string}{w}")"                           return URI;
-"url("{w}([!#$%&*-~]|{nonascii}|{escape})*{w}")"  return URI;
-U\+[0-9a-f?]{1,6}(-[0-9a-f]{1,6})?                return UNICODE_RANGE;
-
-\/\*[^*]*\*+([^/*][^*]*\*+)*\/                    /* ignore comments */
-
-.                return *yytext;</pre>
-
-
-
-<h2><a name=downlevel>11. Namespaces and down-level clients</a></h2>
-
-<p>An important issue is the interaction of CSS selectors with XML
-documents in web clients that were produced prior to this
-document. Unfortunately, due to the fact that namespaces must be
-matched based on the URI which identifies the namespace, not the
-namespace prefix, some mechanism is required to identify namespaces in
-CSS by their URI as well. Without such a mechanism, it is impossible
-to construct a CSS style sheet which will properly match selectors in
-all cases against a random set of XML documents. However, given
-complete knowledge of the XML document to which a style sheet is to be
-applied, and a limited use of namespaces within the XML document, it
-is possible to construct a style sheet in which selectors would match
-elements and attributes correctly.</p>
-
-<p>It should be noted that a down-level CSS client will (if it
-properly conforms to CSS forward compatible parsing rules) ignore all
-<code>@namespace</code> at-rules, as well as all style rules that make
-use of namespace qualified element type or attribute selectors. The
-syntax of delimiting namespace prefixes in CSS was deliberately chosen
-so that down-level CSS clients would ignore the style rules rather
-than possibly match them incorrectly.</p>
-
-<p>The use of default namespaces in CSS makes it possible to write
-element type selectors that will function in both namespace aware CSS
-clients as well as down-level clients. It should be noted that
-down-level clients may incorrectly match selectors against XML
-elements in other namespaces.</p>
-
-<p>The following are scenarios and examples in which it is possible to
-construct style sheets which would function properly in web clients
-that do not implement this proposal.</p>
-
-<ol>
-  <li>
-
-   <p>The XML document does not use namespaces.</p>
-
-   <ul>
-
-    <li>In this case, it is obviously not necessary to declare or use
-    namespaces in the style sheet. Standard CSS element type and
-    attribute selectors will function adequately in a down-level
-    client.</li>
-
-    <li>In a CSS namespace aware client, the default behavior of
-    element selectors matching without regard to namespace will
-    function properly against all elements, since no namespaces are
-    present. However, the use of specific element type selectors that
-    match only elements that have no namespace ("<code>|name</code>")
-    will guarantee that selectors will match only XML elements that do
-    not have a declared namespace. </li>
-
-   </ul>
-
-  </li>
-
-  <li>
-
-   <p>The XML document defines a single, default namespace used
-   throughout the document. No namespace prefixes are used in element
-   names.</p>
-
-   <ul>
-
-    <li>In this case, a down-level client will function as if
-    namespaces were not used in the XML document at all. Standard CSS
-    element type and attribute selectors will match against all
-    elements. </li>
-
-   </ul>
-
-  </li>
-
-  <li>
-
-   <p>The XML document does <b>not</b> use a default namespace, all
-   namespace prefixes used are known to the style sheet author, and
-   there is a direct mapping between namespace prefixes and namespace
-   URIs. (A given prefix may only be mapped to one namespace URI
-   throughout the XML document; there may be multiple prefixes mapped
-   to the same URI).</p>
-
-   <ul>
-
-    <li>In this case, the down-level client will view and match
-    element type and attribute selectors based on their fully
-    qualified name, not the local part as outlined in the <a
-    href="#typenmsp">Type selectors and Namespaces</a> section. CSS
-    selectors may be declared using an escaped colon "<code>\:</code>"
-    to describe the fully qualified names, e.g.
-    "<code>html\:h1</code>" will match
-    <code>&lt;html:h1&gt;</code>. Selectors using the qualified name
-    will only match XML elements that use the same prefix. Other
-    namespace prefixes used in the XML that are mapped to the same URI
-    will not match as expected unless additional CSS style rules are
-    declared for them.</li>
-
-    <li>Note that selectors declared in this fashion will
-    <em>only</em> match in down-level clients. A CSS namespace aware
-    client will match element type and attribute selectors based on
-    the name's local part. Selectors declared with the fully
-    qualified name will not match (unless there is no namespace prefix
-    in the fully qualified name).</li>
-
-   </ul>
-
-  </li>
-
- </ol>
-
-<p>In other scenarios: when the namespace prefixes used in the XML are
-not known in advance by the style sheet author; or a combination of
-elements with no namespace are used in conjunction with elements using
-a default namespace; or the same namespace prefix is mapped to
-<em>different</em> namespace URIs within the same document, or in
-different documents; it is impossible to construct a CSS style sheet
-that will function properly against all elements in those documents,
-unless, the style sheet is written using a namespace URI syntax (as
-outlined in this document or similar) and the document is processed by
-a CSS and XML namespace aware client.</p>
-
-<h2><a name=profiling>12. Profiles</a></h2>
-
-<p>Each specification using Selectors must define the subset of W3C
-Selectors it allows and excludes, and describe the local meaning of
-all the components of that subset.</p>
-
-<p>Non normative examples:
-
-<div class="profile">
-<table class="tprofile">
-  <tbody>
-  <tr>
-    <th class="title" colspan=2>Selectors profile</th></tr>
-  <tr>
-    <th>Specification</th>
-    <td>CSS level 1</td></tr>
-  <tr>
-    <th>Accepts</th>
-    <td>type selectors<br>class selectors<br>ID selectors<br>:link,
-      :visited and :active pseudo-classes<br>descendant combinator
-     <br>::first-line and ::first-letter pseudo-elements</td></tr>
-  <tr>
-    <th>Excludes</th>
-    <td>
-
-<p>universal selector<br>attribute selectors<br>:hover and :focus
-      pseudo-classes<br>:target pseudo-class<br>:lang() pseudo-class<br>all UI
-      element states pseudo-classes<br>all structural
-      pseudo-classes<br>negation pseudo-class<br>all
-      UI element fragments pseudo-elements<br>::before and ::after
-      pseudo-elements<br>child combinators<br>sibling combinators
-
-<p>namespaces</td></tr>
-  <tr>
-    <th>Extra constraints</th>
-    <td>only one class selector allowed per sequence of simple
-  selectors</td></tr></tbody></table><br><br>
-<table class="tprofile">
-  <tbody>
-  <tr>
-    <th class="title" colspan=2>Selectors profile</th></tr>
-  <tr>
-    <th>Specification</th>
-    <td>CSS level 2</td></tr>
-  <tr>
-    <th>Accepts</th>
-    <td>type selectors<br>universal selector<br>attribute presence and
-      values selectors<br>class selectors<br>ID selectors<br>:link, :visited,
-      :active, :hover, :focus, :lang() and :first-child pseudo-classes
-     <br>descendant combinator<br>child combinator<br>adjacent sibling
-      combinator<br>::first-line and ::first-letter pseudo-elements<br>::before
-      and ::after pseudo-elements</td></tr>
-  <tr>
-    <th>Excludes</th>
-    <td>
-
-<p>content selectors<br>substring matching attribute
-      selectors<br>:target pseudo-classes<br>all UI element
-      states pseudo-classes<br>all structural pseudo-classes other
-      than :first-child<br>negation pseudo-class<br>all UI element
-      fragments pseudo-elements<br>general sibling combinators
-
-<p>namespaces</td></tr>
-  <tr>
-    <th>Extra constraints</th>
-    <td>more than one class selector per sequence of simple selectors (CSS1
-      constraint) allowed</td></tr></tbody></table>
-
-<p>In CSS, selectors express pattern matching rules that determine which style
-rules apply to elements in the document tree.
-
-<p>The following selector (CSS level 2) will <b>match</b> all anchors <code>a</code>
-with attribute <code>name</code> set inside a section 1 header <code>h1</code>:
-<pre>h1 a[name]</pre>
-
-<p>All CSS declarations attached to such a selector are applied to elements
-matching it. </div>
-
-<div class="profile">
-<table class="tprofile">
-  <tbody>
-  <tr>
-    <th class="title" colspan=2>Selectors profile</th></tr>
-  <tr>
-    <th>Specification</th>
-      <td>STTS 3</td>
-    </tr>
-  <tr>
-    <th>Accepts</th>
-    <td>
-
-<p>type selectors<br>universal selectors<br>attribute selectors<br>class
-      selectors<br>ID selectors<br>all structural pseudo-classes<br>
-          all combinators
-
-<p>namespaces</td></tr>
-  <tr>
-    <th>Excludes</th>
-    <td>non-accepted pseudo-classes<br>pseudo-elements<br></td></tr>
-  <tr>
-    <th>Extra constraints</th>
-    <td>some selectors and combinators are not allowed in fragment
-      descriptions on the right side of STTS declarations.</td></tr></tbody></table>
-<form>
-<input type="text" name="test10"/>
-<input type="text" name="foo"/>
-<input type="text" name="foo"/>
-<input type="text" name="foo"/>
-<input type="text" name="foo"/>
-<input type="text" name="foo"/>
-<input type="text" name="foo"/>
-<input type="text" name="foo"/>
-<input type="text" name="foo"/>
-<input type="text" name="foo"/>
-<input type="text" name="foo"/>
-<input type="text" name="foo"/>
-<input type="text" name="foo"/>
-<input type="text" name="foo"/>
-<input type="text" name="foo"/>
-<input type="text" name="foo"/>
-<input type="text" name="foo"/>
-<input type="text" name="foo"/>
-<input type="text" name="foo"/>
-<input type="text" name="foo"/>
-<input type="text" name="foo"/>
-<input type="text" name="foo"/>
-<input type="text" name="foo"/>
-<input type="text" name="foo"/>
-<input type="text" name="foo"/>
-</form>
-
-<p>Selectors can be used in STTS 3 in two different
-    manners:
-<ol>
-  <li>a selection mechanism equivalent to CSS selection mechanism: declarations
-  attached to a given selector are applied to elements matching that selector,
-  <li>fragment descriptions that appear on the right side of declarations.
-</li></ol></div>
-
-<h2><a name=Conformance></a>13. Conformance and requirements</h2>
-
-<p>This section defines conformance with the present specification only.
-
-<p>The inability of a user agent to implement part of this specification due to
-the limitations of a particular device (e.g., non interactive user agents will
-probably not implement dynamic pseudo-classes because they make no sense without
-interactivity) does not imply non-conformance.
-
-<p>All specifications reusing Selectors must contain a <a
-href="#profiling">Profile</a> listing the
-subset of Selectors it accepts or excludes, and describing the constraints
-it adds to the current specification.
-
-<p>Invalidity is caused by a parsing error, e.g. an unrecognized token or a token
-which is not allowed at the current parsing point.
-
-<p>User agents must observe the rules for handling parsing errors:
-<ul>
-  <li>a simple selector containing an undeclared namespace prefix is invalid</li>
-  <li>a selector containing an invalid simple selector, an invalid combinator
-    or an invalid token is invalid. </li>
-  <li>a group of selectors containing an invalid selector is invalid.</li>
-</ul>
-
-<p class="foo test10 bar">Specifications reusing Selectors must define how to handle parsing
-errors. (In the case of CSS, the entire rule in which the selector is
-used is dropped.)</p>
-
-<!-- Apparently all these references are out of date:
-<p>Implementations of this specification must behave as
-"recipients of text data" as defined by <a href="#refsCWWW">[CWWW]</a>
-when parsing selectors and attempting matches. (In particular,
-implementations must assume the data is normalized and must not
-normalize it.) Normative rules for matching strings are defined in
-<a href="#refsCWWW">[CWWW]</a> and <a
-href="#refsUNICODE">[UNICODE]</a> and apply to implementations of this
-specification.</p>-->
-
-<h2><a name=Tests></a>14. Tests</h2>
-
-<p>This specification has <a
-href="http://www.w3.org/Style/CSS/Test/CSS3/Selectors/current/">a test
-suite</a> allowing user agents to verify their basic conformance to
-the specification. This test suite does not pretend to be exhaustive
-and does not cover all possible combined cases of Selectors.</p>
-
-<h2><a name=ACKS></a>15. Acknowledgements</h2>
-
-<p>The CSS working group would like to thank everyone who has sent
-comments on this specification over the years.</p>
-
-<p>The working group would like to extend special thanks to Donna
-McManus, Justin Baker, Joel Sklar, and Molly Ives Brower who perfermed
-the final editorial review.</p>
-
-<h2><a name=references>16. References</a></h2>
-
-<dl class="refs">
-
-  <dt>[CSS1]
-  <dd><a name=refsCSS1></a> Bert Bos, H&aring;kon Wium Lie; "<cite>Cascading Style Sheets, level 1</cite>", W3C Recommendation, 17 Dec 1996, revised 11 Jan 1999
-  <dd>(<code><a href="http://www.w3.org/TR/REC-CSS1">http://www.w3.org/TR/REC-CSS1</a></code>)
-
-  <dt>[CSS21]
-  <dd><a name=refsCSS21></a> Bert Bos, Tantek &Ccedil;elik, Ian Hickson, H&aring;kon Wium Lie, editors; "<cite>Cascading Style Sheets, level 2 revision 1</cite>", W3C Working Draft, 13 June 2005
-  <dd>(<code><a href="http://www.w3.org/TR/CSS21">http://www.w3.org/TR/CSS21</a></code>)
-
-  <dt>[CWWW]
-  <dd><a name=refsCWWW></a> Martin J. D&uuml;rst, Fran&ccedil;ois Yergeau, Misha Wolf, Asmus Freytag, Tex Texin, editors; "<cite>Character Model for the World Wide Web</cite>", W3C Recommendation, 15 February 2005
-  <dd>(<code><a href="http://www.w3.org/TR/charmod/">http://www.w3.org/TR/charmod/</a></code>)
-
-  <dt>[FLEX]
-  <dd><a name="refsFLEX"></a> "<cite>Flex: The Lexical Scanner Generator</cite>", Version 2.3.7, ISBN 1882114213
-
-  <dt>[HTML4]
-  <dd><a name="refsHTML4"></a> Dave Ragget, Arnaud Le Hors, Ian Jacobs, editors; "<cite>HTML 4.01 Specification</cite>", W3C Recommendation, 24 December 1999
-  <dd>(<a href="http://www.w3.org/TR/html4/"><code>http://www.w3.org/TR/html4/</code></a>)
-
-  <dt>[MATH]
-  <dd><a name="refsMATH"></a> Patrick Ion, Robert Miner, editors; "<cite>Mathematical Markup Language (MathML) 1.01</cite>", W3C Recommendation, revision of 7 July 1999
-  <dd>(<code><a href="http://www.w3.org/TR/REC-MathML/">http://www.w3.org/TR/REC-MathML/</a></code>)
-
-  <dt>[RFC3066]
-  <dd><a name="refsRFC3066"></a> H. Alvestrand; "<cite>Tags for the Identification of Languages</cite>", Request for Comments 3066, January 2001
-  <dd>(<a href="http://www.ietf.org/rfc/rfc3066.txt"><code>http://www.ietf.org/rfc/rfc3066.txt</code></a>)
-
-  <dt>[STTS]
-  <dd><a name=refsSTTS></a> Daniel Glazman; "<cite>Simple Tree Transformation Sheets 3</cite>", Electricit&eacute; de France, submission to the W3C, 11 November 1998
-  <dd>(<code><a href="http://www.w3.org/TR/NOTE-STTS3">http://www.w3.org/TR/NOTE-STTS3</a></code>)
-
-  <dt>[SVG]
-  <dd><a name="refsSVG"></a> Jon Ferraiolo, &#34276;&#27810; &#28147;, Dean Jackson, editors; "<cite>Scalable Vector Graphics (SVG) 1.1 Specification</cite>", W3C Recommendation, 14 January 2003
-  <dd>(<code><a href="http://www.w3.org/TR/SVG/">http://www.w3.org/TR/SVG/</a></code>)
-
-  <dt>[UNICODE]</dt>
-  <dd><a name="refsUNICODE"></a> <cite><a
-   href="http://www.unicode.org/versions/Unicode4.1.0/">The Unicode Standard, Version 4.1</a></cite>, The Unicode Consortium. Boston, MA, Addison-Wesley, March 2005. ISBN 0-321-18578-1, as amended by <a href="http://www.unicode.org/versions/Unicode4.0.1/">Unicode 4.0.1</a> and <a href="http://www.unicode.org/versions/Unicode4.1.0/">Unicode  4.1.0</a>.
-  <dd>(<code><a href="http://www.unicode.org/versions/">http://www.unicode.org/versions/</a></code>)</dd>
-
-  <dt>[XML10]
-  <dd><a name="refsXML10"></a> Tim Bray, Jean Paoli, C. M. Sperberg-McQueen, Eve Maler, Fran&ccedil;ois Yergeau, editors; "<cite>Extensible Markup Language (XML) 1.0 (Third Edition)</cite>", W3C Recommendation, 4 February 2004
-  <dd>(<a href="http://www.w3.org/TR/REC-xml/"><code>http://www.w3.org/TR/REC-xml/</code></a>)
-
-  <dt>[XMLNAMES]
-  <dd><a name="refsXMLNAMES"></a> Tim Bray, Dave Hollander, Andrew Layman, editors; "<cite>Namespaces in XML</cite>", W3C Recommendation, 14 January 1999
-  <dd>(<a href="http://www.w3.org/TR/REC-xml-names/"><code>http://www.w3.org/TR/REC-xml-names/</code></a>)
-
-  <dt>[YACC]
-  <dd><a name="refsYACC"></a> S. C. Johnson; "<cite>YACC &mdash; Yet another compiler compiler</cite>", Technical Report, Murray Hill, 1975
-
-</dl>
-</body>
-</html>
index 1665fc1..788a221 100644 (file)
@@ -1,7 +1,7 @@
 <html>
 <head>
 <script src="../htmlrunner.js"></script>
-<script src="https://ajax.googleapis.com/ajax/libs/prototype/1.7.0.0/prototype.js"></script>
+<script src="../lib/prototype-1.7.js"></script>
 <script>
 window.onload = function(){
 startTest("cssquery-prototype", 'a6eb02e3');
index 9c74066..916a1f1 100644 (file)
@@ -1,7 +1,7 @@
 <html>
 <head>
 <script src="../htmlrunner.js"></script>
-<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.6.4/jquery.min.js"></script>
+<script src="../lib/jquery-1.6.4.js"></script>
 <script>
 window.onload = function(){
 startTest("jslib-attr-jquery", 'bab725d6');
index 867a925..238df57 100644 (file)
@@ -1,7 +1,7 @@
 <html>
 <head>
 <script src="../htmlrunner.js"></script>
-<script src="https://ajax.googleapis.com/ajax/libs/prototype/1.7.0.0/prototype.js"></script>
+<script src="../lib/prototype-1.7.js"></script>
 <script>
 window.onload = function(){
 startTest("jslib-attr-prototype", 'a2753b79');
index 0a13d2e..72b5552 100644 (file)
@@ -1,7 +1,7 @@
 <html>
 <head>
 <script src="../htmlrunner.js"></script>
-<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.6.4/jquery.min.js"></script>
+<script src="../lib/jquery-1.6.4.js"></script>
 <script>
 window.onload = function(){
 startTest("jslib-event-jquery", 'e7fab8ee');
index 4cad75f..71f29af 100644 (file)
@@ -1,7 +1,7 @@
 <html>
 <head>
 <script src="../htmlrunner.js"></script>
-<script src="https://ajax.googleapis.com/ajax/libs/prototype/1.7.0.0/prototype.js"></script>
+<script src="../lib/prototype-1.7.js"></script>
 <script>
 window.onload = function(){
 startTest("jslib-event-prototype", '1c979bdc');
index 7a27cbe..dadff3b 100644 (file)
@@ -1,7 +1,7 @@
 <html>
 <head>
 <script src="../htmlrunner.js"></script>
-<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.6.4/jquery.min.js"></script>
+<script src="../lib/jquery-1.6.4.js"></script>
 <script>
 window.onload = function(){
 startTest("jslib-modify-jquery", '4dda1446');
index a8ff98c..da7acb2 100644 (file)
@@ -1,7 +1,7 @@
 <html>
 <head>
 <script src="../htmlrunner.js"></script>
-<script src="https://ajax.googleapis.com/ajax/libs/prototype/1.7.0.0/prototype.js"></script>
+<script src="../lib/prototype-1.7.js"></script>
 <script>
 window.onload = function(){
 startTest("jslib-modify-prototype", 'b0a7f89d');
index a358747..1f9beac 100644 (file)
@@ -1,7 +1,7 @@
 <html>
 <head>
 <script src="../htmlrunner.js"></script>
-<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.6.4/jquery.min.js"></script>
+<script src="../lib/jquery-1.6.4.js"></script>
 <script>
 window.onload = function(){
 startTest("jslib-style-jquery", '48860295');
index 8188803..5c7e69e 100644 (file)
@@ -1,7 +1,7 @@
 <html>
 <head>
 <script src="../htmlrunner.js"></script>
-<script src="https://ajax.googleapis.com/ajax/libs/prototype/1.7.0.0/prototype.js"></script>
+<script src="../lib/prototype-1.7.js"></script>
 <script>
 window.onload = function(){
 startTest("jslib-style-prototype", 'dd94462e');
index 010b3d9..3c3d741 100644 (file)
@@ -1,7 +1,7 @@
 <html>
 <head>
 <script src="../htmlrunner.js"></script>
-<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.6.4/jquery.min.js"></script>
+<script src="../lib/jquery-1.6.4.js"></script>
 <script>
 window.onload = function(){
 startTest("jslib-traverse-jquery", '08696563');
index 643a03f..a8b795a 100644 (file)
@@ -1,7 +1,7 @@
 <html>
 <head>
 <script src="../htmlrunner.js"></script>
-<script src="https://ajax.googleapis.com/ajax/libs/prototype/1.7.0.0/prototype.js"></script>
+<script src="../lib/prototype-1.7.js"></script>
 <script>
 window.onload = function(){
 startTest("jslib-traverse-prototype", '16ac685d');
diff --git a/PerformanceTests/Dromaeo/sunspider-3d-morph.html b/PerformanceTests/Dromaeo/sunspider-3d-morph.html
new file mode 100644 (file)
index 0000000..dea109e
--- /dev/null
@@ -0,0 +1,15 @@
+<!DOCTYPE html>
+<html>
+<head>
+<script src="../resources/runner.js"></script>
+<script src="resources/dromaeo/web/jquery.js"></script>
+<script src="resources/dromaeorunner.js"></script>
+<script>
+$(document).ready(function() {
+    DRT.setup("sunspider-3d-morph");
+});
+</script>
+</head>
+<body>
+</body>
+</html>
diff --git a/PerformanceTests/Dromaeo/sunspider-3d-raytrace.html b/PerformanceTests/Dromaeo/sunspider-3d-raytrace.html
new file mode 100644 (file)
index 0000000..e61cdc4
--- /dev/null
@@ -0,0 +1,15 @@
+<!DOCTYPE html>
+<html>
+<head>
+<script src="../resources/runner.js"></script>
+<script src="resources/dromaeo/web/jquery.js"></script>
+<script src="resources/dromaeorunner.js"></script>
+<script>
+$(document).ready(function() {
+    DRT.setup("sunspider-3d-raytrace");
+});
+</script>
+</head>
+<body>
+</body>
+</html>
diff --git a/PerformanceTests/Dromaeo/sunspider-access-binary-trees.html b/PerformanceTests/Dromaeo/sunspider-access-binary-trees.html
new file mode 100644 (file)
index 0000000..d9f8556
--- /dev/null
@@ -0,0 +1,15 @@
+<!DOCTYPE html>
+<html>
+<head>
+<script src="../resources/runner.js"></script>
+<script src="resources/dromaeo/web/jquery.js"></script>
+<script src="resources/dromaeorunner.js"></script>
+<script>
+$(document).ready(function() {
+    DRT.setup("sunspider-access-binary-trees");
+});
+</script>
+</head>
+<body>
+</body>
+</html>
diff --git a/PerformanceTests/Dromaeo/sunspider-access-fannkuch.html b/PerformanceTests/Dromaeo/sunspider-access-fannkuch.html
new file mode 100644 (file)
index 0000000..1d0b7df
--- /dev/null
@@ -0,0 +1,15 @@
+<!DOCTYPE html>
+<html>
+<head>
+<script src="../resources/runner.js"></script>
+<script src="resources/dromaeo/web/jquery.js"></script>
+<script src="resources/dromaeorunner.js"></script>
+<script>
+$(document).ready(function() {
+    DRT.setup("sunspider-access-fannkuch");
+});
+</script>
+</head>
+<body>
+</body>
+</html>
diff --git a/PerformanceTests/Dromaeo/sunspider-access-nbody.html b/PerformanceTests/Dromaeo/sunspider-access-nbody.html
new file mode 100644 (file)
index 0000000..6c6bfcd
--- /dev/null
@@ -0,0 +1,15 @@
+<!DOCTYPE html>
+<html>
+<head>
+<script src="../resources/runner.js"></script>
+<script src="resources/dromaeo/web/jquery.js"></script>
+<script src="resources/dromaeorunner.js"></script>
+<script>
+$(document).ready(function() {
+    DRT.setup("sunspider-access-nbody");
+});
+</script>
+</head>
+<body>
+</body>
+</html>
diff --git a/PerformanceTests/Dromaeo/sunspider-access-nsieve.html b/PerformanceTests/Dromaeo/sunspider-access-nsieve.html
new file mode 100644 (file)
index 0000000..a4c9528
--- /dev/null
@@ -0,0 +1,15 @@
+<!DOCTYPE html>
+<html>
+<head>
+<script src="../resources/runner.js"></script>
+<script src="resources/dromaeo/web/jquery.js"></script>
+<script src="resources/dromaeorunner.js"></script>
+<script>
+$(document).ready(function() {
+    DRT.setup("sunspider-access-nsieve");
+});
+</script>
+</head>
+<body>
+</body>
+</html>
diff --git a/PerformanceTests/Dromaeo/sunspider-bitops-3bit-bits-in-byte.html b/PerformanceTests/Dromaeo/sunspider-bitops-3bit-bits-in-byte.html
new file mode 100644 (file)
index 0000000..6fe28c8
--- /dev/null
@@ -0,0 +1,15 @@
+<!DOCTYPE html>
+<html>
+<head>
+<script src="../resources/runner.js"></script>
+<script src="resources/dromaeo/web/jquery.js"></script>
+<script src="resources/dromaeorunner.js"></script>
+<script>
+$(document).ready(function() {
+    DRT.setup("sunspider-bitops-3bit-bits-in-byte");
+});
+</script>
+</head>
+<body>
+</body>
+</html>
diff --git a/PerformanceTests/Dromaeo/sunspider-bitops-bits-in-byte.html b/PerformanceTests/Dromaeo/sunspider-bitops-bits-in-byte.html
new file mode 100644 (file)
index 0000000..841228b
--- /dev/null
@@ -0,0 +1,15 @@
+<!DOCTYPE html>
+<html>
+<head>
+<script src="../resources/runner.js"></script>
+<script src="resources/dromaeo/web/jquery.js"></script>
+<script src="resources/dromaeorunner.js"></script>
+<script>
+$(document).ready(function() {
+    DRT.setup("sunspider-bitops-bits-in-byte");
+});
+</script>
+</head>
+<body>
+</body>
+</html>
diff --git a/PerformanceTests/Dromaeo/sunspider-bitops-bitwise-and.html b/PerformanceTests/Dromaeo/sunspider-bitops-bitwise-and.html
new file mode 100644 (file)
index 0000000..f57e48a
--- /dev/null
@@ -0,0 +1,15 @@
+<!DOCTYPE html>
+<html>
+<head>
+<script src="../resources/runner.js"></script>
+<script src="resources/dromaeo/web/jquery.js"></script>
+<script src="resources/dromaeorunner.js"></script>
+<script>
+$(document).ready(function() {
+    DRT.setup("sunspider-bitops-bitwise-and");
+});
+</script>
+</head>
+<body>
+</body>
+</html>
diff --git a/PerformanceTests/Dromaeo/sunspider-bitops-nsieve-bits.html b/PerformanceTests/Dromaeo/sunspider-bitops-nsieve-bits.html
new file mode 100644 (file)
index 0000000..2e00431
--- /dev/null
@@ -0,0 +1,15 @@
+<!DOCTYPE html>
+<html>
+<head>
+<script src="../resources/runner.js"></script>
+<script src="resources/dromaeo/web/jquery.js"></script>
+<script src="resources/dromaeorunner.js"></script>
+<script>
+$(document).ready(function() {
+    DRT.setup("sunspider-bitops-nsieve-bits");
+});
+</script>
+</head>
+<body>
+</body>
+</html>
diff --git a/PerformanceTests/Dromaeo/sunspider-controlflow-recursive.html b/PerformanceTests/Dromaeo/sunspider-controlflow-recursive.html
new file mode 100644 (file)
index 0000000..7089d1e
--- /dev/null
@@ -0,0 +1,15 @@
+<!DOCTYPE html>
+<html>
+<head>
+<script src="../resources/runner.js"></script>
+<script src="resources/dromaeo/web/jquery.js"></script>
+<script src="resources/dromaeorunner.js"></script>
+<script>
+$(document).ready(function() {
+    DRT.setup("sunspider-controlflow-recursive");
+});
+</script>
+</head>
+<body>
+</body>
+</html>
diff --git a/PerformanceTests/Dromaeo/sunspider-crypto-aes.html b/PerformanceTests/Dromaeo/sunspider-crypto-aes.html
new file mode 100644 (file)
index 0000000..46acdfc
--- /dev/null
@@ -0,0 +1,15 @@
+<!DOCTYPE html>
+<html>
+<head>
+<script src="../resources/runner.js"></script>
+<script src="resources/dromaeo/web/jquery.js"></script>
+<script src="resources/dromaeorunner.js"></script>
+<script>
+$(document).ready(function() {
+    DRT.setup("sunspider-crypto-aes");
+});
+</script>
+</head>
+<body>
+</body>
+</html>
diff --git a/PerformanceTests/Dromaeo/sunspider-crypto-md5.html b/PerformanceTests/Dromaeo/sunspider-crypto-md5.html
new file mode 100644 (file)
index 0000000..8fcd0c9
--- /dev/null
@@ -0,0 +1,15 @@
+<!DOCTYPE html>
+<html>
+<head>
+<script src="../resources/runner.js"></script>
+<script src="resources/dromaeo/web/jquery.js"></script>
+<script src="resources/dromaeorunner.js"></script>
+<script>
+$(document).ready(function() {
+    DRT.setup("sunspider-crypto-md5");
+});
+</script>
+</head>
+<body>
+</body>
+</html>
diff --git a/PerformanceTests/Dromaeo/sunspider-crypto-sha1.html b/PerformanceTests/Dromaeo/sunspider-crypto-sha1.html
new file mode 100644 (file)
index 0000000..d7f51c2
--- /dev/null
@@ -0,0 +1,15 @@
+<!DOCTYPE html>
+<html>
+<head>
+<script src="../resources/runner.js"></script>
+<script src="resources/dromaeo/web/jquery.js"></script>
+<script src="resources/dromaeorunner.js"></script>
+<script>
+$(document).ready(function() {
+    DRT.setup("sunspider-crypto-sha1");
+});
+</script>
+</head>
+<body>
+</body>
+</html>
diff --git a/PerformanceTests/Dromaeo/sunspider-date-format-tofte.html b/PerformanceTests/Dromaeo/sunspider-date-format-tofte.html
new file mode 100644 (file)
index 0000000..a1b48d4
--- /dev/null
@@ -0,0 +1,15 @@
+<!DOCTYPE html>
+<html>
+<head>
+<script src="../resources/runner.js"></script>
+<script src="resources/dromaeo/web/jquery.js"></script>
+<script src="resources/dromaeorunner.js"></script>
+<script>
+$(document).ready(function() {
+    DRT.setup("sunspider-date-format-tofte");
+});
+</script>
+</head>
+<body>
+</body>
+</html>
diff --git a/PerformanceTests/Dromaeo/sunspider-date-format-xparb.html b/PerformanceTests/Dromaeo/sunspider-date-format-xparb.html
new file mode 100644 (file)
index 0000000..ff93a5f
--- /dev/null
@@ -0,0 +1,15 @@
+<!DOCTYPE html>
+<html>
+<head>
+<script src="../resources/runner.js"></script>
+<script src="resources/dromaeo/web/jquery.js"></script>
+<script src="resources/dromaeorunner.js"></script>
+<script>
+$(document).ready(function() {
+    DRT.setup("sunspider-date-format-xparb");
+});
+</script>
+</head>
+<body>
+</body>
+</html>
diff --git a/PerformanceTests/Dromaeo/sunspider-math-cordic.html b/PerformanceTests/Dromaeo/sunspider-math-cordic.html
new file mode 100644 (file)
index 0000000..14ce6b5
--- /dev/null
@@ -0,0 +1,15 @@
+<!DOCTYPE html>
+<html>
+<head>
+<script src="../resources/runner.js"></script>
+<script src="resources/dromaeo/web/jquery.js"></script>
+<script src="resources/dromaeorunner.js"></script>
+<script>
+$(document).ready(function() {
+    DRT.setup("sunspider-math-cordic");
+});
+</script>
+</head>
+<body>
+</body>
+</html>
diff --git a/PerformanceTests/Dromaeo/sunspider-math-partial-sums.html b/PerformanceTests/Dromaeo/sunspider-math-partial-sums.html
new file mode 100644 (file)
index 0000000..147110b
--- /dev/null
@@ -0,0 +1,15 @@
+<!DOCTYPE html>
+<html>
+<head>
+<script src="../resources/runner.js"></script>
+<script src="resources/dromaeo/web/jquery.js"></script>
+<script src="resources/dromaeorunner.js"></script>
+<script>
+$(document).ready(function() {
+    DRT.setup("sunspider-math-partial-sums");
+});
+</script>
+</head>
+<body>
+</body>
+</html>
diff --git a/PerformanceTests/Dromaeo/sunspider-math-spectral-norm.html b/PerformanceTests/Dromaeo/sunspider-math-spectral-norm.html
new file mode 100644 (file)
index 0000000..61ac0f4
--- /dev/null
@@ -0,0 +1,15 @@
+<!DOCTYPE html>
+<html>
+<head>
+<script src="../resources/runner.js"></script>
+<script src="resources/dromaeo/web/jquery.js"></script>
+<script src="resources/dromaeorunner.js"></script>
+<script>
+$(document).ready(function() {
+    DRT.setup("sunspider-math-spectral-norm");
+});
+</script>
+</head>
+<body>
+</body>
+</html>
diff --git a/PerformanceTests/Dromaeo/sunspider-regexp-dna.html b/PerformanceTests/Dromaeo/sunspider-regexp-dna.html
new file mode 100644 (file)
index 0000000..ffc7800
--- /dev/null
@@ -0,0 +1,15 @@
+<!DOCTYPE html>
+<html>
+<head>
+<script src="../resources/runner.js"></script>
+<script src="resources/dromaeo/web/jquery.js"></script>
+<script src="resources/dromaeorunner.js"></script>
+<script>
+$(document).ready(function() {
+    DRT.setup("sunspider-regexp-dna");
+});
+</script>
+</head>
+<body>
+</body>
+</html>
diff --git a/PerformanceTests/Dromaeo/sunspider-string-fasta.html b/PerformanceTests/Dromaeo/sunspider-string-fasta.html
new file mode 100644 (file)
index 0000000..c5db5ad
--- /dev/null
@@ -0,0 +1,15 @@
+<!DOCTYPE html>
+<html>
+<head>
+<script src="../resources/runner.js"></script>
+<script src="resources/dromaeo/web/jquery.js"></script>
+<script src="resources/dromaeorunner.js"></script>
+<script>
+$(document).ready(function() {
+    DRT.setup("sunspider-string-fasta");
+});
+</script>
+</head>
+<body>
+</body>
+</html>
diff --git a/PerformanceTests/Dromaeo/sunspider-string-tagcloud.html b/PerformanceTests/Dromaeo/sunspider-string-tagcloud.html
new file mode 100644 (file)
index 0000000..abf2c28
--- /dev/null
@@ -0,0 +1,15 @@
+<!DOCTYPE html>
+<html>
+<head>
+<script src="../resources/runner.js"></script>
+<script src="resources/dromaeo/web/jquery.js"></script>
+<script src="resources/dromaeorunner.js"></script>
+<script>
+$(document).ready(function() {
+    DRT.setup("sunspider-string-tagcloud");
+});
+</script>
+</head>
+<body>
+</body>
+</html>
diff --git a/PerformanceTests/Dromaeo/sunspider-string-unpack-code.html b/PerformanceTests/Dromaeo/sunspider-string-unpack-code.html
new file mode 100644 (file)
index 0000000..7433107
--- /dev/null
@@ -0,0 +1,15 @@
+<!DOCTYPE html>
+<html>
+<head>
+<script src="../resources/runner.js"></script>
+<script src="resources/dromaeo/web/jquery.js"></script>
+<script src="resources/dromaeorunner.js"></script>
+<script>
+$(document).ready(function() {
+    DRT.setup("sunspider-string-unpack-code");
+});
+</script>
+</head>
+<body>
+</body>
+</html>
diff --git a/PerformanceTests/Dromaeo/sunspider-string-validate-input.html b/PerformanceTests/Dromaeo/sunspider-string-validate-input.html
new file mode 100644 (file)
index 0000000..bcd2c60
--- /dev/null
@@ -0,0 +1,15 @@
+<!DOCTYPE html>
+<html>
+<head>
+<script src="../resources/runner.js"></script>
+<script src="resources/dromaeo/web/jquery.js"></script>
+<script src="resources/dromaeorunner.js"></script>
+<script>
+$(document).ready(function() {
+    DRT.setup("sunspider-string-validate-input");
+});
+</script>
+</head>
+<body>
+</body>
+</html>
diff --git a/PerformanceTests/Dromaeo/v8-crypto.html b/PerformanceTests/Dromaeo/v8-crypto.html
new file mode 100644 (file)
index 0000000..459267e
--- /dev/null
@@ -0,0 +1,15 @@
+<!DOCTYPE html>
+<html>
+<head>
+<script src="../resources/runner.js"></script>
+<script src="resources/dromaeo/web/jquery.js"></script>
+<script src="resources/dromaeorunner.js"></script>
+<script>
+$(document).ready(function() {
+    DRT.setup("v8-crypto");
+});
+</script>
+</head>
+<body>
+</body>
+</html>
diff --git a/PerformanceTests/Dromaeo/v8-deltablue.html b/PerformanceTests/Dromaeo/v8-deltablue.html
new file mode 100644 (file)
index 0000000..67e9067
--- /dev/null
@@ -0,0 +1,15 @@
+<!DOCTYPE html>
+<html>
+<head>
+<script src="../resources/runner.js"></script>
+<script src="resources/dromaeo/web/jquery.js"></script>
+<script src="resources/dromaeorunner.js"></script>
+<script>
+$(document).ready(function() {
+    DRT.setup("v8-deltablue");
+});
+</script>
+</head>
+<body>
+</body>
+</html>
diff --git a/PerformanceTests/Dromaeo/v8-earley-boyer.html b/PerformanceTests/Dromaeo/v8-earley-boyer.html
new file mode 100644 (file)
index 0000000..5817b06
--- /dev/null
@@ -0,0 +1,15 @@
+<!DOCTYPE html>
+<html>
+<head>
+<script src="../resources/runner.js"></script>
+<script src="resources/dromaeo/web/jquery.js"></script>
+<script src="resources/dromaeorunner.js"></script>
+<script>
+$(document).ready(function() {
+    DRT.setup("v8-earley-boyer");
+});
+</script>
+</head>
+<body>
+</body>
+</html>
diff --git a/PerformanceTests/Dromaeo/v8-raytrace.html b/PerformanceTests/Dromaeo/v8-raytrace.html
new file mode 100644 (file)
index 0000000..d519bd9
--- /dev/null
@@ -0,0 +1,15 @@
+<!DOCTYPE html>
+<html>
+<head>
+<script src="../resources/runner.js"></script>
+<script src="resources/dromaeo/web/jquery.js"></script>
+<script src="resources/dromaeorunner.js"></script>
+<script>
+$(document).ready(function() {
+    DRT.setup("v8-raytrace");
+});
+</script>
+</head>
+<body>
+</body>
+</html>
diff --git a/PerformanceTests/Dromaeo/v8-richards.html b/PerformanceTests/Dromaeo/v8-richards.html
new file mode 100644 (file)
index 0000000..503ef2e
--- /dev/null
@@ -0,0 +1,15 @@
+<!DOCTYPE html>
+<html>
+<head>
+<script src="../resources/runner.js"></script>
+<script src="resources/dromaeo/web/jquery.js"></script>
+<script src="resources/dromaeorunner.js"></script>
+<script>
+$(document).ready(function() {
+    DRT.setup("v8-richards");
+});
+</script>
+</head>
+<body>
+</body>
+</html>
index 1a0b4dd..3b48a08 100644 (file)
@@ -7,6 +7,35 @@ PageLoad
 SunSpider
 XSSAuditor
 
+# We have pure JS tests separately outside Dromaeo.
+Dromaeo/sunspider-3d-morph.html
+Dromaeo/sunspider-3d-raytrace.html
+Dromaeo/sunspider-access-binary-trees.html
+Dromaeo/sunspider-access-fannkuch.html
+Dromaeo/sunspider-access-nbody.html
+Dromaeo/sunspider-access-nsieve.html
+Dromaeo/sunspider-bitops-3bit-bits-in-byte.html
+Dromaeo/sunspider-bitops-bits-in-byte.html
+Dromaeo/sunspider-bitops-bitwise-and.html
+Dromaeo/sunspider-bitops-nsieve-bits.html
+Dromaeo/sunspider-controlflow-recursive.html
+Dromaeo/sunspider-crypto-aes.html
+Dromaeo/sunspider-date-format-tofte.html
+Dromaeo/sunspider-date-format-xparb.html
+Dromaeo/sunspider-math-cordic.html
+Dromaeo/sunspider-math-partial-sums.html
+Dromaeo/sunspider-math-spectral-norm.html
+Dromaeo/sunspider-regexp-dna.html
+Dromaeo/sunspider-string-fasta.html
+Dromaeo/sunspider-string-tagcloud.html
+Dromaeo/sunspider-string-unpack-code.html
+Dromaeo/sunspider-string-validate-input.html
+Dromaeo/v8-crypto.html
+Dromaeo/v8-deltablue.html
+Dromaeo/v8-earley-boyer.html
+Dromaeo/v8-raytrace.html
+Dromaeo/v8-richards.html
+
 # Bug 77024 - Web Inspector: tests in PerformanceTests/inspector/ are timing out
 inspector
 
index 6eb2b0d..eb19594 100644 (file)
@@ -1,3 +1,15 @@
+2012-02-02  Hajime Morrita  <morrita@chromium.org>
+
+        [PerformanceTests] Each Dromaeo test needs its landing html.
+        https://bugs.webkit.org/show_bug.cgi?id=77504
+
+        Reviewed by Ryosuke Niwa.
+
+        Added an ignorable pattern which happens in some Dromaeo tests.
+
+        * Scripts/webkitpy/performance_tests/perftestsrunner.py:
+        (PerfTestsRunner):
+
 2012-02-06  Kalev Lember  <kalevlember@gmail.com>
 
         [GTK] Add missing pango include dir to fix build
index c0af45f..dd5eea2 100644 (file)
@@ -246,7 +246,8 @@ class PerfTestsRunner(object):
         re.compile(r'^\d+(.\d+)?$'),
         # Following are for handle existing test like Dromaeo
         re.compile(re.escape("""main frame - has 1 onunload handler(s)""")),
-        re.compile(re.escape("""frame "<!--framePath //<!--frame0-->-->" - has 1 onunload handler(s)"""))]
+        re.compile(re.escape("""frame "<!--framePath //<!--frame0-->-->" - has 1 onunload handler(s)""")),
+        re.compile(re.escape("""frame "<!--framePath //<!--frame0-->/<!--frame0-->-->" - has 1 onunload handler(s)"""))]
 
     def _should_ignore_line_in_parser_test_result(self, line):
         if not line: