    /**
     * @class Ext.JSON
     * Modified version of Douglas Crockford's JSON.js that doesn't
     * mess with the Object prototype
     * http://www.json.org/js.html
     * @singleton
     */
    Ext.JSON = new(function() {
        var useHasOwn = !! {}.hasOwnProperty,
        isNative = function() {
            var useNative = null;

            return function() {
                if (useNative === null) {
                    useNative = Ext.USE_NATIVE_JSON && window.JSON && JSON.toString() == '[object JSON]';
                }

                return useNative;
            };
        }(),
        pad = function(n) {
            return n < 10 ? "0" + n : n;
        },
        doDecode = function(json) {
            return eval("(" + json + ')');
        },
        doEncode = function(o) {
            if (!Ext.isDefined(o) || o === null) {
                return "null";
            } else if (Ext.isArray(o)) {
                return encodeArray(o);
            } else if (Ext.isDate(o)) {
                return Ext.JSON.encodeDate(o);
            } else if (Ext.isString(o)) {
                return encodeString(o);
            } else if (typeof o == "number") {
                //don't use isNumber here, since finite checks happen inside isNumber
                return isFinite(o) ? String(o) : "null";
            } else if (Ext.isBoolean(o)) {
                return String(o);
            } else if (Ext.isObject(o)) {
                return encodeObject(o);
            } else if (typeof o === "function") {
                return "null";
            }
            return 'undefined';
        },
        m = {
            "\b": '\\b',
            "\t": '\\t',
            "\n": '\\n',
            "\f": '\\f',
            "\r": '\\r',
            '"': '\\"',
            "\\": '\\\\',
            '\x0b': '\\u000b' //ie doesn't handle \v
        },
        charToReplace = /[\\\"\x00-\x1f\x7f-\uffff]/g,
        encodeString = function(s) {
            return '"' + s.replace(charToReplace, function(a) {
                var c = m[a];
                return typeof c === 'string' ? c : '\\u' + ('0000' + a.charCodeAt(0).toString(16)).slice(-4);
            }) + '"';
        },
        encodeArray = function(o) {
            var a = ["[", ""],
            // Note empty string in case there are no serializable members.
            len = o.length,
            i;
            for (i = 0; i < len; i += 1) {
                a.push(doEncode(o[i]), ',');
            }
            // Overwrite trailing comma (or empty string)
            a[a.length - 1] = ']';
            return a.join("");
        },
        encodeObject = function(o) {
            var a = ["{", ""],
            // Note empty string in case there are no serializable members.
            i;
            for (i in o) {
                if (!useHasOwn || o.hasOwnProperty(i)) {
                    a.push(doEncode(i), ":", doEncode(o[i]), ',');
                }
            }
            // Overwrite trailing comma (or empty string)
            a[a.length - 1] = '}';
            return a.join("");
        };

        /**
         * <p>Encodes a Date. This returns the actual string which is inserted into the JSON string as the literal expression.
         * <b>The returned value includes enclosing double quotation marks.</b></p>
         * <p>The default return format is "yyyy-mm-ddThh:mm:ss".</p>
         * <p>To override this:</p><pre><code>
    Ext.JSON.encodeDate = function(d) {
        return Ext.Date.format(d, '"Y-m-d"');
    };
         </code></pre>
         * @param {Date} d The Date to encode
         * @return {String} The string literal to use in a JSON string.
         */
        this.encodeDate = function(o) {
            return '"' + o.getFullYear() + "-"
            + pad(o.getMonth() + 1) + "-"
            + pad(o.getDate()) + "T"
            + pad(o.getHours()) + ":"
            + pad(o.getMinutes()) + ":"
            + pad(o.getSeconds()) + '"';
        };

        /**
         * Encodes an Object, Array or other value
         * @param {Object} o The variable to encode
         * @return {String} The JSON string
         */
        this.encode = function() {
            var ec;
            return function(o) {
                if (!ec) {
                    // setup encoding function on first access
                    ec = isNative() ? JSON.stringify : doEncode;
                }
                return ec(o);
            };
        }();

        /**
         * Decodes (parses) a JSON string to an object. If the JSON is invalid, this function throws a SyntaxError unless the safe option is set.
         * @param {String} json The JSON string
         * @param {Boolean} safe (optional) Whether to return null or throw an exception if the JSON is invalid.
         * @return {Object} The resulting object
         */
        this.decode = function() {
            var dc;
            return function(json, safe) {
                if (!dc) {
                    // setup decoding function on first access
                    dc = isNative() ? JSON.parse : doDecode;
                }
                try {
                    return dc(json);
                } catch (e) {
                    if (safe === true) {
                        return null;
                    }
                    Ext.Error.raise({
                        sourceClass: "Ext.JSON",
                        sourceMethod: "decode",
                        msg: "You're trying to decode an invalid JSON String: " + json
                    });
                }
            };
        }();

    })();
    /**
     * Shorthand for {@link Ext.JSON#encode}
     * @member Ext
     * @method encode
     * @alias Ext.JSON#encode
     */
    Ext.encode = Ext.JSON.encode;
    /**
     * Shorthand for {@link Ext.JSON#decode}
     * @member Ext
     * @method decode
     * @alias Ext.JSON#decode
     */
    Ext.decode = Ext.JSON.decode;