// Create a JSON object only if one does not already exist. We create the
// methods in a closure to avoid creating global variables.

if (!this.JSON2) {
  this.JSON2 = {};
}

(function(){

  function f(n){
    // Format integers to have at least two digits.
    return n < 10 ? '0' + n : n;
  }
  
  if (typeof Date.prototype.toJSON !== 'function') {
  
    Date.prototype.toJSON = function(key){
    
      return isFinite(this.valueOf()) ? this.getUTCFullYear() + '-' +
      f(this.getUTCMonth() + 1) +
      '-' +
      f(this.getUTCDate()) +
      'T' +
      f(this.getUTCHours()) +
      ':' +
      f(this.getUTCMinutes()) +
      ':' +
      f(this.getUTCSeconds()) +
      'Z' : null;
    };
    
    String.prototype.toJSON = Number.prototype.toJSON = Boolean.prototype.toJSON = function(key){
      return this.valueOf();
    };
  }
  
  var cx = /[\u0000\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g, escapable = /[\\\"\x00-\x1f\x7f-\x9f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g, gap, indent, meta = { // table of character substitutions
    '\b': '\\b',
    '\t': '\\t',
    '\n': '\\n',
    '\f': '\\f',
    '\r': '\\r',
    '"': '\\"',
    '\\': '\\\\'
  }, rep;
  
  
  function quote(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 escape
    // sequences.
    
    escapable.lastIndex = 0;
    return escapable.test(string) ? '"' +
    string.replace(escapable, function(a){
      var c = meta[a];
      return typeof c === 'string' ? c : '\\u' + ('0000' + a.charCodeAt(0).toString(16)).slice(-4);
    }) +
    '"' : '"' + string + '"';
  }
  
  
  function str(key, holder, mapTypeAttr){
  
    // Produce a string from holder[key].
    
    var i, // The loop counter.
 k, // The member key.
 v, // The member value.
 length, mind = gap, partial, value = holder[key];
    
    // If the value has a toJSON method, call it to obtain a replacement value.
    
    if (value && typeof value === 'object' &&
    typeof value.toJSON === 'function') {
      value = value.toJSON(key);
    }
    
    // If we were called with a replacer function, then call the replacer to
    // obtain a replacement value.
    
    if (typeof rep === 'function') {
      value = rep.call(holder, key, value);
    }
    
    // What happens next depends on the value's type.
    
    switch (typeof value) {
      case 'string':
        return quote(value);
        
      case 'number':
        
        // JSON numbers must be finite. Encode non-finite numbers as null.
        
        return isFinite(value) ? String(value) : 'null';
        
      case 'boolean':
      case 'null':
        
        // If the value is a boolean or null, convert it to a string. Note:
        // typeof null does not produce 'null'. The case is included here in
        // the remote chance that this gets fixed someday.
        
        return String(value);
        
      // If the type is 'object', we might be dealing with an object or an array or
      // null.
      
      case 'object':
        
        // Due to a specification blunder in ECMAScript, typeof null is 'object',
        // so watch out for that case.
        
        if (!value) {
          return 'null';
        }
        
        // Make an array to hold the partial results of stringifying this object value.
        
        gap += indent;
        partial = [];
        
        // Is the value an array?
        
        if (Object.prototype.toString.apply(value) === '[object Array]') {
        
          // The value is an array. Stringify every element. Use null as a placeholder
          // for non-JSON values.
          
          length = value.length;
          for (i = 0; i < length; i += 1) {
            partial[i] = str(i, value, mapTypeAttr) || 'null';
          }
          
          // Join all of the elements together, separated with commas, and wrap them in
          // brackets.
          v = partial.length === 0 ? '[]' : gap ? '[\n' + gap +
          partial.join(',\n' + gap) +
          '\n' +
          mind +
          ']' : '[' + partial.join(',') + ']';
          gap = mind;
          
          return v;
        }
        
        // If the replacer is an array, use it to select the members to be stringified.
        
        if (rep && typeof rep === 'object') {
          length = rep.length;
          for (i = 0; i < length; i += 1) {
            k = rep[i];
            if (typeof k === 'string') {
              v = str(k, value, mapTypeAttr);
              if (v) {
                partial.push(quote(k) + (gap ? ': ' : ':') + v);
              }
            }
          }
        } else {
        
          // Otherwise, iterate through all of the keys in the object.
          
		  // check if __type property is present and handling is enabled. __type properties has to be first in line
          if (mapTypeAttr == true && value["__type"] != null) {
            partial.push(quote("__type") + (gap ? ': ' : ':') + quote(value["__type"]));
          }
                    
          for (k in value) {
		  	// skip __type attribute since it has been added before
            if (mapTypeAttr == true && k == "__type") {
              continue;
            }
            if (Object.hasOwnProperty.call(value, k)) {
              v = str(k, value, mapTypeAttr);
              if (v) {
                partial.push(quote(k) + (gap ? ': ' : ':') + v);
              }
            }
          }
        }
        
        // Join all of the member texts together, separated with commas,
        // and wrap them in braces.
        
        v = partial.length === 0 ? '{}' : gap ? '{\n' + gap + partial.join(',\n' + gap) + '\n' +
        mind + '}' : '{' + partial.join(',') + '}';
        gap = mind;
        return v;
    }
  }
  
  // If the JSON object does not yet have a stringify method, give it one.
  
  if (typeof JSON2.stringify !== 'function') {
    JSON2.stringify = function(value, mapTypeAttr, replacer, space){
    
      // The stringify method takes a value and an optional replacer, and an optional
      // space parameter, and returns a JSON text. The replacer can be a function
      // that can replace values, or an array of strings that will select the keys.
      // A default replacer method can be provided. Use of the space parameter can
      // produce text that is more easily readable.
      
      var i;
      gap = '';
      indent = '';
      
      // If the space parameter is a number, make an indent string containing that
      // many spaces.
      
      if (typeof space === 'number') {
        for (i = 0; i < space; i += 1) {
          indent += ' ';
        }
        
        // If the space parameter is a string, it will be used as the indent string.
      
      } else if (typeof space === 'string') {
        indent = space;
      }
      
      // If there is a replacer, it must be a function or an array.
      // Otherwise, throw an error.
      
      rep = replacer;
      if (replacer && typeof replacer !== 'function' &&
      (typeof replacer !== 'object' ||
      typeof replacer.length !== 'number')) {
        throw new Error('JSON2.stringify');
      }
      
      // Make a fake root object containing our value under the key of ''.
      // Return the result of stringifying the value.
      
      return str('', {'': value}, mapTypeAttr);
    };
  }
  
  
  // If the JSON object does not yet have a parse method, give it one.
  
  if (typeof JSON2.parse !== 'function') {
    JSON2.parse = function(text, reviver){
    
      // The parse method takes a text and an optional reviver function, and returns
      // a JavaScript value if the text is a valid JSON text.
      
      var j;
      
      function walk(holder, key){
      
        // The walk method is used to recursively walk the resulting structure so
        // that modifications can be made.
        
        var k, v, value = holder[key];
        if (value && typeof value === 'object') {
          for (k in value) {
            if (Object.hasOwnProperty.call(value, k)) {
              v = walk(value, k);
              if (v !== undefined) {
                value[k] = v;
              } else {
                delete value[k];
              }
            }
          }
        }
        return reviver.call(holder, key, value);
      }
      
      
      // Parsing happens in four stages. In the first stage, we replace certain
      // Unicode characters with escape sequences. JavaScript handles many characters
      // incorrectly, either silently deleting them, or treating them as line endings.
      
      cx.lastIndex = 0;
      if (cx.test(text)) {
        text = text.replace(cx, function(a){
          return '\\u' +
          ('0000' + a.charCodeAt(0).toString(16)).slice(-4);
        });
      }
      
      // In the second 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 second stage into 4 regexp operations in order to work around
      // crippling inefficiencies in IE's and Safari's regexp engines. First we
      // replace the JSON 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(/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g, '@').replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g, ']').replace(/(?:^|:|,)(?:\s*\[)+/g, ''))) {
      
        // In the third 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 fourth stage, we recursively walk the new structure, passing
        // each name/value pair to a reviver function for possible transformation.
        
        return typeof reviver === 'function' ? walk({
          '': j
        }, '') : j;
      }
      
      // If the text is not JSON parseable, then a SyntaxError is thrown.
      
      throw new SyntaxError('JSON.parse');
    };
  }
}());

