Importing dromaeo performance tests to src/chrome/test/data.

Committing this for Anton Muhin (antonm@chromium.org).

BUG=none
TEST=none



Review URL: http://codereview.chromium.org/269054

Cr-Mirrored-From: https://chromium.googlesource.com/chromium/src
Cr-Mirrored-Commit: 66cc1b917a01179e5f3f3869dd763be8d1dd27a2
diff --git a/JSON.php b/JSON.php
new file mode 100644
index 0000000..0cddbdd
--- /dev/null
+++ b/JSON.php
@@ -0,0 +1,806 @@
+<?php
+/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
+
+/**
+ * Converts to and from JSON format.
+ *
+ * JSON (JavaScript Object Notation) is a lightweight data-interchange
+ * format. It is easy for humans to read and write. It is easy for machines
+ * to parse and generate. It is based on a subset of the JavaScript
+ * Programming Language, Standard ECMA-262 3rd Edition - December 1999.
+ * This feature can also be found in  Python. JSON is a text format that is
+ * completely language independent but uses conventions that are familiar
+ * to programmers of the C-family of languages, including C, C++, C#, Java,
+ * JavaScript, Perl, TCL, and many others. These properties make JSON an
+ * ideal data-interchange language.
+ *
+ * This package provides a simple encoder and decoder for JSON notation. It
+ * is intended for use with client-side Javascript applications that make
+ * use of HTTPRequest to perform server communication functions - data can
+ * be encoded into JSON notation for use in a client-side javascript, or
+ * decoded from incoming Javascript requests. JSON format is native to
+ * Javascript, and can be directly eval()'ed with no further parsing
+ * overhead
+ *
+ * All strings should be in ASCII or UTF-8 format!
+ *
+ * LICENSE: Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met: Redistributions of source code must retain the
+ * above copyright notice, this list of conditions and the following
+ * disclaimer. Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
+ * NO EVENT SHALL CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
+ * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
+ * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ * @category
+ * @package     Services_JSON
+ * @author      Michal Migurski <mike-json@teczno.com>
+ * @author      Matt Knapp <mdknapp[at]gmail[dot]com>
+ * @author      Brett Stimmerman <brettstimmerman[at]gmail[dot]com>
+ * @copyright   2005 Michal Migurski
+ * @version     CVS: $Id: JSON.php,v 1.31 2006/06/28 05:54:17 migurski Exp $
+ * @license     http://www.opensource.org/licenses/bsd-license.php
+ * @link        http://pear.php.net/pepr/pepr-proposal-show.php?id=198
+ */
+
+/**
+ * Marker constant for Services_JSON::decode(), used to flag stack state
+ */
+define('SERVICES_JSON_SLICE',   1);
+
+/**
+ * Marker constant for Services_JSON::decode(), used to flag stack state
+ */
+define('SERVICES_JSON_IN_STR',  2);
+
+/**
+ * Marker constant for Services_JSON::decode(), used to flag stack state
+ */
+define('SERVICES_JSON_IN_ARR',  3);
+
+/**
+ * Marker constant for Services_JSON::decode(), used to flag stack state
+ */
+define('SERVICES_JSON_IN_OBJ',  4);
+
+/**
+ * Marker constant for Services_JSON::decode(), used to flag stack state
+ */
+define('SERVICES_JSON_IN_CMT', 5);
+
+/**
+ * Behavior switch for Services_JSON::decode()
+ */
+define('SERVICES_JSON_LOOSE_TYPE', 16);
+
+/**
+ * Behavior switch for Services_JSON::decode()
+ */
+define('SERVICES_JSON_SUPPRESS_ERRORS', 32);
+
+/**
+ * Converts to and from JSON format.
+ *
+ * Brief example of use:
+ *
+ * <code>
+ * // create a new instance of Services_JSON
+ * $json = new Services_JSON();
+ *
+ * // convert a complexe value to JSON notation, and send it to the browser
+ * $value = array('foo', 'bar', array(1, 2, 'baz'), array(3, array(4)));
+ * $output = $json->encode($value);
+ *
+ * print($output);
+ * // prints: ["foo","bar",[1,2,"baz"],[3,[4]]]
+ *
+ * // accept incoming POST data, assumed to be in JSON notation
+ * $input = file_get_contents('php://input', 1000000);
+ * $value = $json->decode($input);
+ * </code>
+ */
+class Services_JSON
+{
+   /**
+    * constructs a new JSON instance
+    *
+    * @param    int     $use    object behavior flags; combine with boolean-OR
+    *
+    *                           possible values:
+    *                           - SERVICES_JSON_LOOSE_TYPE:  loose typing.
+    *                                   "{...}" syntax creates associative arrays
+    *                                   instead of objects in decode().
+    *                           - SERVICES_JSON_SUPPRESS_ERRORS:  error suppression.
+    *                                   Values which can't be encoded (e.g. resources)
+    *                                   appear as NULL instead of throwing errors.
+    *                                   By default, a deeply-nested resource will
+    *                                   bubble up with an error, so all return values
+    *                                   from encode() should be checked with isError()
+    */
+    function Services_JSON($use = 0)
+    {
+        $this->use = $use;
+    }
+
+   /**
+    * convert a string from one UTF-16 char to one UTF-8 char
+    *
+    * Normally should be handled by mb_convert_encoding, but
+    * provides a slower PHP-only method for installations
+    * that lack the multibye string extension.
+    *
+    * @param    string  $utf16  UTF-16 character
+    * @return   string  UTF-8 character
+    * @access   private
+    */
+    function utf162utf8($utf16)
+    {
+        // oh please oh please oh please oh please oh please
+        if(function_exists('mb_convert_encoding')) {
+            return mb_convert_encoding($utf16, 'UTF-8', 'UTF-16');
+        }
+
+        $bytes = (ord($utf16{0}) << 8) | ord($utf16{1});
+
+        switch(true) {
+            case ((0x7F & $bytes) == $bytes):
+                // this case should never be reached, because we are in ASCII range
+                // see: http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
+                return chr(0x7F & $bytes);
+
+            case (0x07FF & $bytes) == $bytes:
+                // return a 2-byte UTF-8 character
+                // see: http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
+                return chr(0xC0 | (($bytes >> 6) & 0x1F))
+                     . chr(0x80 | ($bytes & 0x3F));
+
+            case (0xFFFF & $bytes) == $bytes:
+                // return a 3-byte UTF-8 character
+                // see: http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
+                return chr(0xE0 | (($bytes >> 12) & 0x0F))
+                     . chr(0x80 | (($bytes >> 6) & 0x3F))
+                     . chr(0x80 | ($bytes & 0x3F));
+        }
+
+        // ignoring UTF-32 for now, sorry
+        return '';
+    }
+
+   /**
+    * convert a string from one UTF-8 char to one UTF-16 char
+    *
+    * Normally should be handled by mb_convert_encoding, but
+    * provides a slower PHP-only method for installations
+    * that lack the multibye string extension.
+    *
+    * @param    string  $utf8   UTF-8 character
+    * @return   string  UTF-16 character
+    * @access   private
+    */
+    function utf82utf16($utf8)
+    {
+        // oh please oh please oh please oh please oh please
+        if(function_exists('mb_convert_encoding')) {
+            return mb_convert_encoding($utf8, 'UTF-16', 'UTF-8');
+        }
+
+        switch(strlen($utf8)) {
+            case 1:
+                // this case should never be reached, because we are in ASCII range
+                // see: http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
+                return $utf8;
+
+            case 2:
+                // return a UTF-16 character from a 2-byte UTF-8 char
+                // see: http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
+                return chr(0x07 & (ord($utf8{0}) >> 2))
+                     . chr((0xC0 & (ord($utf8{0}) << 6))
+                         | (0x3F & ord($utf8{1})));
+
+            case 3:
+                // return a UTF-16 character from a 3-byte UTF-8 char
+                // see: http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
+                return chr((0xF0 & (ord($utf8{0}) << 4))
+                         | (0x0F & (ord($utf8{1}) >> 2)))
+                     . chr((0xC0 & (ord($utf8{1}) << 6))
+                         | (0x7F & ord($utf8{2})));
+        }
+
+        // ignoring UTF-32 for now, sorry
+        return '';
+    }
+
+   /**
+    * encodes an arbitrary variable into JSON format
+    *
+    * @param    mixed   $var    any number, boolean, string, array, or object to be encoded.
+    *                           see argument 1 to Services_JSON() above for array-parsing behavior.
+    *                           if var is a strng, note that encode() always expects it
+    *                           to be in ASCII or UTF-8 format!
+    *
+    * @return   mixed   JSON string representation of input var or an error if a problem occurs
+    * @access   public
+    */
+    function encode($var)
+    {
+        switch (gettype($var)) {
+            case 'boolean':
+                return $var ? 'true' : 'false';
+
+            case 'NULL':
+                return 'null';
+
+            case 'integer':
+                return (int) $var;
+
+            case 'double':
+            case 'float':
+                return (float) $var;
+
+            case 'string':
+                // STRINGS ARE EXPECTED TO BE IN ASCII OR UTF-8 FORMAT
+                $ascii = '';
+                $strlen_var = strlen($var);
+
+               /*
+                * Iterate over every character in the string,
+                * escaping with a slash or encoding to UTF-8 where necessary
+                */
+                for ($c = 0; $c < $strlen_var; ++$c) {
+
+                    $ord_var_c = ord($var{$c});
+
+                    switch (true) {
+                        case $ord_var_c == 0x08:
+                            $ascii .= '\b';
+                            break;
+                        case $ord_var_c == 0x09:
+                            $ascii .= '\t';
+                            break;
+                        case $ord_var_c == 0x0A:
+                            $ascii .= '\n';
+                            break;
+                        case $ord_var_c == 0x0C:
+                            $ascii .= '\f';
+                            break;
+                        case $ord_var_c == 0x0D:
+                            $ascii .= '\r';
+                            break;
+
+                        case $ord_var_c == 0x22:
+                        case $ord_var_c == 0x2F:
+                        case $ord_var_c == 0x5C:
+                            // double quote, slash, slosh
+                            $ascii .= '\\'.$var{$c};
+                            break;
+
+                        case (($ord_var_c >= 0x20) && ($ord_var_c <= 0x7F)):
+                            // characters U-00000000 - U-0000007F (same as ASCII)
+                            $ascii .= $var{$c};
+                            break;
+
+                        case (($ord_var_c & 0xE0) == 0xC0):
+                            // characters U-00000080 - U-000007FF, mask 110XXXXX
+                            // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
+                            $char = pack('C*', $ord_var_c, ord($var{$c + 1}));
+                            $c += 1;
+                            $utf16 = $this->utf82utf16($char);
+                            $ascii .= sprintf('\u%04s', bin2hex($utf16));
+                            break;
+
+                        case (($ord_var_c & 0xF0) == 0xE0):
+                            // characters U-00000800 - U-0000FFFF, mask 1110XXXX
+                            // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
+                            $char = pack('C*', $ord_var_c,
+                                         ord($var{$c + 1}),
+                                         ord($var{$c + 2}));
+                            $c += 2;
+                            $utf16 = $this->utf82utf16($char);
+                            $ascii .= sprintf('\u%04s', bin2hex($utf16));
+                            break;
+
+                        case (($ord_var_c & 0xF8) == 0xF0):
+                            // characters U-00010000 - U-001FFFFF, mask 11110XXX
+                            // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
+                            $char = pack('C*', $ord_var_c,
+                                         ord($var{$c + 1}),
+                                         ord($var{$c + 2}),
+                                         ord($var{$c + 3}));
+                            $c += 3;
+                            $utf16 = $this->utf82utf16($char);
+                            $ascii .= sprintf('\u%04s', bin2hex($utf16));
+                            break;
+
+                        case (($ord_var_c & 0xFC) == 0xF8):
+                            // characters U-00200000 - U-03FFFFFF, mask 111110XX
+                            // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
+                            $char = pack('C*', $ord_var_c,
+                                         ord($var{$c + 1}),
+                                         ord($var{$c + 2}),
+                                         ord($var{$c + 3}),
+                                         ord($var{$c + 4}));
+                            $c += 4;
+                            $utf16 = $this->utf82utf16($char);
+                            $ascii .= sprintf('\u%04s', bin2hex($utf16));
+                            break;
+
+                        case (($ord_var_c & 0xFE) == 0xFC):
+                            // characters U-04000000 - U-7FFFFFFF, mask 1111110X
+                            // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
+                            $char = pack('C*', $ord_var_c,
+                                         ord($var{$c + 1}),
+                                         ord($var{$c + 2}),
+                                         ord($var{$c + 3}),
+                                         ord($var{$c + 4}),
+                                         ord($var{$c + 5}));
+                            $c += 5;
+                            $utf16 = $this->utf82utf16($char);
+                            $ascii .= sprintf('\u%04s', bin2hex($utf16));
+                            break;
+                    }
+                }
+
+                return '"'.$ascii.'"';
+
+            case 'array':
+               /*
+                * As per JSON spec if any array key is not an integer
+                * we must treat the the whole array as an object. We
+                * also try to catch a sparsely populated associative
+                * array with numeric keys here because some JS engines
+                * will create an array with empty indexes up to
+                * max_index which can cause memory issues and because
+                * the keys, which may be relevant, will be remapped
+                * otherwise.
+                *
+                * As per the ECMA and JSON specification an object may
+                * have any string as a property. Unfortunately due to
+                * a hole in the ECMA specification if the key is a
+                * ECMA reserved word or starts with a digit the
+                * parameter is only accessible using ECMAScript's
+                * bracket notation.
+                */
+
+                // treat as a JSON object
+                if (is_array($var) && count($var) && (array_keys($var) !== range(0, sizeof($var) - 1))) {
+                    $properties = array_map(array($this, 'name_value'),
+                                            array_keys($var),
+                                            array_values($var));
+
+                    foreach($properties as $property) {
+                        if(Services_JSON::isError($property)) {
+                            return $property;
+                        }
+                    }
+
+                    return '{' . join(',', $properties) . '}';
+                }
+
+                // treat it like a regular array
+                $elements = array_map(array($this, 'encode'), $var);
+
+                foreach($elements as $element) {
+                    if(Services_JSON::isError($element)) {
+                        return $element;
+                    }
+                }
+
+                return '[' . join(',', $elements) . ']';
+
+            case 'object':
+                $vars = get_object_vars($var);
+
+                $properties = array_map(array($this, 'name_value'),
+                                        array_keys($vars),
+                                        array_values($vars));
+
+                foreach($properties as $property) {
+                    if(Services_JSON::isError($property)) {
+                        return $property;
+                    }
+                }
+
+                return '{' . join(',', $properties) . '}';
+
+            default:
+                return ($this->use & SERVICES_JSON_SUPPRESS_ERRORS)
+                    ? 'null'
+                    : new Services_JSON_Error(gettype($var)." can not be encoded as JSON string");
+        }
+    }
+
+   /**
+    * array-walking function for use in generating JSON-formatted name-value pairs
+    *
+    * @param    string  $name   name of key to use
+    * @param    mixed   $value  reference to an array element to be encoded
+    *
+    * @return   string  JSON-formatted name-value pair, like '"name":value'
+    * @access   private
+    */
+    function name_value($name, $value)
+    {
+        $encoded_value = $this->encode($value);
+
+        if(Services_JSON::isError($encoded_value)) {
+            return $encoded_value;
+        }
+
+        return $this->encode(strval($name)) . ':' . $encoded_value;
+    }
+
+   /**
+    * reduce a string by removing leading and trailing comments and whitespace
+    *
+    * @param    $str    string      string value to strip of comments and whitespace
+    *
+    * @return   string  string value stripped of comments and whitespace
+    * @access   private
+    */
+    function reduce_string($str)
+    {
+        $str = preg_replace(array(
+
+                // eliminate single line comments in '// ...' form
+                '#^\s*//(.+)$#m',
+
+                // eliminate multi-line comments in '/* ... */' form, at start of string
+                '#^\s*/\*(.+)\*/#Us',
+
+                // eliminate multi-line comments in '/* ... */' form, at end of string
+                '#/\*(.+)\*/\s*$#Us'
+
+            ), '', $str);
+
+        // eliminate extraneous space
+        return trim($str);
+    }
+
+   /**
+    * decodes a JSON string into appropriate variable
+    *
+    * @param    string  $str    JSON-formatted string
+    *
+    * @return   mixed   number, boolean, string, array, or object
+    *                   corresponding to given JSON input string.
+    *                   See argument 1 to Services_JSON() above for object-output behavior.
+    *                   Note that decode() always returns strings
+    *                   in ASCII or UTF-8 format!
+    * @access   public
+    */
+    function decode($str)
+    {
+        $str = $this->reduce_string($str);
+
+        switch (strtolower($str)) {
+            case 'true':
+                return true;
+
+            case 'false':
+                return false;
+
+            case 'null':
+                return null;
+
+            default:
+                $m = array();
+
+                if (is_numeric($str)) {
+                    // Lookie-loo, it's a number
+
+                    // This would work on its own, but I'm trying to be
+                    // good about returning integers where appropriate:
+                    // return (float)$str;
+
+                    // Return float or int, as appropriate
+                    return ((float)$str == (integer)$str)
+                        ? (integer)$str
+                        : (float)$str;
+
+                } elseif (preg_match('/^("|\').*(\1)$/s', $str, $m) && $m[1] == $m[2]) {
+                    // STRINGS RETURNED IN UTF-8 FORMAT
+                    $delim = substr($str, 0, 1);
+                    $chrs = substr($str, 1, -1);
+                    $utf8 = '';
+                    $strlen_chrs = strlen($chrs);
+
+                    for ($c = 0; $c < $strlen_chrs; ++$c) {
+
+                        $substr_chrs_c_2 = substr($chrs, $c, 2);
+                        $ord_chrs_c = ord($chrs{$c});
+
+                        switch (true) {
+                            case $substr_chrs_c_2 == '\b':
+                                $utf8 .= chr(0x08);
+                                ++$c;
+                                break;
+                            case $substr_chrs_c_2 == '\t':
+                                $utf8 .= chr(0x09);
+                                ++$c;
+                                break;
+                            case $substr_chrs_c_2 == '\n':
+                                $utf8 .= chr(0x0A);
+                                ++$c;
+                                break;
+                            case $substr_chrs_c_2 == '\f':
+                                $utf8 .= chr(0x0C);
+                                ++$c;
+                                break;
+                            case $substr_chrs_c_2 == '\r':
+                                $utf8 .= chr(0x0D);
+                                ++$c;
+                                break;
+
+                            case $substr_chrs_c_2 == '\\"':
+                            case $substr_chrs_c_2 == '\\\'':
+                            case $substr_chrs_c_2 == '\\\\':
+                            case $substr_chrs_c_2 == '\\/':
+                                if (($delim == '"' && $substr_chrs_c_2 != '\\\'') ||
+                                   ($delim == "'" && $substr_chrs_c_2 != '\\"')) {
+                                    $utf8 .= $chrs{++$c};
+                                }
+                                break;
+
+                            case preg_match('/\\\u[0-9A-F]{4}/i', substr($chrs, $c, 6)):
+                                // single, escaped unicode character
+                                $utf16 = chr(hexdec(substr($chrs, ($c + 2), 2)))
+                                       . chr(hexdec(substr($chrs, ($c + 4), 2)));
+                                $utf8 .= $this->utf162utf8($utf16);
+                                $c += 5;
+                                break;
+
+                            case ($ord_chrs_c >= 0x20) && ($ord_chrs_c <= 0x7F):
+                                $utf8 .= $chrs{$c};
+                                break;
+
+                            case ($ord_chrs_c & 0xE0) == 0xC0:
+                                // characters U-00000080 - U-000007FF, mask 110XXXXX
+                                //see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
+                                $utf8 .= substr($chrs, $c, 2);
+                                ++$c;
+                                break;
+
+                            case ($ord_chrs_c & 0xF0) == 0xE0:
+                                // characters U-00000800 - U-0000FFFF, mask 1110XXXX
+                                // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
+                                $utf8 .= substr($chrs, $c, 3);
+                                $c += 2;
+                                break;
+
+                            case ($ord_chrs_c & 0xF8) == 0xF0:
+                                // characters U-00010000 - U-001FFFFF, mask 11110XXX
+                                // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
+                                $utf8 .= substr($chrs, $c, 4);
+                                $c += 3;
+                                break;
+
+                            case ($ord_chrs_c & 0xFC) == 0xF8:
+                                // characters U-00200000 - U-03FFFFFF, mask 111110XX
+                                // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
+                                $utf8 .= substr($chrs, $c, 5);
+                                $c += 4;
+                                break;
+
+                            case ($ord_chrs_c & 0xFE) == 0xFC:
+                                // characters U-04000000 - U-7FFFFFFF, mask 1111110X
+                                // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
+                                $utf8 .= substr($chrs, $c, 6);
+                                $c += 5;
+                                break;
+
+                        }
+
+                    }
+
+                    return $utf8;
+
+                } elseif (preg_match('/^\[.*\]$/s', $str) || preg_match('/^\{.*\}$/s', $str)) {
+                    // array, or object notation
+
+                    if ($str{0} == '[') {
+                        $stk = array(SERVICES_JSON_IN_ARR);
+                        $arr = array();
+                    } else {
+                        if ($this->use & SERVICES_JSON_LOOSE_TYPE) {
+                            $stk = array(SERVICES_JSON_IN_OBJ);
+                            $obj = array();
+                        } else {
+                            $stk = array(SERVICES_JSON_IN_OBJ);
+                            $obj = new stdClass();
+                        }
+                    }
+
+                    array_push($stk, array('what'  => SERVICES_JSON_SLICE,
+                                           'where' => 0,
+                                           'delim' => false));
+
+                    $chrs = substr($str, 1, -1);
+                    $chrs = $this->reduce_string($chrs);
+
+                    if ($chrs == '') {
+                        if (reset($stk) == SERVICES_JSON_IN_ARR) {
+                            return $arr;
+
+                        } else {
+                            return $obj;
+
+                        }
+                    }
+
+                    //print("\nparsing {$chrs}\n");
+
+                    $strlen_chrs = strlen($chrs);
+
+                    for ($c = 0; $c <= $strlen_chrs; ++$c) {
+
+                        $top = end($stk);
+                        $substr_chrs_c_2 = substr($chrs, $c, 2);
+
+                        if (($c == $strlen_chrs) || (($chrs{$c} == ',') && ($top['what'] == SERVICES_JSON_SLICE))) {
+                            // found a comma that is not inside a string, array, etc.,
+                            // OR we've reached the end of the character list
+                            $slice = substr($chrs, $top['where'], ($c - $top['where']));
+                            array_push($stk, array('what' => SERVICES_JSON_SLICE, 'where' => ($c + 1), 'delim' => false));
+                            //print("Found split at {$c}: ".substr($chrs, $top['where'], (1 + $c - $top['where']))."\n");
+
+                            if (reset($stk) == SERVICES_JSON_IN_ARR) {
+                                // we are in an array, so just push an element onto the stack
+                                array_push($arr, $this->decode($slice));
+
+                            } elseif (reset($stk) == SERVICES_JSON_IN_OBJ) {
+                                // we are in an object, so figure
+                                // out the property name and set an
+                                // element in an associative array,
+                                // for now
+                                $parts = array();
+                                
+                                if (preg_match('/^\s*(["\'].*[^\\\]["\'])\s*:\s*(\S.*),?$/Uis', $slice, $parts)) {
+                                    // "name":value pair
+                                    $key = $this->decode($parts[1]);
+                                    $val = $this->decode($parts[2]);
+
+                                    if ($this->use & SERVICES_JSON_LOOSE_TYPE) {
+                                        $obj[$key] = $val;
+                                    } else {
+                                        $obj->$key = $val;
+                                    }
+                                } elseif (preg_match('/^\s*(\w+)\s*:\s*(\S.*),?$/Uis', $slice, $parts)) {
+                                    // name:value pair, where name is unquoted
+                                    $key = $parts[1];
+                                    $val = $this->decode($parts[2]);
+
+                                    if ($this->use & SERVICES_JSON_LOOSE_TYPE) {
+                                        $obj[$key] = $val;
+                                    } else {
+                                        $obj->$key = $val;
+                                    }
+                                }
+
+                            }
+
+                        } elseif ((($chrs{$c} == '"') || ($chrs{$c} == "'")) && ($top['what'] != SERVICES_JSON_IN_STR)) {
+                            // found a quote, and we are not inside a string
+                            array_push($stk, array('what' => SERVICES_JSON_IN_STR, 'where' => $c, 'delim' => $chrs{$c}));
+                            //print("Found start of string at {$c}\n");
+
+                        } elseif (($chrs{$c} == $top['delim']) &&
+                                 ($top['what'] == SERVICES_JSON_IN_STR) &&
+                                 ((strlen(substr($chrs, 0, $c)) - strlen(rtrim(substr($chrs, 0, $c), '\\'))) % 2 != 1)) {
+                            // found a quote, we're in a string, and it's not escaped
+                            // we know that it's not escaped becase there is _not_ an
+                            // odd number of backslashes at the end of the string so far
+                            array_pop($stk);
+                            //print("Found end of string at {$c}: ".substr($chrs, $top['where'], (1 + 1 + $c - $top['where']))."\n");
+
+                        } elseif (($chrs{$c} == '[') &&
+                                 in_array($top['what'], array(SERVICES_JSON_SLICE, SERVICES_JSON_IN_ARR, SERVICES_JSON_IN_OBJ))) {
+                            // found a left-bracket, and we are in an array, object, or slice
+                            array_push($stk, array('what' => SERVICES_JSON_IN_ARR, 'where' => $c, 'delim' => false));
+                            //print("Found start of array at {$c}\n");
+
+                        } elseif (($chrs{$c} == ']') && ($top['what'] == SERVICES_JSON_IN_ARR)) {
+                            // found a right-bracket, and we're in an array
+                            array_pop($stk);
+                            //print("Found end of array at {$c}: ".substr($chrs, $top['where'], (1 + $c - $top['where']))."\n");
+
+                        } elseif (($chrs{$c} == '{') &&
+                                 in_array($top['what'], array(SERVICES_JSON_SLICE, SERVICES_JSON_IN_ARR, SERVICES_JSON_IN_OBJ))) {
+                            // found a left-brace, and we are in an array, object, or slice
+                            array_push($stk, array('what' => SERVICES_JSON_IN_OBJ, 'where' => $c, 'delim' => false));
+                            //print("Found start of object at {$c}\n");
+
+                        } elseif (($chrs{$c} == '}') && ($top['what'] == SERVICES_JSON_IN_OBJ)) {
+                            // found a right-brace, and we're in an object
+                            array_pop($stk);
+                            //print("Found end of object at {$c}: ".substr($chrs, $top['where'], (1 + $c - $top['where']))."\n");
+
+                        } elseif (($substr_chrs_c_2 == '/*') &&
+                                 in_array($top['what'], array(SERVICES_JSON_SLICE, SERVICES_JSON_IN_ARR, SERVICES_JSON_IN_OBJ))) {
+                            // found a comment start, and we are in an array, object, or slice
+                            array_push($stk, array('what' => SERVICES_JSON_IN_CMT, 'where' => $c, 'delim' => false));
+                            $c++;
+                            //print("Found start of comment at {$c}\n");
+
+                        } elseif (($substr_chrs_c_2 == '*/') && ($top['what'] == SERVICES_JSON_IN_CMT)) {
+                            // found a comment end, and we're in one now
+                            array_pop($stk);
+                            $c++;
+
+                            for ($i = $top['where']; $i <= $c; ++$i)
+                                $chrs = substr_replace($chrs, ' ', $i, 1);
+
+                            //print("Found end of comment at {$c}: ".substr($chrs, $top['where'], (1 + $c - $top['where']))."\n");
+
+                        }
+
+                    }
+
+                    if (reset($stk) == SERVICES_JSON_IN_ARR) {
+                        return $arr;
+
+                    } elseif (reset($stk) == SERVICES_JSON_IN_OBJ) {
+                        return $obj;
+
+                    }
+
+                }
+        }
+    }
+
+    /**
+     * @todo Ultimately, this should just call PEAR::isError()
+     */
+    function isError($data, $code = null)
+    {
+        if (class_exists('pear')) {
+            return PEAR::isError($data, $code);
+        } elseif (is_object($data) && (get_class($data) == 'services_json_error' ||
+                                 is_subclass_of($data, 'services_json_error'))) {
+            return true;
+        }
+
+        return false;
+    }
+}
+
+if (class_exists('PEAR_Error')) {
+
+    class Services_JSON_Error extends PEAR_Error
+    {
+        function Services_JSON_Error($message = 'unknown error', $code = null,
+                                     $mode = null, $options = null, $userinfo = null)
+        {
+            parent::PEAR_Error($message, $code, $mode, $options, $userinfo);
+        }
+    }
+
+} else {
+
+    /**
+     * @todo Ultimately, this class shall be descended from PEAR_Error
+     */
+    class Services_JSON_Error
+    {
+        function Services_JSON_Error($message = 'unknown error', $code = null,
+                                     $mode = null, $options = null, $userinfo = null)
+        {
+
+        }
+    }
+
+}
+    
+?>
diff --git a/README.chromium b/README.chromium
new file mode 100644
index 0000000..07aec2a
--- /dev/null
+++ b/README.chromium
@@ -0,0 +1,6 @@
+This directory contains Dromaeo, a JavaScript and DOM performance benchmark.
+
+Dromaeo was developed and released by John Resig (jresig at mozilla.com)/
+
+This copy was fecthed from http://github.com/jeresig/dromaeo (at commit
+0b96e6b0f98996853e1a302b9783f83fc57c5ffa) and built with make web.
diff --git a/application.css b/application.css
new file mode 100644
index 0000000..e540dd2
--- /dev/null
+++ b/application.css
@@ -0,0 +1,115 @@
+ol.results { text-align: left; display: none; font-size: 10px; list-style: none; display: none; }
+.alldone ol.results { display: block; width: 48%; float: left; }
+ol.results li { clear: both; overflow: auto; }
+ol.results b { display: block; width: 200px; float: left; text-align: right; padding-right: 15px; }
+#info { clear:both;width:420px;margin:0 auto;text-align:left; padding: 10px; }
+div.results { width:420px;margin:0 auto;margin-bottom:20px;text-align:left; padding: 10px 10px 10px 10px; }
+#info span { font-weight: bold; padding-top: 8px; }
+h1 { text-align: left; }
+h1 img { float:left;margin-right: 15px;margin-top: -10px; border: 0; }
+h1 small { font-weight:normal; }
+iframe { display: none; }
+div.resultwrap { text-align: center; }
+table.results { font-size: 12px; margin: 0 auto; }
+table.results td, table.results th.name, table.results th { text-align: right; }
+table.results .winner { color: #000; background-color: #c7331d; }
+table.results .tie { color: #000; background-color: #f9f2a1; }
+
+body  {
+	font: normal 11px "Lucida Grande", Helvetica, Arial, sans-serif;
+	background: black url(images/bg.png) repeat-x;
+	margin: 0px auto;
+	padding: 0px; 
+	color: #eee; 
+	text-align: center;
+	line-height: 180%;
+}	
+div, img, form, ul {
+	margin: 0px; 
+	padding: 0px;
+	border: 0px; 
+}
+small			{font-size: 9px;}
+div, span, td, .text_l {text-align: left;}	
+.clear 			{clear: both;}	
+.text_r 		{text-align: right;}
+.text_c 		{text-align: center;}
+a 				{font: normal  "Arial", sans-serif; color: #f9f2a1; }
+.left 			{float: left;}
+.right 			{float: right;}
+
+#wrapper 		{width: 690px; margin: 0px auto; padding: 0px; margin-top: -7px; text-align: center;}
+#content		{margin-bottom: 30px;}
+#main			{padding-bottom: 40px;}
+
+#top			{background: url(images/top.png) repeat-x; height: 250px;}
+#logo			{position: absolute; top: 0; left: 0; width: 100%; text-align: center; z-index: 100;}
+#logo img		{ margin: 0px auto; padding: 0px;}
+.dino1			{position: absolute; top: 105px; right: 300px; z-index: 15;}
+.dino2			{position: absolute; top: 110px; left: 15%;  z-index: 12;}
+.dino3			{position: absolute; top: 120px; left: 400px;  z-index: 31;}
+.dino4			{position: absolute; top: 96px; left: 200px;  z-index: 8;}
+.dino5			{position: absolute; top: 110px; right: 85px;  z-index: 14;}
+.dino6			{position: absolute; top: 105px; left: 30%;  z-index: 14;}
+.dino7			{position: absolute; top: 110px; left: 70%;  z-index: 22;}
+.dino8			{position: absolute; top: 105px; left: 37%;  z-index: 20;}
+.coment			{position: absolute; top: 0px; right: 0px;  z-index: 2; float: right;}
+
+.clouds			{position: absolute; top: 10px; right: 11%;  z-index: 12;}
+.clouds2		{position: absolute; top: 50px; right: 29%;  z-index: 13;}
+.clouds5		{position: absolute; top: 0px; right: 15%;  z-index: 16;}
+.clouds3			{position: absolute; top: 15px; left: 10%;  z-index: 15;}
+.clouds4		{position: absolute; top: 10px; left: 15%;  z-index: 14;}
+
+.water		{position: absolute; top: 110px; right: 9%;  z-index: 13;}
+
+
+/* rendered html stuff */
+
+table.results	{text-align: center; margin: 0px auto; padding: 0px; background: none;}
+table.results td, table.results th 			{padding: 2px;}
+table.results tr.onetest td, table.results tr.onetest th 			{padding: 0px;}
+table.results tr.hidden { display: none; }
+#info			{margin-bottom: 10px;}
+table.results .winner			{background: #58bd79;}
+.name			{font-weight: bold;}
+
+div.resultwrap	{margin: 10px 0 10px 0;}
+div.results		{padding: 10px; margin-bottom: 20px; background: #c7331d;}
+
+div.result-item { position: relative; width: 48%; float: left; overflow: hidden; margin-left: 1%; margin-right: 1%; height: 100px; }
+.alldone div.result-item { width: 98%; height: auto; margin-bottom: 10px; overflow: auto; }
+.alldone div.result-item p { width: 48%; float: left; }
+
+div.result-item p { padding: 0px 4px; }
+
+div.test { overflow: hidden; margin: 4px 0; }
+div.test b { display: block; width: 100%; text-align: left; margin: 0px; background: #c7331d; padding: 4px; }
+/*div.done div.test b {background: #58bd79;}*/
+div.done div.test b {background: #222;}
+div.bar { width: 100px; border: 1px inset #666; background: #c7331d; text-align: left; position: absolute; top: 7px; right: 4px; }
+div.bar div { height: 20px; background: #222; text-align: right; }
+div.done div.bar div {background: #58bd79; color: #000;}
+div.bar span { padding-left: 5px; padding-right: 5px; }
+
+#info { margin: auto; }
+
+h1 { font-size: 28px; border-bottom: 1px solid #AAA; position: relative; padding: 0px 1% 2px 1%;}
+h1 div.bar { font-size: 10px; width: 275px; top: -2px; right: 1%; }
+h1 input { position: absolute; top: 0px; right: 300px; }
+
+h2 { font-size: 20px; border-bottom: 1px solid #AAA; position: relative; padding: 0px 1% 2px 1%;}
+h2 a { color: #FFF; }
+h2 div.bar { font-size: 10px; width: 275px; top: -2px; right: 1%; }
+h2 input { position: absolute; top: 0px; right: 300px; }
+
+ul#tests { clear:both;width:420px;margin:0 auto;text-align:left; padding: 10px; list-style: none; }
+#tests b { background: #c7331d; color: #000; display: block; padding: 4px 0 4px 4px; margin-left: -20px; margin-bottom: 5px; font-size: 1.1em; -webkit-border-radius: 4px; -moz-border-radius: 4px; font-weight: normal; }
+#tests b.recommended { background: #58bd79; }
+#tests a:first-of-type { font-size: 1.2em; }
+#tests b a { font-weight: bold; color: #000; }
+#tests li { padding-left: 10px; padding-bottom: 5px; }
+
+#overview { position: relative; }
+#overview a { font-size: 10px; top: -29px; left: 8px; position: absolute; }
+#overview table a { position: static; }
diff --git a/favicon.ico b/favicon.ico
new file mode 100644
index 0000000..d444389
--- /dev/null
+++ b/favicon.ico
Binary files differ
diff --git a/favicon.png b/favicon.png
new file mode 100644
index 0000000..d772102
--- /dev/null
+++ b/favicon.png
Binary files differ
diff --git a/htmlrunner.js b/htmlrunner.js
new file mode 100644
index 0000000..1365792
--- /dev/null
+++ b/htmlrunner.js
@@ -0,0 +1,4 @@
+var startTest = top.startTest || function(){};
+var test = top.test || function(name, fn){ fn(); };
+var endTest = top.endTest || function(){};
+var prep = top.prep || function(fn){ fn(); };
diff --git a/ie.css b/ie.css
new file mode 100644
index 0000000..aca3787
--- /dev/null
+++ b/ie.css
@@ -0,0 +1,30 @@
+/* -------------------------------------------------------------- 
+   
+   ie.css
+   
+   Contains every hack for Internet Explorer versions prior 
+   to IE7, so that our core files stay sweet and nimble.
+   
+-------------------------------------------------------------- */
+
+/* Make sure the layout is centered in IE5 */
+body        { text-align: center; }
+.container  { text-align: left; }
+
+
+/* This fixes the problem where IE6 adds an extra 3px margin to
+   two columns that are floated up against each other. */
+
+* html .column { overflow-x: hidden; } /* IE6 fix */
+
+.pull-1, .pull-2, .pull-3, .pull-4,
+.push-1, .push-2, .push-3, .push-4, 
+ul, ol {
+  position: relative; /* Keeps IE6 from cutting pulled/pushed images */
+}
+
+/* Fixes incorrect styling of legend in IE6 fieldsets. */
+legend { margin-bottom:1.4em; }
+
+/* Fixes incorrect placement of numbers in ol's in IE6/7 */
+ol { margin-left:2em; }
\ No newline at end of file
diff --git a/images/bg.png b/images/bg.png
new file mode 100644
index 0000000..bd659a8
--- /dev/null
+++ b/images/bg.png
Binary files differ
diff --git a/images/clouds.png b/images/clouds.png
new file mode 100644
index 0000000..c9f7dc2
--- /dev/null
+++ b/images/clouds.png
Binary files differ
diff --git a/images/clouds2.png b/images/clouds2.png
new file mode 100644
index 0000000..ac835dc
--- /dev/null
+++ b/images/clouds2.png
Binary files differ
diff --git a/images/comets.png b/images/comets.png
new file mode 100644
index 0000000..37dd962
--- /dev/null
+++ b/images/comets.png
Binary files differ
diff --git a/images/dino1.png b/images/dino1.png
new file mode 100644
index 0000000..2dda272
--- /dev/null
+++ b/images/dino1.png
Binary files differ
diff --git a/images/dino2.png b/images/dino2.png
new file mode 100644
index 0000000..ccfa15c
--- /dev/null
+++ b/images/dino2.png
Binary files differ
diff --git a/images/dino3.png b/images/dino3.png
new file mode 100644
index 0000000..a766b28
--- /dev/null
+++ b/images/dino3.png
Binary files differ
diff --git a/images/dino4.png b/images/dino4.png
new file mode 100644
index 0000000..03301d3
--- /dev/null
+++ b/images/dino4.png
Binary files differ
diff --git a/images/dino5.png b/images/dino5.png
new file mode 100644
index 0000000..5fd028d
--- /dev/null
+++ b/images/dino5.png
Binary files differ
diff --git a/images/dino6.png b/images/dino6.png
new file mode 100644
index 0000000..ded8106
--- /dev/null
+++ b/images/dino6.png
Binary files differ
diff --git a/images/dino7.png b/images/dino7.png
new file mode 100644
index 0000000..ac2021b
--- /dev/null
+++ b/images/dino7.png
Binary files differ
diff --git a/images/dino8.png b/images/dino8.png
new file mode 100644
index 0000000..a4b1fe4
--- /dev/null
+++ b/images/dino8.png
Binary files differ
diff --git a/images/left.png b/images/left.png
new file mode 100644
index 0000000..b688f2b
--- /dev/null
+++ b/images/left.png
Binary files differ
diff --git a/images/logo.png b/images/logo.png
new file mode 100644
index 0000000..199fda7
--- /dev/null
+++ b/images/logo.png
Binary files differ
diff --git a/images/logo2.png b/images/logo2.png
new file mode 100644
index 0000000..427687f
--- /dev/null
+++ b/images/logo2.png
Binary files differ
diff --git a/images/logo3.png b/images/logo3.png
new file mode 100644
index 0000000..306c485
--- /dev/null
+++ b/images/logo3.png
Binary files differ
diff --git a/images/right.png b/images/right.png
new file mode 100644
index 0000000..154cb41
--- /dev/null
+++ b/images/right.png
Binary files differ
diff --git a/images/top.png b/images/top.png
new file mode 100644
index 0000000..24039c3
--- /dev/null
+++ b/images/top.png
Binary files differ
diff --git a/images/water.png b/images/water.png
new file mode 100644
index 0000000..40a0f0d
--- /dev/null
+++ b/images/water.png
Binary files differ
diff --git a/index.html b/index.html
new file mode 100644
index 0000000..1a995d0
--- /dev/null
+++ b/index.html
@@ -0,0 +1,59 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+  <meta http-equiv="Content-Type" content="text/html; utf-8" />
+  <title>Dromaeo: JavaScript Performance Testing</title>
+  <link href="reset.css" rel="stylesheet" type="text/css" />
+  <!--[if lt IE 7.]>
+  <link href="ie.css" rel="stylesheet" type="text/css" />
+  <script defer type="text/javascript" src="pngfix.js"></script>
+  <![endif]-->
+  <link href="application.css" rel="stylesheet" type="text/css" />
+  <script src="jquery.js"></script>
+  <script src="json.js"></script>
+  <script src="webrunner.js"></script>
+</head>
+<body>
+        <div id="top" >
+          <div id="logo">
+            <a href="./"><img src="images/logo3.png" class="png"/></a>
+          </div>
+          <img src="images/dino1.png" class="dino1 png"/>
+          <img src="images/left.png" class="left png"/>
+          <img src="images/dino2.png" class="dino2 png"/>
+          <img src="images/dino2.png" class="dino2 png"/>
+          <img src="images/dino3.png" class="dino3 png"/>
+          <img src="images/dino4.png" class="dino4 png"/>
+          <img src="images/dino5.png" class="dino5 png"/>
+          <img src="images/dino7.png" class="dino7 png"/>
+          <img src="images/dino8.png" class="dino8 png"/>
+          <img src="images/dino6.png" class="dino6 png"/>
+          <img src="images/clouds2.png" class="clouds2 png"/>
+          <img src="images/clouds.png" class="clouds png"/>
+          <img src="images/clouds2.png" class="clouds3 png"/>
+          <img src="images/clouds.png" class="clouds4 png"/>
+          <img src="images/clouds2.png" class="clouds5 png"/>
+          <img src="images/comets.png" class="right png"/>
+        </div>
+        <div id="wrapper">
+        <div id="main">
+<div id="info"><span>Mozilla JavaScript performance test suite.</span><br/>More information about <a href="http://wiki.mozilla.org/Dromaeo">Dromaeo</a> can be found on the Mozilla wiki.</div>
+<h1 id="overview" class="test"><span>Performance Tests</span> <input type="button" id="pause" class="pause" value="Loading..."/><div class="bar"><div id="timebar" style="width:25%;"><span class="left">Est.&nbsp;Time:&nbsp;<strong id="left">0:00</strong></span></div></div><a href="./">&laquo; View All Tests</a></h1><br style="clear:both;"/>
+<ul id="tests">
+  <li><b class="recommended"><a href="?recommended">&raquo; Run Recommended Tests</a><br/>(All tests except for those testing the CSS Selector engines.)</b></li>
+  <li><b><a href="?all">&raquo; Run All Tests</a></b><br/><br/></li>
+
+  <li><b><a href="?dromaeo|sunspider|v8">&raquo; Run All JavaScript Tests</a></b></li>
+  <li><a href="?dromaeo">Dromaeo JavaScript Tests</a><br/>(Tests Strings, RegExps, Arrays, and eval.)</li>
+  <li><a href="?sunspider">SunSpider JavaScript Tests</a><br/>(From the <a href="http://www2.webkit.org/perf/sunspider-0.9/sunspider.html">WebKit team</a>. Tests Math, Bitops, Looping, and Functions.)</li>
+  <li><a href="?v8">V8 JavaScript Tests</a><br/>(From the <a href="http://code.google.com/apis/v8/benchmarks.html">V8 team</a>. Tests Functions, Strings, and Objects.)<br/><br/></li>
+
+  <li><b><a href="?dom|jslib|cssquery">&raquo; Run All DOM Tests</a></b></li>
+  <li><a href="?dom">DOM Core Tests</a><br/>(Tests DOM Querying, Traversing, Manipulation, and Atributes.)</li>
+  <li><a href="?jslib">JavaScript Library Tests</a><br/>(Tests DOM functionality in jQuery and Prototype.)</li>
+  <li><a href="?cssquery">CSS Selector Tests</a><br/>(From the <a href="http://code.google.com/p/slickspeed/">MooTools team</a>. Tests jQuery, Prototype, Dojo, MooTools, YUI, and ExtJS.)</li>
+</ul>
+</div>
+</div>
+</body>
+</html>
diff --git a/jquery.js b/jquery.js
new file mode 100644
index 0000000..2e43a82
--- /dev/null
+++ b/jquery.js
@@ -0,0 +1,3408 @@
+(function(){
+/*
+ * jQuery 1.2.3 - 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-02-06 00:21:25 -0500 (Wed, 06 Feb 2008) $
+ * $Rev: 4663 $
+ */
+
+// Map over jQuery in case of overwrite
+if ( window.jQuery )
+	var _jQuery = window.jQuery;
+
+var jQuery = window.jQuery = function( selector, context ) {
+	// The jQuery object is actually just the init constructor 'enhanced'
+	return new jQuery.prototype.init( selector, context );
+};
+
+// Map over the $ in case of overwrite
+if ( window.$ )
+	var _$ = window.$;
+	
+// Map the jQuery namespace to the '$' one
+window.$ = jQuery;
+
+// 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
+var isSimple = /^.[^:#\[\.]*$/;
+
+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
+		} else 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
+						else {
+							this[0] = elem;
+							this.length = 1;
+							return this;
+						}
+
+					else
+						selector = [];
+				}
+
+			// HANDLE: $(expr, [context])
+			// (which is just equivalent to: $(content).find(expr)
+			} else
+				return new jQuery( context ).find( selector );
+
+		// HANDLE: $(function)
+		// Shortcut for document ready
+		} else if ( jQuery.isFunction( selector ) )
+			return new jQuery( document )[ jQuery.fn.ready ? "ready" : "load" ]( selector );
+
+		return this.setArray(
+			// HANDLE: $(array)
+			selector.constructor == Array && selector ||
+
+			// HANDLE: $(arraylike)
+			// Watch for when an array-like object, contains DOM nodes, is passed in as the selector
+			(selector.jquery || selector.length && selector != window && !selector.nodeType && selector[0] != undefined && selector[0].nodeType) && jQuery.makeArray( selector ) ||
+
+			// HANDLE: $(*)
+			[ selector ] );
+	},
+	
+	// The current version of jQuery being used
+	jquery: "1.2.3",
+
+	// 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
+		this.each(function(i){
+			if ( this == elem )
+				ret = i;
+		});
+
+		return ret;
+	},
+
+	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.length && jQuery[ type || "attr" ]( this[0], name ) || undefined;
+
+			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 !selector ? this : this.pushStack( jQuery.merge( 
+			this.get(),
+			selector.constructor == String ? 
+				jQuery( selector ).get() :
+				selector.length != undefined && (!selector.nodeName || jQuery.nodeName(selector, "form")) ?
+					selector : [selector] ) );
+	},
+
+	is: function( selector ) {
+		return selector ?
+			jQuery.multiFilter( selector, this ).length > 0 :
+			false;
+	},
+
+	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;
+		}
+
+		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 = value.constructor == Array ?
+					value :
+					[ 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.length ?
+				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 == null ) {
+			var data = this.triggerHandler("getData" + parts[1] + "!", [parts[0]]);
+			
+			if ( data == undefined && this.length )
+				data = jQuery.data( this[0], key );
+
+			return data == null && 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.prototype.init.prototype = jQuery.prototype;
+
+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 );
+}
+
+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 == 1 ) {
+		target = this;
+		i = 0;
+	}
+
+	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 ) {
+				// Prevent never-ending loop
+				if ( target === options[ name ] )
+					continue;
+
+				// Recurse if we're merging object values
+				if ( deep && options[ name ] && typeof options[ name ] == "object" && target[ name ] && !options[ name ].nodeType )
+					target[ name ] = jQuery.extend( target[ name ], options[ name ] );
+
+				// Don't bring in undefined values
+				else if ( options[ name ] != undefined )
+					target[ name ] = options[ name ];
+
+			}
+
+	// Return the modified object
+	return target;
+};
+
+var expando = "jQuery" + (new Date()).getTime(), uuid = 0, windowData = {};
+
+// exclude the following css properties to add px
+var exclude = /z-?index|font-?weight|opacity|zoom|line-?height/i;
+
+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 && /function/i.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 ) );
+
+			head.appendChild( script );
+			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 ) {
+		if ( args ) {
+			if ( object.length == undefined ) {
+				for ( var name in object )
+					if ( callback.apply( object[ name ], args ) === false )
+						break;
+			} else
+				for ( var i = 0, length = object.length; i < length; i++ )
+					if ( callback.apply( object[ i ], args ) === false )
+						break;
+
+		// A special, fast, case for the most common use of each
+		} else {
+			if ( object.length == undefined ) {
+				for ( var name in object )
+					if ( callback.call( object[ name ], name, object[ name ] ) === false )
+						break;
+			} else
+				for ( var i = 0, length = object.length, 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 is(".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;
+
+		// A helper method for determining if an element's values are broken
+		function color( elem ) {
+			if ( !jQuery.browser.safari )
+				return false;
+
+			var ret = document.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( elem.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 = elem.style.outline;
+			elem.style.outline = "0 solid black";
+			elem.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 && elem.style && elem.style[ name ] )
+			ret = elem.style[ name ];
+
+		else if ( document.defaultView && document.defaultView.getComputedStyle ) {
+
+			// Only "float" is needed here
+			if ( name.match( /float/i ) )
+				name = "float";
+
+			name = name.replace( /([A-Z])/g, "-$1" ).toLowerCase();
+
+			var getComputedStyle = document.defaultView.getComputedStyle( elem, null );
+
+			if ( getComputedStyle && !color( elem ) )
+				ret = getComputedStyle.getPropertyValue( name );
+
+			// If the element isn't reporting its values properly in Safari
+			// then some display: none elements are involved
+			else {
+				var swap = [], stack = [];
+
+				// Locate all of the parent display: none elements
+				for ( var a = elem; 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 ( var i = 0; 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" :
+					( getComputedStyle && getComputedStyle.getPropertyValue( name ) ) || "";
+
+				// Finally, revert the display styles back
+				for ( var 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 style = elem.style.left, runtimeStyle = elem.runtimeStyle.left;
+
+				// Put in the new values to get a computed value out
+				elem.runtimeStyle.left = elem.currentStyle.left;
+				elem.style.left = ret || 0;
+				ret = elem.style.pixelLeft + "px";
+
+				// Revert the changed values
+				elem.style.left = style;
+				elem.runtimeStyle.left = runtimeStyle;
+			}
+		}
+
+		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 = elem.toString();
+			
+			// 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 fix = jQuery.isXMLDoc( elem ) ?
+			{} :
+			jQuery.props;
+
+		// 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;
+		
+		// Certain attributes only work when accessed via the old DOM 0 way
+		if ( fix[ name ] ) {
+			if ( value != undefined )
+				elem[ fix[ name ] ] = value;
+
+			return elem[ fix[ name ] ];
+
+		} else if ( jQuery.browser.msie && name == "style" )
+			return jQuery.attr( elem.style, "cssText", value );
+
+		else if ( value == undefined && jQuery.browser.msie && jQuery.nodeName( elem, "form" ) && (name == "action" || name == "method") )
+			return elem.getAttributeNode( name ).nodeValue;
+
+		// IE elem.getAttribute passes even for style
+		else if ( elem.tagName ) {
+
+			if ( value != undefined ) {
+				// 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";
+
+				// convert the value to a string (all browsers do this but IE) see #1070
+				elem.setAttribute( name, "" + value );
+			}
+
+			if ( jQuery.browser.msie && /href|src/.test( name ) && !jQuery.isXMLDoc( elem ) ) 
+				return elem.getAttribute( name, 2 );
+
+			return elem.getAttribute( name );
+
+		// elem is actually elem.style ... set the style
+		} else {
+			// IE actually uses filters for opacity
+			if ( name == "opacity" && jQuery.browser.msie ) {
+				if ( value != undefined ) {
+					// 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\([^)]*\)/, "" ) +
+						(parseFloat( value ).toString() == "NaN" ? "" : "alpha(opacity=" + value * 100 + ")");
+				}
+	
+				return elem.filter && elem.filter.indexOf("opacity=") >= 0 ?
+					(parseFloat( elem.filter.match(/opacity=([^)]*)/)[1] ) / 100).toString() :
+					"";
+			}
+
+			name = name.replace(/-([a-z])/ig, function(all, letter){
+				return letter.toUpperCase();
+			});
+
+			if ( value != undefined )
+				elem[ name ] = value;
+
+			return elem[ name ];
+		}
+	},
+	
+	trim: function( text ) {
+		return (text || "").replace( /^\s+|\s+$/g, "" );
+	},
+
+	makeArray: function( array ) {
+		var ret = [];
+
+		// Need to use typeof to fight Safari childNodes crashes
+		if ( typeof array != "array" )
+			for ( var i = 0, length = array.length; i < length; i++ )
+				ret.push( array[ i ] );
+		else
+			ret = array.slice( 0 );
+
+		return ret;
+	},
+
+	inArray: function( elem, array ) {
+		for ( var i = 0, length = array.length; i < length; i++ )
+			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
+
+		// Also, we need to make sure that the correct elements are being returned
+		// (IE returns comment nodes in a '*' query)
+		if ( jQuery.browser.msie ) {
+			for ( var i = 0; second[ i ]; i++ )
+				if ( second[ i ].nodeType != 8 )
+					first.push( second[ i ] );
+
+		} else
+			for ( var i = 0; second[ i ]; i++ )
+				first.push( second[ i ] );
+
+		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 ) || 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 && value != undefined ) {
+				if ( value.constructor != Array )
+					value = [ value ];
+
+				ret = ret.concat( value );
+			}
+		}
+
+		return 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,
+		innerHTML: "innerHTML",
+		className: "className",
+		value: "value",
+		disabled: "disabled",
+		checked: "checked",
+		readonly: "readOnly",
+		selected: "selected",
+		maxlength: "maxLength",
+		selectedIndex: "selectedIndex",
+		defaultValue: "defaultValue",
+		tagName: "tagName",
+		nodeName: "nodeName"
+	}
+});
+
+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" );
+	};
+});
+
+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-chlid, #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
+			var re = quickChild;
+			var 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 = [];
+		var 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 && (!elem || 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 != undefined )
+			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 = function() { 
+				// Pass arguments and context to original handler 
+				return fn.apply(this, arguments); 
+			};
+
+			// Store data in unique handler 
+			handler.data = data;
+
+			// Set the guid of unique handler to the same of original handler, so it can be removed 
+			handler.guid = fn.guid;
+		}
+
+		// 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(){
+				// returned undefined or false
+				var val;
+
+				// 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 val;
+		
+				val = jQuery.event.handle.apply(arguments.callee.elem, arguments);
+		
+				return val;
+			});
+		// 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 seperated 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( this.fix({ type: type, target: elem }) );
+
+			// Enforce the right trigger type
+			data[0].type = type;
+			if ( exclusive )
+				data[0].exclusive = true;
+
+			// Trigger the event
+			if ( jQuery.isFunction( jQuery.data(elem, "handle") ) )
+				val = jQuery.data(elem, "handle").apply( elem, data );
+
+			// Handle triggering native .onfoo handlers
+			if ( !fn && 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;
+
+		// Empty object is for triggered events with no data
+		event = jQuery.event.fix( event || window.event || {} ); 
+
+		// Namespaced event handlers
+		var parts = event.type.split(".");
+		event.type = parts[0];
+
+		var handlers = jQuery.data(this, "events") && jQuery.data(this, "events")[event.type], args = Array.prototype.slice.call( arguments, 1 );
+		args.unshift( event );
+
+		for ( var j in handlers ) {
+			var handler = handlers[j];
+			// Pass in a reference to the handler function itself
+			// So that we can later remove it
+			args[0].handler = handler;
+			args[0].data = handler.data;
+
+			// Filter the functions by class
+			if ( !parts[1] && !event.exclusive || handler.type == parts[1] ) {
+				var ret = handler.apply( this, args );
+
+				if ( val !== false )
+					val = ret;
+
+				if ( ret === false ) {
+					event.preventDefault();
+					event.stopPropagation();
+				}
+			}
+		}
+
+		// Clean up added properties in IE to prevent memory leak
+		if (jQuery.browser.msie)
+			event.target = event.preventDefault = event.stopPropagation =
+				event.handler = event.data = null;
+
+		return val;
+	},
+
+	fix: function(event) {
+		// store a copy of the original event object 
+		// and clone to set read-only properties
+		var originalEvent = event;
+		event = jQuery.extend({}, originalEvent);
+		
+		// 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 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 = originalEvent.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;
+	},
+	
+	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
+				arguments[0].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
+				arguments[0].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 ) {
+		return this.each(function(){
+			jQuery.event.add( this, type, function(event) {
+				jQuery(this).unbind(event);
+				return (fn || data).apply( this, arguments);
+			}, 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 ) {
+		if ( this[0] )
+			return jQuery.event.trigger( type, data, this[0], false, fn );
+		return undefined;
+	},
+
+	toggle: function() {
+		// Save reference to arguments for access in closure
+		var args = arguments;
+
+		return this.click(function(event) {
+			// Figure out which function to execute
+			this.lastToggle = 0 == this.lastToggle ? 1 : 0;
+			
+			// 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.apply( 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({
+	load: function( url, params, callback ) {
+		if ( jQuery.isFunction( url ) )
+			return this.bind("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 = (new Date).getTime();
+
+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: {
+		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 ) {
+		var jsonp, jsre = /=\?(&|$)/g, status, data;
+
+		// 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));
+
+		// 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 ( s.type.toLowerCase() == "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 && s.type.toLowerCase() == "get" ) {
+			var ts = (new Date()).getTime();
+			// 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 && s.type.toLowerCase() == "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" );
+
+		// If we're requesting a remote document
+		// and trying to load JSON or Script with a GET
+		if ( (!s.url.indexOf("http") || !s.url.indexOf("//")) && s.dataType == "script" && s.type.toLowerCase() == "get" ) {
+			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 xml = window.ActiveXObject ? new ActiveXObject("Microsoft.XMLHTTP") : new XMLHttpRequest();
+
+		// Open the socket
+		xml.open(s.type, s.url, s.async, s.username, s.password);
+
+		// 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 )
+				xml.setRequestHeader("Content-Type", s.contentType);
+
+			// Set the If-Modified-Since header, if ifModified mode.
+			if ( s.ifModified )
+				xml.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
+			xml.setRequestHeader("X-Requested-With", "XMLHttpRequest");
+
+			// Set the Accepts header for the server, depending on the dataType
+			xml.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(xml);
+			
+		if ( s.global )
+			jQuery.event.trigger("ajaxSend", [xml, 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 && xml && (xml.readyState == 4 || isTimeout == "timeout") ) {
+				requestDone = true;
+				
+				// clear poll interval
+				if (ival) {
+					clearInterval(ival);
+					ival = null;
+				}
+				
+				status = isTimeout == "timeout" && "timeout" ||
+					!jQuery.httpSuccess( xml ) && "error" ||
+					s.ifModified && jQuery.httpNotModified( xml, 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( xml, s.dataType );
+					} 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 = xml.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, xml, status);
+
+				// Fire the complete handlers
+				complete();
+
+				// Stop memory leaks
+				if ( s.async )
+					xml = 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 ( xml ) {
+						// Cancel the request
+						xml.abort();
+	
+						if( !requestDone )
+							onreadystatechange( "timeout" );
+					}
+				}, s.timeout);
+		}
+			
+		// Send the data
+		try {
+			xml.send(s.data);
+		} catch(e) {
+			jQuery.handleError(s, xml, 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", [xml, s] );
+		}
+
+		function complete(){
+			// Process result
+			if ( s.complete )
+				s.complete(xml, status);
+
+			// The request was completed
+			if ( s.global )
+				jQuery.event.trigger( "ajaxComplete", [xml, s] );
+
+			// Handle the global AJAX counter
+			if ( s.global && ! --jQuery.active )
+				jQuery.event.trigger( "ajaxStop" );
+		}
+		
+		// return XMLHttpRequest to allow aborting the request etc.
+		return xml;
+	},
+
+	handleError: function( s, xml, status, e ) {
+		// If a local callback was specified, fire it
+		if ( s.error ) s.error( xml, status, e );
+
+		// Fire the global callback
+		if ( s.global )
+			jQuery.event.trigger( "ajaxError", [xml, s, e] );
+	},
+
+	// Counter for holding the number of active queries
+	active: 0,
+
+	// Determines if an XMLHttpRequest was successful or not
+	httpSuccess: function( r ) {
+		try {
+			// IE error sometimes returns 1223 when it should be 204 so treat it as success, see #1450
+			return !r.status && location.protocol == "file:" ||
+				( r.status >= 200 && r.status < 300 ) || r.status == 304 || r.status == 1223 ||
+				jQuery.browser.safari && r.status == undefined;
+		} catch(e){}
+		return false;
+	},
+
+	// Determines if an XMLHttpRequest returns NotModified
+	httpNotModified: function( xml, url ) {
+		try {
+			var xmlRes = xml.getResponseHeader("Last-Modified");
+
+			// Firefox always returns 200. check Last-Modified date
+			return xml.status == 304 || xmlRes == jQuery.lastModified[url] ||
+				jQuery.browser.safari && xml.status == undefined;
+		} catch(e){}
+		return false;
+	},
+
+	httpData: function( r, type ) {
+		var ct = r.getResponseHeader("content-type");
+		var xml = type == "xml" || !type && ct && ct.indexOf("xml") >= 0;
+		var data = xml ? r.responseXML : r.responseText;
+
+		if ( xml && data.documentElement.tagName == "parsererror" )
+			throw "parsererror";
+
+		// 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( 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( fn, fn2 ) :
+			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);
+			var hidden = jQuery(this).is(":hidden"), self = this;
+			
+			for ( var p in prop ) {
+				if ( prop[p] == "hide" && hidden || prop[p] == "show" && !hidden )
+					return jQuery.isFunction(opt.complete) && opt.complete.apply(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.apply(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 )
+		return undefined;
+
+	type = type || "fx";
+
+	var q = jQuery.data( elem, type + "queue" );
+
+	if ( !q || array )
+		q = jQuery.data( elem, type + "queue", 
+			array ? 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].apply( 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 : 
+			{ slow: 600, fast: 200 }[opt.duration]) || 400;
+	
+		// Queueing
+		opt.old = opt.complete;
+		opt.complete = function(){
+			if ( opt.queue !== false )
+				jQuery(this).dequeue();
+			if ( jQuery.isFunction( opt.old ) )
+				opt.old.apply( 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.apply( 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 = (new Date()).getTime();
+		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 = (new Date()).getTime();
+
+		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 a callback was provided, execute it
+			if ( done && jQuery.isFunction( this.options.complete ) )
+				// Execute the complete function
+				this.options.complete.apply( 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.fx.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),
+		    fixed        = jQuery.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 && jQuery.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(jQuery.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 && jQuery.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 || jQuery.css(offsetChild, "position") == "absolute")) || 
+				(mozilla && jQuery.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) || 0;
+		top += parseInt(t) || 0;
+	}
+
+	return results;
+};
+})();
diff --git a/json.js b/json.js
new file mode 100644
index 0000000..6fc8ed6
--- /dev/null
+++ b/json.js
@@ -0,0 +1,275 @@
+/*
+    json2.js
+    2008-02-14
+
+    Public Domain
+
+    No warranty expressed or implied. Use at your own risk.
+
+    See http://www.JSON.org/js.html
+
+    This file creates a global JSON object containing two methods:
+
+        JSON.stringify(value, whitelist)
+            value       any JavaScript value, usually an object or array.
+
+            whitelist   an optional array parameter that determines how object
+                        values are stringified.
+
+            This method produces a JSON text from a JavaScript value.
+            There are three possible ways to stringify an object, depending
+            on the optional whitelist parameter.
+
+            If an object has a toJSON method, then the toJSON() method will be
+            called. The value returned from the toJSON method will be
+            stringified.
+
+            Otherwise, if the optional whitelist parameter is an array, then
+            the elements of the array will be used to select members of the
+            object for stringification.
+
+            Otherwise, if there is no whitelist parameter, then all of the
+            members of the object will be stringified.
+
+            Values that do not have JSON representaions, such as undefined or
+            functions, will not be serialized. Such values in objects will be
+            dropped; in arrays will be replaced with null.
+            JSON.stringify(undefined) returns undefined. Dates will be
+            stringified as quoted ISO dates.
+
+            Example:
+
+            var text = JSON.stringify(['e', {pluribus: 'unum'}]);
+            // text is '["e",{"pluribus":"unum"}]'
+
+        JSON.parse(text, filter)
+            This method parses a JSON text to produce an object or
+            array. It can throw a SyntaxError exception.
+
+            The optional filter parameter is a function that can filter and
+            transform the results. It receives each of the keys and values, and
+            its return value is used instead of the original value. If it
+            returns what it received, then structure is not modified. If it
+            returns undefined then the member is deleted.
+
+            Example:
+
+            // Parse the text. If a key contains the string 'date' then
+            // convert the value to a date.
+
+            myData = JSON.parse(text, function (key, value) {
+                return key.indexOf('date') >= 0 ? new Date(value) : value;
+            });
+
+    This is a reference implementation. You are free to copy, modify, or
+    redistribute.
+
+    Use your own copy. It is extremely unwise to load third party
+    code into your pages.
+*/
+
+/*jslint evil: true */
+
+/*global JSON */
+
+/*members "\b", "\t", "\n", "\f", "\r", "\"", JSON, "\\", apply,
+    charCodeAt, floor, getUTCDate, getUTCFullYear, getUTCHours,
+    getUTCMinutes, getUTCMonth, getUTCSeconds, hasOwnProperty, join, length,
+    parse, propertyIsEnumerable, prototype, push, replace, stringify, test,
+    toJSON, toString
+*/
+
+if (!this.JSON) {
+
+    JSON = function () {
+
+        function f(n) {    // Format integers to have at least two digits.
+            return n < 10 ? '0' + n : n;
+        }
+
+        Date.prototype.toJSON = function () {
+
+// Eventually, this method will be based on the date.toISOString method.
+
+            return this.getUTCFullYear()   + '-' +
+                 f(this.getUTCMonth() + 1) + '-' +
+                 f(this.getUTCDate())      + 'T' +
+                 f(this.getUTCHours())     + ':' +
+                 f(this.getUTCMinutes())   + ':' +
+                 f(this.getUTCSeconds())   + 'Z';
+        };
+
+
+        var m = {    // table of character substitutions
+            '\b': '\\b',
+            '\t': '\\t',
+            '\n': '\\n',
+            '\f': '\\f',
+            '\r': '\\r',
+            '"' : '\\"',
+            '\\': '\\\\'
+        };
+
+        function stringify(value, whitelist) {
+            var a,          // The array holding the partial texts.
+                i,          // The loop counter.
+                k,          // The member key.
+                l,          // Length.
+                r = /["\\\x00-\x1f\x7f-\x9f]/g,
+                v;          // The member value.
+
+            switch (typeof value) {
+            case 'string':
+
+// If the string contains no control characters, no quote characters, and no
+// backslash characters, then we can safely slap some quotes around it.
+// Otherwise we must also replace the offending characters with safe sequences.
+
+                return r.test(value) ?
+                    '"' + value.replace(r, function (a) {
+                        var c = m[a];
+                        if (c) {
+                            return c;
+                        }
+                        c = a.charCodeAt();
+                        return '\\u00' + Math.floor(c / 16).toString(16) +
+                                                   (c % 16).toString(16);
+                    }) + '"' :
+                    '"' + value + '"';
+
+            case 'number':
+
+// JSON numbers must be finite. Encode non-finite numbers as null.
+
+                return isFinite(value) ? String(value) : 'null';
+
+            case 'boolean':
+            case 'null':
+                return String(value);
+
+            case 'object':
+
+// Due to a specification blunder in ECMAScript,
+// typeof null is 'object', so watch out for that case.
+
+                if (!value) {
+                    return 'null';
+                }
+
+// If the object has a toJSON method, call it, and stringify the result.
+
+                if (typeof value.toJSON === 'function') {
+                    return stringify(value.toJSON());
+                }
+                a = [];
+                if (typeof value.length === 'number' &&
+                        !(value.propertyIsEnumerable('length'))) {
+
+// The object is an array. Stringify every element. Use null as a placeholder
+// for non-JSON values.
+
+                    l = value.length;
+                    for (i = 0; i < l; i += 1) {
+                        a.push(stringify(value[i], whitelist) || 'null');
+                    }
+
+// Join all of the elements together and wrap them in brackets.
+
+                    return '[' + a.join(',') + ']';
+                }
+                if (whitelist) {
+
+// If a whitelist (array of keys) is provided, use it to select the components
+// of the object.
+
+                    l = whitelist.length;
+                    for (i = 0; i < l; i += 1) {
+                        k = whitelist[i];
+                        if (typeof k === 'string') {
+                            v = stringify(value[k], whitelist);
+                            if (v) {
+                                a.push(stringify(k) + ':' + v);
+                            }
+                        }
+                    }
+                } else {
+
+// Otherwise, iterate through all of the keys in the object.
+
+                    for (k in value) {
+                        if (typeof k === 'string') {
+                            v = stringify(value[k], whitelist);
+                            if (v) {
+                                a.push(stringify(k) + ':' + v);
+                            }
+                        }
+                    }
+                }
+
+// Join all of the member texts together and wrap them in braces.
+
+                return '{' + a.join(',') + '}';
+            }
+        }
+
+        return {
+            stringify: stringify,
+            parse: function (text, filter) {
+                var j;
+
+                function walk(k, v) {
+                    var i, n;
+                    if (v && typeof v === 'object') {
+                        for (i in v) {
+                            if (Object.prototype.hasOwnProperty.apply(v, [i])) {
+                                n = walk(i, v[i]);
+                                if (n !== undefined) {
+                                    v[i] = n;
+                                } else {
+                                    delete v[i];
+                                }
+                            }
+                        }
+                    }
+                    return filter(k, v);
+                }
+
+
+// Parsing happens in three stages. In the first stage, we run the text against
+// regular expressions that look for non-JSON patterns. We are especially
+// concerned with '()' and 'new' because they can cause invocation, and '='
+// because it can cause mutation. But just to be safe, we want to reject all
+// unexpected forms.
+
+// We split the first stage into 4 regexp operations in order to work around
+// crippling inefficiencies in IE's and Safari's regexp engines. First we
+// replace all backslash pairs with '@' (a non-JSON character). Second, we
+// replace all simple value tokens with ']' characters. Third, we delete all
+// open brackets that follow a colon or comma or that begin the text. Finally,
+// we look to see that the remaining characters are only whitespace or ']' or
+// ',' or ':' or '{' or '}'. If that is so, then the text is safe for eval.
+
+                if (/^[\],:{}\s]*$/.test(text.replace(/\\./g, '@').
+replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g, ']').
+replace(/(?:^|:|,)(?:\s*\[)+/g, ''))) {
+
+// In the second stage we use the eval function to compile the text into a
+// JavaScript structure. The '{' operator is subject to a syntactic ambiguity
+// in JavaScript: it can begin a block or an object literal. We wrap the text
+// in parens to eliminate the ambiguity.
+
+                    j = eval('(' + text + ')');
+
+// In the optional third stage, we recursively walk the new structure, passing
+// each name/value pair to a filter function for possible transformation.
+
+                    return typeof filter === 'function' ? walk('', j) : j;
+                }
+
+// If the text is not JSON parseable, then a SyntaxError is thrown.
+
+                throw new SyntaxError('parseJSON');
+            }
+        };
+    }();
+}
diff --git a/lib/dojo.js b/lib/dojo.js
new file mode 100644
index 0000000..3110641
--- /dev/null
+++ b/lib/dojo.js
@@ -0,0 +1,8458 @@
+/*
+	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/lib/ext-base.js b/lib/ext-base.js
new file mode 100644
index 0000000..b68f63d
--- /dev/null
+++ b/lib/ext-base.js
@@ -0,0 +1,10 @@
+/*

+ * Ext JS Library 2.2

+ * Copyright(c) 2006-2008, Ext JS, LLC.

+ * licensing@extjs.com

+ * 

+ * http://extjs.com/license

+ */

+

+Ext={version:"2.2"};window["undefined"]=window["undefined"];Ext.apply=function(C,D,B){if(B){Ext.apply(C,B)}if(C&&D&&typeof D=="object"){for(var A in D){C[A]=D[A]}}return C};(function(){var idSeed=0;var ua=navigator.userAgent.toLowerCase();var isStrict=document.compatMode=="CSS1Compat",isOpera=ua.indexOf("opera")>-1,isSafari=(/webkit|khtml/).test(ua),isSafari3=isSafari&&ua.indexOf("webkit/5")!=-1,isIE=!isOpera&&ua.indexOf("msie")>-1,isIE7=!isOpera&&ua.indexOf("msie 7")>-1,isGecko=!isSafari&&ua.indexOf("gecko")>-1,isGecko3=!isSafari&&ua.indexOf("rv:1.9")>-1,isBorderBox=isIE&&!isStrict,isWindows=(ua.indexOf("windows")!=-1||ua.indexOf("win32")!=-1),isMac=(ua.indexOf("macintosh")!=-1||ua.indexOf("mac os x")!=-1),isAir=(ua.indexOf("adobeair")!=-1),isLinux=(ua.indexOf("linux")!=-1),isSecure=window.location.href.toLowerCase().indexOf("https")===0;if(isIE&&!isIE7){try{document.execCommand("BackgroundImageCache",false,true)}catch(e){}}Ext.apply(Ext,{isStrict:isStrict,isSecure:isSecure,isReady:false,enableGarbageCollector:true,enableListenerCollection:false,SSL_SECURE_URL:"javascript:false",BLANK_IMAGE_URL:"http:/"+"/extjs.com/s.gif",emptyFn:function(){},applyIf:function(o,c){if(o&&c){for(var p in c){if(typeof o[p]=="undefined"){o[p]=c[p]}}}return o},addBehaviors:function(o){if(!Ext.isReady){Ext.onReady(function(){Ext.addBehaviors(o)});return }var cache={};for(var b in o){var parts=b.split("@");if(parts[1]){var s=parts[0];if(!cache[s]){cache[s]=Ext.select(s)}cache[s].on(parts[1],o[b])}}cache=null},id:function(el,prefix){prefix=prefix||"ext-gen";el=Ext.getDom(el);var id=prefix+(++idSeed);return el?(el.id?el.id:(el.id=id)):id},extend:function(){var io=function(o){for(var m in o){this[m]=o[m]}};var oc=Object.prototype.constructor;return function(sb,sp,overrides){if(typeof sp=="object"){overrides=sp;sp=sb;sb=overrides.constructor!=oc?overrides.constructor:function(){sp.apply(this,arguments)}}var F=function(){},sbp,spp=sp.prototype;F.prototype=spp;sbp=sb.prototype=new F();sbp.constructor=sb;sb.superclass=spp;if(spp.constructor==oc){spp.constructor=sp}sb.override=function(o){Ext.override(sb,o)};sbp.override=io;Ext.override(sb,overrides);sb.extend=function(o){Ext.extend(sb,o)};return sb}}(),override:function(origclass,overrides){if(overrides){var p=origclass.prototype;for(var method in overrides){p[method]=overrides[method]}}},namespace:function(){var a=arguments,o=null,i,j,d,rt;for(i=0;i<a.length;++i){d=a[i].split(".");rt=d[0];eval("if (typeof "+rt+" == \"undefined\"){"+rt+" = {};} o = "+rt+";");for(j=1;j<d.length;++j){o[d[j]]=o[d[j]]||{};o=o[d[j]]}}},urlEncode:function(o){if(!o){return""}var buf=[];for(var key in o){var ov=o[key],k=encodeURIComponent(key);var type=typeof ov;if(type=="undefined"){buf.push(k,"=&")}else{if(type!="function"&&type!="object"){buf.push(k,"=",encodeURIComponent(ov),"&")}else{if(Ext.isArray(ov)){if(ov.length){for(var i=0,len=ov.length;i<len;i++){buf.push(k,"=",encodeURIComponent(ov[i]===undefined?"":ov[i]),"&")}}else{buf.push(k,"=&")}}}}}buf.pop();return buf.join("")},urlDecode:function(string,overwrite){if(!string||!string.length){return{}}var obj={};var pairs=string.split("&");var pair,name,value;for(var i=0,len=pairs.length;i<len;i++){pair=pairs[i].split("=");name=decodeURIComponent(pair[0]);value=decodeURIComponent(pair[1]);if(overwrite!==true){if(typeof obj[name]=="undefined"){obj[name]=value}else{if(typeof obj[name]=="string"){obj[name]=[obj[name]];obj[name].push(value)}else{obj[name].push(value)}}}else{obj[name]=value}}return obj},each:function(array,fn,scope){if(typeof array.length=="undefined"||typeof array=="string"){array=[array]}for(var i=0,len=array.length;i<len;i++){if(fn.call(scope||array[i],array[i],i,array)===false){return i}}},combine:function(){var as=arguments,l=as.length,r=[];for(var i=0;i<l;i++){var a=as[i];if(Ext.isArray(a)){r=r.concat(a)}else{if(a.length!==undefined&&!a.substr){r=r.concat(Array.prototype.slice.call(a,0))}else{r.push(a)}}}return r},escapeRe:function(s){return s.replace(/([.*+?^${}()|[\]\/\\])/g,"\\$1")},callback:function(cb,scope,args,delay){if(typeof cb=="function"){if(delay){cb.defer(delay,scope,args||[])}else{cb.apply(scope,args||[])}}},getDom:function(el){if(!el||!document){return null}return el.dom?el.dom:(typeof el=="string"?document.getElementById(el):el)},getDoc:function(){return Ext.get(document)},getBody:function(){return Ext.get(document.body||document.documentElement)},getCmp:function(id){return Ext.ComponentMgr.get(id)},num:function(v,defaultValue){if(typeof v!="number"){return defaultValue}return v},destroy:function(){for(var i=0,a=arguments,len=a.length;i<len;i++){var as=a[i];if(as){if(typeof as.destroy=="function"){as.destroy()}else{if(as.dom){as.removeAllListeners();as.remove()}}}}},removeNode:isIE?function(){var d;return function(n){if(n&&n.tagName!="BODY"){d=d||document.createElement("div");d.appendChild(n);d.innerHTML=""}}}():function(n){if(n&&n.parentNode&&n.tagName!="BODY"){n.parentNode.removeChild(n)}},type:function(o){if(o===undefined||o===null){return false}if(o.htmlElement){return"element"}var t=typeof o;if(t=="object"&&o.nodeName){switch(o.nodeType){case 1:return"element";case 3:return(/\S/).test(o.nodeValue)?"textnode":"whitespace"}}if(t=="object"||t=="function"){switch(o.constructor){case Array:return"array";case RegExp:return"regexp"}if(typeof o.length=="number"&&typeof o.item=="function"){return"nodelist"}}return t},isEmpty:function(v,allowBlank){return v===null||v===undefined||(!allowBlank?v==="":false)},value:function(v,defaultValue,allowBlank){return Ext.isEmpty(v,allowBlank)?defaultValue:v},isArray:function(v){return v&&typeof v.length=="number"&&typeof v.splice=="function"},isDate:function(v){return v&&typeof v.getFullYear=="function"},isOpera:isOpera,isSafari:isSafari,isSafari3:isSafari3,isSafari2:isSafari&&!isSafari3,isIE:isIE,isIE6:isIE&&!isIE7,isIE7:isIE7,isGecko:isGecko,isGecko2:isGecko&&!isGecko3,isGecko3:isGecko3,isBorderBox:isBorderBox,isLinux:isLinux,isWindows:isWindows,isMac:isMac,isAir:isAir,useShims:((isIE&&!isIE7)||(isMac&&isGecko&&!isGecko3))});Ext.ns=Ext.namespace})();Ext.ns("Ext","Ext.util","Ext.grid","Ext.dd","Ext.tree","Ext.data","Ext.form","Ext.menu","Ext.state","Ext.lib","Ext.layout","Ext.app","Ext.ux");Ext.apply(Function.prototype,{createCallback:function(){var A=arguments;var B=this;return function(){return B.apply(window,A)}},createDelegate:function(C,B,A){var D=this;return function(){var F=B||arguments;if(A===true){F=Array.prototype.slice.call(arguments,0);F=F.concat(B)}else{if(typeof A=="number"){F=Array.prototype.slice.call(arguments,0);var E=[A,0].concat(B);Array.prototype.splice.apply(F,E)}}return D.apply(C||window,F)}},defer:function(C,E,B,A){var D=this.createDelegate(E,B,A);if(C){return setTimeout(D,C)}D();return 0},createSequence:function(B,A){if(typeof B!="function"){return this}var C=this;return function(){var D=C.apply(this||window,arguments);B.apply(A||this||window,arguments);return D}},createInterceptor:function(B,A){if(typeof B!="function"){return this}var C=this;return function(){B.target=this;B.method=C;if(B.apply(A||this||window,arguments)===false){return }return C.apply(this||window,arguments)}}});Ext.applyIf(String,{escape:function(A){return A.replace(/('|\\)/g,"\\$1")},leftPad:function(D,B,C){var A=new String(D);if(!C){C=" "}while(A.length<B){A=C+A}return A.toString()},format:function(B){var A=Array.prototype.slice.call(arguments,1);return B.replace(/\{(\d+)\}/g,function(C,D){return A[D]})}});String.prototype.toggle=function(B,A){return this==B?A:B};String.prototype.trim=function(){var A=/^\s+|\s+$/g;return function(){return this.replace(A,"")}}();Ext.applyIf(Number.prototype,{constrain:function(B,A){return Math.min(Math.max(this,B),A)}});Ext.applyIf(Array.prototype,{indexOf:function(C){for(var B=0,A=this.length;B<A;B++){if(this[B]==C){return B}}return -1},remove:function(B){var A=this.indexOf(B);if(A!=-1){this.splice(A,1)}return this}});Date.prototype.getElapsed=function(A){return Math.abs((A||new Date()).getTime()-this.getTime())};
+(function(){var B;Ext.lib.Dom={getViewWidth:function(E){return E?this.getDocumentWidth():this.getViewportWidth()},getViewHeight:function(E){return E?this.getDocumentHeight():this.getViewportHeight()},getDocumentHeight:function(){var E=(document.compatMode!="CSS1Compat")?document.body.scrollHeight:document.documentElement.scrollHeight;return Math.max(E,this.getViewportHeight())},getDocumentWidth:function(){var E=(document.compatMode!="CSS1Compat")?document.body.scrollWidth:document.documentElement.scrollWidth;return Math.max(E,this.getViewportWidth())},getViewportHeight:function(){if(Ext.isIE){return Ext.isStrict?document.documentElement.clientHeight:document.body.clientHeight}else{return self.innerHeight}},getViewportWidth:function(){if(Ext.isIE){return Ext.isStrict?document.documentElement.clientWidth:document.body.clientWidth}else{return self.innerWidth}},isAncestor:function(F,G){F=Ext.getDom(F);G=Ext.getDom(G);if(!F||!G){return false}if(F.contains&&!Ext.isSafari){return F.contains(G)}else{if(F.compareDocumentPosition){return !!(F.compareDocumentPosition(G)&16)}else{var E=G.parentNode;while(E){if(E==F){return true}else{if(!E.tagName||E.tagName.toUpperCase()=="HTML"){return false}}E=E.parentNode}return false}}},getRegion:function(E){return Ext.lib.Region.getRegion(E)},getY:function(E){return this.getXY(E)[1]},getX:function(E){return this.getXY(E)[0]},getXY:function(G){var F,K,M,N,J=(document.body||document.documentElement);G=Ext.getDom(G);if(G==J){return[0,0]}if(G.getBoundingClientRect){M=G.getBoundingClientRect();N=C(document).getScroll();return[M.left+N.left,M.top+N.top]}var O=0,L=0;F=G;var E=C(G).getStyle("position")=="absolute";while(F){O+=F.offsetLeft;L+=F.offsetTop;if(!E&&C(F).getStyle("position")=="absolute"){E=true}if(Ext.isGecko){K=C(F);var P=parseInt(K.getStyle("borderTopWidth"),10)||0;var H=parseInt(K.getStyle("borderLeftWidth"),10)||0;O+=H;L+=P;if(F!=G&&K.getStyle("overflow")!="visible"){O+=H;L+=P}}F=F.offsetParent}if(Ext.isSafari&&E){O-=J.offsetLeft;L-=J.offsetTop}if(Ext.isGecko&&!E){var I=C(J);O+=parseInt(I.getStyle("borderLeftWidth"),10)||0;L+=parseInt(I.getStyle("borderTopWidth"),10)||0}F=G.parentNode;while(F&&F!=J){if(!Ext.isOpera||(F.tagName!="TR"&&C(F).getStyle("display")!="inline")){O-=F.scrollLeft;L-=F.scrollTop}F=F.parentNode}return[O,L]},setXY:function(E,F){E=Ext.fly(E,"_setXY");E.position();var G=E.translatePoints(F);if(F[0]!==false){E.dom.style.left=G.left+"px"}if(F[1]!==false){E.dom.style.top=G.top+"px"}},setX:function(F,E){this.setXY(F,[E,false])},setY:function(E,F){this.setXY(E,[false,F])}};Ext.lib.Event=function(){var F=false;var G=[];var K=[];var I=0;var H=[];var E=0;var J=null;return{POLL_RETRYS:200,POLL_INTERVAL:20,EL:0,TYPE:1,FN:2,WFN:3,OBJ:3,ADJ_SCOPE:4,_interval:null,startInterval:function(){if(!this._interval){var L=this;var M=function(){L._tryPreloadAttach()};this._interval=setInterval(M,this.POLL_INTERVAL)}},onAvailable:function(N,L,O,M){H.push({id:N,fn:L,obj:O,override:M,checkReady:false});I=this.POLL_RETRYS;this.startInterval()},addListener:function(Q,M,P){Q=Ext.getDom(Q);if(!Q||!P){return false}if("unload"==M){K[K.length]=[Q,M,P];return true}var O=function(R){return typeof Ext!="undefined"?P(Ext.lib.Event.getEvent(R)):false};var L=[Q,M,P,O];var N=G.length;G[N]=L;this.doAdd(Q,M,O,false);return true},removeListener:function(S,O,R){var Q,N;S=Ext.getDom(S);if(!R){return this.purgeElement(S,false,O)}if("unload"==O){for(Q=0,N=K.length;Q<N;Q++){var M=K[Q];if(M&&M[0]==S&&M[1]==O&&M[2]==R){K.splice(Q,1);return true}}return false}var L=null;var P=arguments[3];if("undefined"==typeof P){P=this._getCacheIndex(S,O,R)}if(P>=0){L=G[P]}if(!S||!L){return false}this.doRemove(S,O,L[this.WFN],false);delete G[P][this.WFN];delete G[P][this.FN];G.splice(P,1);return true},getTarget:function(N,M){N=N.browserEvent||N;var L=N.target||N.srcElement;return this.resolveTextNode(L)},resolveTextNode:function(L){if(Ext.isSafari&&L&&3==L.nodeType){return L.parentNode}else{return L}},getPageX:function(M){M=M.browserEvent||M;var L=M.pageX;if(!L&&0!==L){L=M.clientX||0;if(Ext.isIE){L+=this.getScroll()[1]}}return L},getPageY:function(L){L=L.browserEvent||L;var M=L.pageY;if(!M&&0!==M){M=L.clientY||0;if(Ext.isIE){M+=this.getScroll()[0]}}return M},getXY:function(L){L=L.browserEvent||L;return[this.getPageX(L),this.getPageY(L)]},getRelatedTarget:function(M){M=M.browserEvent||M;var L=M.relatedTarget;if(!L){if(M.type=="mouseout"){L=M.toElement}else{if(M.type=="mouseover"){L=M.fromElement}}}return this.resolveTextNode(L)},getTime:function(N){N=N.browserEvent||N;if(!N.time){var M=new Date().getTime();try{N.time=M}catch(L){this.lastError=L;return M}}return N.time},stopEvent:function(L){this.stopPropagation(L);this.preventDefault(L)},stopPropagation:function(L){L=L.browserEvent||L;if(L.stopPropagation){L.stopPropagation()}else{L.cancelBubble=true}},preventDefault:function(L){L=L.browserEvent||L;if(L.preventDefault){L.preventDefault()}else{L.returnValue=false}},getEvent:function(M){var L=M||window.event;if(!L){var N=this.getEvent.caller;while(N){L=N.arguments[0];if(L&&Event==L.constructor){break}N=N.caller}}return L},getCharCode:function(L){L=L.browserEvent||L;return L.charCode||L.keyCode||0},_getCacheIndex:function(Q,N,P){for(var O=0,M=G.length;O<M;++O){var L=G[O];if(L&&L[this.FN]==P&&L[this.EL]==Q&&L[this.TYPE]==N){return O}}return -1},elCache:{},getEl:function(L){return document.getElementById(L)},clearCache:function(){},_load:function(M){F=true;var L=Ext.lib.Event;if(Ext.isIE){L.doRemove(window,"load",L._load)}},_tryPreloadAttach:function(){if(this.locked){return false}this.locked=true;var R=!F;if(!R){R=(I>0)}var Q=[];for(var M=0,L=H.length;M<L;++M){var P=H[M];if(P){var O=this.getEl(P.id);if(O){if(!P.checkReady||F||O.nextSibling||(document&&document.body)){var N=O;if(P.override){if(P.override===true){N=P.obj}else{N=P.override}}P.fn.call(N,P.obj);H[M]=null}}else{Q.push(P)}}}I=(Q.length===0)?0:I-1;if(R){this.startInterval()}else{clearInterval(this._interval);this._interval=null}this.locked=false;return true},purgeElement:function(P,Q,N){var R=this.getListeners(P,N);if(R){for(var O=0,L=R.length;O<L;++O){var M=R[O];this.removeListener(P,M.type,M.fn)}}if(Q&&P&&P.childNodes){for(O=0,L=P.childNodes.length;O<L;++O){this.purgeElement(P.childNodes[O],Q,N)}}},getListeners:function(M,R){var P=[],L;if(!R){L=[G,K]}else{if(R=="unload"){L=[K]}else{L=[G]}}for(var O=0;O<L.length;++O){var T=L[O];if(T&&T.length>0){for(var Q=0,S=T.length;Q<S;++Q){var N=T[Q];if(N&&N[this.EL]===M&&(!R||R===N[this.TYPE])){P.push({type:N[this.TYPE],fn:N[this.FN],obj:N[this.OBJ],adjust:N[this.ADJ_SCOPE],index:Q})}}}}return(P.length)?P:null},_unload:function(S){var R=Ext.lib.Event,P,O,M,L,N;for(P=0,L=K.length;P<L;++P){M=K[P];if(M){var Q=window;if(M[R.ADJ_SCOPE]){if(M[R.ADJ_SCOPE]===true){Q=M[R.OBJ]}else{Q=M[R.ADJ_SCOPE]}}M[R.FN].call(Q,R.getEvent(S),M[R.OBJ]);K[P]=null;M=null;Q=null}}K=null;if(G&&G.length>0){O=G.length;while(O){N=O-1;M=G[N];if(M){R.removeListener(M[R.EL],M[R.TYPE],M[R.FN],N)}O=O-1}M=null;R.clearCache()}R.doRemove(window,"unload",R._unload)},getScroll:function(){var L=document.documentElement,M=document.body;if(L&&(L.scrollTop||L.scrollLeft)){return[L.scrollTop,L.scrollLeft]}else{if(M){return[M.scrollTop,M.scrollLeft]}else{return[0,0]}}},doAdd:function(){if(window.addEventListener){return function(O,M,N,L){O.addEventListener(M,N,(L))}}else{if(window.attachEvent){return function(O,M,N,L){O.attachEvent("on"+M,N)}}else{return function(){}}}}(),doRemove:function(){if(window.removeEventListener){return function(O,M,N,L){O.removeEventListener(M,N,(L))}}else{if(window.detachEvent){return function(N,L,M){N.detachEvent("on"+L,M)}}else{return function(){}}}}()}}();var D=Ext.lib.Event;D.on=D.addListener;D.un=D.removeListener;if(document&&document.body){D._load()}else{D.doAdd(window,"load",D._load)}D.doAdd(window,"unload",D._unload);D._tryPreloadAttach();Ext.lib.Ajax={request:function(K,I,E,J,F){if(F){var G=F.headers;if(G){for(var H in G){if(G.hasOwnProperty(H)){this.initHeader(H,G[H],false)}}}if(F.xmlData){if(!G||!G["Content-Type"]){this.initHeader("Content-Type","text/xml",false)}K=(K?K:(F.method?F.method:"POST"));J=F.xmlData}else{if(F.jsonData){if(!G||!G["Content-Type"]){this.initHeader("Content-Type","application/json",false)}K=(K?K:(F.method?F.method:"POST"));J=typeof F.jsonData=="object"?Ext.encode(F.jsonData):F.jsonData}}}return this.asyncRequest(K,I,E,J)},serializeForm:function(F){if(typeof F=="string"){F=(document.getElementById(F)||document.forms[F])}var G,E,H,J,K="",M=false;for(var L=0;L<F.elements.length;L++){G=F.elements[L];J=F.elements[L].disabled;E=F.elements[L].name;H=F.elements[L].value;if(!J&&E){switch(G.type){case"select-one":case"select-multiple":for(var I=0;I<G.options.length;I++){if(G.options[I].selected){if(Ext.isIE){K+=encodeURIComponent(E)+"="+encodeURIComponent(G.options[I].attributes["value"].specified?G.options[I].value:G.options[I].text)+"&"}else{K+=encodeURIComponent(E)+"="+encodeURIComponent(G.options[I].hasAttribute("value")?G.options[I].value:G.options[I].text)+"&"}}}break;case"radio":case"checkbox":if(G.checked){K+=encodeURIComponent(E)+"="+encodeURIComponent(H)+"&"}break;case"file":case undefined:case"reset":case"button":break;case"submit":if(M==false){K+=encodeURIComponent(E)+"="+encodeURIComponent(H)+"&";M=true}break;default:K+=encodeURIComponent(E)+"="+encodeURIComponent(H)+"&";break}}}K=K.substr(0,K.length-1);return K},headers:{},hasHeaders:false,useDefaultHeader:true,defaultPostHeader:"application/x-www-form-urlencoded; charset=UTF-8",useDefaultXhrHeader:true,defaultXhrHeader:"XMLHttpRequest",hasDefaultHeaders:true,defaultHeaders:{},poll:{},timeout:{},pollInterval:50,transactionId:0,setProgId:function(E){this.activeX.unshift(E)},setDefaultPostHeader:function(E){this.useDefaultHeader=E},setDefaultXhrHeader:function(E){this.useDefaultXhrHeader=E},setPollingInterval:function(E){if(typeof E=="number"&&isFinite(E)){this.pollInterval=E}},createXhrObject:function(I){var H,E;try{E=new XMLHttpRequest();H={conn:E,tId:I}}catch(G){for(var F=0;F<this.activeX.length;++F){try{E=new ActiveXObject(this.activeX[F]);H={conn:E,tId:I};break}catch(G){}}}finally{return H}},getConnectionObject:function(){var F;var G=this.transactionId;try{F=this.createXhrObject(G);if(F){this.transactionId++}}catch(E){}finally{return F}},asyncRequest:function(I,F,H,E){var G=this.getConnectionObject();if(!G){return null}else{G.conn.open(I,F,true);if(this.useDefaultXhrHeader){if(!this.defaultHeaders["X-Requested-With"]){this.initHeader("X-Requested-With",this.defaultXhrHeader,true)}}if(E&&this.useDefaultHeader&&(!this.hasHeaders||!this.headers["Content-Type"])){this.initHeader("Content-Type",this.defaultPostHeader)}if(this.hasDefaultHeaders||this.hasHeaders){this.setHeader(G)}this.handleReadyState(G,H);G.conn.send(E||null);return G}},handleReadyState:function(F,G){var E=this;if(G&&G.timeout){this.timeout[F.tId]=window.setTimeout(function(){E.abort(F,G,true)},G.timeout)}this.poll[F.tId]=window.setInterval(function(){if(F.conn&&F.conn.readyState==4){window.clearInterval(E.poll[F.tId]);delete E.poll[F.tId];if(G&&G.timeout){window.clearTimeout(E.timeout[F.tId]);delete E.timeout[F.tId]}E.handleTransactionResponse(F,G)}},this.pollInterval)},handleTransactionResponse:function(I,J,E){if(!J){this.releaseObject(I);return }var G,F;try{if(I.conn.status!==undefined&&I.conn.status!=0){G=I.conn.status}else{G=13030}}catch(H){G=13030}if(G>=200&&G<300){F=this.createResponseObject(I,J.argument);if(J.success){if(!J.scope){J.success(F)}else{J.success.apply(J.scope,[F])}}}else{switch(G){case 12002:case 12029:case 12030:case 12031:case 12152:case 13030:F=this.createExceptionObject(I.tId,J.argument,(E?E:false));if(J.failure){if(!J.scope){J.failure(F)}else{J.failure.apply(J.scope,[F])}}break;default:F=this.createResponseObject(I,J.argument);if(J.failure){if(!J.scope){J.failure(F)}else{J.failure.apply(J.scope,[F])}}}}this.releaseObject(I);F=null},createResponseObject:function(E,K){var H={};var M={};try{var G=E.conn.getAllResponseHeaders();var J=G.split("\n");for(var I=0;I<J.length;I++){var F=J[I].indexOf(":");if(F!=-1){M[J[I].substring(0,F)]=J[I].substring(F+2)}}}catch(L){}H.tId=E.tId;H.status=E.conn.status;H.statusText=E.conn.statusText;H.getResponseHeader=M;H.getAllResponseHeaders=G;H.responseText=E.conn.responseText;H.responseXML=E.conn.responseXML;if(typeof K!==undefined){H.argument=K}return H},createExceptionObject:function(L,H,E){var J=0;var K="communication failure";var G=-1;var F="transaction aborted";var I={};I.tId=L;if(E){I.status=G;I.statusText=F}else{I.status=J;I.statusText=K}if(H){I.argument=H}return I},initHeader:function(E,H,G){var F=(G)?this.defaultHeaders:this.headers;if(F[E]===undefined){F[E]=H}else{F[E]=H+","+F[E]}if(G){this.hasDefaultHeaders=true}else{this.hasHeaders=true}},setHeader:function(E){if(this.hasDefaultHeaders){for(var F in this.defaultHeaders){if(this.defaultHeaders.hasOwnProperty(F)){E.conn.setRequestHeader(F,this.defaultHeaders[F])}}}if(this.hasHeaders){for(var F in this.headers){if(this.headers.hasOwnProperty(F)){E.conn.setRequestHeader(F,this.headers[F])}}this.headers={};this.hasHeaders=false}},resetDefaultHeaders:function(){delete this.defaultHeaders;this.defaultHeaders={};this.hasDefaultHeaders=false},abort:function(F,G,E){if(this.isCallInProgress(F)){F.conn.abort();window.clearInterval(this.poll[F.tId]);delete this.poll[F.tId];if(E){delete this.timeout[F.tId]}this.handleTransactionResponse(F,G,true);return true}else{return false}},isCallInProgress:function(E){if(E.conn){return E.conn.readyState!=4&&E.conn.readyState!=0}else{return false}},releaseObject:function(E){E.conn=null;E=null},activeX:["MSXML2.XMLHTTP.3.0","MSXML2.XMLHTTP","Microsoft.XMLHTTP"]};Ext.lib.Region=function(G,H,E,F){this.top=G;this[1]=G;this.right=H;this.bottom=E;this.left=F;this[0]=F};Ext.lib.Region.prototype={contains:function(E){return(E.left>=this.left&&E.right<=this.right&&E.top>=this.top&&E.bottom<=this.bottom)},getArea:function(){return((this.bottom-this.top)*(this.right-this.left))},intersect:function(I){var G=Math.max(this.top,I.top);var H=Math.min(this.right,I.right);var E=Math.min(this.bottom,I.bottom);var F=Math.max(this.left,I.left);if(E>=G&&H>=F){return new Ext.lib.Region(G,H,E,F)}else{return null}},union:function(I){var G=Math.min(this.top,I.top);var H=Math.max(this.right,I.right);var E=Math.max(this.bottom,I.bottom);var F=Math.min(this.left,I.left);return new Ext.lib.Region(G,H,E,F)},constrainTo:function(E){this.top=this.top.constrain(E.top,E.bottom);this.bottom=this.bottom.constrain(E.top,E.bottom);this.left=this.left.constrain(E.left,E.right);this.right=this.right.constrain(E.left,E.right);return this},adjust:function(G,F,E,H){this.top+=G;this.left+=F;this.right+=H;this.bottom+=E;return this}};Ext.lib.Region.getRegion=function(H){var J=Ext.lib.Dom.getXY(H);var G=J[1];var I=J[0]+H.offsetWidth;var E=J[1]+H.offsetHeight;var F=J[0];return new Ext.lib.Region(G,I,E,F)};Ext.lib.Point=function(E,F){if(Ext.isArray(E)){F=E[1];E=E[0]}this.x=this.right=this.left=this[0]=E;this.y=this.top=this.bottom=this[1]=F};Ext.lib.Point.prototype=new Ext.lib.Region();Ext.lib.Anim={scroll:function(H,F,I,J,E,G){return this.run(H,F,I,J,E,G,Ext.lib.Scroll)},motion:function(H,F,I,J,E,G){return this.run(H,F,I,J,E,G,Ext.lib.Motion)},color:function(H,F,I,J,E,G){return this.run(H,F,I,J,E,G,Ext.lib.ColorAnim)},run:function(I,F,K,L,E,H,G){G=G||Ext.lib.AnimBase;if(typeof L=="string"){L=Ext.lib.Easing[L]}var J=new G(I,F,K,L);J.animateX(function(){Ext.callback(E,H)});return J}};function C(E){if(!B){B=new Ext.Element.Flyweight()}B.dom=E;return B}if(Ext.isIE){function A(){var E=Function.prototype;delete E.createSequence;delete E.defer;delete E.createDelegate;delete E.createCallback;delete E.createInterceptor;window.detachEvent("onunload",A)}window.attachEvent("onunload",A)}Ext.lib.AnimBase=function(F,E,G,H){if(F){this.init(F,E,G,H)}};Ext.lib.AnimBase.prototype={toString:function(){var E=this.getEl();var F=E.id||E.tagName;return("Anim "+F)},patterns:{noNegatives:/width|height|opacity|padding/i,offsetAttribute:/^((width|height)|(top|left))$/,defaultUnit:/width|height|top$|bottom$|left$|right$/i,offsetUnit:/\d+(em|%|en|ex|pt|in|cm|mm|pc)$/i},doMethod:function(E,G,F){return this.method(this.currentFrame,G,F-G,this.totalFrames)},setAttribute:function(E,G,F){if(this.patterns.noNegatives.test(E)){G=(G>0)?G:0}Ext.fly(this.getEl(),"_anim").setStyle(E,G+F)},getAttribute:function(E){var G=this.getEl();var I=C(G).getStyle(E);if(I!=="auto"&&!this.patterns.offsetUnit.test(I)){return parseFloat(I)}var F=this.patterns.offsetAttribute.exec(E)||[];var J=!!(F[3]);var H=!!(F[2]);if(H||(C(G).getStyle("position")=="absolute"&&J)){I=G["offset"+F[0].charAt(0).toUpperCase()+F[0].substr(1)]}else{I=0}return I},getDefaultUnit:function(E){if(this.patterns.defaultUnit.test(E)){return"px"}return""},animateX:function(G,E){var F=function(){this.onComplete.removeListener(F);if(typeof G=="function"){G.call(E||this,this)}};this.onComplete.addListener(F,this);this.animate()},setRuntimeAttribute:function(F){var K;var G;var H=this.attributes;this.runtimeAttributes[F]={};var J=function(L){return(typeof L!=="undefined")};if(!J(H[F]["to"])&&!J(H[F]["by"])){return false}K=(J(H[F]["from"]))?H[F]["from"]:this.getAttribute(F);if(J(H[F]["to"])){G=H[F]["to"]}else{if(J(H[F]["by"])){if(K.constructor==Array){G=[];for(var I=0,E=K.length;I<E;++I){G[I]=K[I]+H[F]["by"][I]}}else{G=K+H[F]["by"]}}}this.runtimeAttributes[F].start=K;this.runtimeAttributes[F].end=G;this.runtimeAttributes[F].unit=(J(H[F].unit))?H[F]["unit"]:this.getDefaultUnit(F)},init:function(G,L,K,E){var F=false;var H=null;var J=0;G=Ext.getDom(G);this.attributes=L||{};this.duration=K||1;this.method=E||Ext.lib.Easing.easeNone;this.useSeconds=true;this.currentFrame=0;this.totalFrames=Ext.lib.AnimMgr.fps;this.getEl=function(){return G};this.isAnimated=function(){return F};this.getStartTime=function(){return H};this.runtimeAttributes={};this.animate=function(){if(this.isAnimated()){return false}this.currentFrame=0;this.totalFrames=(this.useSeconds)?Math.ceil(Ext.lib.AnimMgr.fps*this.duration):this.duration;Ext.lib.AnimMgr.registerElement(this)};this.stop=function(O){if(O){this.currentFrame=this.totalFrames;this._onTween.fire()}Ext.lib.AnimMgr.stop(this)};var N=function(){this.onStart.fire();this.runtimeAttributes={};for(var O in this.attributes){this.setRuntimeAttribute(O)}F=true;J=0;H=new Date()};var M=function(){var Q={duration:new Date()-this.getStartTime(),currentFrame:this.currentFrame};Q.toString=function(){return("duration: "+Q.duration+", currentFrame: "+Q.currentFrame)};this.onTween.fire(Q);var P=this.runtimeAttributes;for(var O in P){this.setAttribute(O,this.doMethod(O,P[O].start,P[O].end),P[O].unit)}J+=1};var I=function(){var O=(new Date()-H)/1000;var P={duration:O,frames:J,fps:J/O};P.toString=function(){return("duration: "+P.duration+", frames: "+P.frames+", fps: "+P.fps)};F=false;J=0;this.onComplete.fire(P)};this._onStart=new Ext.util.Event(this);this.onStart=new Ext.util.Event(this);this.onTween=new Ext.util.Event(this);this._onTween=new Ext.util.Event(this);this.onComplete=new Ext.util.Event(this);this._onComplete=new Ext.util.Event(this);this._onStart.addListener(N);this._onTween.addListener(M);this._onComplete.addListener(I)}};Ext.lib.AnimMgr=new function(){var G=null;var F=[];var E=0;this.fps=1000;this.delay=1;this.registerElement=function(J){F[F.length]=J;E+=1;J._onStart.fire();this.start()};this.unRegister=function(K,J){K._onComplete.fire();J=J||I(K);if(J!=-1){F.splice(J,1)}E-=1;if(E<=0){this.stop()}};this.start=function(){if(G===null){G=setInterval(this.run,this.delay)}};this.stop=function(L){if(!L){clearInterval(G);for(var K=0,J=F.length;K<J;++K){if(F[0].isAnimated()){this.unRegister(F[0],0)}}F=[];G=null;E=0}else{this.unRegister(L)}};this.run=function(){for(var L=0,J=F.length;L<J;++L){var K=F[L];if(!K||!K.isAnimated()){continue}if(K.currentFrame<K.totalFrames||K.totalFrames===null){K.currentFrame+=1;if(K.useSeconds){H(K)}K._onTween.fire()}else{Ext.lib.AnimMgr.stop(K,L)}}};var I=function(L){for(var K=0,J=F.length;K<J;++K){if(F[K]==L){return K}}return -1};var H=function(K){var N=K.totalFrames;var M=K.currentFrame;var L=(K.currentFrame*K.duration*1000/K.totalFrames);var J=(new Date()-K.getStartTime());var O=0;if(J<K.duration*1000){O=Math.round((J/L-1)*K.currentFrame)}else{O=N-(M+1)}if(O>0&&isFinite(O)){if(K.currentFrame+O>=N){O=N-(M+1)}K.currentFrame+=O}}};Ext.lib.Bezier=new function(){this.getPosition=function(I,H){var J=I.length;var G=[];for(var F=0;F<J;++F){G[F]=[I[F][0],I[F][1]]}for(var E=1;E<J;++E){for(F=0;F<J-E;++F){G[F][0]=(1-H)*G[F][0]+H*G[parseInt(F+1,10)][0];G[F][1]=(1-H)*G[F][1]+H*G[parseInt(F+1,10)][1]}}return[G[0][0],G[0][1]]}};(function(){Ext.lib.ColorAnim=function(I,H,J,K){Ext.lib.ColorAnim.superclass.constructor.call(this,I,H,J,K)};Ext.extend(Ext.lib.ColorAnim,Ext.lib.AnimBase);var F=Ext.lib;var G=F.ColorAnim.superclass;var E=F.ColorAnim.prototype;E.toString=function(){var H=this.getEl();var I=H.id||H.tagName;return("ColorAnim "+I)};E.patterns.color=/color$/i;E.patterns.rgb=/^rgb\(([0-9]+)\s*,\s*([0-9]+)\s*,\s*([0-9]+)\)$/i;E.patterns.hex=/^#?([0-9A-F]{2})([0-9A-F]{2})([0-9A-F]{2})$/i;E.patterns.hex3=/^#?([0-9A-F]{1})([0-9A-F]{1})([0-9A-F]{1})$/i;E.patterns.transparent=/^transparent|rgba\(0, 0, 0, 0\)$/;E.parseColor=function(H){if(H.length==3){return H}var I=this.patterns.hex.exec(H);if(I&&I.length==4){return[parseInt(I[1],16),parseInt(I[2],16),parseInt(I[3],16)]}I=this.patterns.rgb.exec(H);if(I&&I.length==4){return[parseInt(I[1],10),parseInt(I[2],10),parseInt(I[3],10)]}I=this.patterns.hex3.exec(H);if(I&&I.length==4){return[parseInt(I[1]+I[1],16),parseInt(I[2]+I[2],16),parseInt(I[3]+I[3],16)]}return null};E.getAttribute=function(H){var J=this.getEl();if(this.patterns.color.test(H)){var K=C(J).getStyle(H);if(this.patterns.transparent.test(K)){var I=J.parentNode;K=C(I).getStyle(H);while(I&&this.patterns.transparent.test(K)){I=I.parentNode;K=C(I).getStyle(H);if(I.tagName.toUpperCase()=="HTML"){K="#fff"}}}}else{K=G.getAttribute.call(this,H)}return K};E.doMethod=function(I,M,J){var L;if(this.patterns.color.test(I)){L=[];for(var K=0,H=M.length;K<H;++K){L[K]=G.doMethod.call(this,I,M[K],J[K])}L="rgb("+Math.floor(L[0])+","+Math.floor(L[1])+","+Math.floor(L[2])+")"}else{L=G.doMethod.call(this,I,M,J)}return L};E.setRuntimeAttribute=function(I){G.setRuntimeAttribute.call(this,I);if(this.patterns.color.test(I)){var K=this.attributes;var M=this.parseColor(this.runtimeAttributes[I].start);var J=this.parseColor(this.runtimeAttributes[I].end);if(typeof K[I]["to"]==="undefined"&&typeof K[I]["by"]!=="undefined"){J=this.parseColor(K[I].by);for(var L=0,H=M.length;L<H;++L){J[L]=M[L]+J[L]}}this.runtimeAttributes[I].start=M;this.runtimeAttributes[I].end=J}}})();Ext.lib.Easing={easeNone:function(F,E,H,G){return H*F/G+E},easeIn:function(F,E,H,G){return H*(F/=G)*F+E},easeOut:function(F,E,H,G){return -H*(F/=G)*(F-2)+E},easeBoth:function(F,E,H,G){if((F/=G/2)<1){return H/2*F*F+E}return -H/2*((--F)*(F-2)-1)+E},easeInStrong:function(F,E,H,G){return H*(F/=G)*F*F*F+E},easeOutStrong:function(F,E,H,G){return -H*((F=F/G-1)*F*F*F-1)+E},easeBothStrong:function(F,E,H,G){if((F/=G/2)<1){return H/2*F*F*F*F+E}return -H/2*((F-=2)*F*F*F-2)+E},elasticIn:function(G,E,K,J,F,I){if(G==0){return E}if((G/=J)==1){return E+K}if(!I){I=J*0.3}if(!F||F<Math.abs(K)){F=K;var H=I/4}else{var H=I/(2*Math.PI)*Math.asin(K/F)}return -(F*Math.pow(2,10*(G-=1))*Math.sin((G*J-H)*(2*Math.PI)/I))+E},elasticOut:function(G,E,K,J,F,I){if(G==0){return E}if((G/=J)==1){return E+K}if(!I){I=J*0.3}if(!F||F<Math.abs(K)){F=K;var H=I/4}else{var H=I/(2*Math.PI)*Math.asin(K/F)}return F*Math.pow(2,-10*G)*Math.sin((G*J-H)*(2*Math.PI)/I)+K+E},elasticBoth:function(G,E,K,J,F,I){if(G==0){return E}if((G/=J/2)==2){return E+K}if(!I){I=J*(0.3*1.5)}if(!F||F<Math.abs(K)){F=K;var H=I/4}else{var H=I/(2*Math.PI)*Math.asin(K/F)}if(G<1){return -0.5*(F*Math.pow(2,10*(G-=1))*Math.sin((G*J-H)*(2*Math.PI)/I))+E}return F*Math.pow(2,-10*(G-=1))*Math.sin((G*J-H)*(2*Math.PI)/I)*0.5+K+E},backIn:function(F,E,I,H,G){if(typeof G=="undefined"){G=1.70158}return I*(F/=H)*F*((G+1)*F-G)+E},backOut:function(F,E,I,H,G){if(typeof G=="undefined"){G=1.70158}return I*((F=F/H-1)*F*((G+1)*F+G)+1)+E},backBoth:function(F,E,I,H,G){if(typeof G=="undefined"){G=1.70158}if((F/=H/2)<1){return I/2*(F*F*(((G*=(1.525))+1)*F-G))+E}return I/2*((F-=2)*F*(((G*=(1.525))+1)*F+G)+2)+E},bounceIn:function(F,E,H,G){return H-Ext.lib.Easing.bounceOut(G-F,0,H,G)+E},bounceOut:function(F,E,H,G){if((F/=G)<(1/2.75)){return H*(7.5625*F*F)+E}else{if(F<(2/2.75)){return H*(7.5625*(F-=(1.5/2.75))*F+0.75)+E}else{if(F<(2.5/2.75)){return H*(7.5625*(F-=(2.25/2.75))*F+0.9375)+E}}}return H*(7.5625*(F-=(2.625/2.75))*F+0.984375)+E},bounceBoth:function(F,E,H,G){if(F<G/2){return Ext.lib.Easing.bounceIn(F*2,0,H,G)*0.5+E}return Ext.lib.Easing.bounceOut(F*2-G,0,H,G)*0.5+H*0.5+E}};(function(){Ext.lib.Motion=function(K,J,L,M){if(K){Ext.lib.Motion.superclass.constructor.call(this,K,J,L,M)}};Ext.extend(Ext.lib.Motion,Ext.lib.ColorAnim);var H=Ext.lib;var I=H.Motion.superclass;var F=H.Motion.prototype;F.toString=function(){var J=this.getEl();var K=J.id||J.tagName;return("Motion "+K)};F.patterns.points=/^points$/i;F.setAttribute=function(J,L,K){if(this.patterns.points.test(J)){K=K||"px";I.setAttribute.call(this,"left",L[0],K);I.setAttribute.call(this,"top",L[1],K)}else{I.setAttribute.call(this,J,L,K)}};F.getAttribute=function(J){if(this.patterns.points.test(J)){var K=[I.getAttribute.call(this,"left"),I.getAttribute.call(this,"top")]}else{K=I.getAttribute.call(this,J)}return K};F.doMethod=function(J,N,K){var M=null;if(this.patterns.points.test(J)){var L=this.method(this.currentFrame,0,100,this.totalFrames)/100;M=H.Bezier.getPosition(this.runtimeAttributes[J],L)}else{M=I.doMethod.call(this,J,N,K)}return M};F.setRuntimeAttribute=function(S){if(this.patterns.points.test(S)){var K=this.getEl();var M=this.attributes;var J;var O=M["points"]["control"]||[];var L;var P,R;if(O.length>0&&!Ext.isArray(O[0])){O=[O]}else{var N=[];for(P=0,R=O.length;P<R;++P){N[P]=O[P]}O=N}Ext.fly(K,"_anim").position();if(G(M["points"]["from"])){Ext.lib.Dom.setXY(K,M["points"]["from"])}else{Ext.lib.Dom.setXY(K,Ext.lib.Dom.getXY(K))}J=this.getAttribute("points");if(G(M["points"]["to"])){L=E.call(this,M["points"]["to"],J);var Q=Ext.lib.Dom.getXY(this.getEl());for(P=0,R=O.length;P<R;++P){O[P]=E.call(this,O[P],J)}}else{if(G(M["points"]["by"])){L=[J[0]+M["points"]["by"][0],J[1]+M["points"]["by"][1]];for(P=0,R=O.length;P<R;++P){O[P]=[J[0]+O[P][0],J[1]+O[P][1]]}}}this.runtimeAttributes[S]=[J];if(O.length>0){this.runtimeAttributes[S]=this.runtimeAttributes[S].concat(O)}this.runtimeAttributes[S][this.runtimeAttributes[S].length]=L}else{I.setRuntimeAttribute.call(this,S)}};var E=function(J,L){var K=Ext.lib.Dom.getXY(this.getEl());J=[J[0]-K[0]+L[0],J[1]-K[1]+L[1]];return J};var G=function(J){return(typeof J!=="undefined")}})();(function(){Ext.lib.Scroll=function(I,H,J,K){if(I){Ext.lib.Scroll.superclass.constructor.call(this,I,H,J,K)}};Ext.extend(Ext.lib.Scroll,Ext.lib.ColorAnim);var F=Ext.lib;var G=F.Scroll.superclass;var E=F.Scroll.prototype;E.toString=function(){var H=this.getEl();var I=H.id||H.tagName;return("Scroll "+I)};E.doMethod=function(H,K,I){var J=null;if(H=="scroll"){J=[this.method(this.currentFrame,K[0],I[0]-K[0],this.totalFrames),this.method(this.currentFrame,K[1],I[1]-K[1],this.totalFrames)]}else{J=G.doMethod.call(this,H,K,I)}return J};E.getAttribute=function(H){var J=null;var I=this.getEl();if(H=="scroll"){J=[I.scrollLeft,I.scrollTop]}else{J=G.getAttribute.call(this,H)}return J};E.setAttribute=function(H,K,J){var I=this.getEl();if(H=="scroll"){I.scrollLeft=K[0];I.scrollTop=K[1]}else{G.setAttribute.call(this,H,K,J)}}})()})();
diff --git a/lib/ext-core.js b/lib/ext-core.js
new file mode 100644
index 0000000..aa36cfb
--- /dev/null
+++ b/lib/ext-core.js
@@ -0,0 +1,19 @@
+/*

+ * Ext JS Library 2.2

+ * Copyright(c) 2006-2008, Ext JS, LLC.

+ * licensing@extjs.com

+ * 

+ * http://extjs.com/license

+ */

+

+Ext.DomHelper=function(){var L=null;var F=/^(?:br|frame|hr|img|input|link|meta|range|spacer|wbr|area|param|col)$/i;var B=/^table|tbody|tr|td$/i;var A=function(T){if(typeof T=="string"){return T}var O="";if(Ext.isArray(T)){for(var R=0,P=T.length;R<P;R++){O+=A(T[R])}return O}if(!T.tag){T.tag="div"}O+="<"+T.tag;for(var N in T){if(N=="tag"||N=="children"||N=="cn"||N=="html"||typeof T[N]=="function"){continue}if(N=="style"){var S=T["style"];if(typeof S=="function"){S=S.call()}if(typeof S=="string"){O+=" style=\""+S+"\""}else{if(typeof S=="object"){O+=" style=\"";for(var Q in S){if(typeof S[Q]!="function"){O+=Q+":"+S[Q]+";"}}O+="\""}}}else{if(N=="cls"){O+=" class=\""+T["cls"]+"\""}else{if(N=="htmlFor"){O+=" for=\""+T["htmlFor"]+"\""}else{O+=" "+N+"=\""+T[N]+"\""}}}}if(F.test(T.tag)){O+="/>"}else{O+=">";var U=T.children||T.cn;if(U){O+=A(U)}else{if(T.html){O+=T.html}}O+="</"+T.tag+">"}return O};var M=function(T,O){var S;if(Ext.isArray(T)){S=document.createDocumentFragment();for(var R=0,P=T.length;R<P;R++){M(T[R],S)}}else{if(typeof T=="string"){S=document.createTextNode(T)}else{S=document.createElement(T.tag||"div");var Q=!!S.setAttribute;for(var N in T){if(N=="tag"||N=="children"||N=="cn"||N=="html"||N=="style"||typeof T[N]=="function"){continue}if(N=="cls"){S.className=T["cls"]}else{if(Q){S.setAttribute(N,T[N])}else{S[N]=T[N]}}}Ext.DomHelper.applyStyles(S,T.style);var U=T.children||T.cn;if(U){M(U,S)}else{if(T.html){S.innerHTML=T.html}}}}if(O){O.appendChild(S)}return S};var I=function(S,Q,P,R){L.innerHTML=[Q,P,R].join("");var N=-1,O=L;while(++N<S){O=O.firstChild}return O};var J="<table>",E="</table>",C=J+"<tbody>",K="</tbody>"+E,H=C+"<tr>",D="</tr>"+K;var G=function(N,O,Q,P){if(!L){L=document.createElement("div")}var R;var S=null;if(N=="td"){if(O=="afterbegin"||O=="beforeend"){return }if(O=="beforebegin"){S=Q;Q=Q.parentNode}else{S=Q.nextSibling;Q=Q.parentNode}R=I(4,H,P,D)}else{if(N=="tr"){if(O=="beforebegin"){S=Q;Q=Q.parentNode;R=I(3,C,P,K)}else{if(O=="afterend"){S=Q.nextSibling;Q=Q.parentNode;R=I(3,C,P,K)}else{if(O=="afterbegin"){S=Q.firstChild}R=I(4,H,P,D)}}}else{if(N=="tbody"){if(O=="beforebegin"){S=Q;Q=Q.parentNode;R=I(2,J,P,E)}else{if(O=="afterend"){S=Q.nextSibling;Q=Q.parentNode;R=I(2,J,P,E)}else{if(O=="afterbegin"){S=Q.firstChild}R=I(3,C,P,K)}}}else{if(O=="beforebegin"||O=="afterend"){return }if(O=="afterbegin"){S=Q.firstChild}R=I(2,J,P,E)}}}Q.insertBefore(R,S);return R};return{useDom:false,markup:function(N){return A(N)},applyStyles:function(P,Q){if(Q){P=Ext.fly(P);if(typeof Q=="string"){var O=/\s?([a-z\-]*)\:\s?([^;]*);?/gi;var R;while((R=O.exec(Q))!=null){P.setStyle(R[1],R[2])}}else{if(typeof Q=="object"){for(var N in Q){P.setStyle(N,Q[N])}}else{if(typeof Q=="function"){Ext.DomHelper.applyStyles(P,Q.call())}}}}},insertHtml:function(P,R,Q){P=P.toLowerCase();if(R.insertAdjacentHTML){if(B.test(R.tagName)){var O;if(O=G(R.tagName.toLowerCase(),P,R,Q)){return O}}switch(P){case"beforebegin":R.insertAdjacentHTML("BeforeBegin",Q);return R.previousSibling;case"afterbegin":R.insertAdjacentHTML("AfterBegin",Q);return R.firstChild;case"beforeend":R.insertAdjacentHTML("BeforeEnd",Q);return R.lastChild;case"afterend":R.insertAdjacentHTML("AfterEnd",Q);return R.nextSibling}throw"Illegal insertion point -> \""+P+"\""}var N=R.ownerDocument.createRange();var S;switch(P){case"beforebegin":N.setStartBefore(R);S=N.createContextualFragment(Q);R.parentNode.insertBefore(S,R);return R.previousSibling;case"afterbegin":if(R.firstChild){N.setStartBefore(R.firstChild);S=N.createContextualFragment(Q);R.insertBefore(S,R.firstChild);return R.firstChild}else{R.innerHTML=Q;return R.firstChild}case"beforeend":if(R.lastChild){N.setStartAfter(R.lastChild);S=N.createContextualFragment(Q);R.appendChild(S);return R.lastChild}else{R.innerHTML=Q;return R.lastChild}case"afterend":N.setStartAfter(R);S=N.createContextualFragment(Q);R.parentNode.insertBefore(S,R.nextSibling);return R.nextSibling}throw"Illegal insertion point -> \""+P+"\""},insertBefore:function(N,P,O){return this.doInsert(N,P,O,"beforeBegin")},insertAfter:function(N,P,O){return this.doInsert(N,P,O,"afterEnd","nextSibling")},insertFirst:function(N,P,O){return this.doInsert(N,P,O,"afterBegin","firstChild")},doInsert:function(Q,S,R,T,P){Q=Ext.getDom(Q);var O;if(this.useDom){O=M(S,null);(P==="firstChild"?Q:Q.parentNode).insertBefore(O,P?Q[P]:Q)}else{var N=A(S);O=this.insertHtml(T,Q,N)}return R?Ext.get(O,true):O},append:function(P,R,Q){P=Ext.getDom(P);var O;if(this.useDom){O=M(R,null);P.appendChild(O)}else{var N=A(R);O=this.insertHtml("beforeEnd",P,N)}return Q?Ext.get(O,true):O},overwrite:function(N,P,O){N=Ext.getDom(N);N.innerHTML=A(P);return O?Ext.get(N.firstChild,true):N.firstChild},createTemplate:function(O){var N=A(O);return new Ext.Template(N)}}}();
+Ext.Template=function(E){var B=arguments;if(Ext.isArray(E)){E=E.join("")}else{if(B.length>1){var C=[];for(var D=0,A=B.length;D<A;D++){if(typeof B[D]=="object"){Ext.apply(this,B[D])}else{C[C.length]=B[D]}}E=C.join("")}}this.html=E;if(this.compiled){this.compile()}};Ext.Template.prototype={applyTemplate:function(B){if(this.compiled){return this.compiled(B)}var A=this.disableFormats!==true;var E=Ext.util.Format,C=this;var D=function(G,I,L,H){if(L&&A){if(L.substr(0,5)=="this."){return C.call(L.substr(5),B[I],B)}else{if(H){var K=/^\s*['"](.*)["']\s*$/;H=H.split(",");for(var J=0,F=H.length;J<F;J++){H[J]=H[J].replace(K,"$1")}H=[B[I]].concat(H)}else{H=[B[I]]}return E[L].apply(E,H)}}else{return B[I]!==undefined?B[I]:""}};return this.html.replace(this.re,D)},set:function(A,B){this.html=A;this.compiled=null;if(B){this.compile()}return this},disableFormats:false,re:/\{([\w-]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,compile:function(){var fm=Ext.util.Format;var useF=this.disableFormats!==true;var sep=Ext.isGecko?"+":",";var fn=function(m,name,format,args){if(format&&useF){args=args?","+args:"";if(format.substr(0,5)!="this."){format="fm."+format+"("}else{format="this.call(\""+format.substr(5)+"\", ";args=", values"}}else{args="";format="(values['"+name+"'] == undefined ? '' : "}return"'"+sep+format+"values['"+name+"']"+args+")"+sep+"'"};var body;if(Ext.isGecko){body="this.compiled = function(values){ return '"+this.html.replace(/\\/g,"\\\\").replace(/(\r\n|\n)/g,"\\n").replace(/'/g,"\\'").replace(this.re,fn)+"';};"}else{body=["this.compiled = function(values){ return ['"];body.push(this.html.replace(/\\/g,"\\\\").replace(/(\r\n|\n)/g,"\\n").replace(/'/g,"\\'").replace(this.re,fn));body.push("'].join('');};");body=body.join("")}eval(body);return this},call:function(C,B,A){return this[C](B,A)},insertFirst:function(B,A,C){return this.doInsert("afterBegin",B,A,C)},insertBefore:function(B,A,C){return this.doInsert("beforeBegin",B,A,C)},insertAfter:function(B,A,C){return this.doInsert("afterEnd",B,A,C)},append:function(B,A,C){return this.doInsert("beforeEnd",B,A,C)},doInsert:function(C,E,B,A){E=Ext.getDom(E);var D=Ext.DomHelper.insertHtml(C,E,this.applyTemplate(B));return A?Ext.get(D,true):D},overwrite:function(B,A,C){B=Ext.getDom(B);B.innerHTML=this.applyTemplate(A);return C?Ext.get(B.firstChild,true):B.firstChild}};Ext.Template.prototype.apply=Ext.Template.prototype.applyTemplate;Ext.DomHelper.Template=Ext.Template;Ext.Template.from=function(B,A){B=Ext.getDom(B);return new Ext.Template(B.value||B.innerHTML,A||"")};
+Ext.DomQuery=function(){var cache={},simpleCache={},valueCache={};var nonSpace=/\S/;var trimRe=/^\s+|\s+$/g;var tplRe=/\{(\d+)\}/g;var modeRe=/^(\s?[\/>+~]\s?|\s|$)/;var tagTokenRe=/^(#)?([\w-\*]+)/;var nthRe=/(\d*)n\+?(\d*)/,nthRe2=/\D/;function child(p,index){var i=0;var n=p.firstChild;while(n){if(n.nodeType==1){if(++i==index){return n}}n=n.nextSibling}return null}function next(n){while((n=n.nextSibling)&&n.nodeType!=1){}return n}function prev(n){while((n=n.previousSibling)&&n.nodeType!=1){}return n}function children(d){var n=d.firstChild,ni=-1;while(n){var nx=n.nextSibling;if(n.nodeType==3&&!nonSpace.test(n.nodeValue)){d.removeChild(n)}else{n.nodeIndex=++ni}n=nx}return this}function byClassName(c,a,v){if(!v){return c}var r=[],ri=-1,cn;for(var i=0,ci;ci=c[i];i++){if((" "+ci.className+" ").indexOf(v)!=-1){r[++ri]=ci}}return r}function attrValue(n,attr){if(!n.tagName&&typeof n.length!="undefined"){n=n[0]}if(!n){return null}if(attr=="for"){return n.htmlFor}if(attr=="class"||attr=="className"){return n.className}return n.getAttribute(attr)||n[attr]}function getNodes(ns,mode,tagName){var result=[],ri=-1,cs;if(!ns){return result}tagName=tagName||"*";if(typeof ns.getElementsByTagName!="undefined"){ns=[ns]}if(!mode){for(var i=0,ni;ni=ns[i];i++){cs=ni.getElementsByTagName(tagName);for(var j=0,ci;ci=cs[j];j++){result[++ri]=ci}}}else{if(mode=="/"||mode==">"){var utag=tagName.toUpperCase();for(var i=0,ni,cn;ni=ns[i];i++){cn=ni.children||ni.childNodes;for(var j=0,cj;cj=cn[j];j++){if(cj.nodeName==utag||cj.nodeName==tagName||tagName=="*"){result[++ri]=cj}}}}else{if(mode=="+"){var utag=tagName.toUpperCase();for(var i=0,n;n=ns[i];i++){while((n=n.nextSibling)&&n.nodeType!=1){}if(n&&(n.nodeName==utag||n.nodeName==tagName||tagName=="*")){result[++ri]=n}}}else{if(mode=="~"){for(var i=0,n;n=ns[i];i++){while((n=n.nextSibling)&&(n.nodeType!=1||(tagName=="*"||n.tagName.toLowerCase()!=tagName))){}if(n){result[++ri]=n}}}}}}return result}function concat(a,b){if(b.slice){return a.concat(b)}for(var i=0,l=b.length;i<l;i++){a[a.length]=b[i]}return a}function byTag(cs,tagName){if(cs.tagName||cs==document){cs=[cs]}if(!tagName){return cs}var r=[],ri=-1;tagName=tagName.toLowerCase();for(var i=0,ci;ci=cs[i];i++){if(ci.nodeType==1&&ci.tagName.toLowerCase()==tagName){r[++ri]=ci}}return r}function byId(cs,attr,id){if(cs.tagName||cs==document){cs=[cs]}if(!id){return cs}var r=[],ri=-1;for(var i=0,ci;ci=cs[i];i++){if(ci&&ci.id==id){r[++ri]=ci;return r}}return r}function byAttribute(cs,attr,value,op,custom){var r=[],ri=-1,st=custom=="{";var f=Ext.DomQuery.operators[op];for(var i=0,ci;ci=cs[i];i++){var a;if(st){a=Ext.DomQuery.getStyle(ci,attr)}else{if(attr=="class"||attr=="className"){a=ci.className}else{if(attr=="for"){a=ci.htmlFor}else{if(attr=="href"){a=ci.getAttribute("href",2)}else{a=ci.getAttribute(attr)}}}}if((f&&f(a,value))||(!f&&a)){r[++ri]=ci}}return r}function byPseudo(cs,name,value){return Ext.DomQuery.pseudos[name](cs,value)}var isIE=window.ActiveXObject?true:false;eval("var batch = 30803;");var key=30803;function nodupIEXml(cs){var d=++key;cs[0].setAttribute("_nodup",d);var r=[cs[0]];for(var i=1,len=cs.length;i<len;i++){var c=cs[i];if(!c.getAttribute("_nodup")!=d){c.setAttribute("_nodup",d);r[r.length]=c}}for(var i=0,len=cs.length;i<len;i++){cs[i].removeAttribute("_nodup")}return r}function nodup(cs){if(!cs){return[]}var len=cs.length,c,i,r=cs,cj,ri=-1;if(!len||typeof cs.nodeType!="undefined"||len==1){return cs}if(isIE&&typeof cs[0].selectSingleNode!="undefined"){return nodupIEXml(cs)}var d=++key;cs[0]._nodup=d;for(i=1;c=cs[i];i++){if(c._nodup!=d){c._nodup=d}else{r=[];for(var j=0;j<i;j++){r[++ri]=cs[j]}for(j=i+1;cj=cs[j];j++){if(cj._nodup!=d){cj._nodup=d;r[++ri]=cj}}return r}}return r}function quickDiffIEXml(c1,c2){var d=++key;for(var i=0,len=c1.length;i<len;i++){c1[i].setAttribute("_qdiff",d)}var r=[];for(var i=0,len=c2.length;i<len;i++){if(c2[i].getAttribute("_qdiff")!=d){r[r.length]=c2[i]}}for(var i=0,len=c1.length;i<len;i++){c1[i].removeAttribute("_qdiff")}return r}function quickDiff(c1,c2){var len1=c1.length;if(!len1){return c2}if(isIE&&c1[0].selectSingleNode){return quickDiffIEXml(c1,c2)}var d=++key;for(var i=0;i<len1;i++){c1[i]._qdiff=d}var r=[];for(var i=0,len=c2.length;i<len;i++){if(c2[i]._qdiff!=d){r[r.length]=c2[i]}}return r}function quickId(ns,mode,root,id){if(ns==root){var d=root.ownerDocument||root;return d.getElementById(id)}ns=getNodes(ns,mode,"*");return byId(ns,null,id)}return{getStyle:function(el,name){return Ext.fly(el).getStyle(name)},compile:function(path,type){type=type||"select";var fn=["var f = function(root){\n var mode; ++batch; var n = root || document;\n"];var q=path,mode,lq;var tk=Ext.DomQuery.matchers;var tklen=tk.length;var mm;var lmode=q.match(modeRe);if(lmode&&lmode[1]){fn[fn.length]="mode=\""+lmode[1].replace(trimRe,"")+"\";";q=q.replace(lmode[1],"")}while(path.substr(0,1)=="/"){path=path.substr(1)}while(q&&lq!=q){lq=q;var tm=q.match(tagTokenRe);if(type=="select"){if(tm){if(tm[1]=="#"){fn[fn.length]="n = quickId(n, mode, root, \""+tm[2]+"\");"}else{fn[fn.length]="n = getNodes(n, mode, \""+tm[2]+"\");"}q=q.replace(tm[0],"")}else{if(q.substr(0,1)!="@"){fn[fn.length]="n = getNodes(n, mode, \"*\");"}}}else{if(tm){if(tm[1]=="#"){fn[fn.length]="n = byId(n, null, \""+tm[2]+"\");"}else{fn[fn.length]="n = byTag(n, \""+tm[2]+"\");"}q=q.replace(tm[0],"")}}while(!(mm=q.match(modeRe))){var matched=false;for(var j=0;j<tklen;j++){var t=tk[j];var m=q.match(t.re);if(m){fn[fn.length]=t.select.replace(tplRe,function(x,i){return m[i]});q=q.replace(m[0],"");matched=true;break}}if(!matched){throw"Error parsing selector, parsing failed at \""+q+"\""}}if(mm[1]){fn[fn.length]="mode=\""+mm[1].replace(trimRe,"")+"\";";q=q.replace(mm[1],"")}}fn[fn.length]="return nodup(n);\n}";eval(fn.join(""));return f},select:function(path,root,type){if(!root||root==document){root=document}if(typeof root=="string"){root=document.getElementById(root)}var paths=path.split(",");var results=[];for(var i=0,len=paths.length;i<len;i++){var p=paths[i].replace(trimRe,"");if(!cache[p]){cache[p]=Ext.DomQuery.compile(p);if(!cache[p]){throw p+" is not a valid selector"}}var result=cache[p](root);if(result&&result!=document){results=results.concat(result)}}if(paths.length>1){return nodup(results)}return results},selectNode:function(path,root){return Ext.DomQuery.select(path,root)[0]},selectValue:function(path,root,defaultValue){path=path.replace(trimRe,"");if(!valueCache[path]){valueCache[path]=Ext.DomQuery.compile(path,"select")}var n=valueCache[path](root);n=n[0]?n[0]:n;var v=(n&&n.firstChild?n.firstChild.nodeValue:null);return((v===null||v===undefined||v==="")?defaultValue:v)},selectNumber:function(path,root,defaultValue){var v=Ext.DomQuery.selectValue(path,root,defaultValue||0);return parseFloat(v)},is:function(el,ss){if(typeof el=="string"){el=document.getElementById(el)}var isArray=Ext.isArray(el);var result=Ext.DomQuery.filter(isArray?el:[el],ss);return isArray?(result.length==el.length):(result.length>0)},filter:function(els,ss,nonMatches){ss=ss.replace(trimRe,"");if(!simpleCache[ss]){simpleCache[ss]=Ext.DomQuery.compile(ss,"simple")}var result=simpleCache[ss](els);return nonMatches?quickDiff(result,els):result},matchers:[{re:/^\.([\w-]+)/,select:"n = byClassName(n, null, \" {1} \");"},{re:/^\:([\w-]+)(?:\(((?:[^\s>\/]*|.*?))\))?/,select:"n = byPseudo(n, \"{1}\", \"{2}\");"},{re:/^(?:([\[\{])(?:@)?([\w-]+)\s?(?:(=|.=)\s?['"]?(.*?)["']?)?[\]\}])/,select:"n = byAttribute(n, \"{2}\", \"{4}\", \"{3}\", \"{1}\");"},{re:/^#([\w-]+)/,select:"n = byId(n, null, \"{1}\");"},{re:/^@([\w-]+)/,select:"return {firstChild:{nodeValue:attrValue(n, \"{1}\")}};"}],operators:{"=":function(a,v){return a==v},"!=":function(a,v){return a!=v},"^=":function(a,v){return a&&a.substr(0,v.length)==v},"$=":function(a,v){return a&&a.substr(a.length-v.length)==v},"*=":function(a,v){return a&&a.indexOf(v)!==-1},"%=":function(a,v){return(a%v)==0},"|=":function(a,v){return a&&(a==v||a.substr(0,v.length+1)==v+"-")},"~=":function(a,v){return a&&(" "+a+" ").indexOf(" "+v+" ")!=-1}},pseudos:{"first-child":function(c){var r=[],ri=-1,n;for(var i=0,ci;ci=n=c[i];i++){while((n=n.previousSibling)&&n.nodeType!=1){}if(!n){r[++ri]=ci}}return r},"last-child":function(c){var r=[],ri=-1,n;for(var i=0,ci;ci=n=c[i];i++){while((n=n.nextSibling)&&n.nodeType!=1){}if(!n){r[++ri]=ci}}return r},"nth-child":function(c,a){var r=[],ri=-1;var m=nthRe.exec(a=="even"&&"2n"||a=="odd"&&"2n+1"||!nthRe2.test(a)&&"n+"+a||a);var f=(m[1]||1)-0,l=m[2]-0;for(var i=0,n;n=c[i];i++){var pn=n.parentNode;if(batch!=pn._batch){var j=0;for(var cn=pn.firstChild;cn;cn=cn.nextSibling){if(cn.nodeType==1){cn.nodeIndex=++j}}pn._batch=batch}if(f==1){if(l==0||n.nodeIndex==l){r[++ri]=n}}else{if((n.nodeIndex+l)%f==0){r[++ri]=n}}}return r},"only-child":function(c){var r=[],ri=-1;for(var i=0,ci;ci=c[i];i++){if(!prev(ci)&&!next(ci)){r[++ri]=ci}}return r},"empty":function(c){var r=[],ri=-1;for(var i=0,ci;ci=c[i];i++){var cns=ci.childNodes,j=0,cn,empty=true;while(cn=cns[j]){++j;if(cn.nodeType==1||cn.nodeType==3){empty=false;break}}if(empty){r[++ri]=ci}}return r},"contains":function(c,v){var r=[],ri=-1;for(var i=0,ci;ci=c[i];i++){if((ci.textContent||ci.innerText||"").indexOf(v)!=-1){r[++ri]=ci}}return r},"nodeValue":function(c,v){var r=[],ri=-1;for(var i=0,ci;ci=c[i];i++){if(ci.firstChild&&ci.firstChild.nodeValue==v){r[++ri]=ci}}return r},"checked":function(c){var r=[],ri=-1;for(var i=0,ci;ci=c[i];i++){if(ci.checked==true){r[++ri]=ci}}return r},"not":function(c,ss){return Ext.DomQuery.filter(c,ss,true)},"any":function(c,selectors){var ss=selectors.split("|");var r=[],ri=-1,s;for(var i=0,ci;ci=c[i];i++){for(var j=0;s=ss[j];j++){if(Ext.DomQuery.is(ci,s)){r[++ri]=ci;break}}}return r},"odd":function(c){return this["nth-child"](c,"odd")},"even":function(c){return this["nth-child"](c,"even")},"nth":function(c,a){return c[a-1]||[]},"first":function(c){return c[0]||[]},"last":function(c){return c[c.length-1]||[]},"has":function(c,ss){var s=Ext.DomQuery.select;var r=[],ri=-1;for(var i=0,ci;ci=c[i];i++){if(s(ss,ci).length>0){r[++ri]=ci}}return r},"next":function(c,ss){var is=Ext.DomQuery.is;var r=[],ri=-1;for(var i=0,ci;ci=c[i];i++){var n=next(ci);if(n&&is(n,ss)){r[++ri]=ci}}return r},"prev":function(c,ss){var is=Ext.DomQuery.is;var r=[],ri=-1;for(var i=0,ci;ci=c[i];i++){var n=prev(ci);if(n&&is(n,ss)){r[++ri]=ci}}return r}}}}();Ext.query=Ext.DomQuery.select;
+Ext.util.Observable=function(){if(this.listeners){this.on(this.listeners);delete this.listeners}};Ext.util.Observable.prototype={fireEvent:function(){if(this.eventsSuspended!==true){var A=this.events[arguments[0].toLowerCase()];if(typeof A=="object"){return A.fire.apply(A,Array.prototype.slice.call(arguments,1))}}return true},filterOptRe:/^(?:scope|delay|buffer|single)$/,addListener:function(A,C,B,F){if(typeof A=="object"){F=A;for(var E in F){if(this.filterOptRe.test(E)){continue}if(typeof F[E]=="function"){this.addListener(E,F[E],F.scope,F)}else{this.addListener(E,F[E].fn,F[E].scope,F[E])}}return }F=(!F||typeof F=="boolean")?{}:F;A=A.toLowerCase();var D=this.events[A]||true;if(typeof D=="boolean"){D=new Ext.util.Event(this,A);this.events[A]=D}D.addListener(C,B,F)},removeListener:function(A,C,B){var D=this.events[A.toLowerCase()];if(typeof D=="object"){D.removeListener(C,B)}},purgeListeners:function(){for(var A in this.events){if(typeof this.events[A]=="object"){this.events[A].clearListeners()}}},relayEvents:function(F,D){var E=function(G){return function(){return this.fireEvent.apply(this,Ext.combine(G,Array.prototype.slice.call(arguments,0)))}};for(var C=0,A=D.length;C<A;C++){var B=D[C];if(!this.events[B]){this.events[B]=true}F.on(B,E(B),this)}},addEvents:function(D){if(!this.events){this.events={}}if(typeof D=="string"){for(var C=0,A=arguments,B;B=A[C];C++){if(!this.events[A[C]]){this.events[A[C]]=true}}}else{Ext.applyIf(this.events,D)}},hasListener:function(A){var B=this.events[A];return typeof B=="object"&&B.listeners.length>0},suspendEvents:function(){this.eventsSuspended=true},resumeEvents:function(){this.eventsSuspended=false},getMethodEvent:function(G){if(!this.methodEvents){this.methodEvents={}}var F=this.methodEvents[G];if(!F){F={};this.methodEvents[G]=F;F.originalFn=this[G];F.methodName=G;F.before=[];F.after=[];var C,B,D;var E=this;var A=function(J,I,H){if((B=J.apply(I||E,H))!==undefined){if(typeof B==="object"){if(B.returnValue!==undefined){C=B.returnValue}else{C=B}if(B.cancel===true){D=true}}else{if(B===false){D=true}else{C=B}}}};this[G]=function(){C=B=undefined;D=false;var I=Array.prototype.slice.call(arguments,0);for(var J=0,H=F.before.length;J<H;J++){A(F.before[J].fn,F.before[J].scope,I);if(D){return C}}if((B=F.originalFn.apply(E,I))!==undefined){C=B}for(var J=0,H=F.after.length;J<H;J++){A(F.after[J].fn,F.after[J].scope,I);if(D){return C}}return C}}return F},beforeMethod:function(D,B,A){var C=this.getMethodEvent(D);C.before.push({fn:B,scope:A})},afterMethod:function(D,B,A){var C=this.getMethodEvent(D);C.after.push({fn:B,scope:A})},removeMethodListener:function(F,D,C){var E=this.getMethodEvent(F);for(var B=0,A=E.before.length;B<A;B++){if(E.before[B].fn==D&&E.before[B].scope==C){E.before.splice(B,1);return }}for(var B=0,A=E.after.length;B<A;B++){if(E.after[B].fn==D&&E.after[B].scope==C){E.after.splice(B,1);return }}}};Ext.util.Observable.prototype.on=Ext.util.Observable.prototype.addListener;Ext.util.Observable.prototype.un=Ext.util.Observable.prototype.removeListener;Ext.util.Observable.capture=function(C,B,A){C.fireEvent=C.fireEvent.createInterceptor(B,A)};Ext.util.Observable.releaseCapture=function(A){A.fireEvent=Ext.util.Observable.prototype.fireEvent};(function(){var B=function(F,G,E){var D=new Ext.util.DelayedTask();return function(){D.delay(G.buffer,F,E,Array.prototype.slice.call(arguments,0))}};var C=function(F,G,E,D){return function(){G.removeListener(E,D);return F.apply(D,arguments)}};var A=function(E,F,D){return function(){var G=Array.prototype.slice.call(arguments,0);setTimeout(function(){E.apply(D,G)},F.delay||10)}};Ext.util.Event=function(E,D){this.name=D;this.obj=E;this.listeners=[]};Ext.util.Event.prototype={addListener:function(G,F,E){F=F||this.obj;if(!this.isListening(G,F)){var D=this.createListener(G,F,E);if(!this.firing){this.listeners.push(D)}else{this.listeners=this.listeners.slice(0);this.listeners.push(D)}}},createListener:function(G,F,H){H=H||{};F=F||this.obj;var D={fn:G,scope:F,options:H};var E=G;if(H.delay){E=A(E,H,F)}if(H.single){E=C(E,this,G,F)}if(H.buffer){E=B(E,H,F)}D.fireFn=E;return D},findListener:function(I,H){H=H||this.obj;var F=this.listeners;for(var G=0,D=F.length;G<D;G++){var E=F[G];if(E.fn==I&&E.scope==H){return G}}return -1},isListening:function(E,D){return this.findListener(E,D)!=-1},removeListener:function(F,E){var D;if((D=this.findListener(F,E))!=-1){if(!this.firing){this.listeners.splice(D,1)}else{this.listeners=this.listeners.slice(0);this.listeners.splice(D,1)}return true}return false},clearListeners:function(){this.listeners=[]},fire:function(){var F=this.listeners,I,D=F.length;if(D>0){this.firing=true;var G=Array.prototype.slice.call(arguments,0);for(var H=0;H<D;H++){var E=F[H];if(E.fireFn.apply(E.scope||this.obj||window,arguments)===false){this.firing=false;return false}}this.firing=false}return true}}})();
+Ext.EventManager=function(){var X,Q,M=false;var N,W,H,S;var P=Ext.lib.Event;var R=Ext.lib.Dom;var A="Ex"+"t";var J={};var O=function(b,E,a,Z,Y){var d=Ext.id(b);if(!J[d]){J[d]={}}var c=J[d];if(!c[E]){c[E]=[]}var D=c[E];D.push({id:d,ename:E,fn:a,wrap:Z,scope:Y});P.on(b,E,Z);if(E=="mousewheel"&&b.addEventListener){b.addEventListener("DOMMouseScroll",Z,false);P.on(window,"unload",function(){b.removeEventListener("DOMMouseScroll",Z,false)})}if(E=="mousedown"&&b==document){Ext.EventManager.stoppedMouseDownEvent.addListener(Z)}};var I=function(Y,a,e,g){Y=Ext.getDom(Y);var D=Ext.id(Y),f=J[D],E;if(f){var c=f[a],Z;if(c){for(var b=0,d=c.length;b<d;b++){Z=c[b];if(Z.fn==e&&(!g||Z.scope==g)){E=Z.wrap;P.un(Y,a,E);c.splice(b,1);break}}}}if(a=="mousewheel"&&Y.addEventListener&&E){Y.removeEventListener("DOMMouseScroll",E,false)}if(a=="mousedown"&&Y==document&&E){Ext.EventManager.stoppedMouseDownEvent.removeListener(E)}};var F=function(a){a=Ext.getDom(a);var c=Ext.id(a),b=J[c],E;if(b){for(var Z in b){if(b.hasOwnProperty(Z)){E=b[Z];for(var Y=0,D=E.length;Y<D;Y++){P.un(a,Z,E[Y].wrap);E[Y]=null}}b[Z]=null}delete J[c]}};var C=function(){if(!M){M=Ext.isReady=true;if(Ext.isGecko||Ext.isOpera){document.removeEventListener("DOMContentLoaded",C,false)}}if(Q){clearInterval(Q);Q=null}if(X){X.fire();X.clearListeners()}};var B=function(){X=new Ext.util.Event();if(Ext.isReady){return }P.on(window,"load",C);if(Ext.isGecko||Ext.isOpera){document.addEventListener("DOMContentLoaded",C,false)}else{if(Ext.isIE){Q=setInterval(function(){try{Ext.isReady||(document.documentElement.doScroll("left"))}catch(D){return }C()},5);document.onreadystatechange=function(){if(document.readyState=="complete"){document.onreadystatechange=null;C()}}}else{if(Ext.isSafari){Q=setInterval(function(){var D=document.readyState;if(D=="complete"){C()}},10)}}}};var V=function(E,Y){var D=new Ext.util.DelayedTask(E);return function(Z){Z=new Ext.EventObjectImpl(Z);D.delay(Y.buffer,E,null,[Z])}};var T=function(a,Z,D,Y,E){return function(b){Ext.EventManager.removeListener(Z,D,Y,E);a(b)}};var G=function(D,E){return function(Y){Y=new Ext.EventObjectImpl(Y);setTimeout(function(){D(Y)},E.delay||10)}};var L=function(Y,E,D,c,b){var d=(!D||typeof D=="boolean")?{}:D;c=c||d.fn;b=b||d.scope;var a=Ext.getDom(Y);if(!a){throw"Error listening for \""+E+"\". Element \""+Y+"\" doesn't exist."}var Z=function(g){if(!window[A]){return }g=Ext.EventObject.setEvent(g);var f;if(d.delegate){f=g.getTarget(d.delegate,a);if(!f){return }}else{f=g.target}if(d.stopEvent===true){g.stopEvent()}if(d.preventDefault===true){g.preventDefault()}if(d.stopPropagation===true){g.stopPropagation()}if(d.normalized===false){g=g.browserEvent}c.call(b||a,g,f,d)};if(d.delay){Z=G(Z,d)}if(d.single){Z=T(Z,a,E,c,b)}if(d.buffer){Z=V(Z,d)}O(a,E,c,Z,b);return Z};var K=/^(?:scope|delay|buffer|single|stopEvent|preventDefault|stopPropagation|normalized|args|delegate)$/;var U={addListener:function(Y,D,a,Z,E){if(typeof D=="object"){var c=D;for(var b in c){if(K.test(b)){continue}if(typeof c[b]=="function"){L(Y,b,c,c[b],c.scope)}else{L(Y,b,c[b])}}return }return L(Y,D,E,a,Z)},removeListener:function(E,D,Z,Y){return I(E,D,Z,Y)},removeAll:function(D){return F(D)},onDocumentReady:function(Y,E,D){if(!X){B()}if(M||Ext.isReady){D||(D={});Y.defer(D.delay||0,E)}else{X.addListener(Y,E,D)}},onWindowResize:function(Y,E,D){if(!N){N=new Ext.util.Event();W=new Ext.util.DelayedTask(function(){N.fire(R.getViewWidth(),R.getViewHeight())});P.on(window,"resize",this.fireWindowResize,this)}N.addListener(Y,E,D)},fireWindowResize:function(){if(N){if((Ext.isIE||Ext.isAir)&&W){W.delay(50)}else{N.fire(R.getViewWidth(),R.getViewHeight())}}},onTextResize:function(Z,Y,D){if(!H){H=new Ext.util.Event();var E=new Ext.Element(document.createElement("div"));E.dom.className="x-text-resize";E.dom.innerHTML="X";E.appendTo(document.body);S=E.dom.offsetHeight;setInterval(function(){if(E.dom.offsetHeight!=S){H.fire(S,S=E.dom.offsetHeight)}},this.textResizeInterval)}H.addListener(Z,Y,D)},removeResizeListener:function(E,D){if(N){N.removeListener(E,D)}},fireResize:function(){if(N){N.fire(R.getViewWidth(),R.getViewHeight())}},ieDeferSrc:false,textResizeInterval:50};U.on=U.addListener;U.un=U.removeListener;U.stoppedMouseDownEvent=new Ext.util.Event();return U}();Ext.onReady=Ext.EventManager.onDocumentReady;(function(){var A=function(){var C=document.body||document.getElementsByTagName("body")[0];if(!C){return false}var B=[" ",Ext.isIE?"ext-ie "+(Ext.isIE6?"ext-ie6":"ext-ie7"):Ext.isGecko?"ext-gecko "+(Ext.isGecko2?"ext-gecko2":"ext-gecko3"):Ext.isOpera?"ext-opera":Ext.isSafari?"ext-safari":""];if(Ext.isMac){B.push("ext-mac")}if(Ext.isLinux){B.push("ext-linux")}if(Ext.isBorderBox){B.push("ext-border-box")}if(Ext.isStrict){var D=C.parentNode;if(D){D.className+=" ext-strict"}}C.className+=B.join(" ");return true};if(!A()){Ext.onReady(A)}})();Ext.EventObject=function(){var B=Ext.lib.Event;var A={3:13,63234:37,63235:39,63232:38,63233:40,63276:33,63277:34,63272:46,63273:36,63275:35};var C=Ext.isIE?{1:0,4:1,2:2}:(Ext.isSafari?{1:0,2:1,3:2}:{0:0,1:1,2:2});Ext.EventObjectImpl=function(D){if(D){this.setEvent(D.browserEvent||D)}};Ext.EventObjectImpl.prototype={browserEvent:null,button:-1,shiftKey:false,ctrlKey:false,altKey:false,BACKSPACE:8,TAB:9,NUM_CENTER:12,ENTER:13,RETURN:13,SHIFT:16,CTRL:17,CONTROL:17,ALT:18,PAUSE:19,CAPS_LOCK:20,ESC:27,SPACE:32,PAGE_UP:33,PAGEUP:33,PAGE_DOWN:34,PAGEDOWN:34,END:35,HOME:36,LEFT:37,UP:38,RIGHT:39,DOWN:40,PRINT_SCREEN:44,INSERT:45,DELETE:46,ZERO:48,ONE:49,TWO:50,THREE:51,FOUR:52,FIVE:53,SIX:54,SEVEN:55,EIGHT:56,NINE:57,A:65,B:66,C:67,D:68,E:69,F:70,G:71,H:72,I:73,J:74,K:75,L:76,M:77,N:78,O:79,P:80,Q:81,R:82,S:83,T:84,U:85,V:86,W:87,X:88,Y:89,Z:90,CONTEXT_MENU:93,NUM_ZERO:96,NUM_ONE:97,NUM_TWO:98,NUM_THREE:99,NUM_FOUR:100,NUM_FIVE:101,NUM_SIX:102,NUM_SEVEN:103,NUM_EIGHT:104,NUM_NINE:105,NUM_MULTIPLY:106,NUM_PLUS:107,NUM_MINUS:109,NUM_PERIOD:110,NUM_DIVISION: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,setEvent:function(D){if(D==this||(D&&D.browserEvent)){return D}this.browserEvent=D;if(D){this.button=D.button?C[D.button]:(D.which?D.which-1:-1);if(D.type=="click"&&this.button==-1){this.button=0}this.type=D.type;this.shiftKey=D.shiftKey;this.ctrlKey=D.ctrlKey||D.metaKey;this.altKey=D.altKey;this.keyCode=D.keyCode;this.charCode=D.charCode;this.target=B.getTarget(D);this.xy=B.getXY(D)}else{this.button=-1;this.shiftKey=false;this.ctrlKey=false;this.altKey=false;this.keyCode=0;this.charCode=0;this.target=null;this.xy=[0,0]}return this},stopEvent:function(){if(this.browserEvent){if(this.browserEvent.type=="mousedown"){Ext.EventManager.stoppedMouseDownEvent.fire(this)}B.stopEvent(this.browserEvent)}},preventDefault:function(){if(this.browserEvent){B.preventDefault(this.browserEvent)}},isNavKeyPress:function(){var D=this.keyCode;D=Ext.isSafari?(A[D]||D):D;return(D>=33&&D<=40)||D==this.RETURN||D==this.TAB||D==this.ESC},isSpecialKey:function(){var D=this.keyCode;return(this.type=="keypress"&&this.ctrlKey)||D==9||D==13||D==40||D==27||(D==16)||(D==17)||(D>=18&&D<=20)||(D>=33&&D<=35)||(D>=36&&D<=39)||(D>=44&&D<=45)},stopPropagation:function(){if(this.browserEvent){if(this.browserEvent.type=="mousedown"){Ext.EventManager.stoppedMouseDownEvent.fire(this)}B.stopPropagation(this.browserEvent)}},getCharCode:function(){return this.charCode||this.keyCode},getKey:function(){var D=this.keyCode||this.charCode;return Ext.isSafari?(A[D]||D):D},getPageX:function(){return this.xy[0]},getPageY:function(){return this.xy[1]},getTime:function(){if(this.browserEvent){return B.getTime(this.browserEvent)}return null},getXY:function(){return this.xy},getTarget:function(E,F,D){return E?Ext.fly(this.target).findParent(E,F,D):(D?Ext.get(this.target):this.target)},getRelatedTarget:function(){if(this.browserEvent){return B.getRelatedTarget(this.browserEvent)}return null},getWheelDelta:function(){var D=this.browserEvent;var E=0;if(D.wheelDelta){E=D.wheelDelta/120}else{if(D.detail){E=-D.detail/3}}return E},hasModifier:function(){return((this.ctrlKey||this.altKey)||this.shiftKey)?true:false},within:function(E,F){var D=this[F?"getRelatedTarget":"getTarget"]();return D&&Ext.fly(E).contains(D)},getPoint:function(){return new Ext.lib.Point(this.xy[0],this.xy[1])}};return new Ext.EventObjectImpl()}();
+(function(){var D=Ext.lib.Dom;var E=Ext.lib.Event;var A=Ext.lib.Anim;var propCache={};var camelRe=/(-[a-z])/gi;var camelFn=function(m,a){return a.charAt(1).toUpperCase()};var view=document.defaultView;Ext.Element=function(element,forceNew){var dom=typeof element=="string"?document.getElementById(element):element;if(!dom){return null}var id=dom.id;if(forceNew!==true&&id&&Ext.Element.cache[id]){return Ext.Element.cache[id]}this.dom=dom;this.id=id||Ext.id(dom)};var El=Ext.Element;El.prototype={originalDisplay:"",visibilityMode:1,defaultUnit:"px",setVisibilityMode:function(visMode){this.visibilityMode=visMode;return this},enableDisplayMode:function(display){this.setVisibilityMode(El.DISPLAY);if(typeof display!="undefined"){this.originalDisplay=display}return this},findParent:function(simpleSelector,maxDepth,returnEl){var p=this.dom,b=document.body,depth=0,dq=Ext.DomQuery,stopEl;maxDepth=maxDepth||50;if(typeof maxDepth!="number"){stopEl=Ext.getDom(maxDepth);maxDepth=10}while(p&&p.nodeType==1&&depth<maxDepth&&p!=b&&p!=stopEl){if(dq.is(p,simpleSelector)){return returnEl?Ext.get(p):p}depth++;p=p.parentNode}return null},findParentNode:function(simpleSelector,maxDepth,returnEl){var p=Ext.fly(this.dom.parentNode,"_internal");return p?p.findParent(simpleSelector,maxDepth,returnEl):null},up:function(simpleSelector,maxDepth){return this.findParentNode(simpleSelector,maxDepth,true)},is:function(simpleSelector){return Ext.DomQuery.is(this.dom,simpleSelector)},animate:function(args,duration,onComplete,easing,animType){this.anim(args,{duration:duration,callback:onComplete,easing:easing},animType);return this},anim:function(args,opt,animType,defaultDur,defaultEase,cb){animType=animType||"run";opt=opt||{};var anim=Ext.lib.Anim[animType](this.dom,args,(opt.duration||defaultDur)||0.35,(opt.easing||defaultEase)||"easeOut",function(){Ext.callback(cb,this);Ext.callback(opt.callback,opt.scope||this,[this,opt])},this);opt.anim=anim;return anim},preanim:function(a,i){return !a[i]?false:(typeof a[i]=="object"?a[i]:{duration:a[i+1],callback:a[i+2],easing:a[i+3]})},clean:function(forceReclean){if(this.isCleaned&&forceReclean!==true){return this}var ns=/\S/;var d=this.dom,n=d.firstChild,ni=-1;while(n){var nx=n.nextSibling;if(n.nodeType==3&&!ns.test(n.nodeValue)){d.removeChild(n)}else{n.nodeIndex=++ni}n=nx}this.isCleaned=true;return this},scrollIntoView:function(container,hscroll){var c=Ext.getDom(container)||Ext.getBody().dom;var el=this.dom;var o=this.getOffsetsTo(c),l=o[0]+c.scrollLeft,t=o[1]+c.scrollTop,b=t+el.offsetHeight,r=l+el.offsetWidth;var ch=c.clientHeight;var ct=parseInt(c.scrollTop,10);var cl=parseInt(c.scrollLeft,10);var cb=ct+ch;var cr=cl+c.clientWidth;if(el.offsetHeight>ch||t<ct){c.scrollTop=t}else{if(b>cb){c.scrollTop=b-ch}}c.scrollTop=c.scrollTop;if(hscroll!==false){if(el.offsetWidth>c.clientWidth||l<cl){c.scrollLeft=l}else{if(r>cr){c.scrollLeft=r-c.clientWidth}}c.scrollLeft=c.scrollLeft}return this},scrollChildIntoView:function(child,hscroll){Ext.fly(child,"_scrollChildIntoView").scrollIntoView(this,hscroll)},autoHeight:function(animate,duration,onComplete,easing){var oldHeight=this.getHeight();this.clip();this.setHeight(1);setTimeout(function(){var height=parseInt(this.dom.scrollHeight,10);if(!animate){this.setHeight(height);this.unclip();if(typeof onComplete=="function"){onComplete()}}else{this.setHeight(oldHeight);this.setHeight(height,animate,duration,function(){this.unclip();if(typeof onComplete=="function"){onComplete()}}.createDelegate(this),easing)}}.createDelegate(this),0);return this},contains:function(el){if(!el){return false}return D.isAncestor(this.dom,el.dom?el.dom:el)},isVisible:function(deep){var vis=!(this.getStyle("visibility")=="hidden"||this.getStyle("display")=="none");if(deep!==true||!vis){return vis}var p=this.dom.parentNode;while(p&&p.tagName.toLowerCase()!="body"){if(!Ext.fly(p,"_isVisible").isVisible()){return false}p=p.parentNode}return true},select:function(selector,unique){return El.select(selector,unique,this.dom)},query:function(selector){return Ext.DomQuery.select(selector,this.dom)},child:function(selector,returnDom){var n=Ext.DomQuery.selectNode(selector,this.dom);return returnDom?n:Ext.get(n)},down:function(selector,returnDom){var n=Ext.DomQuery.selectNode(" > "+selector,this.dom);return returnDom?n:Ext.get(n)},initDD:function(group,config,overrides){var dd=new Ext.dd.DD(Ext.id(this.dom),group,config);return Ext.apply(dd,overrides)},initDDProxy:function(group,config,overrides){var dd=new Ext.dd.DDProxy(Ext.id(this.dom),group,config);return Ext.apply(dd,overrides)},initDDTarget:function(group,config,overrides){var dd=new Ext.dd.DDTarget(Ext.id(this.dom),group,config);return Ext.apply(dd,overrides)},setVisible:function(visible,animate){if(!animate||!A){if(this.visibilityMode==El.DISPLAY){this.setDisplayed(visible)}else{this.fixDisplay();this.dom.style.visibility=visible?"visible":"hidden"}}else{var dom=this.dom;var visMode=this.visibilityMode;if(visible){this.setOpacity(0.01);this.setVisible(true)}this.anim({opacity:{to:(visible?1:0)}},this.preanim(arguments,1),null,0.35,"easeIn",function(){if(!visible){if(visMode==El.DISPLAY){dom.style.display="none"}else{dom.style.visibility="hidden"}Ext.get(dom).setOpacity(1)}})}return this},isDisplayed:function(){return this.getStyle("display")!="none"},toggle:function(animate){this.setVisible(!this.isVisible(),this.preanim(arguments,0));return this},setDisplayed:function(value){if(typeof value=="boolean"){value=value?this.originalDisplay:"none"}this.setStyle("display",value);return this},focus:function(){try{this.dom.focus()}catch(e){}return this},blur:function(){try{this.dom.blur()}catch(e){}return this},addClass:function(className){if(Ext.isArray(className)){for(var i=0,len=className.length;i<len;i++){this.addClass(className[i])}}else{if(className&&!this.hasClass(className)){this.dom.className=this.dom.className+" "+className}}return this},radioClass:function(className){var siblings=this.dom.parentNode.childNodes;for(var i=0;i<siblings.length;i++){var s=siblings[i];if(s.nodeType==1){Ext.get(s).removeClass(className)}}this.addClass(className);return this},removeClass:function(className){if(!className||!this.dom.className){return this}if(Ext.isArray(className)){for(var i=0,len=className.length;i<len;i++){this.removeClass(className[i])}}else{if(this.hasClass(className)){var re=this.classReCache[className];if(!re){re=new RegExp("(?:^|\\s+)"+className+"(?:\\s+|$)","g");this.classReCache[className]=re}this.dom.className=this.dom.className.replace(re," ")}}return this},classReCache:{},toggleClass:function(className){if(this.hasClass(className)){this.removeClass(className)}else{this.addClass(className)}return this},hasClass:function(className){return className&&(" "+this.dom.className+" ").indexOf(" "+className+" ")!=-1},replaceClass:function(oldClassName,newClassName){this.removeClass(oldClassName);this.addClass(newClassName);return this},getStyles:function(){var a=arguments,len=a.length,r={};for(var i=0;i<len;i++){r[a[i]]=this.getStyle(a[i])}return r},getStyle:function(){return view&&view.getComputedStyle?function(prop){var el=this.dom,v,cs,camel;if(prop=="float"){prop="cssFloat"}if(v=el.style[prop]){return v}if(cs=view.getComputedStyle(el,"")){if(!(camel=propCache[prop])){camel=propCache[prop]=prop.replace(camelRe,camelFn)}return cs[camel]}return null}:function(prop){var el=this.dom,v,cs,camel;if(prop=="opacity"){if(typeof el.style.filter=="string"){var m=el.style.filter.match(/alpha\(opacity=(.*)\)/i);if(m){var fv=parseFloat(m[1]);if(!isNaN(fv)){return fv?fv/100:0}}}return 1}else{if(prop=="float"){prop="styleFloat"}}if(!(camel=propCache[prop])){camel=propCache[prop]=prop.replace(camelRe,camelFn)}if(v=el.style[camel]){return v}if(cs=el.currentStyle){return cs[camel]}return null}}(),setStyle:function(prop,value){if(typeof prop=="string"){var camel;if(!(camel=propCache[prop])){camel=propCache[prop]=prop.replace(camelRe,camelFn)}if(camel=="opacity"){this.setOpacity(value)}else{this.dom.style[camel]=value}}else{for(var style in prop){if(typeof prop[style]!="function"){this.setStyle(style,prop[style])}}}return this},applyStyles:function(style){Ext.DomHelper.applyStyles(this.dom,style);return this},getX:function(){return D.getX(this.dom)},getY:function(){return D.getY(this.dom)},getXY:function(){return D.getXY(this.dom)},getOffsetsTo:function(el){var o=this.getXY();var e=Ext.fly(el,"_internal").getXY();return[o[0]-e[0],o[1]-e[1]]},setX:function(x,animate){if(!animate||!A){D.setX(this.dom,x)}else{this.setXY([x,this.getY()],this.preanim(arguments,1))}return this},setY:function(y,animate){if(!animate||!A){D.setY(this.dom,y)}else{this.setXY([this.getX(),y],this.preanim(arguments,1))}return this},setLeft:function(left){this.setStyle("left",this.addUnits(left));return this},setTop:function(top){this.setStyle("top",this.addUnits(top));return this},setRight:function(right){this.setStyle("right",this.addUnits(right));return this},setBottom:function(bottom){this.setStyle("bottom",this.addUnits(bottom));return this},setXY:function(pos,animate){if(!animate||!A){D.setXY(this.dom,pos)}else{this.anim({points:{to:pos}},this.preanim(arguments,1),"motion")}return this},setLocation:function(x,y,animate){this.setXY([x,y],this.preanim(arguments,2));return this},moveTo:function(x,y,animate){this.setXY([x,y],this.preanim(arguments,2));return this},getRegion:function(){return D.getRegion(this.dom)},getHeight:function(contentHeight){var h=this.dom.offsetHeight||0;h=contentHeight!==true?h:h-this.getBorderWidth("tb")-this.getPadding("tb");return h<0?0:h},getWidth:function(contentWidth){var w=this.dom.offsetWidth||0;w=contentWidth!==true?w:w-this.getBorderWidth("lr")-this.getPadding("lr");return w<0?0:w},getComputedHeight:function(){var h=Math.max(this.dom.offsetHeight,this.dom.clientHeight);if(!h){h=parseInt(this.getStyle("height"),10)||0;if(!this.isBorderBox()){h+=this.getFrameWidth("tb")}}return h},getComputedWidth:function(){var w=Math.max(this.dom.offsetWidth,this.dom.clientWidth);if(!w){w=parseInt(this.getStyle("width"),10)||0;if(!this.isBorderBox()){w+=this.getFrameWidth("lr")}}return w},getSize:function(contentSize){return{width:this.getWidth(contentSize),height:this.getHeight(contentSize)}},getStyleSize:function(){var w,h,d=this.dom,s=d.style;if(s.width&&s.width!="auto"){w=parseInt(s.width,10);if(Ext.isBorderBox){w-=this.getFrameWidth("lr")}}if(s.height&&s.height!="auto"){h=parseInt(s.height,10);if(Ext.isBorderBox){h-=this.getFrameWidth("tb")}}return{width:w||this.getWidth(true),height:h||this.getHeight(true)}},getViewSize:function(){var d=this.dom,doc=document,aw=0,ah=0;if(d==doc||d==doc.body){return{width:D.getViewWidth(),height:D.getViewHeight()}}else{return{width:d.clientWidth,height:d.clientHeight}}},getValue:function(asNumber){return asNumber?parseInt(this.dom.value,10):this.dom.value},adjustWidth:function(width){if(typeof width=="number"){if(this.autoBoxAdjust&&!this.isBorderBox()){width-=(this.getBorderWidth("lr")+this.getPadding("lr"))}if(width<0){width=0}}return width},adjustHeight:function(height){if(typeof height=="number"){if(this.autoBoxAdjust&&!this.isBorderBox()){height-=(this.getBorderWidth("tb")+this.getPadding("tb"))}if(height<0){height=0}}return height},setWidth:function(width,animate){width=this.adjustWidth(width);if(!animate||!A){this.dom.style.width=this.addUnits(width)}else{this.anim({width:{to:width}},this.preanim(arguments,1))}return this},setHeight:function(height,animate){height=this.adjustHeight(height);if(!animate||!A){this.dom.style.height=this.addUnits(height)}else{this.anim({height:{to:height}},this.preanim(arguments,1))}return this},setSize:function(width,height,animate){if(typeof width=="object"){height=width.height;width=width.width}width=this.adjustWidth(width);height=this.adjustHeight(height);if(!animate||!A){this.dom.style.width=this.addUnits(width);this.dom.style.height=this.addUnits(height)}else{this.anim({width:{to:width},height:{to:height}},this.preanim(arguments,2))}return this},setBounds:function(x,y,width,height,animate){if(!animate||!A){this.setSize(width,height);this.setLocation(x,y)}else{width=this.adjustWidth(width);height=this.adjustHeight(height);this.anim({points:{to:[x,y]},width:{to:width},height:{to:height}},this.preanim(arguments,4),"motion")}return this},setRegion:function(region,animate){this.setBounds(region.left,region.top,region.right-region.left,region.bottom-region.top,this.preanim(arguments,1));return this},addListener:function(eventName,fn,scope,options){Ext.EventManager.on(this.dom,eventName,fn,scope||this,options)},removeListener:function(eventName,fn,scope){Ext.EventManager.removeListener(this.dom,eventName,fn,scope||this);return this},removeAllListeners:function(){Ext.EventManager.removeAll(this.dom);return this},relayEvent:function(eventName,observable){this.on(eventName,function(e){observable.fireEvent(eventName,e)})},setOpacity:function(opacity,animate){if(!animate||!A){var s=this.dom.style;if(Ext.isIE){s.zoom=1;s.filter=(s.filter||"").replace(/alpha\([^\)]*\)/gi,"")+(opacity==1?"":" alpha(opacity="+opacity*100+")")}else{s.opacity=opacity}}else{this.anim({opacity:{to:opacity}},this.preanim(arguments,1),null,0.35,"easeIn")}return this},getLeft:function(local){if(!local){return this.getX()}else{return parseInt(this.getStyle("left"),10)||0}},getRight:function(local){if(!local){return this.getX()+this.getWidth()}else{return(this.getLeft(true)+this.getWidth())||0}},getTop:function(local){if(!local){return this.getY()}else{return parseInt(this.getStyle("top"),10)||0}},getBottom:function(local){if(!local){return this.getY()+this.getHeight()}else{return(this.getTop(true)+this.getHeight())||0}},position:function(pos,zIndex,x,y){if(!pos){if(this.getStyle("position")=="static"){this.setStyle("position","relative")}}else{this.setStyle("position",pos)}if(zIndex){this.setStyle("z-index",zIndex)}if(x!==undefined&&y!==undefined){this.setXY([x,y])}else{if(x!==undefined){this.setX(x)}else{if(y!==undefined){this.setY(y)}}}},clearPositioning:function(value){value=value||"";this.setStyle({"left":value,"right":value,"top":value,"bottom":value,"z-index":"","position":"static"});return this},getPositioning:function(){var l=this.getStyle("left");var t=this.getStyle("top");return{"position":this.getStyle("position"),"left":l,"right":l?"":this.getStyle("right"),"top":t,"bottom":t?"":this.getStyle("bottom"),"z-index":this.getStyle("z-index")}},getBorderWidth:function(side){return this.addStyles(side,El.borders)},getPadding:function(side){return this.addStyles(side,El.paddings)},setPositioning:function(pc){this.applyStyles(pc);if(pc.right=="auto"){this.dom.style.right=""}if(pc.bottom=="auto"){this.dom.style.bottom=""}return this},fixDisplay:function(){if(this.getStyle("display")=="none"){this.setStyle("visibility","hidden");this.setStyle("display",this.originalDisplay);if(this.getStyle("display")=="none"){this.setStyle("display","block")}}},setOverflow:function(v){if(v=="auto"&&Ext.isMac&&Ext.isGecko2){this.dom.style.overflow="hidden";(function(){this.dom.style.overflow="auto"}).defer(1,this)}else{this.dom.style.overflow=v}},setLeftTop:function(left,top){this.dom.style.left=this.addUnits(left);this.dom.style.top=this.addUnits(top);return this},move:function(direction,distance,animate){var xy=this.getXY();direction=direction.toLowerCase();switch(direction){case"l":case"left":this.moveTo(xy[0]-distance,xy[1],this.preanim(arguments,2));break;case"r":case"right":this.moveTo(xy[0]+distance,xy[1],this.preanim(arguments,2));break;case"t":case"top":case"up":this.moveTo(xy[0],xy[1]-distance,this.preanim(arguments,2));break;case"b":case"bottom":case"down":this.moveTo(xy[0],xy[1]+distance,this.preanim(arguments,2));break}return this},clip:function(){if(!this.isClipped){this.isClipped=true;this.originalClip={"o":this.getStyle("overflow"),"x":this.getStyle("overflow-x"),"y":this.getStyle("overflow-y")};this.setStyle("overflow","hidden");this.setStyle("overflow-x","hidden");this.setStyle("overflow-y","hidden")}return this},unclip:function(){if(this.isClipped){this.isClipped=false;var o=this.originalClip;if(o.o){this.setStyle("overflow",o.o)}if(o.x){this.setStyle("overflow-x",o.x)}if(o.y){this.setStyle("overflow-y",o.y)}}return this},getAnchorXY:function(anchor,local,s){var w,h,vp=false;if(!s){var d=this.dom;if(d==document.body||d==document){vp=true;w=D.getViewWidth();h=D.getViewHeight()}else{w=this.getWidth();h=this.getHeight()}}else{w=s.width;h=s.height}var x=0,y=0,r=Math.round;switch((anchor||"tl").toLowerCase()){case"c":x=r(w*0.5);y=r(h*0.5);break;case"t":x=r(w*0.5);y=0;break;case"l":x=0;y=r(h*0.5);break;case"r":x=w;y=r(h*0.5);break;case"b":x=r(w*0.5);y=h;break;case"tl":x=0;y=0;break;case"bl":x=0;y=h;break;case"br":x=w;y=h;break;case"tr":x=w;y=0;break}if(local===true){return[x,y]}if(vp){var sc=this.getScroll();return[x+sc.left,y+sc.top]}var o=this.getXY();return[x+o[0],y+o[1]]},getAlignToXY:function(el,p,o){el=Ext.get(el);if(!el||!el.dom){throw"Element.alignToXY with an element that doesn't exist"}var d=this.dom;var c=false;var p1="",p2="";o=o||[0,0];if(!p){p="tl-bl"}else{if(p=="?"){p="tl-bl?"}else{if(p.indexOf("-")==-1){p="tl-"+p}}}p=p.toLowerCase();var m=p.match(/^([a-z]+)-([a-z]+)(\?)?$/);if(!m){throw"Element.alignTo with an invalid alignment "+p}p1=m[1];p2=m[2];c=!!m[3];var a1=this.getAnchorXY(p1,true);var a2=el.getAnchorXY(p2,false);var x=a2[0]-a1[0]+o[0];var y=a2[1]-a1[1]+o[1];if(c){var w=this.getWidth(),h=this.getHeight(),r=el.getRegion();var dw=D.getViewWidth()-5,dh=D.getViewHeight()-5;var p1y=p1.charAt(0),p1x=p1.charAt(p1.length-1);var p2y=p2.charAt(0),p2x=p2.charAt(p2.length-1);var swapY=((p1y=="t"&&p2y=="b")||(p1y=="b"&&p2y=="t"));var swapX=((p1x=="r"&&p2x=="l")||(p1x=="l"&&p2x=="r"));var doc=document;var scrollX=(doc.documentElement.scrollLeft||doc.body.scrollLeft||0)+5;var scrollY=(doc.documentElement.scrollTop||doc.body.scrollTop||0)+5;if((x+w)>dw+scrollX){x=swapX?r.left-w:dw+scrollX-w}if(x<scrollX){x=swapX?r.right:scrollX}if((y+h)>dh+scrollY){y=swapY?r.top-h:dh+scrollY-h}if(y<scrollY){y=swapY?r.bottom:scrollY}}return[x,y]},getConstrainToXY:function(){var os={top:0,left:0,bottom:0,right:0};return function(el,local,offsets,proposedXY){el=Ext.get(el);offsets=offsets?Ext.applyIf(offsets,os):os;var vw,vh,vx=0,vy=0;if(el.dom==document.body||el.dom==document){vw=Ext.lib.Dom.getViewWidth();vh=Ext.lib.Dom.getViewHeight()}else{vw=el.dom.clientWidth;vh=el.dom.clientHeight;if(!local){var vxy=el.getXY();vx=vxy[0];vy=vxy[1]}}var s=el.getScroll();vx+=offsets.left+s.left;vy+=offsets.top+s.top;vw-=offsets.right;vh-=offsets.bottom;var vr=vx+vw;var vb=vy+vh;var xy=proposedXY||(!local?this.getXY():[this.getLeft(true),this.getTop(true)]);var x=xy[0],y=xy[1];var w=this.dom.offsetWidth,h=this.dom.offsetHeight;var moved=false;if((x+w)>vr){x=vr-w;moved=true}if((y+h)>vb){y=vb-h;moved=true}if(x<vx){x=vx;moved=true}if(y<vy){y=vy;moved=true}return moved?[x,y]:false}}(),adjustForConstraints:function(xy,parent,offsets){return this.getConstrainToXY(parent||document,false,offsets,xy)||xy},alignTo:function(element,position,offsets,animate){var xy=this.getAlignToXY(element,position,offsets);this.setXY(xy,this.preanim(arguments,3));return this},anchorTo:function(el,alignment,offsets,animate,monitorScroll,callback){var action=function(){this.alignTo(el,alignment,offsets,animate);Ext.callback(callback,this)};Ext.EventManager.onWindowResize(action,this);var tm=typeof monitorScroll;if(tm!="undefined"){Ext.EventManager.on(window,"scroll",action,this,{buffer:tm=="number"?monitorScroll:50})}action.call(this);return this},clearOpacity:function(){if(window.ActiveXObject){if(typeof this.dom.style.filter=="string"&&(/alpha/i).test(this.dom.style.filter)){this.dom.style.filter=""}}else{this.dom.style.opacity="";this.dom.style["-moz-opacity"]="";this.dom.style["-khtml-opacity"]=""}return this},hide:function(animate){this.setVisible(false,this.preanim(arguments,0));return this},show:function(animate){this.setVisible(true,this.preanim(arguments,0));return this},addUnits:function(size){return Ext.Element.addUnits(size,this.defaultUnit)},update:function(html,loadScripts,callback){if(typeof html=="undefined"){html=""}if(loadScripts!==true){this.dom.innerHTML=html;if(typeof callback=="function"){callback()}return this}var id=Ext.id();var dom=this.dom;html+="<span id=\""+id+"\"></span>";E.onAvailable(id,function(){var hd=document.getElementsByTagName("head")[0];var re=/(?:<script([^>]*)?>)((\n|\r|.)*?)(?:<\/script>)/ig;var srcRe=/\ssrc=([\'\"])(.*?)\1/i;var typeRe=/\stype=([\'\"])(.*?)\1/i;var match;while(match=re.exec(html)){var attrs=match[1];var srcMatch=attrs?attrs.match(srcRe):false;if(srcMatch&&srcMatch[2]){var s=document.createElement("script");s.src=srcMatch[2];var typeMatch=attrs.match(typeRe);if(typeMatch&&typeMatch[2]){s.type=typeMatch[2]}hd.appendChild(s)}else{if(match[2]&&match[2].length>0){if(window.execScript){window.execScript(match[2])}else{window.eval(match[2])}}}}var el=document.getElementById(id);if(el){Ext.removeNode(el)}if(typeof callback=="function"){callback()}});dom.innerHTML=html.replace(/(?:<script.*?>)((\n|\r|.)*?)(?:<\/script>)/ig,"");return this},load:function(){var um=this.getUpdater();um.update.apply(um,arguments);return this},getUpdater:function(){if(!this.updateManager){this.updateManager=new Ext.Updater(this)}return this.updateManager},unselectable:function(){this.dom.unselectable="on";this.swallowEvent("selectstart",true);this.applyStyles("-moz-user-select:none;-khtml-user-select:none;");this.addClass("x-unselectable");return this},getCenterXY:function(){return this.getAlignToXY(document,"c-c")},center:function(centerIn){this.alignTo(centerIn||document,"c-c");return this},isBorderBox:function(){return noBoxAdjust[this.dom.tagName.toLowerCase()]||Ext.isBorderBox},getBox:function(contentBox,local){var xy;if(!local){xy=this.getXY()}else{var left=parseInt(this.getStyle("left"),10)||0;var top=parseInt(this.getStyle("top"),10)||0;xy=[left,top]}var el=this.dom,w=el.offsetWidth,h=el.offsetHeight,bx;if(!contentBox){bx={x:xy[0],y:xy[1],0:xy[0],1:xy[1],width:w,height:h}}else{var l=this.getBorderWidth("l")+this.getPadding("l");var r=this.getBorderWidth("r")+this.getPadding("r");var t=this.getBorderWidth("t")+this.getPadding("t");var b=this.getBorderWidth("b")+this.getPadding("b");bx={x:xy[0]+l,y:xy[1]+t,0:xy[0]+l,1:xy[1]+t,width:w-(l+r),height:h-(t+b)}}bx.right=bx.x+bx.width;bx.bottom=bx.y+bx.height;return bx},getFrameWidth:function(sides,onlyContentBox){return onlyContentBox&&Ext.isBorderBox?0:(this.getPadding(sides)+this.getBorderWidth(sides))},setBox:function(box,adjust,animate){var w=box.width,h=box.height;if((adjust&&!this.autoBoxAdjust)&&!this.isBorderBox()){w-=(this.getBorderWidth("lr")+this.getPadding("lr"));h-=(this.getBorderWidth("tb")+this.getPadding("tb"))}this.setBounds(box.x,box.y,w,h,this.preanim(arguments,2));return this},repaint:function(){var dom=this.dom;this.addClass("x-repaint");setTimeout(function(){Ext.get(dom).removeClass("x-repaint")},1);return this},getMargins:function(side){if(!side){return{top:parseInt(this.getStyle("margin-top"),10)||0,left:parseInt(this.getStyle("margin-left"),10)||0,bottom:parseInt(this.getStyle("margin-bottom"),10)||0,right:parseInt(this.getStyle("margin-right"),10)||0}}else{return this.addStyles(side,El.margins)}},addStyles:function(sides,styles){var val=0,v,w;for(var i=0,len=sides.length;i<len;i++){v=this.getStyle(styles[sides.charAt(i)]);if(v){w=parseInt(v,10);if(w){val+=(w>=0?w:-1*w)}}}return val},createProxy:function(config,renderTo,matchBox){config=typeof config=="object"?config:{tag:"div",cls:config};var proxy;if(renderTo){proxy=Ext.DomHelper.append(renderTo,config,true)}else{proxy=Ext.DomHelper.insertBefore(this.dom,config,true)}if(matchBox){proxy.setBox(this.getBox())}return proxy},mask:function(msg,msgCls){if(this.getStyle("position")=="static"){this.setStyle("position","relative")}if(this._maskMsg){this._maskMsg.remove()}if(this._mask){this._mask.remove()}this._mask=Ext.DomHelper.append(this.dom,{cls:"ext-el-mask"},true);this.addClass("x-masked");this._mask.setDisplayed(true);if(typeof msg=="string"){this._maskMsg=Ext.DomHelper.append(this.dom,{cls:"ext-el-mask-msg",cn:{tag:"div"}},true);var mm=this._maskMsg;mm.dom.className=msgCls?"ext-el-mask-msg "+msgCls:"ext-el-mask-msg";mm.dom.firstChild.innerHTML=msg;mm.setDisplayed(true);mm.center(this)}if(Ext.isIE&&!(Ext.isIE7&&Ext.isStrict)&&this.getStyle("height")=="auto"){this._mask.setSize(this.dom.clientWidth,this.getHeight())}return this._mask},unmask:function(){if(this._mask){if(this._maskMsg){this._maskMsg.remove();delete this._maskMsg}this._mask.remove();delete this._mask}this.removeClass("x-masked")},isMasked:function(){return this._mask&&this._mask.isVisible()},createShim:function(){var el=document.createElement("iframe");el.frameBorder="0";el.className="ext-shim";if(Ext.isIE&&Ext.isSecure){el.src=Ext.SSL_SECURE_URL}var shim=Ext.get(this.dom.parentNode.insertBefore(el,this.dom));shim.autoBoxAdjust=false;return shim},remove:function(){Ext.removeNode(this.dom);delete El.cache[this.dom.id]},hover:function(overFn,outFn,scope){var preOverFn=function(e){if(!e.within(this,true)){overFn.apply(scope||this,arguments)}};var preOutFn=function(e){if(!e.within(this,true)){outFn.apply(scope||this,arguments)}};this.on("mouseover",preOverFn,this.dom);this.on("mouseout",preOutFn,this.dom);return this},addClassOnOver:function(className){this.hover(function(){Ext.fly(this,"_internal").addClass(className)},function(){Ext.fly(this,"_internal").removeClass(className)});return this},addClassOnFocus:function(className){this.on("focus",function(){Ext.fly(this,"_internal").addClass(className)},this.dom);this.on("blur",function(){Ext.fly(this,"_internal").removeClass(className)},this.dom);return this},addClassOnClick:function(className){var dom=this.dom;this.on("mousedown",function(){Ext.fly(dom,"_internal").addClass(className);var d=Ext.getDoc();var fn=function(){Ext.fly(dom,"_internal").removeClass(className);d.removeListener("mouseup",fn)};d.on("mouseup",fn)});return this},swallowEvent:function(eventName,preventDefault){var fn=function(e){e.stopPropagation();if(preventDefault){e.preventDefault()}};if(Ext.isArray(eventName)){for(var i=0,len=eventName.length;i<len;i++){this.on(eventName[i],fn)}return this}this.on(eventName,fn);return this},parent:function(selector,returnDom){return this.matchNode("parentNode","parentNode",selector,returnDom)},next:function(selector,returnDom){return this.matchNode("nextSibling","nextSibling",selector,returnDom)},prev:function(selector,returnDom){return this.matchNode("previousSibling","previousSibling",selector,returnDom)},first:function(selector,returnDom){return this.matchNode("nextSibling","firstChild",selector,returnDom)},last:function(selector,returnDom){return this.matchNode("previousSibling","lastChild",selector,returnDom)},matchNode:function(dir,start,selector,returnDom){var n=this.dom[start];while(n){if(n.nodeType==1&&(!selector||Ext.DomQuery.is(n,selector))){return !returnDom?Ext.get(n):n}n=n[dir]}return null},appendChild:function(el){el=Ext.get(el);el.appendTo(this);return this},createChild:function(config,insertBefore,returnDom){config=config||{tag:"div"};if(insertBefore){return Ext.DomHelper.insertBefore(insertBefore,config,returnDom!==true)}return Ext.DomHelper[!this.dom.firstChild?"overwrite":"append"](this.dom,config,returnDom!==true)},appendTo:function(el){el=Ext.getDom(el);el.appendChild(this.dom);return this},insertBefore:function(el){el=Ext.getDom(el);el.parentNode.insertBefore(this.dom,el);return this},insertAfter:function(el){el=Ext.getDom(el);el.parentNode.insertBefore(this.dom,el.nextSibling);return this},insertFirst:function(el,returnDom){el=el||{};if(typeof el=="object"&&!el.nodeType&&!el.dom){return this.createChild(el,this.dom.firstChild,returnDom)}else{el=Ext.getDom(el);this.dom.insertBefore(el,this.dom.firstChild);return !returnDom?Ext.get(el):el}},insertSibling:function(el,where,returnDom){var rt;if(Ext.isArray(el)){for(var i=0,len=el.length;i<len;i++){rt=this.insertSibling(el[i],where,returnDom)}return rt}where=where?where.toLowerCase():"before";el=el||{};var refNode=where=="before"?this.dom:this.dom.nextSibling;if(typeof el=="object"&&!el.nodeType&&!el.dom){if(where=="after"&&!this.dom.nextSibling){rt=Ext.DomHelper.append(this.dom.parentNode,el,!returnDom)}else{rt=Ext.DomHelper[where=="after"?"insertAfter":"insertBefore"](this.dom,el,!returnDom)}}else{rt=this.dom.parentNode.insertBefore(Ext.getDom(el),refNode);if(!returnDom){rt=Ext.get(rt)}}return rt},wrap:function(config,returnDom){if(!config){config={tag:"div"}}var newEl=Ext.DomHelper.insertBefore(this.dom,config,!returnDom);newEl.dom?newEl.dom.appendChild(this.dom):newEl.appendChild(this.dom);return newEl},replace:function(el){el=Ext.get(el);this.insertBefore(el);el.remove();return this},replaceWith:function(el){if(typeof el=="object"&&!el.nodeType&&!el.dom){el=this.insertSibling(el,"before")}else{el=Ext.getDom(el);this.dom.parentNode.insertBefore(el,this.dom)}El.uncache(this.id);this.dom.parentNode.removeChild(this.dom);this.dom=el;this.id=Ext.id(el);El.cache[this.id]=this;return this},insertHtml:function(where,html,returnEl){var el=Ext.DomHelper.insertHtml(where,this.dom,html);return returnEl?Ext.get(el):el},set:function(o,useSet){var el=this.dom;useSet=typeof useSet=="undefined"?(el.setAttribute?true:false):useSet;for(var attr in o){if(attr=="style"||typeof o[attr]=="function"){continue}if(attr=="cls"){el.className=o["cls"]}else{if(o.hasOwnProperty(attr)){if(useSet){el.setAttribute(attr,o[attr])}else{el[attr]=o[attr]}}}}if(o.style){Ext.DomHelper.applyStyles(el,o.style)}return this},addKeyListener:function(key,fn,scope){var config;if(typeof key!="object"||Ext.isArray(key)){config={key:key,fn:fn,scope:scope}}else{config={key:key.key,shift:key.shift,ctrl:key.ctrl,alt:key.alt,fn:fn,scope:scope}}return new Ext.KeyMap(this,config)},addKeyMap:function(config){return new Ext.KeyMap(this,config)},isScrollable:function(){var dom=this.dom;return dom.scrollHeight>dom.clientHeight||dom.scrollWidth>dom.clientWidth},scrollTo:function(side,value,animate){var prop=side.toLowerCase()=="left"?"scrollLeft":"scrollTop";if(!animate||!A){this.dom[prop]=value}else{var to=prop=="scrollLeft"?[value,this.dom.scrollTop]:[this.dom.scrollLeft,value];this.anim({scroll:{"to":to}},this.preanim(arguments,2),"scroll")}return this},scroll:function(direction,distance,animate){if(!this.isScrollable()){return }var el=this.dom;var l=el.scrollLeft,t=el.scrollTop;var w=el.scrollWidth,h=el.scrollHeight;var cw=el.clientWidth,ch=el.clientHeight;direction=direction.toLowerCase();var scrolled=false;var a=this.preanim(arguments,2);switch(direction){case"l":case"left":if(w-l>cw){var v=Math.min(l+distance,w-cw);this.scrollTo("left",v,a);scrolled=true}break;case"r":case"right":if(l>0){var v=Math.max(l-distance,0);this.scrollTo("left",v,a);scrolled=true}break;case"t":case"top":case"up":if(t>0){var v=Math.max(t-distance,0);this.scrollTo("top",v,a);scrolled=true}break;case"b":case"bottom":case"down":if(h-t>ch){var v=Math.min(t+distance,h-ch);this.scrollTo("top",v,a);scrolled=true}break}return scrolled},translatePoints:function(x,y){if(typeof x=="object"||Ext.isArray(x)){y=x[1];x=x[0]}var p=this.getStyle("position");var o=this.getXY();var l=parseInt(this.getStyle("left"),10);var t=parseInt(this.getStyle("top"),10);if(isNaN(l)){l=(p=="relative")?0:this.dom.offsetLeft}if(isNaN(t)){t=(p=="relative")?0:this.dom.offsetTop}return{left:(x-o[0]+l),top:(y-o[1]+t)}},getScroll:function(){var d=this.dom,doc=document;if(d==doc||d==doc.body){var l,t;if(Ext.isIE&&Ext.isStrict){l=doc.documentElement.scrollLeft||(doc.body.scrollLeft||0);t=doc.documentElement.scrollTop||(doc.body.scrollTop||0)}else{l=window.pageXOffset||(doc.body.scrollLeft||0);t=window.pageYOffset||(doc.body.scrollTop||0)}return{left:l,top:t}}else{return{left:d.scrollLeft,top:d.scrollTop}}},getColor:function(attr,defaultValue,prefix){var v=this.getStyle(attr);if(!v||v=="transparent"||v=="inherit"){return defaultValue}var color=typeof prefix=="undefined"?"#":prefix;if(v.substr(0,4)=="rgb("){var rvs=v.slice(4,v.length-1).split(",");for(var i=0;i<3;i++){var h=parseInt(rvs[i]);var s=h.toString(16);if(h<16){s="0"+s}color+=s}}else{if(v.substr(0,1)=="#"){if(v.length==4){for(var i=1;i<4;i++){var c=v.charAt(i);color+=c+c}}else{if(v.length==7){color+=v.substr(1)}}}}return(color.length>5?color.toLowerCase():defaultValue)},boxWrap:function(cls){cls=cls||"x-box";var el=Ext.get(this.insertHtml("beforeBegin",String.format("<div class=\"{0}\">"+El.boxMarkup+"</div>",cls)));el.child("."+cls+"-mc").dom.appendChild(this.dom);return el},getAttributeNS:Ext.isIE?function(ns,name){var d=this.dom;var type=typeof d[ns+":"+name];if(type!="undefined"&&type!="unknown"){return d[ns+":"+name]}return d[name]}:function(ns,name){var d=this.dom;return d.getAttributeNS(ns,name)||d.getAttribute(ns+":"+name)||d.getAttribute(name)||d[name]},getTextWidth:function(text,min,max){return(Ext.util.TextMetrics.measure(this.dom,Ext.value(text,this.dom.innerHTML,true)).width).constrain(min||0,max||1000000)}};var ep=El.prototype;ep.on=ep.addListener;ep.mon=ep.addListener;ep.getUpdateManager=ep.getUpdater;ep.un=ep.removeListener;ep.autoBoxAdjust=true;El.unitPattern=/\d+(px|em|%|en|ex|pt|in|cm|mm|pc)$/i;El.addUnits=function(v,defaultUnit){if(v===""||v=="auto"){return v}if(v===undefined){return""}if(typeof v=="number"||!El.unitPattern.test(v)){return v+(defaultUnit||"px")}return v};El.boxMarkup="<div class=\"{0}-tl\"><div class=\"{0}-tr\"><div class=\"{0}-tc\"></div></div></div><div class=\"{0}-ml\"><div class=\"{0}-mr\"><div class=\"{0}-mc\"></div></div></div><div class=\"{0}-bl\"><div class=\"{0}-br\"><div class=\"{0}-bc\"></div></div></div>";El.VISIBILITY=1;El.DISPLAY=2;El.borders={l:"border-left-width",r:"border-right-width",t:"border-top-width",b:"border-bottom-width"};El.paddings={l:"padding-left",r:"padding-right",t:"padding-top",b:"padding-bottom"};El.margins={l:"margin-left",r:"margin-right",t:"margin-top",b:"margin-bottom"};El.cache={};var docEl;El.get=function(el){var ex,elm,id;if(!el){return null}if(typeof el=="string"){if(!(elm=document.getElementById(el))){return null}if(ex=El.cache[el]){ex.dom=elm}else{ex=El.cache[el]=new El(elm)}return ex}else{if(el.tagName){if(!(id=el.id)){id=Ext.id(el)}if(ex=El.cache[id]){ex.dom=el}else{ex=El.cache[id]=new El(el)}return ex}else{if(el instanceof El){if(el!=docEl){el.dom=document.getElementById(el.id)||el.dom;El.cache[el.id]=el}return el}else{if(el.isComposite){return el}else{if(Ext.isArray(el)){return El.select(el)}else{if(el==document){if(!docEl){var f=function(){};f.prototype=El.prototype;docEl=new f();docEl.dom=document}return docEl}}}}}}return null};El.uncache=function(el){for(var i=0,a=arguments,len=a.length;i<len;i++){if(a[i]){delete El.cache[a[i].id||a[i]]}}};El.garbageCollect=function(){if(!Ext.enableGarbageCollector){clearInterval(El.collectorThread);return }for(var eid in El.cache){var el=El.cache[eid],d=el.dom;if(!d||!d.parentNode||(!d.offsetParent&&!document.getElementById(eid))){delete El.cache[eid];if(d&&Ext.enableListenerCollection){Ext.EventManager.removeAll(d)}}}};El.collectorThreadId=setInterval(El.garbageCollect,30000);var flyFn=function(){};flyFn.prototype=El.prototype;var _cls=new flyFn();El.Flyweight=function(dom){this.dom=dom};El.Flyweight.prototype=_cls;El.Flyweight.prototype.isFlyweight=true;El._flyweights={};El.fly=function(el,named){named=named||"_global";el=Ext.getDom(el);if(!el){return null}if(!El._flyweights[named]){El._flyweights[named]=new El.Flyweight()}El._flyweights[named].dom=el;return El._flyweights[named]};Ext.get=El.get;Ext.fly=El.fly;var noBoxAdjust=Ext.isStrict?{select:1}:{input:1,select:1,textarea:1};if(Ext.isIE||Ext.isGecko){noBoxAdjust["button"]=1}Ext.EventManager.on(window,"unload",function(){delete El.cache;delete El._flyweights})})();
+Ext.enableFx=true;Ext.Fx={slideIn:function(A,C){var B=this.getFxEl();C=C||{};B.queueFx(C,function(){A=A||"t";this.fixDisplay();var D=this.getFxRestore();var I=this.getBox();this.setSize(I);var F=this.fxWrap(D.pos,C,"hidden");var K=this.dom.style;K.visibility="visible";K.position="absolute";var E=function(){B.fxUnwrap(F,D.pos,C);K.width=D.width;K.height=D.height;B.afterFx(C)};var J,L={to:[I.x,I.y]},H={to:I.width},G={to:I.height};switch(A.toLowerCase()){case"t":F.setSize(I.width,0);K.left=K.bottom="0";J={height:G};break;case"l":F.setSize(0,I.height);K.right=K.top="0";J={width:H};break;case"r":F.setSize(0,I.height);F.setX(I.right);K.left=K.top="0";J={width:H,points:L};break;case"b":F.setSize(I.width,0);F.setY(I.bottom);K.left=K.top="0";J={height:G,points:L};break;case"tl":F.setSize(0,0);K.right=K.bottom="0";J={width:H,height:G};break;case"bl":F.setSize(0,0);F.setY(I.y+I.height);K.right=K.top="0";J={width:H,height:G,points:L};break;case"br":F.setSize(0,0);F.setXY([I.right,I.bottom]);K.left=K.top="0";J={width:H,height:G,points:L};break;case"tr":F.setSize(0,0);F.setX(I.x+I.width);K.left=K.bottom="0";J={width:H,height:G,points:L};break}this.dom.style.visibility="visible";F.show();arguments.callee.anim=F.fxanim(J,C,"motion",0.5,"easeOut",E)});return this},slideOut:function(A,C){var B=this.getFxEl();C=C||{};B.queueFx(C,function(){A=A||"t";var I=this.getFxRestore();var D=this.getBox();this.setSize(D);var G=this.fxWrap(I.pos,C,"visible");var F=this.dom.style;F.visibility="visible";F.position="absolute";G.setSize(D);var J=function(){if(C.useDisplay){B.setDisplayed(false)}else{B.hide()}B.fxUnwrap(G,I.pos,C);F.width=I.width;F.height=I.height;B.afterFx(C)};var E,H={to:0};switch(A.toLowerCase()){case"t":F.left=F.bottom="0";E={height:H};break;case"l":F.right=F.top="0";E={width:H};break;case"r":F.left=F.top="0";E={width:H,points:{to:[D.right,D.y]}};break;case"b":F.left=F.top="0";E={height:H,points:{to:[D.x,D.bottom]}};break;case"tl":F.right=F.bottom="0";E={width:H,height:H};break;case"bl":F.right=F.top="0";E={width:H,height:H,points:{to:[D.x,D.bottom]}};break;case"br":F.left=F.top="0";E={width:H,height:H,points:{to:[D.x+D.width,D.bottom]}};break;case"tr":F.left=F.bottom="0";E={width:H,height:H,points:{to:[D.right,D.y]}};break}arguments.callee.anim=G.fxanim(E,C,"motion",0.5,"easeOut",J)});return this},puff:function(B){var A=this.getFxEl();B=B||{};A.queueFx(B,function(){this.clearOpacity();this.show();var F=this.getFxRestore();var D=this.dom.style;var G=function(){if(B.useDisplay){A.setDisplayed(false)}else{A.hide()}A.clearOpacity();A.setPositioning(F.pos);D.width=F.width;D.height=F.height;D.fontSize="";A.afterFx(B)};var E=this.getWidth();var C=this.getHeight();arguments.callee.anim=this.fxanim({width:{to:this.adjustWidth(E*2)},height:{to:this.adjustHeight(C*2)},points:{by:[-(E*0.5),-(C*0.5)]},opacity:{to:0},fontSize:{to:200,unit:"%"}},B,"motion",0.5,"easeOut",G)});return this},switchOff:function(B){var A=this.getFxEl();B=B||{};A.queueFx(B,function(){this.clearOpacity();this.clip();var D=this.getFxRestore();var C=this.dom.style;var E=function(){if(B.useDisplay){A.setDisplayed(false)}else{A.hide()}A.clearOpacity();A.setPositioning(D.pos);C.width=D.width;C.height=D.height;A.afterFx(B)};this.fxanim({opacity:{to:0.3}},null,null,0.1,null,function(){this.clearOpacity();(function(){this.fxanim({height:{to:1},points:{by:[0,this.getHeight()*0.5]}},B,"motion",0.3,"easeIn",E)}).defer(100,this)})});return this},highlight:function(A,C){var B=this.getFxEl();C=C||{};B.queueFx(C,function(){A=A||"ffff9c";var D=C.attr||"backgroundColor";this.clearOpacity();this.show();var G=this.getColor(D);var H=this.dom.style[D];var F=(C.endColor||G)||"ffffff";var I=function(){B.dom.style[D]=H;B.afterFx(C)};var E={};E[D]={from:A,to:F};arguments.callee.anim=this.fxanim(E,C,"color",1,"easeIn",I)});return this},frame:function(A,C,D){var B=this.getFxEl();D=D||{};B.queueFx(D,function(){A=A||"#C3DAF9";if(A.length==6){A="#"+A}C=C||1;var G=D.duration||1;this.show();var E=this.getBox();var F=function(){var H=Ext.getBody().createChild({style:{visbility:"hidden",position:"absolute","z-index":"35000",border:"0px solid "+A}});var I=Ext.isBorderBox?2:1;H.animate({top:{from:E.y,to:E.y-20},left:{from:E.x,to:E.x-20},borderWidth:{from:0,to:10},opacity:{from:1,to:0},height:{from:E.height,to:(E.height+(20*I))},width:{from:E.width,to:(E.width+(20*I))}},G,function(){H.remove();if(--C>0){F()}else{B.afterFx(D)}})};F.call(this)});return this},pause:function(C){var A=this.getFxEl();var B={};A.queueFx(B,function(){setTimeout(function(){A.afterFx(B)},C*1000)});return this},fadeIn:function(B){var A=this.getFxEl();B=B||{};A.queueFx(B,function(){this.setOpacity(0);this.fixDisplay();this.dom.style.visibility="visible";var C=B.endOpacity||1;arguments.callee.anim=this.fxanim({opacity:{to:C}},B,null,0.5,"easeOut",function(){if(C==1){this.clearOpacity()}A.afterFx(B)})});return this},fadeOut:function(B){var A=this.getFxEl();B=B||{};A.queueFx(B,function(){arguments.callee.anim=this.fxanim({opacity:{to:B.endOpacity||0}},B,null,0.5,"easeOut",function(){if(this.visibilityMode==Ext.Element.DISPLAY||B.useDisplay){this.dom.style.display="none"}else{this.dom.style.visibility="hidden"}this.clearOpacity();A.afterFx(B)})});return this},scale:function(A,B,C){this.shift(Ext.apply({},C,{width:A,height:B}));return this},shift:function(B){var A=this.getFxEl();B=B||{};A.queueFx(B,function(){var E={},D=B.width,F=B.height,C=B.x,H=B.y,G=B.opacity;if(D!==undefined){E.width={to:this.adjustWidth(D)}}if(F!==undefined){E.height={to:this.adjustHeight(F)}}if(B.left!==undefined){E.left={to:B.left}}if(B.top!==undefined){E.top={to:B.top}}if(B.right!==undefined){E.right={to:B.right}}if(B.bottom!==undefined){E.bottom={to:B.bottom}}if(C!==undefined||H!==undefined){E.points={to:[C!==undefined?C:this.getX(),H!==undefined?H:this.getY()]}}if(G!==undefined){E.opacity={to:G}}if(B.xy!==undefined){E.points={to:B.xy}}arguments.callee.anim=this.fxanim(E,B,"motion",0.35,"easeOut",function(){A.afterFx(B)})});return this},ghost:function(A,C){var B=this.getFxEl();C=C||{};B.queueFx(C,function(){A=A||"b";var H=this.getFxRestore();var E=this.getWidth(),G=this.getHeight();var F=this.dom.style;var J=function(){if(C.useDisplay){B.setDisplayed(false)}else{B.hide()}B.clearOpacity();B.setPositioning(H.pos);F.width=H.width;F.height=H.height;B.afterFx(C)};var D={opacity:{to:0},points:{}},I=D.points;switch(A.toLowerCase()){case"t":I.by=[0,-G];break;case"l":I.by=[-E,0];break;case"r":I.by=[E,0];break;case"b":I.by=[0,G];break;case"tl":I.by=[-E,-G];break;case"bl":I.by=[-E,G];break;case"br":I.by=[E,G];break;case"tr":I.by=[E,-G];break}arguments.callee.anim=this.fxanim(D,C,"motion",0.5,"easeOut",J)});return this},syncFx:function(){this.fxDefaults=Ext.apply(this.fxDefaults||{},{block:false,concurrent:true,stopFx:false});return this},sequenceFx:function(){this.fxDefaults=Ext.apply(this.fxDefaults||{},{block:false,concurrent:false,stopFx:false});return this},nextFx:function(){var A=this.fxQueue[0];if(A){A.call(this)}},hasActiveFx:function(){return this.fxQueue&&this.fxQueue[0]},stopFx:function(){if(this.hasActiveFx()){var A=this.fxQueue[0];if(A&&A.anim&&A.anim.isAnimated()){this.fxQueue=[A];A.anim.stop(true)}}return this},beforeFx:function(A){if(this.hasActiveFx()&&!A.concurrent){if(A.stopFx){this.stopFx();return true}return false}return true},hasFxBlock:function(){var A=this.fxQueue;return A&&A[0]&&A[0].block},queueFx:function(C,A){if(!this.fxQueue){this.fxQueue=[]}if(!this.hasFxBlock()){Ext.applyIf(C,this.fxDefaults);if(!C.concurrent){var B=this.beforeFx(C);A.block=C.block;this.fxQueue.push(A);if(B){this.nextFx()}}else{A.call(this)}}return this},fxWrap:function(F,D,C){var B;if(!D.wrap||!(B=Ext.get(D.wrap))){var A;if(D.fixPosition){A=this.getXY()}var E=document.createElement("div");E.style.visibility=C;B=Ext.get(this.dom.parentNode.insertBefore(E,this.dom));B.setPositioning(F);if(B.getStyle("position")=="static"){B.position("relative")}this.clearPositioning("auto");B.clip();B.dom.appendChild(this.dom);if(A){B.setXY(A)}}return B},fxUnwrap:function(A,C,B){this.clearPositioning();this.setPositioning(C);if(!B.wrap){A.dom.parentNode.insertBefore(this.dom,A.dom);A.remove()}},getFxRestore:function(){var A=this.dom.style;return{pos:this.getPositioning(),width:A.width,height:A.height}},afterFx:function(A){if(A.afterStyle){this.applyStyles(A.afterStyle)}if(A.afterCls){this.addClass(A.afterCls)}if(A.remove===true){this.remove()}Ext.callback(A.callback,A.scope,[this]);if(!A.concurrent){this.fxQueue.shift();this.nextFx()}},getFxEl:function(){return Ext.get(this.dom)},fxanim:function(D,E,B,F,C,A){B=B||"run";E=E||{};var G=Ext.lib.Anim[B](this.dom,D,(E.duration||F)||0.35,(E.easing||C)||"easeOut",function(){Ext.callback(A,this)},this);E.anim=G;return G}};Ext.Fx.resize=Ext.Fx.scale;Ext.apply(Ext.Element.prototype,Ext.Fx);
+Ext.CompositeElement=function(A){this.elements=[];this.addElements(A)};Ext.CompositeElement.prototype={isComposite:true,addElements:function(E){if(!E){return this}if(typeof E=="string"){E=Ext.Element.selectorFunction(E)}var D=this.elements;var B=D.length-1;for(var C=0,A=E.length;C<A;C++){D[++B]=Ext.get(E[C])}return this},fill:function(A){this.elements=[];this.add(A);return this},filter:function(A){var B=[];this.each(function(C){if(C.is(A)){B[B.length]=C.dom}});this.fill(B);return this},invoke:function(E,B){var D=this.elements;for(var C=0,A=D.length;C<A;C++){Ext.Element.prototype[E].apply(D[C],B)}return this},add:function(A){if(typeof A=="string"){this.addElements(Ext.Element.selectorFunction(A))}else{if(A.length!==undefined){this.addElements(A)}else{this.addElements([A])}}return this},each:function(E,D){var C=this.elements;for(var B=0,A=C.length;B<A;B++){if(E.call(D||C[B],C[B],this,B)===false){break}}return this},item:function(A){return this.elements[A]||null},first:function(){return this.item(0)},last:function(){return this.item(this.elements.length-1)},getCount:function(){return this.elements.length},contains:function(A){return this.indexOf(A)!==-1},indexOf:function(A){return this.elements.indexOf(Ext.get(A))},removeElement:function(D,F){if(Ext.isArray(D)){for(var C=0,A=D.length;C<A;C++){this.removeElement(D[C])}return this}var B=typeof D=="number"?D:this.indexOf(D);if(B!==-1&&this.elements[B]){if(F){var E=this.elements[B];if(E.dom){E.remove()}else{Ext.removeNode(E)}}this.elements.splice(B,1)}return this},replaceElement:function(D,C,A){var B=typeof D=="number"?D:this.indexOf(D);if(B!==-1){if(A){this.elements[B].replaceWith(C)}else{this.elements.splice(B,1,Ext.get(C))}}return this},clear:function(){this.elements=[]}};(function(){Ext.CompositeElement.createCall=function(B,C){if(!B[C]){B[C]=function(){return this.invoke(C,arguments)}}};for(var A in Ext.Element.prototype){if(typeof Ext.Element.prototype[A]=="function"){Ext.CompositeElement.createCall(Ext.CompositeElement.prototype,A)}}})();Ext.CompositeElementLite=function(A){Ext.CompositeElementLite.superclass.constructor.call(this,A);this.el=new Ext.Element.Flyweight()};Ext.extend(Ext.CompositeElementLite,Ext.CompositeElement,{addElements:function(E){if(E){if(Ext.isArray(E)){this.elements=this.elements.concat(E)}else{var D=this.elements;var B=D.length-1;for(var C=0,A=E.length;C<A;C++){D[++B]=E[C]}}}return this},invoke:function(F,B){var D=this.elements;var E=this.el;for(var C=0,A=D.length;C<A;C++){E.dom=D[C];Ext.Element.prototype[F].apply(E,B)}return this},item:function(A){if(!this.elements[A]){return null}this.el.dom=this.elements[A];return this.el},addListener:function(B,G,F,E){var D=this.elements;for(var C=0,A=D.length;C<A;C++){Ext.EventManager.on(D[C],B,G,F||D[C],E)}return this},each:function(F,E){var C=this.elements;var D=this.el;for(var B=0,A=C.length;B<A;B++){D.dom=C[B];if(F.call(E||D,D,this,B)===false){break}}return this},indexOf:function(A){return this.elements.indexOf(Ext.getDom(A))},replaceElement:function(D,C,A){var B=typeof D=="number"?D:this.indexOf(D);if(B!==-1){C=Ext.getDom(C);if(A){var E=this.elements[B];E.parentNode.insertBefore(C,E);Ext.removeNode(E)}this.elements.splice(B,1,C)}return this}});Ext.CompositeElementLite.prototype.on=Ext.CompositeElementLite.prototype.addListener;if(Ext.DomQuery){Ext.Element.selectorFunction=Ext.DomQuery.select}Ext.Element.select=function(A,D,B){var C;if(typeof A=="string"){C=Ext.Element.selectorFunction(A,B)}else{if(A.length!==undefined){C=A}else{throw"Invalid selector"}}if(D===true){return new Ext.CompositeElement(C)}else{return new Ext.CompositeElementLite(C)}};Ext.select=Ext.Element.select;
+Ext.data.Connection=function(A){Ext.apply(this,A);this.addEvents("beforerequest","requestcomplete","requestexception");Ext.data.Connection.superclass.constructor.call(this)};Ext.extend(Ext.data.Connection,Ext.util.Observable,{timeout:30000,autoAbort:false,disableCaching:true,disableCachingParam:"_dc",request:function(E){if(this.fireEvent("beforerequest",this,E)!==false){var C=E.params;if(typeof C=="function"){C=C.call(E.scope||window,E)}if(typeof C=="object"){C=Ext.urlEncode(C)}if(this.extraParams){var G=Ext.urlEncode(this.extraParams);C=C?(C+"&"+G):G}var B=E.url||this.url;if(typeof B=="function"){B=B.call(E.scope||window,E)}if(E.form){var D=Ext.getDom(E.form);B=B||D.action;var J=D.getAttribute("enctype");if(E.isUpload||(J&&J.toLowerCase()=="multipart/form-data")){return this.doFormUpload(E,C,B)}var I=Ext.lib.Ajax.serializeForm(D);C=C?(C+"&"+I):I}var K=E.headers;if(this.defaultHeaders){K=Ext.apply(K||{},this.defaultHeaders);if(!E.headers){E.headers=K}}var F={success:this.handleResponse,failure:this.handleFailure,scope:this,argument:{options:E},timeout:E.timeout||this.timeout};var A=E.method||this.method||((C||E.xmlData||E.jsonData)?"POST":"GET");if(A=="GET"&&(this.disableCaching&&E.disableCaching!==false)||E.disableCaching===true){var H=E.disableCachingParam||this.disableCachingParam;B+=(B.indexOf("?")!=-1?"&":"?")+H+"="+(new Date().getTime())}if(typeof E.autoAbort=="boolean"){if(E.autoAbort){this.abort()}}else{if(this.autoAbort!==false){this.abort()}}if((A=="GET"||E.xmlData||E.jsonData)&&C){B+=(B.indexOf("?")!=-1?"&":"?")+C;C=""}this.transId=Ext.lib.Ajax.request(A,B,F,C,E);return this.transId}else{Ext.callback(E.callback,E.scope,[E,null,null]);return null}},isLoading:function(A){if(A){return Ext.lib.Ajax.isCallInProgress(A)}else{return this.transId?true:false}},abort:function(A){if(A||this.isLoading()){Ext.lib.Ajax.abort(A||this.transId)}},handleResponse:function(A){this.transId=false;var B=A.argument.options;A.argument=B?B.argument:null;this.fireEvent("requestcomplete",this,A,B);Ext.callback(B.success,B.scope,[A,B]);Ext.callback(B.callback,B.scope,[B,true,A])},handleFailure:function(A,C){this.transId=false;var B=A.argument.options;A.argument=B?B.argument:null;this.fireEvent("requestexception",this,A,B,C);Ext.callback(B.failure,B.scope,[A,B]);Ext.callback(B.callback,B.scope,[B,false,A])},doFormUpload:function(E,A,B){var C=Ext.id();var F=document.createElement("iframe");F.id=C;F.name=C;F.className="x-hidden";if(Ext.isIE){F.src=Ext.SSL_SECURE_URL}document.body.appendChild(F);if(Ext.isIE){document.frames[C].name=C}var D=Ext.getDom(E.form);D.target=C;D.method="POST";D.enctype=D.encoding="multipart/form-data";if(B){D.action=B}var L,J;if(A){L=[];A=Ext.urlDecode(A,false);for(var H in A){if(A.hasOwnProperty(H)){J=document.createElement("input");J.type="hidden";J.name=H;J.value=A[H];D.appendChild(J);L.push(J)}}}function G(){var M={responseText:"",responseXML:null};M.argument=E?E.argument:null;try{var O;if(Ext.isIE){O=F.contentWindow.document}else{O=(F.contentDocument||window.frames[C].document)}if(O&&O.body){M.responseText=O.body.innerHTML}if(O&&O.XMLDocument){M.responseXML=O.XMLDocument}else{M.responseXML=O}}catch(N){}Ext.EventManager.removeListener(F,"load",G,this);this.fireEvent("requestcomplete",this,M,E);Ext.callback(E.success,E.scope,[M,E]);Ext.callback(E.callback,E.scope,[E,true,M]);setTimeout(function(){Ext.removeNode(F)},100)}Ext.EventManager.on(F,"load",G,this);D.submit();if(L){for(var I=0,K=L.length;I<K;I++){Ext.removeNode(L[I])}}}});Ext.Ajax=new Ext.data.Connection({autoAbort:false,serializeForm:function(A){return Ext.lib.Ajax.serializeForm(A)}});
+Ext.Updater=Ext.extend(Ext.util.Observable,{constructor:function(B,A){B=Ext.get(B);if(!A&&B.updateManager){return B.updateManager}this.el=B;this.defaultUrl=null;this.addEvents("beforeupdate","update","failure");var C=Ext.Updater.defaults;this.sslBlankUrl=C.sslBlankUrl;this.disableCaching=C.disableCaching;this.indicatorText=C.indicatorText;this.showLoadIndicator=C.showLoadIndicator;this.timeout=C.timeout;this.loadScripts=C.loadScripts;this.transaction=null;this.refreshDelegate=this.refresh.createDelegate(this);this.updateDelegate=this.update.createDelegate(this);this.formUpdateDelegate=this.formUpdate.createDelegate(this);if(!this.renderer){this.renderer=this.getDefaultRenderer()}Ext.Updater.superclass.constructor.call(this)},getDefaultRenderer:function(){return new Ext.Updater.BasicRenderer()},getEl:function(){return this.el},update:function(B,F,G,D){if(this.fireEvent("beforeupdat