// Augment the basic prototypes if they have not already been augmented.
if (!Object.prototype.toJSONString) {
    Array.prototype.toJSONString = function (w) {
        var a = [],     // The array holding the partial texts.
            i,          // Loop counter.
            l = this.length,
            v;          // The value to be stringified.
						// For each value in this array...
        for (i = 0; i < l; i += 1) {
            v = this[i];
            switch (typeof v) {
            case 'object':
						// Serialize a JavaScript object value. Ignore objects thats lack the
						// toJSONString method. Due to a specification error in ECMAScript,
						// typeof null is 'object', so watch out for that case.
                if (v) {
                    if (typeof v.toJSONString === 'function') {
                        a.push(v.toJSONString(w));
                    }
                } else {
                    a.push('null');
                }
                break;

            case 'string':
            case 'number':
            case 'boolean':
                a.push(v.toJSONString());
								// Values without a JSON representation are ignored.
            }
        }
				// Join all of the member texts together and wrap them in brackets.
        return '[' + a.join(',') + ']';
    };
    Boolean.prototype.toJSONString = function () {
        return String(this);
    };
    Date.prototype.toJSONString = function () {
      			// Eventually, this method will be based on the date.toISOString method.
          	function f(n) {
      			// Format integers to have at least two digits.
            return n < 10 ? '0' + n : n;
        }
        return '"' + this.getUTCFullYear() + '-' +
                f(this.getUTCMonth() + 1)  + '-' +
                f(this.getUTCDate())       + 'T' +
                f(this.getUTCHours())      + ':' +
                f(this.getUTCMinutes())    + ':' +
                f(this.getUTCSeconds())    + 'Z"';
    };
    Number.prototype.toJSONString = function () {
		// JSON numbers must be finite. Encode non-finite numbers as null.
        return isFinite(this) ? String(this) : 'null';
    };
    Object.prototype.toJSONString = function (w) {
        var a = [],     // The array holding the partial texts.
            k,          // The current key.
            i,          // The loop counter.
            v;          // The current value.
						// If a whitelist (array of keys) is provided, use it assemble the components
						// of the object.
        if (w) {
            for (i = 0; i < w.length; i += 1) {
                k = w[i];
                if (typeof k === 'string') {
                    v = this[k];
                    switch (typeof v) {
                    case 'object':
                    // Serialize a JavaScript object value. Ignore objects that lack the
                    // toJSONString method. Due to a specification error in ECMAScript,
                    // typeof null is 'object', so watch out for that case.
                        if (v) {
                            if (typeof v.toJSONString === 'function') {
                                a.push(k.toJSONString() + ':' +
                                       v.toJSONString(w));
                            }
                        } else {
                            a.push(k.toJSONString() + ':null');
                        }
                        break;
                    case 'string':
                    case 'number':
                    case 'boolean':
                        a.push(k.toJSONString() + ':' + v.toJSONString());
												// Values without a JSON representation are ignored.
                    }
                }
            }
        } else {
        // Iterate through all of the keys in the object, ignoring the proto chain
        // and keys that are not strings.
            for (k in this) {
                if (typeof k === 'string' &&
                        Object.prototype.hasOwnProperty.apply(this, [k])) {
                    v = this[k];
                    switch (typeof v) {
                    case 'object':
                        // Serialize a JavaScript object value. Ignore objects that lack the
                        // toJSONString method. Due to a specification error in ECMAScript,
                        // typeof null is 'object', so watch out for that case.
                        if (v) {
                            if (typeof v.toJSONString === 'function') {
                                a.push(k.toJSONString() + ':' +
                                       v.toJSONString());
                            }
                        } else {
                            a.push(k.toJSONString() + ':null');
                        }
                        break;
                    case 'string':
                    case 'number':
                    case 'boolean':
                        a.push(k.toJSONString() + ':' + v.toJSONString());
												// Values without a JSON representation are ignored.
                    }
                }
            }
        }
				// Join all of the member texts together and wrap them in braces.
        return '{' + a.join(',') + '}';
    };
    (function (s) {
        // Augment String.prototype. We do this in an immediate anonymous function to
        // avoid defining global variables.
        // m is a table of character substitutions.
        var m = {
            '\b': '\\b',
            '\t': '\\t',
            '\n': '\\n',
            '\f': '\\f',
            '\r': '\\r',
            '"' : '\\"',
            '\\': '\\\\'
        };
        s.parseJSON = function (filter) {
            var j;
            function walk(k, v) {
                var i;
                if (v && typeof v === 'object') {
                    for (i in v) {
                        if (Object.prototype.hasOwnProperty.apply(v, [i])) {
                            v[i] = walk(i, v[i]);
                        }
                    }
                }
                return filter(k, v);
            }
            // Parsing happens in three stages. In the first stage, we run the text against
            // a regular expression which looks for non-JSON characters. We are especially
            // concerned with '()' and 'new' because they can cause invocation, and '='
            // because it can cause mutation. But just to be safe, we will reject all
            // unexpected characters.
            // We split the first stage into 3 regexp operations in order to work around
            // crippling deficiencies in Safari's regexp engine. First we replace all
            // backslash pairs with '@' (a non-JSON character). Second we delete all of
            // the string literals. Third, we look to see if only JSON characters
            // remain. If so, then the text is safe for eval.
            if (/^[,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t]*$/.test(this.
                    replace(/\\./g, '@').
                    replace(/"[^"\\\n\r]*"/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('(' + this + ')');
                    // 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');
        };
        s.toJSONString = function () {
        // If the string contains no control characters, no quote characters, and no
        // backslash characters, then we can simply slap some quotes around it.
        // Otherwise we must also replace the offending characters with safe
        // sequences.
            if (/["\\\x00-\x1f]/.test(this)) {
                return '"' + this.replace(/[\x00-\x1f\\"]/g, 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);
                }) + '"';
            }
            return '"' + this + '"';
        };
    })(String.prototype);
}