if (this.JSON2 && !this.JSON2.parseWithDate) {
  var reISO = /^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2}(?:\.\d*)?)Z$/;
  var reMsAjax = /^\/Date\((d|-|.*)\)[\/|\\]$/;
  // original var reMsAjax = /^\/Date\((d|-|.*)\)\/$/;
  
  JSON2.parseWithDate = function(json){
    /// <summary>
    /// parses a JSON string and turns ISO or MSAJAX date strings
    /// into native JS date objects
    /// </summary>    
    /// <param name="json" type="var">json with dates to parse</param>        
    /// </param>
    /// <returns type="value, array or object" />
    try {
      var res = JSON2.parse(json, function(key, value){
        if (typeof value === 'string') {
          var a = reISO.exec(value);
          if (a) 
            return new Date(Date.UTC(+a[1], +a[2] - 1, +a[3], +a[4], +a[5], +a[6]));
          a = reMsAjax.exec(value);
          if (a) {
            var b = a[1].split(/[-+,.]/);
            return new Date(b[0] ? +b[0] : 0 - +b[1]);
          }
        }
        return value;
      });
      return res;
    } 
    catch (e) {
      // orignal error thrown has no error message so rethrow with message
      throw new Error("JSON content could not be parsed");
      return null;
    }
  };
  JSON2.stringifyWcf = function(json, mapTypeAttr){
    /// <summary>
    /// Wcf specific stringify that encodes dates in the
    /// a WCF compatible format ("/Date(9991231231)/")
    /// Note: this format works ONLY with WCF. 
    ///       ASMX can use ISO dates as of .NET 3.5 SP1
    /// </summary>
    /// <param name="key" type="var">property name</param>    
    /// <param name="value" type="var">value of the property</param>            
    return JSON2.stringify(json, mapTypeAttr, function(key, value){
      if (typeof value == "string") {
        var a = reISO.exec(value);
        if (a) {
          var val = '/Date(' + new Date(Date.UTC(+a[1], +a[2] - 1, +a[3], +a[4], +a[5], +a[6])).getTime() + ')/';
          this[key] = val;
          return val;
        }
      }
      return value;
    })
  };
}
