function toJSONString(v) {
     var sResult = '';

         switch (typeof v) {
      
      // 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.
      
                  case 'object':
                      if (v) {
                        switch(v.constructor) {
                           case Date:
                              sResult = date2JSONString(v);
                              break;
                           case Array:
                              sResult = array2JSONString(v);
                              break;
                           default:
                              sResult = object2JSONString(v);
                        }
                      } else {
                         sResult = "null";
                      }

                     break;
      
      // Otherwise, serialize the value.
      
                  case 'string':
                        sResult = string2JSONString(v);
                     break;
                  case 'number':
                        sResult = number2JSONString(v);
                     break;
                  case 'boolean':
                        sResult = boolean2JSONString(v);
                     break;
      
      // Values without a JSON representation are ignored.
      
         }

     return sResult;
}

function arrayp(a,b,s) {

// p accumulates text fragments in an array. It inserts a comma before all
// except the first fragment.

            if (b) {
                a.push(',');
            }
            a.push(s);
            return a;
}


function array2JSONString(vArray) {
        var a = ['['],  // The array holding the text fragments.
            b = false,          // A boolean indicating that a comma is required.
            i,          // Loop counter.
            l = vArray.length,
            v;          // The value to be stringified.

// For each value in this array...
        for (i = 0; i < l; i += 1) {
            v = vArray[i];
            a = arrayp(a,b,toJSONString(v));
            b = true;
        }

// Join all of the fragments together and return.

        a.push(']');
        return a.join('');
}


function boolean2JSONString(vBool) {
        return String(vBool);
}

function datef(n) {
// Format integers to have at least two digits.
   return n < 10 ? '0' + n : n;
}


function date2JSONString(vDate) {

// Ultimately, this method will be equivalent to the date.toISOString method.
        return '"' + vDate.getFullYear() + '-' +
                datef(vDate.getMonth() + 1) + '-' +
                datef(vDate.getDate()) + 'T' +
                datef(vDate.getHours()) + ':' +
                datef(vDate.getMinutes()) + ':' +
                datef(vDate.getSeconds()) + '"';
}


function number2JSONString(vNum) {

// JSON numbers must be finite. Encode non-finite numbers as null.

        return isFinite(vNum) ? String(vNum) : "null";
}


function objectp(a,b,k,s) {

// p accumulates text fragment pairs in an array. It inserts a comma before all
// except the first fragment pair.

      if (b) {
            a.push(',');
      }
      a.push(toJSONString(k), ':', s);
      return a;
}


function object2JSONString(vObj) {
        var a = ['{'],  // The array holding the text fragments.
            b = false,          // A boolean indicating that a comma is required.
            k,          // The current key.
            v;          // The current value.


// Iterate through all of the keys in the object, ignoring the proto chain.

        for (k in vObj) {
            if (vObj.hasOwnProperty(k)) {
                v = vObj[k];
                a = objectp(a,b,k,toJSONString(v));
                b = true;
            }
        }

// Join all of the fragments together and return.

        a.push('}');
        return a.join('');
    }


// m is a table of character substitutions.

function string2JSONString(vStr) {
      var m = {
         '\b': '\\b',
         '\t': '\\t',
         '\n': '\\n',
         '\f': '\\f',
         '\r': '\\r',
         '"' : '\\"',
         '\\': '\\\\'
      }

// 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(vStr)) {
            return '"' + vStr.replace(/([\x00-\x1f\\"])/g, function (a, b) {
               var c = m[b];
               if (c) {
                  return c;
               }
               c = b.charCodeAt();
               return '\\u00' +
                  Math.floor(c / 16).toString(16) +
                  (c % 16).toString(16);
            }) + '"';
      }
      return '"' + vStr + '"';
}