context: //#define USE_SharpZipLib
  #if !UNITY_WEBPLAYER
  #define USE_FileIO
  #endif
  
  /* * * * *
   * A simple JSON Parser / builder
   * ------------------------------
   * 
   * It mainly has been written as a simple JSON parser. It can build a JSON string
   * from the node-tree, or generate a node tree from any valid JSON string.
   * 
   * If you want to use compression when saving to file / stream / B64 you have to include
   * SharpZipLib ( http://www.icsharpcode.net/opensource/sharpziplib/ ) in your project and
   * define "USE_SharpZipLib" at the top of the file
   * 
   * Written by Bunny83 
   * 2012-06-09
   * 
   * Features / attributes:
   * - provides strongly typed node classes and lists / dictionaries
   * - provides easy access to class members / array items / data values
   * - the parser ignores data types. Each value is a string.
   * - only double quotes (") are used for quoting strings.
   * - values and names are not restricted to quoted strings. They simply add up and are trimmed.
   * - There are only 3 types: arrays(JSONArray), objects(JSONClass) and values(JSONData)
   * - provides "casting" properties to easily convert to / from those types:
   *   int / float / double / bool
   * - provides a common interface for each node so no explicit casting is required.
   * - the parser try to avoid errors, but if malformed JSON is parsed the result is undefined
   * 
   * 
   * 2012-12-17 Update:
   * - Added internal JSONLazyCreator class which simplifies the construction of a JSON tree
   *   Now you can simple reference any item that doesn't exist yet and it will return a JSONLazyCreator
   *   The class determines the required type by it's further use, creates the type and removes itself.
   * - Added binary serialization / deserialization.
   * - Added support for BZip2 zipped binary format. Requires the SharpZipLib ( http://www.icsharpcode.net/opensource/sharpziplib/ )
   *   The usage of the SharpZipLib library can be disabled by removing or commenting out the USE_SharpZipLib define at the top
   * - The serializer uses different types when it comes to store the values. Since my data values
   *   are all of type string, the serializer will "try" which format fits best. The order is: int, float, double, bool, string.
   *   It's not the most efficient way but for a moderate amount of data it should work on all platforms.
   * 
   * * * * */
  using System;
  using System.Collections;
  using System.Collections.Generic;
  using System.Linq;
   
   
  namespace SimpleJSON
  {
      public enum JSONBinaryTag
      {
          Array            = 1,
          Class            = 2,
          Value            = 3,
          IntValue        = 4,
          DoubleValue        = 5,
          BoolValue        = 6,
          FloatValue        = 7,
      }
   
      public class JSONNode
      {
          #region common interface
          public virtual void Add(string aKey, JSONNode aItem){ }
          public virtual JSONNode this[int aIndex]   { get { return null; } set { } }
          public virtual JSONNode this[string aKey]  { get { return null; } set { } }
          public virtual string Value                { get { return "";   } set { } }
          public virtual int Count                   { get { return 0;    } }
  		public virtual string GetKey(int aIndex){ return ""; }
  		public virtual List<string> GetAllKeys(){ return null; }
  		public virtual void ChangeKey(string old_key,string new_key){ }
  
          public virtual void Add(JSONNode aItem)
          {
              Add("", aItem);
          }
   
          public virtual JSONNode Remove(string aKey) { return null; }
          public virtual JSONNode Remove(int aIndex) { return null; }
          public virtual JSONNode Remove(JSONNode aNode) { return aNode; }
   
          public virtual IEnumerable<JSONNode> Childs { get { yield break;} }
          public IEnumerable<JSONNode> DeepChilds
          {
              get
              {
                  foreach (var C in Childs)
                      foreach (var D in C.DeepChilds)
                          yield return D;
              }
          }
   
          public override string ToString()
          {
              return "JSONNode";
          }
          public virtual string ToString(string aPrefix)
          {
              return "JSONNode";
          }
   
          #endregion common interface
   
          #region typecasting properties
          public virtual int AsInt
          {
              get
              {
                  int v = 0;
                  if (int.TryParse(Value,out v))
                      return v;
                  return 0;
              }
              set
              {
                  Value = value.ToString();
              }
          }
          public virtual float AsFloat
          {
              get
              {
                  float v = 0.0f;
                  if (float.TryParse(Value,out v))
                      return v;
                  return 0.0f;
              }
              set
              {
                  Value = value.ToString();
              }
          }
          public virtual double AsDouble
          {
              get
              {
                  double v = 0.0;
                  if (double.TryParse(Value,out v))
                      return v;
                  return 0.0;
              }
              set
              {
                  Value = value.ToString();
              }
          }
          public virtual bool AsBool
          {
              get
              {
                  bool v = false;
                  if (bool.TryParse(Value,out v))
                      return v;
                  return !string.IsNullOrEmpty(Value);
              }
              set
              {
                  Value = (value)?"true":"false";
              }
          }
          public virtual JSONArray AsArray
          {
              get
              {
                  return this as JSONArray;
              }
          }
          public virtual JSONClass AsObject
          {
              get
              {
                  return this as JSONClass;
              }
          }
   
   
          #endregion typecasting properties
   
          #region operators
          public static implicit operator JSONNode(string s)
          {
              return new JSONData(s);
          }
          public static implicit operator string(JSONNode d)
          {
              return (d == null)?null:d.Value;
          }
          public static bool operator ==(JSONNode a, object b)
          {
              if (b == null && a is JSONLazyCreator)
                  return true;
              return System.Object.ReferenceEquals(a,b);
          }
   
          public static bool operator !=(JSONNode a, object b)
          {
              return !(a == b);
          }
          public override bool Equals (object obj)
          {
              return System.Object.ReferenceEquals(this, obj);
          }
          public override int GetHashCode ()
          {
              return base.GetHashCode();
          }
   
   
          #endregion operators
   
          internal static string Escape(string aText)
          {
              string result = "";
              foreach(char c in aText)
              {
                  switch(c)
                  {
                      case '\\' : result += "\\\\"; break;
                      case '\"' : result += "\\\""; break;
                      case '\n' : result += "\\n" ; break;
                      case '\r' : result += "\\r" ; break;
                      case '\t' : result += "\\t" ; break;
                      case '\b' : result += "\\b" ; break;
                      case '\f' : result += "\\f" ; break;
                      default   : result += c     ; break;
                  }
              }
              return result;
          }
   
          public static JSONNode Parse(string aJSON)
          {
              Stack<JSONNode> stack = new Stack<JSONNode>();
              JSONNode ctx = null;
              int i = 0;
              string Token = "";
              string TokenName = "";
              bool QuoteMode = false;
              while (i < aJSON.Length)
              {
                  switch (aJSON[i])
                  {
                      case '{':
                          if (QuoteMode)
                          {
                              Token += aJSON[i];
                              break;
                          }
                          stack.Push(new JSONClass());
                          if (ctx != null)
                          {
                              TokenName = TokenName.Trim();
                              if (ctx is JSONArray)
                                  ctx.Add(stack.Peek());
                              else if (TokenName != "")
                                  ctx.Add(TokenName,stack.Peek());
                          }
                          TokenName = "";
                          Token = "";
                          ctx = stack.Peek();
                      break;
   
                      case '[':
                          if (QuoteMode)
                          {
                              Token += aJSON[i];
                              break;
                          }
   
                          stack.Push(new JSONArray());
                          if (ctx != null)
                          {
                              TokenName = TokenName.Trim();
                              if (ctx is JSONArray)
                                  ctx.Add(stack.Peek());
                              else if (TokenName != "")
                                  ctx.Add(TokenName,stack.Peek());
                          }
                          TokenName = "";
                          Token = "";
                          ctx = stack.Peek();
                      break;
   
                      case '}':
                      case ']':
                          if (QuoteMode)
                          {
                              Token += aJSON[i];
                              break;
                          }
                          if (stack.Count == 0)
  						throw new Exception("JSON Parse: Too many closing brackets "+i.ToString());
   
                          stack.Pop();
                          if (Token != "")
                          {
                              TokenName = TokenName.Trim();
                              if (ctx is JSONArray)
                                  ctx.Add(Token);
                              else if (TokenName != "")
                                  ctx.Add(TokenName,Token);
                          }
                          TokenName = "";
                          Token = "";
                          if (stack.Count>0)
                              ctx = stack.Peek();
                      break;
   
                      case ':':
                          if (QuoteMode)
                          {
                              Token += aJSON[i];
                              break;
                          }
                          TokenName = Token;
                          Token = "";
                      break;
   
                      case '"':
                          QuoteMode ^= true;
                      break;
   
                      case ',':
                          if (QuoteMode)
                          {
                              Token += aJSON[i];
                              break;
                          }
                          if (Token != "")
                          {
                              if (ctx is JSONArray)
                                  ctx.Add(Token);
                              else if (TokenName != "")
                                  ctx.Add(TokenName, Token);
                          }
                          TokenName = "";
                          Token = "";
                      break;
   
                      case '\r':
                      case '\n':
                      break;
   
                      case ' ':
                      case '\t':
                          if (QuoteMode)
                              Token += aJSON[i];
                      break;
   
                      case '\\':
                          ++i;
                          if (QuoteMode)
                          {
                              char C = aJSON[i];
                              switch (C)
                              {
                                  case 't' : Token += '\t'; break;
                                  case 'r' : Token += '\r'; break;
                                  case 'n' : Token += '\n'; break;
                                  case 'b' : Token += '\b'; break;
                                  case 'f' : Token += '\f'; break;
                                  case 'u':
                                  {
                                      string s = aJSON.Substring(i+1,4);
                                      Token += (char)int.Parse(s, System.Globalization.NumberStyles.AllowHexSpecifier);
                                      i += 4;
                                      break;
                                  }
                                  default  : Token += C; break;
                              }
                          }
                      break;
   
                      default:
                          Token += aJSON[i];
                      break;
                  }
                  ++i;
              }
              if (QuoteMode)
              {
                  throw new Exception("JSON Parse: Quotation marks seems to be messed up.");
              }
              return ctx;
          }
   
          public virtual void Serialize(System.IO.BinaryWriter aWriter) {}
   
          public void SaveToStream(System.IO.Stream aData)
          {
              var W = new System.IO.BinaryWriter(aData);
              Serialize(W);
          }
   
          #if USE_SharpZipLib
          public void SaveToCompressedStream(System.IO.Stream aData)
          {
              using (var gzipOut = new ICSharpCode.SharpZipLib.BZip2.BZip2OutputStream(aData))
              {
                  gzipOut.IsStreamOwner = false;
                  SaveToStream(gzipOut);
                  gzipOut.Close();
              }
          }
   
          public void SaveToCompressedFile(string aFileName)
          {
              #if USE_FileIO
              System.IO.Directory.CreateDirectory((new System.IO.FileInfo(aFileName)).Directory.FullName);
              using(var F = System.IO.File.OpenWrite(aFileName))
              {
                  SaveToCompressedStream(F);
              }
              #else
              throw new Exception("Can't use File IO stuff in webplayer");
              #endif
          }
          public string SaveToCompressedBase64()
          {
              using (var stream = new System.IO.MemoryStream())
              {
                  SaveToCompressedStream(stream);
                  stream.Position = 0;
                  return System.Convert.ToBase64String(stream.ToArray());
              }
          }
   
          #else
          public void SaveToCompressedStream(System.IO.Stream aData)
          {
              throw new Exception("Can't use compressed functions. You need include the SharpZipLib and uncomment the define at the top of SimpleJSON");
          }
          public void SaveToCompressedFile(string aFileName)
          {
              throw new Exception("Can't use compressed functions. You need include the SharpZipLib and uncomment the define at the top of SimpleJSON");
          }
          public string SaveToCompressedBase64()
          {
              throw new Exception("Can't use compressed functions. You need include the SharpZipLib and uncomment the define at the top of SimpleJSON");
          }
          #endif
          
          public void SaveToFile(string aFileName)
          {
              #if USE_FileIO
              System.IO.Directory.CreateDirectory((new System.IO.FileInfo(aFileName)).Directory.FullName);
              using(var F = System.IO.File.OpenWrite(aFileName))
              {
                  SaveToStream(F);
              }
              #else
              throw new Exception("Can't use File IO stuff in webplayer");
              #endif
          }
          public string SaveToBase64()
          {
              using (var stream = new System.IO.MemoryStream())
              {
                  SaveToStream(stream);
                  stream.Position = 0;
                  return System.Convert.ToBase64String(stream.ToArray());
              }
          }
          public static JSONNode Deserialize(System.IO.BinaryReader aReader)
          {
              JSONBinaryTag type = (JSONBinaryTag)aReader.ReadByte();
              switch(type)
              {
              case JSONBinaryTag.Array:
              {
                  int count = aReader.ReadInt32();
                  JSONArray tmp = new JSONArray();
                  for(int i = 0; i < count; i++)
                      tmp.Add(Deserialize(aReader));
                  return tmp;
              }
              case JSONBinaryTag.Class:
              {
                  int count = aReader.ReadInt32();                
                  JSONClass tmp = new JSONClass();
                  for(int i = 0; i < count; i++)
                  {
  
gt:                     string key = aReader.ReadString();