// From jquery-json

var escapeable = /["\\\x00-\x1f\x7f-\x9f]/g;
var meta = {	// table of character substitutions
		'\b': '\\b',
		'\t': '\\t',
		'\n': '\\n',
		'\f': '\\f',
		'\r': '\\r',
		'"' : '\\"',
		'\\': '\\\\'
	};

compactJSON = function(o)
{
	return toJSON(o, true);
};

toJSON = function(o, compact)
{
	var type = typeof(o);
	
	if (type == "undefined")
		return "undefined";
	else if (type == "number" || type == "boolean")
		return o + "";
	else if (o === null)
		return "null";
	
	// Is it a string?
	if (type == "string") 
	{
		return quoteString(o);
	}
	
	// Does it have a .toJSON function?
	if (type == "object" && typeof o.toJSON == "function") 
		return o.toJSON(compact);
	
	// Is it an array?
	if (type != "function" && typeof(o.length) == "number") 
	{
		var ret = [];
		for (var i = 0; i < o.length; i++) {
			ret.push( toJSON(o[i], compact) );
		}
		if (compact)
			return "[" + ret.join(",") + "]";
		else
			return "[" + ret.join(", ") + "]";
	}
	
	// If it's a function, we have to warn somebody!
	if (type == "function") {
		throw new TypeError("Unable to convert object of type 'function' to json.");
	}
	
	// It's probably an object, then.
	var ret = [];
	for (var k in o) {
		var name;
		type = typeof(k);
		
		if (type == "number")
			name = '"' + k + '"';
		else if (type == "string")
			name = quoteString(k);
		else
			continue;  //skip non-string or number keys
		
		var val = toJSON(o[k], compact);
		if (typeof(val) != "string") {
			// skip non-serializable values
			continue;
		}
		
		if (compact)
			ret.push(name + ":" + val);
		else
			ret.push(name + ": " + val);
	}
	return "{" + ret.join(", ") + "}";
};

quoteString = function(string)
// Places quotes around a string, inteligently.
// 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 escape
// sequences.
{
	if (escapeable.test(string))
	{
		return '"' + string.replace(escapeable, function (a) 
		{
			var c = meta[a];
			if (typeof c === 'string') {
				return c;
			}
			c = a.charCodeAt();
			return '\\u00' + Math.floor(c / 16).toString(16) + (c % 16).toString(16);
		}) + '"';
	}
	return '"' + string + '"';
};