text: //
  // GENERATED FILE - DO NOT EDIT DIRECTLY
  //
  // See scripts/build_browser_thrift_lib.js
  //
  //
  (function() {
  var crouton_thrift = {};
  //
  // Autogenerated by Thrift Compiler (0.9.2)
  //
  // DO NOT EDIT UNLESS YOU ARE SURE THAT YOU KNOW WHAT YOU ARE DOING
  //
  
  
  if (typeof crouton_thrift === 'undefined') {
    crouton_thrift = {};
  }
  crouton_thrift.KeyValue = function(args) {
    this.Key = null;
    this.Value = null;
    if (args) {
      if (args.Key !== undefined) {
        this.Key = args.Key;
      } else {
        throw new Thrift.TProtocolException(Thrift.TProtocolExceptionType.UNKNOWN, 'Required field Key is unset!');
      }
      if (args.Value !== undefined) {
        this.Value = args.Value;
      } else {
        throw new Thrift.TProtocolException(Thrift.TProtocolExceptionType.UNKNOWN, 'Required field Value is unset!');
      }
    }
  };
  crouton_thrift.KeyValue.prototype = {};
  crouton_thrift.KeyValue.prototype.read = function(input) {
    input.readStructBegin();
    while (true)
    {
      var ret = input.readFieldBegin();
      var fname = ret.fname;
      var ftype = ret.ftype;
      var fid = ret.fid;
      if (ftype == Thrift.Type.STOP) {
        break;
      }
      switch (fid)
      {
        case 1:
        if (ftype == Thrift.Type.STRING) {
          this.Key = input.readString().value;
        } else {
          input.skip(ftype);
        }
        break;
        case 2:
        if (ftype == Thrift.Type.STRING) {
          this.Value = input.readString().value;
        } else {
          input.skip(ftype);
        }
        break;
        default:
          input.skip(ftype);
      }
      input.readFieldEnd();
    }
    input.readStructEnd();
    return;
  };
  
  crouton_thrift.KeyValue.prototype.write = function(output) {
    output.writeStructBegin('KeyValue');
    if (this.Key !== null && this.Key !== undefined) {
      output.writeFieldBegin('Key', Thrift.Type.STRING, 1);
      output.writeString(this.Key);
      output.writeFieldEnd();
    }
    if (this.Value !== null && this.Value !== undefined) {
      output.writeFieldBegin('Value', Thrift.Type.STRING, 2);
      output.writeString(this.Value);
      output.writeFieldEnd();
    }
    output.writeFieldStop();
    output.writeStructEnd();
    return;
  };
  
  crouton_thrift.NamedCounter = function(args) {
    this.Name = null;
    this.Value = null;
    if (args) {
      if (args.Name !== undefined) {
        this.Name = args.Name;
      } else {
        throw new Thrift.TProtocolException(Thrift.TProtocolExceptionType.UNKNOWN, 'Required field Name is unset!');
      }
      if (args.Value !== undefined) {
        this.Value = args.Value;
      } else {
        throw new Thrift.TProtocolException(Thrift.TProtocolExceptionType.UNKNOWN, 'Required field Value is unset!');
      }
    }
  };
  crouton_thrift.NamedCounter.prototype = {};
  crouton_thrift.NamedCounter.prototype.read = function(input) {
    input.readStructBegin();
    while (true)
    {
      var ret = input.readFieldBegin();
      var fname = ret.fname;
      var ftype = ret.ftype;
      var fid = ret.fid;
      if (ftype == Thrift.Type.STOP) {
        break;
      }
      switch (fid)
      {
        case 1:
        if (ftype == Thrift.Type.STRING) {
          this.Name = input.readString().value;
        } else {
          input.skip(ftype);
        }
        break;
        case 2:
        if (ftype == Thrift.Type.I64) {
          this.Value = input.readI64().value;
        } else {
          input.skip(ftype);
        }
        break;
        default:
          input.skip(ftype);
      }
      input.readFieldEnd();
    }
    input.readStructEnd();
    return;
  };
  
  crouton_thrift.NamedCounter.prototype.write = function(output) {
    output.writeStructBegin('NamedCounter');
    if (this.Name !== null && this.Name !== undefined) {
      output.writeFieldBegin('Name', Thrift.Type.STRING, 1);
      output.writeString(this.Name);
      output.writeFieldEnd();
    }
    if (this.Value !== null && this.Value !== undefined) {
      output.writeFieldBegin('Value', Thrift.Type.I64, 2);
      output.writeI64(this.Value);
      output.writeFieldEnd();
    }
    output.writeFieldStop();
    output.writeStructEnd();
    return;
  };
  
  crouton_thrift.Runtime = function(args) {
    this.guid = null;
    this.start_micros = null;
    this.group_name = null;
    this.attrs = null;
    if (args) {
      if (args.guid !== undefined) {
        this.guid = args.guid;
      }
      if (args.start_micros !== undefined) {
        this.start_micros = args.start_micros;
      }
      if (args.group_name !== undefined) {
        this.group_name = args.group_name;
      }
      if (args.attrs !== undefined) {
        this.attrs = args.attrs;
      }
    }
  };
  crouton_thrift.Runtime.prototype = {};
  crouton_thrift.Runtime.prototype.read = function(input) {
    input.readStructBegin();
    while (true)
    {
      var ret = input.readFieldBegin();
      var fname = ret.fname;
      var ftype = ret.ftype;
      var fid = ret.fid;
      if (ftype == Thrift.Type.STOP) {
        break;
      }
      switch (fid)
      {
        case 1:
        if (ftype == Thrift.Type.STRING) {
          this.guid = input.readString().value;
        } else {
          input.skip(ftype);
        }
        break;
        case 2:
        if (ftype == Thrift.Type.I64) {
          this.start_micros = input.readI64().value;
        } else {
          input.skip(ftype);
        }
        break;
        case 3:
        if (ftype == Thrift.Type.STRING) {
          this.group_name = input.readString().value;
        } else {
          input.skip(ftype);
        }
        break;
        case 4:
        if (ftype == Thrift.Type.LIST) {
          var _size0 = 0;
          var _rtmp34;
          this.attrs = [];
          var _etype3 = 0;
          _rtmp34 = input.readListBegin();
          _etype3 = _rtmp34.etype;
          _size0 = _rtmp34.size;
          for (var _i5 = 0; _i5 < _size0; ++_i5)
          {
            var elem6 = null;
            elem6 = new crouton_thrift.KeyValue();
            elem6.read(input);
            this.attrs.push(elem6);
          }
          input.readListEnd();
        } else {
          input.skip(ftype);
        }
        break;
        default:
          input.skip(ftype);
      }
      input.readFieldEnd();
    }
    input.readStructEnd();
    return;
  };
  
  crouton_thrift.Runtime.prototype.write = function(output) {
    output.writeStructBegin('Runtime');
    if (this.guid !== null && this.guid !== undefined) {
      output.writeFieldBegin('guid', Thrift.Type.STRING, 1);
      output.writeString(this.guid);
      output.writeFieldEnd();
    }
    if (this.start_micros !== null && this.start_micros !== undefined) {
      output.writeFieldBegin('start_micros', Thrift.Type.I64, 2);
      output.writeI64(this.start_micros);
      output.writeFieldEnd();
    }
    if (this.group_name !== null && this.group_name !== undefined) {
      output.writeFieldBegin('group_name', Thrift.Type.STRING, 3);
      output.writeString(this.group_name);
      output.writeFieldEnd();
    }
    if (this.attrs !== null && this.attrs !== undefined) {
      output.writeFieldBegin('attrs', Thrift.Type.LIST, 4);
      output.writeListBegin(Thrift.Type.STRUCT, this.attrs.length);
      for (var iter7 in this.attrs)
      {
        if (this.attrs.hasOwnProperty(iter7))
        {
          iter7 = this.attrs[iter7];
          iter7.write(output);
        }
      }
      output.writeListEnd();
      output.writeFieldEnd();
    }
    output.writeFieldStop();
    output.writeStructEnd();
    return;
  };
  
  crouton_thrift.LogRecord = function(args) {
    this.timestamp_micros = null;
    this.runtime_guid = null;
    this.span_guid = null;
    this.stable_name = null;
    this.message = null;
    this.level = null;
    this.thread_id = null;
    this.filename = null;
    this.line_number = null;
    this.stack_frames = null;
    this.payload_json = null;
    this.error_flag = null;
    if (args) {
      if (args.timestamp_micros !== undefined) {
        this.timestamp_micros = args.timestamp_micros;
      }
      if (args.runtime_guid !== undefined) {
        this.runtime_guid = args.runtime_guid;
      }
      if (args.span_guid !== undefined) {
        this.span_guid = args.span_guid;
      }
      if (args.stable_name !== undefined) {
        this.stable_name = args.stable_name;
      }
      if (args.message !== undefined) {
        this.message = args.message;
      }
      if (args.level !== undefined) {
        this.level = args.level;
      }
      if (args.thread_id !== undefined) {
        this.thread_id = args.thread_id;
      }
      if (args.filename !== undefined) {
        this.filename = args.filename;
      }
      if (args.line_number !== undefined) {
        this.line_number = args.line_number;
      }
      if (args.stack_frames !== undefined) {
        this.stack_frames = args.stack_frames;
      }
      if (args.payload_json !== undefined) {
        this.payload_json = args.payload_json;
      }
      if (args.error_flag !== undefined) {
        this.error_flag = args.error_flag;
      }
    }
  };
  crouton_thrift.LogRecord.prototype = {};
  crouton_thrift.LogRecord.prototype.read = function(input) {
    input.readStructBegin();
    while (true)
    {
      var ret = input.readFieldBegin();
      var fname = ret.fname;
      var ftype = ret.ftype;
      var fid = ret.fid;
      if (ftype == Thrift.Type.STOP) {
        break;
      }
      switch (fid)
      {
        case 1:
        if (ftype == Thrift.Type.I64) {
          this.timestamp_micros = input.readI64().value;
        } else {
          input.skip(ftype);
        }
        break;
        case 2:
        if (ftype == Thrift.Type.STRING) {
          this.runtime_guid = input.readString().value;
        } else {
          input.skip(ftype);
        }
        break;
        case 3:
        if (ftype == Thrift.Type.STRING) {
          this.span_guid = input.readString().value;
        } else {
          input.skip(ftype);
        }
        break;
        case 4:
        if (ftype == Thrift.Type.STRING) {
          this.stable_name = input.readString().value;
        } else {
          input.skip(ftype);
        }
        break;
        case 5:
        if (ftype == Thrift.Type.STRING) {
          this.message = input.readString().value;
        } else {
          input.skip(ftype);
        }
        break;
        case 6:
        if (ftype == Thrift.Type.STRING) {
          this.level = input.readString().value;
        } else {
          input.skip(ftype);
        }
        break;
        case 7:
        if (ftype == Thrift.Type.I64) {
          this.thread_id = input.readI64().value;
        } else {
          input.skip(ftype);
        }
        break;
        case 8:
        if (ftype == Thrift.Type.STRING) {
          this.filename = input.readString().value;
        } else {
          input.skip(ftype);
        }
        break;
        case 9:
        if (ftype == Thrift.Type.I64) {
          this.line_number = input.readI64().value;
        } else {
          input.skip(ftype);
        }
        break;
        case 10:
        if (ftype == Thrift.Type.LIST) {
          var _size8 = 0;
          var _rtmp312;
          this.stack_frames = [];
          var _etype11 = 0;
          _rtmp312 = input.readListBegin();
          _etype11 = _rtmp312.etype;
          _size8 = _rtmp312.size;
          for (var _i13 = 0; _i13 < _size8; ++_i13)
          {
            var elem14 = null;
            elem14 = input.readString().value;
            this.stack_frames.push(elem14);
          }
          input.readListEnd();
        } else {
          input.skip(ftype);
        }
        break;
        case 11:
        if (ftype == Thrift.Type.STRING) {
          this.payload_json = input.readString().value;
        } else {
          input.skip(ftype);
        }
        break;
        case 12:
        if (ftype == Thrift.Type.BOOL) {
          this.error_flag = input.readBool().value;
        } else {
          input.skip(ftype);
        }
        break;
        default:
          input.skip(ftype);
      }
      input.readFieldEnd();
    }
    input.readStructEnd();
    return;
  };
  
  crouton_thrift.LogRecord.prototype.write = function(output) {
    output.writeStructBegin('LogRecord');
    if (this.timestamp_micros !== null && this.timestamp_micros !== undefined) {
      output.writeFieldBegin('timestamp_micros', Thrift.Type.I64, 1);
      output.writeI64(this.timestamp_micros);
      output.writeFieldEnd();
    }
    if (this.runtime_guid !== null && this.runtime_guid !== undefined) {
      output.writeFieldBegin('runtime_guid', Thrift.Type.STRING, 2);
      output.writeString(this.runtime_guid);
      output.writeFieldEnd();
    }
    if (this.span_guid !== null && this.span_guid !== undefined) {
      output.writeFieldBegin('span_guid', Thrift.Type.STRING, 3);
      output.writeString(this.span_guid);
      output.writeFieldEnd();
    }
    if (this.stable_name !== null && this.stable_name !== undefined) {
      output.writeFieldBegin('stable_name', Thrift.Type.STRING, 4);
      output.writeString(this.stable_name);
      output.writeFieldEnd();
    }
    if (this.message !== null && this.message !== undefined) {
      output.writeFieldBegin('message', Thrift.Type.STRING, 5);
      output.writeString(this.message);
      output.writeFieldEnd();
    }
    if (this.level !== null && this.level !== undefined) {
      output.writeFieldBegin('level', Thrift.Type.STRING, 6);
      output.writeString(this.level);
      output.writeFieldEnd();
    }
    if (this.thread_id !== null && this.thread_id !== undefined) {
      output.writeFieldBegin('thread_id', Thrift.Type.I64, 7);
      output.writeI64(this.thread_id);
      output.writeFieldEnd();
    }
    if (this.filename !== null && this.filename !== undefined) {
      output.writeFieldBegin('filename', Thrift.Type.STRING, 8);
      output.writeString(this.filename);
      output.writeFieldEnd();
    }
    if (this.line_number !== null && this.line_number !== undefined) {
      output.writeFieldBegin('line_number', Thrift.Type.I64, 9);
      output.writeI64(this.line_number);
      output.writeFieldEnd();
    }
    if (this.stack_frames !== null && this.stack_frames !== undefined) {
      output.writeFieldBegin('stack_frames', Thrift.Type.LIST, 10);
      output.writeListBegin(Thrift.Type.STRING, this.stack_frames.length);
      for (var iter15 in this.stack_frames)
      {
        if (this.stack_frames.hasOwnProperty(iter15))
        {
          iter15 = this.stack_frames[iter15];
          output.writeString(iter15);
        }
      }
      output.writeListEnd();
      output.writeFieldEnd();
    }
    if (this.payload_json !== null && this.payload_json !== undefined) {
      output.writeFieldBegin('payload_json', Thrift.Type.STRING, 11);
      output.writeString(this.payload_json);
      output.writeFieldEnd();
    }
    if (this.error_flag !== null && this.error_flag !== undefined) {
      output.writeFieldBegin('error_flag', Thrift.Type.BOOL, 12);
      output.writeBool(this.error_flag);
      output.writeFieldEnd();
    }
    output.writeFieldStop();
    output.writeStructEnd();
    return;
  };
  
  crouton_thrift.TraceJoinId = function(args) {
    this.TraceKey = null;
    this.Value = null;
    if (args) {
      if (args.TraceKey !== undefined) {
        this.TraceKey = args.TraceKey;
      } else {
        throw new Thrift.TProtocolException(Thrift.TProtocolExceptionType.UNKNOWN, 'Required field TraceKey is unset!');
      }
      if (args.Value !== undefined) {
        this.Value = args.Value;
      } else {
        throw new Thrift.TProtocolException(Thrift.TProtocolExceptionType.UNKNOWN, 'Required field Value is unset!');
      }
    }
  };
  crouton_thrift.TraceJoinId.prototype = {};
  crouton_thrift.TraceJoinId.prototype.read = function(input) {
    input.readStructBegin();
    while (true)
    {
      var ret = input.readFieldBegin();
      var fname = ret.fname;
      var ftype = ret.ftype;
      var fid = ret.fid;
      if (ftype == Thrift.Type.STOP) {
        break;
      }
      switch (fid)
      {
        case 1:
        if (ftype == Thrift.Type.STRING) {
          this.TraceKey = input.readString().value;
        } else {
          input.skip(ftype);
        }
        break;
        case 2:
        if (ftype == Thrift.Type.STRING) {
          this.Value = input.readString().value;
        } else {
          input.skip(ftype);
        }
        break;
        default:
          input.skip(ftype);
      }
      input.readFieldEnd();
    }
    input.readStructEnd();
    return;
  };
  
  crouton_thrift.TraceJoinId.prototype.write = function(output) {
    output.writeStructBegin('TraceJoinId');
    if (this.TraceKey !== null && this.TraceKey !== undefined) {
      output.writeFieldBegin('TraceKey', Thrift.Type.STRING, 1);
      output.writeString(this.TraceKey);
      output.writeFieldEnd();
    }
    if (this.Value !== null && this.Value !== undefined) {
      output.writeFieldBegin('Value', Thrift.Type.STRING, 2);
      output.writeString(this.Value);
      output.writeFieldEnd();
    }
    output.writeFieldStop();
    output.writeStructEnd();
    return;
  };
  
  crouton_thrift.SpanRecord = function(args) {
    this.span_guid = null;
    this.runtime_guid = null;
    this.span_name = null;
    this.join_ids = null;
    this.oldest_micros = null;
    this.youngest_micros = null;
    this.attributes = null;
    this.error_flag = null;
    if (args) {
      if (args.span_guid !== undefined) {
        this.span_guid = args.span_guid;
      }
      if (args.runtime_guid !== undefined) {
        this.runtime_guid = args.runtime_guid;
      }
      if (args.span_name !== undefined) {
        this.span_name = args.span_name;
      }
      if (args.join_ids !== undefined) {
        this.join_ids = args.join_ids;
      }
      if (args.oldest_micros !== undefined) {
        this.oldest_micros = args.oldest_micros;
      }
      if (args.youngest_micros !== undefined) {
        this.youngest_micros = args.youngest_micros;
      }
      if (args.attributes !== undefined) {
        this.attributes = args.attributes;
      }
      if (args.error_flag !== undefined) {
        this.error_flag = args.error_flag;
      }
    }
  };
  crouton_thrift.SpanRecord.prototype = {};
  crouton_thrift.SpanRecord.prototype.read = function(input) {
    input.readStructBegin();
    while (true)
    {
      var ret = input.readFieldBegin();
      var fname = ret.fname;
      var ftype = ret.ftype;
      var fid = ret.fid;
      if (ftype == Thrift.Type.STOP) {
        break;
      }
      switch (fid)
      {
        case 1:
        if (ftype == Thrift.Type.STRING) {
          this.span_guid = input.readString().value;
        } else {
          input.skip(ftype);
        }
        break;
        case 2:
        if (ftype == Thrift.Type.STRING) {
          this.runtime_guid = input.readString().value;
        } else {
          input.skip(ftype);
        }
        break;
        case 3:
        if (ftype == Thrift.Type.STRING) {
          this.span_name = input.readString().value;
        } else {
          input.skip(ftype);
        }
        break;
        case 4:
        if (ftype == Thrift.Type.LIST) {
          var _size16 = 0;
          var _rtmp320;
          this.join_ids = [];
          var _etype19 = 0;
          _rtmp320 = input.readListBegin();
          _etype19 = _rtmp320.etype;
          _size16 = _rtmp320.size;
          for (var _i21 = 0; _i21 < _size16; ++_i21)
          {
            var elem22 = null;
            elem22 = new crouton_thrift.TraceJoinId();
            elem22.read(input);
            this.join_ids.push(elem22);
          }
          input.readListEnd();
        } else {
          input.skip(ftype);
        }
        break;
        case 5:
        if (ftype == Thrift.Type.I64) {
          this.oldest_micros = input.readI64().value;
        } else {
          input.skip(ftype);
        }
        break;
        case 6:
        if (ftype == Thrift.Type.I64) {
          this.youngest_micros = input.readI64().value;
        } else {
          input.skip(ftype);
        }
        break;
        case 8:
        if (ftype == Thrift.Type.LIST) {
          var _size23 = 0;
          var _rtmp327;
          this.attributes = [];
          var _etype26 = 0;
          _rtmp327 = input.readListBegin();
          _etype26 = _rtmp327.etype;
          _size23 = _rtmp327.size;
          for (var _i28 = 0; _i28 < _size23; ++_i28)
          {
            var elem29 = null;
            elem29 = new crouton_thrift.KeyValue();
            elem29.read(input);
            this.attributes.push(elem29);
          }
          input.readListEnd();
        } else {
          input.skip(ftype);
        }
        break;
        case 9:
        if (ftype == Thrift.Type.BOOL) {
          this.error_flag = input.readBool().value;
        } else {
          input.skip(ftype);
        }
        break;
        default:
          input.skip(ftype);
      }
      input.readFieldEnd();
    }
    input.readStructEnd();
    return;
  };
  
  crouton_thrift.SpanRecord.prototype.write = function(output) {
    output.writeStructBegin('SpanRecord');
    if (this.span_guid !== null && this.span_guid !== undefined) {
      output.writeFieldBegin('span_guid', Thrift.Type.STRING, 1);
      output.writeString(this.span_guid);
      output.writeFieldEnd();
    }
    if (this.runtime_guid !== null && this.runtime_guid !== undefined) {
      output.writeFieldBegin('runtime_guid', Thrift.Type.STRING, 2);
      output.writeString(this.runtime_guid);
      output.writeFieldEnd();
    }
    if (this.span_name !== null && this.span_name !== undefined) {
      output.writeFieldBegin('span_name', Thrift.Type.STRING, 3);
      output.writeString(this.span_name);
      output.writeFieldEnd();
    }
    if (this.join_ids !== null && this.join_ids !== undefined) {
      output.writeFieldBegin('join_ids', Thrift.Type.LIST, 4);
      output.writeListBegin(Thrift.Type.STRUCT, this.join_ids.length);
      for (var iter30 in this.join_ids)
      {
        if (this.join_ids.hasOwnProperty(iter30))
        {
          iter30 = this.join_ids[iter30];
          iter30.write(output);
        }
      }
      output.writeListEnd();
      output.writeFieldEnd();
    }
    if (this.oldest_micros !== null && this.oldest_micros !== undefined) {
      output.writeFieldBegin('oldest_micros', Thrift.Type.I64, 5);
      output.writeI64(this.oldest_micros);
      output.writeFieldEnd();
    }
    if (this.youngest_micros !== null && this.youngest_micros !== undefined) {
      output.writeFieldBegin('youngest_micros', Thrift.Type.I64, 6);
      output.writeI64(this.youngest_micros);
      output.writeFieldEnd();
    }
    if (this.attributes !== null && this.attributes !== undefined) {
      output.writeFieldBegin('attributes', Thrift.Type.LIST, 8);
      output.writeListBegin(Thrift.Type.STRUCT, this.attributes.length);
      for (var iter31 in this.attributes)
      {
        if (this.attributes.hasOwnProperty(iter31))
        {
          iter31 = this.attributes[iter31];
          iter31.write(output);
        }
      }
      output.writeListEnd();
      output.writeFieldEnd();
    }
    if (this.error_flag !== null && this.error_flag !== undefined) {
      output.writeFieldBegin('error_flag', Thrift.Type.BOOL, 9);
      output.writeBool(this.error_flag);
      output.writeFieldEnd();
    }
    output.writeFieldStop();
    output.writeStructEnd();
    return;
  };
  
  crouton_thrift.Auth = function(args) {
    this.access_token = null;
    if (args) {
      if (args.access_token !== undefined) {
        this.access_token = args.access_token;
      }
    }
  };
  crouton_thrift.Auth.prototype = {};
  crouton_thrift.Auth.prototype.read = function(input) {
    input.readStructBegin();
    while (true)
    {
      var ret = input.readFieldBegin();
      var fname = ret.fname;
      var ftype = ret.ftype;
      var fid = ret.fid;
      if (ftype == Thrift.Type.STOP) {
        break;
      }
      switch (fid)
      {
        case 1:
        if (ftype == Thrift.Type.STRING) {
          this.access_token = input.readString().value;
        } else {
          input.skip(ftype);
        }
        break;
        case 0:
          input.skip(ftype);
          break;
        default:
          input.skip(ftype);
      }
      input.readFieldEnd();
    }
    input.readStructEnd();
    return;
  };
  
  crouton_thrift.Auth.prototype.write = function(output) {
    output.writeStructBegin('Auth');
    if (this.access_token !== null && this.access_token !== undefined) {
      output.writeFieldBegin('access_token', Thrift.Type.STRING, 1);
      output.writeString(this.access_token);
      output.writeFieldEnd();
    }
    output.writeFieldStop();
    output.writeStructEnd();
    return;
  };
  
  crouton_thrift.Timing = function(args) {
    this.receive_micros = null;
    this.transmit_micros = null;
    if (args) {
      if (args.receive_micros !== undefined) {
        this.receive_micros = args.receive_micros;
      }
      if (args.transmit_micros !== undefined) {
        this.transmit_micros = args.transmit_micros;
      }
    }
  };
  crouton_thrift.Timing.prototype = {};
  crouton_thrift.Timing.prototype.read = function(input) {
    input.readStructBegin();
    while (true)
    {
      var ret = input.readFieldBegin();
      var fname = ret.fname;
      var ftype = ret.ftype;
      var fid = ret.fid;
      if (ftype == Thrift.Type.STOP) {
        break;
      }
      switch (fid)
      {
        case 1:
        if (ftype == Thrift.Type.I64) {
          this.receive_micros = input.readI64().value;
        } else {
          input.skip(ftype);
        }
        break;
        case 2:
        if (ftype == Thrift.Type.I64) {
          this.transmit_micros = input.readI64().value;
        } else {
          input.skip(ftype);
        }
        break;
        default:
          input.skip(ftype);
      }
      input.readFieldEnd();
    }
    input.readStructEnd();
    return;
  };
  
  crouton_thrift.Timing.prototype.write = function(output) {
    output.writeStructBegin('Timing');
    if (this.receive_micros !== null && this.receive_micros !== undefined) {
      output.writeFieldBegin('receive_micros', Thrift.Type.I64, 1);
      output.writeI64(this.receive_micros);
      output.writeFieldEnd();
    }
    if (this.transmit_micros !== null && this.transmit_micros !== undefined) {
      output.writeFieldBegin('transmit_micros', Thrift.Type.I64, 2);
      output.writeI64(this.transmit_micros);
      output.writeFieldEnd();
    }
    output.writeFieldStop();
    output.writeStructEnd();
    return;
  };
  
  crouton_thrift.SampleCount = function(args) {
    this.oldest_micros = null;
    this.youngest_micros = null;
    this.count = null;
    if (args) {
      if (args.oldest_micros !== undefined) {
        this.oldest_micros = args.oldest_micros;
      }
      if (args.youngest_micros !== undefined) {
        this.youngest_micros = args.youngest_micros;
      }
      if (args.count !== undefined) {
        this.count = args.count;
      }
    }
  };
  crouton_thrift.SampleCount.prototype = {};
  crouton_thrift.SampleCount.prototype.read = function(input) {
    input.readStructBegin();
    while (true)
    {
      var ret = input.readFieldBegin();
      var fname = ret.fname;
      var ftype = ret.ftype;
      var fid = ret.fid;
      if (ftype == Thrift.Type.STOP) {
        break;
      }
      switch (fid)
      {
        case 1:
        if (ftype == Thrift.Type.I64) {
          this.oldest_micros = input.readI64().value;
        } else {
          input.skip(ftype);
        }
        break;
        case 2:
        if (ftype == Thrift.Type.I64) {
          this.youngest_micros = input.readI64().value;
        } else {
          input.skip(ftype);
        }
        break;
        case 3:
        if (ftype == Thrift.Type.I64) {
          this.count = input.readI64().value;
        } else {
          input.skip(ftype);
        }
        break;
        default:
          input.skip(ftype);
      }
      input.readFieldEnd();
    }
    input.readStructEnd();
    return;
  };
  
  crouton_thrift.SampleCount.prototype.write = function(output) {
    output.writeStructBegin('SampleCount');
    if (this.oldest_micros !== null && this.oldest_micros !== undefined) {
      output.writeFieldBegin('oldest_micros', Thrift.Type.I64, 1);
      output.writeI64(this.oldest_micros);
      output.writeFieldEnd();
    }
    if (this.youngest_micros !== null && this.youngest_micros !== undefined) {
      output.writeFieldBegin('youngest_micros', Thrift.Type.I64, 2);
      output.writeI64(this.youngest_micros);
      output.writeFieldEnd();
    }
    if (this.count !== null && this.count !== undefined) {
      output.writeFieldBegin('count', Thrift.Type.I64, 3);
      output.writeI64(this.count);
      output.writeFieldEnd();
    }
    output.writeFieldStop();
    output.writeStructEnd();
    return;
  };
  
  crouton_thrift.ReportRequest = function(args) {
    this.runtime = null;
    this.span_records = null;
    this.log_records = null;
    this.timestamp_offset_micros = null;
    this.oldest_micros = null;
    this.youngest_micros = null;
    this.counters = null;
    if (args) {
      if (args.runtime !== undefined) {
        this.runtime = args.runtime;
      }
      if (args.span_records !== undefined) {
        this.span_records = args.span_records;
      }
      if (args.log_records !== undefined) {
        this.log_records = args.log_records;
      }
      if (args.timestamp_offset_micros !== undefined) {
        this.timestamp_offset_micros = args.timestamp_offset_micros;
      }
      if (args.oldest_micros !== undefined) {
        this.oldest_micros = args.oldest_micros;
      }
      if (args.youngest_micros !== undefined) {
        this.youngest_micros = args.youngest_micros;
      }
      if (args.counters !== undefined) {
        this.counters = args.counters;
      }
    }
  };
  crouton_thrift.ReportRequest.prototype = {};
  crouton_thrift.ReportRequest.prototype.read = function(input) {
    input.readStructBegin();
    while (true)
    {
      var ret = input.readFieldBegin();
      var fname = ret.fname;
      var ftype = ret.ftype;
      var fid = ret.fid;
      if (ftype == Thrift.Type.STOP) {
        break;
      }
      switch (fid)
      {
        case 1:
        if (ftype == Thrift.Type.STRUCT) {
          this.runtime = new crouton_thrift.Runtime();
          this.runtime.read(input);
        } else {
          input.skip(ftype);
        }
        break;
        case 3:
        if (ftype == Thrift.Type.LIST) {
          var _size32 = 0;
          var _rtmp336;
          this.span_records = [];
          var _etype35 = 0;
          _rtmp336 = input.readListBegin();
          _etype35 = _rtmp336.etype;
          _size32 = _rtmp336.size;
          for (var _i37 = 0; _i37 < _size32; ++_i37)
          {
            var elem38 = null;
            elem38 = new crouton_thrift.SpanRecord();
            elem38.read(input);
            this.span_records.push(elem38);
          }
          input.readListEnd();
        } else {
          input.skip(ftype);
        }
        break;
        case 4:
        if (ftype == Thrift.Type.LIST) {
          var _size39 = 0;
          var _rtmp343;
          this.log_records = [];
          var _etype42 = 0;
          _rtmp343 = input.readListBegin();
          _etype42 = _rtmp343.etype;
          _size39 = _rtmp343.size;
          for (var _i44 = 0; _i44 < _size39; ++_i44)
          {
            var elem45 = null;
            elem45 = new crouton_thrift.LogRecord();
            elem45.read(input);
            this.log_records.push(elem45);
          }
          input.readListEnd();
        } else {
          input.skip(ftype);
        }
        break;
        case 5:
        if (ftype == Thrift.Type.I64) {
          this.timestamp_offset_micros = input.readI64().value;
        } else {
          input.skip(ftype);
        }
        break;
        case 7:
        if (ftype == Thrift.Type.I64) {
          this.oldest_micros = input.readI64().value;
        } else {
          input.skip(ftype);
        }
        break;
        case 8:
        if (ftype == Thrift.Type.I64) {
          this.youngest_micros = input.readI64().value;
        } else {
          input.skip(ftype);
        }
        break;
        case 9:
        if (ftype == Thrift.Type.LIST) {
          var _size46 = 0;
          var _rtmp350;
          this.counters = [];
          var _etype49 = 0;
          _rtmp350 = input.readListBegin();
          _etype49 = _rtmp350.etype;
          _size46 = _rtmp350.size;
          for (var _i51 = 0; _i51 < _size46; ++_i51)
          {
            var elem52 = null;
            elem52 = new crouton_thrift.NamedCounter();
            elem52.read(input);
            this.counters.push(elem52);
          }
          input.readListEnd();
        } else {
          input.skip(ftype);
        }
        break;
        default:
          input.skip(ftype);
      }
      input.readFieldEnd();
    }
    input.readStructEnd();
    return;
  };
  
  crouton_thrift.ReportRequest.prototype.write = function(output) {
    output.writeStructBegin('ReportRequest');
    if (this.runtime !== null && this.runtime !== undefined) {
      output.writeFieldBegin('runtime', Thrift.Type.STRUCT, 1);
      this.runtime.write(output);
      output.writeFieldEnd();
    }
    if (this.span_records !== null && this.span_records !== undefined) {
      output.writeFieldBegin('span_records', Thrift.Type.LIST, 3);
      output.writeListBegin(Thrift.Type.STRUCT, this.span_records.length);
      for (var iter53 in this.span_records)
      {
        if (this.span_records.hasOwnProperty(iter53))
        {
          iter53 = this.span_records[iter53];
          iter53.write(output);
        }
      }
      output.writeListEnd();
      output.writeFieldEnd();
    }
    if (this.log_records !== null && this.log_records !== undefined) {
      output.writeFieldBegin('log_records', Thrift.Type.LIST, 4);
      output.writeListBegin(Thrift.Type.STRUCT, this.log_records.length);
      for (var iter54 in this.log_records)
      {
        if (this.log_records.hasOwnProperty(iter54))
        {
          iter54 = this.log_records[iter54];
          iter54.write(output);
        }
      }
      output.writeListEnd();
      output.writeFieldEnd();
    }
    if (this.timestamp_offset_micros !== null && this.timestamp_offset_micros !== undefined) {
      output.writeFieldBegin('timestamp_offset_micros', Thrift.Type.I64, 5);
      output.writeI64(this.timestamp_offset_micros);
      output.writeFieldEnd();
    }
    if (this.oldest_micros !== null && this.oldest_micros !== undefined) {
      output.writeFieldBegin('oldest_micros', Thrift.Type.I64, 7);
      output.writeI64(this.oldest_micros);
      output.writeFieldEnd();
    }
    if (this.youngest_micros !== null && this.youngest_micros !== undefined) {
      output.writeFieldBegin('youngest_micros', Thrift.Type.I64, 8);
      output.writeI64(this.youngest_micros);
      output.writeFieldEnd();
    }
    if (this.counters !== null && this.counters !== undefined) {
      output.writeFieldBegin('counters', Thrift.Type.LIST, 9);
      output.writeListBegin(Thrift.Type.STRUCT, this.counters.length);
      for (var iter55 in this.counters)
      {
        if (this.counters.hasOwnProperty(iter55))
        {
          iter55 = this.counters[iter55];
          iter55.write(output);
        }
      }
      output.writeListEnd();
      output.writeFieldEnd();
    }
    output.writeFieldStop();
    output.writeStructEnd();
    return;
  };
  
  crouton_thrift.Command = function(args) {
    this.disable = null;
    if (args) {
      if (args.disable !== undefined) {
        this.disable = args.disable;
      }
    }
  };
  crouton_thrift.Command.prototype = {};
  crouton_thrift.Command.prototype.read = function(input) {
    input.readStructBegin();
    while (true)
    {
      var ret = input.readFieldBegin();
      var fname = ret.fname;
      var ftype = ret.ftype;
      var fid = ret.fid;
      if (ftype == Thrift.Type.STOP) {
        break;
      }
      switch (fid)
      {
        case 1:
        if (ftype == Thrift.Type.BOOL) {
          this.disable = input.readBool().value;
        } else {
          input.skip(ftype);
        }
        break;
        case 0:
          input.skip(ftype);
          break;
        default:
          input.skip(ftype);
      }
      input.readFieldEnd();
    }
    input.readStructEnd();
    return;
  };
  
  crouton_thrift.Command.prototype.write = function(output) {
    output.writeStructBegin('Command');
    if (this.disable !== null && this.disable !== undefined) {
      output.writeFieldBegin('disable', Thrift.Type.BOOL, 1);
      output.writeBool(this.disable);
      output.writeFieldEnd();
    }
    output.writeFieldStop();
    output.writeStructEnd();
    return;
  };
  
  crouton_thrift.ReportResponse = function(args) {
    this.commands = null;
    this.timing = null;
    this.errors = null;
    if (args) {
      if (args.commands !== undefined) {
        this.commands = args.commands;
      }
      if (args.timing !== undefined) {
        this.timing = args.timing;
      }
      if (args.errors !== undefined) {
        this.errors = args.errors;
      }
    }
  };
  crouton_thrift.ReportResponse.prototype = {};
  crouton_thrift.ReportResponse.prototype.read = function(input) {
    input.readStructBegin();
    while (true)
    {
      var ret = input.readFieldBegin();
      var fname = ret.fname;
      var ftype = ret.ftype;
      var fid = ret.fid;
      if (ftype == Thrift.Type.STOP) {
        break;
      }
      switch (fid)
      {
        case 1:
        if (ftype == Thrift.Type.LIST) {
          var _size56 = 0;
          var _rtmp360;
          this.commands = [];
          var _etype59 = 0;
          _rtmp360 = input.readListBegin();
          _etype59 = _rtmp360.etype;
          _size56 = _rtmp360.size;
          for (var _i61 = 0; _i61 < _size56; ++_i61)
          {
            var elem62 = null;
            elem62 = new crouton_thrift.Command();
            elem62.read(input);
            this.commands.push(elem62);
          }
          input.readListEnd();
        } else {
          input.skip(ftype);
        }
        break;
        case 2:
        if (ftype == Thrift.Type.STRUCT) {
          this.timing = new crouton_thrift.Timing();
          this.timing.read(input);
        } else {
          input.skip(ftype);
        }
        break;
        case 3:
        if (ftype == Thrift.Type.LIST) {
          var _size63 = 0;
          var _rtmp367;
          this.errors = [];
          var _etype66 = 0;
          _rtmp367 = input.readListBegin();
          _etype66 = _rtmp367.etype;
          _size63 = _rtmp367.size;
          for (var _i68 = 0; _i68 < _size63; ++_i68)
          {
            var elem69 = null;
            elem69 = input.readString().value;
            this.errors.push(elem69);
          }
          input.readListEnd();
        } else {
          input.skip(ftype);
        }
        break;
        default:
          input.skip(ftype);
      }
      input.readFieldEnd();
    }
    input.readStructEnd();
    return;
  };
  
  crouton_thrift.ReportResponse.prototype.write = function(output) {
    output.writeStructBegin('ReportResponse');
    if (this.commands !== null && this.commands !== undefined) {
      output.writeFieldBegin('commands', Thrift.Type.LIST, 1);
      output.writeListBegin(Thrift.Type.STRUCT, this.commands.length);
      for (var iter70 in this.commands)
      {
        if (this.commands.hasOwnProperty(iter70))
        {
          iter70 = this.commands[iter70];
          iter70.write(output);
        }
      }
      output.writeListEnd();
      output.writeFieldEnd();
    }
    if (this.timing !== null && this.timing !== undefined) {
      output.writeFieldBegin('timing', Thrift.Type.STRUCT, 2);
      this.timing.write(output);
      output.writeFieldEnd();
    }
    if (this.errors !== null && this.errors !== undefined) {
      output.writeFieldBegin('errors', Thrift.Type.LIST, 3);
      output.writeListBegin(Thrift.Type.STRING, this.errors.length);
      for (var iter71 in this.errors)
      {
        if (this.errors.hasOwnProperty(iter71))
        {
          iter71 = this.errors[iter71];
          output.writeString(iter71);
        }
      }
      output.writeListEnd();
      output.writeFieldEnd();
    }
    output.writeFieldStop();
    output.writeStructEnd();
    return;
  };
  
  
  //
  // Autogenerated by Thrift Compiler (0.9.2)
  //
  // DO NOT EDIT UNLESS YOU ARE SURE THAT YOU KNOW WHAT YOU ARE DOING
  //
  
  
  //HELPER FUNCTIONS AND STRUCTURES
  
  crouton_thrift.ReportingService_Report_args = function(args) {
    this.auth = null;
    this.request = null;
    if (args) {
      if (args.auth !== undefined) {
        this.auth = args.auth;
      }
      if (args.request !== undefined) {
        this.request = args.request;
      }
    }
  };
  crouton_thrift.ReportingService_Report_args.prototype = {};
  crouton_thrift.ReportingService_Report_args.prototype.read = function(input) {
    input.readStructBegin();
    while (true)
    {
      var ret = input.readFieldBegin();
      var fname = ret.fname;
      var ftype = ret.ftype;
      var fid = ret.fid;
      if (ftype == Thrift.Type.STOP) {
        break;
      }
      switch (fid)
      {
        case 1:
        if (ftype == Thrift.Type.STRUCT) {
          this.auth = new crouton_thrift.Auth();
          this.auth.read(input);
        } else {
          input.skip(ftype);
        }
        break;
        case 2:
        if (ftype == Thrift.Type.STRUCT) {
          this.request = new crouton_thrift.ReportRequest();
          this.request.read(input);
        } else {
          input.skip(ftype);
        }
        break;
        default:
          input.skip(ftype);
      }
      input.readFieldEnd();
    }
    input.readStructEnd();
    return;
  };
  
  crouton_thrift.ReportingService_Report_args.prototype.write = function(output) {
    output.writeStructBegin('ReportingService_Report_args');
    if (this.auth !== null && this.auth !== undefined) {
      output.writeFieldBegin('auth', Thrift.Type.STRUCT, 1);
      this.auth.write(output);
      output.writeFieldEnd();
    }
    if (this.request !== null && this.request !== undefined) {
      output.writeFieldBegin('request', Thrift.Type.STRUCT, 2);
      this.request.write(output);
      output.writeFieldEnd();
    }
    output.writeFieldStop();
    output.writeStructEnd();
    return;
  };
  
  crouton_thrift.ReportingService_Report_result = function(args) {
    this.success = null;
    if (args) {
      if (args.success !== undefined) {
        this.success = args.success;
      }
    }
  };
  crouton_thrift.ReportingService_Report_result.prototype = {};
  crouton_thrift.ReportingService_Report_result.prototype.read = function(input) {
    input.readStructBegin();
    while (true)
    {
      var ret = input.readFieldBegin();
      var fname = ret.fname;
      var ftype = ret.ftype;
      var fid = ret.fid;
      if (ftype == Thrift.Type.STOP) {
        break;
      }
      switch (fid)
      {
        case 0:
        if (ftype == Thrift.Type.STRUCT) {
          this.success = new crouton_thrift.ReportResponse();
          this.success.read(input);
        } else {
          input.skip(ftype);
        }
        break;
        case 0:
          input.skip(ftype);
          break;
        default:
          input.skip(ftype);
      }
      input.readFieldEnd();
    }
    input.readStructEnd();
    return;
  };
  
  crouton_thrift.ReportingService_Report_result.prototype.write = function(output) {
    output.writeStructBegin('ReportingService_Report_result');
    if (this.success !== null && this.success !== undefined) {
      output.writeFieldBegin('success', Thrift.Type.STRUCT, 0);
      this.success.write(output);
      output.writeFieldEnd();
    }
    output.writeFieldStop();
    output.writeStructEnd();
    return;
  };
  
  crouton_thrift.ReportingServiceClient = function(input, output) {
      this.input = input;
      this.output = (!output) ? input : output;
      this.seqid = 0;
  };
  crouton_thrift.ReportingServiceClient.prototype = {};
  crouton_thrift.ReportingServiceClient.prototype.Report = function(auth, request, callback) {
    this.send_Report(auth, request, callback); 
    if (!callback) {
      return this.recv_Report();
    }
  };
  
  crouton_thrift.ReportingServiceClient.prototype.send_Report = function(auth, request, callback) {
    this.output.writeMessageBegin('Report', Thrift.MessageType.CALL, this.seqid);
    var args = new crouton_thrift.ReportingService_Report_args();
    args.auth = auth;
    args.request = request;
    args.write(this.output);
    this.output.writeMessageEnd();
    if (callback) {
      var self = this;
      this.output.getTransport().flush(true, function() {
        var result = null;
        try {
          result = self.recv_Report();
        } catch (e) {
          result = e;
        }
        callback(result);
      });
    } else {
      return this.output.getTransport().flush();
    }
  };
  
  crouton_thrift.ReportingServiceClient.prototype.recv_Report = function() {
    var ret = this.input.readMessageBegin();
    var fname = ret.fname;
    var mtype = ret.mtype;
    var rseqid = ret.rseqid;
    if (mtype == Thrift.MessageType.EXCEPTION) {
      var x = new Thrift.TApplicationException();
      x.read(this.input);
      this.input.readMessageEnd();
      throw x;
    }
    var result = new crouton_thrift.ReportingService_Report_result();
    result.read(this.input);
    this.input.readMessageEnd();
  
    if (null !== result.success) {
      return result.success;
    }
    throw 'Report failed: unknown result';
  };
  
  /*
   * Licensed to the Apache Software Foundation (ASF) under one
   * or more contributor license agreements. See the NOTICE file
   * distributed with this work for additional information
   * regarding copyright ownership. The ASF licenses this file
   * to you under the Apache License, Version 2.0 (the
   * "License"); you may not use this file except in compliance
   * with the License. You may obtain a copy of the License at
   *
   *   http://www.apache.org/licenses/LICENSE-2.0
   *
   * Unless required by applicable law or agreed to in writing,
   * software distributed under the License is distributed on an
   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
   * KIND, either express or implied. See the License for the
   * specific language governing permissions and limitations
   * under the License.
   */
  
  /*jshint evil:true*/
  
  /**
   * The Thrift namespace houses the Apache Thrift JavaScript library 
   * elements providing JavaScript bindings for the Apache Thrift RPC 
   * system. End users will typically only directly make use of the 
   * Transport (TXHRTransport/TWebSocketTransport) and Protocol 
   * (TJSONPRotocol/TBinaryProtocol) constructors.
   * 
   * Object methods beginning with a __ (e.g. __onOpen()) are internal 
   * and should not be called outside of the object's own methods.
   * 
   * This library creates one global object: Thrift
   * Code in this library must never create additional global identifiers,
   * all features must be scoped within the Thrift namespace.
   * @namespace
   * @example
   *     var transport = new Thrift.Transport("http://localhost:8585");
   *     var protocol  = new Thrift.Protocol(transport);
   *     var client = new MyThriftSvcClient(protocol);
   *     var result = client.MyMethod();
   */
  var Thrift = {
      /**
       * Thrift JavaScript library version.
       * @readonly
       * @const {string} Version
       * @memberof Thrift
       */
      Version: '1.0.0-dev',
  
      /**
       * Thrift IDL type string to Id mapping.
       * @readonly
       * @property {number}  STOP   - End of a set of fields.
       * @property {number}  VOID   - No value (only legal for return types).
       * @property {number}  BOOL   - True/False integer.
       * @property {number}  BYTE   - Signed 8 bit integer.
       * @property {number}  I08    - Signed 8 bit integer.     
       * @property {number}  DOUBLE - 64 bit IEEE 854 floating point.
       * @property {number}  I16    - Signed 16 bit integer.
       * @property {number}  I32    - Signed 32 bit integer.
       * @property {number}  I64    - Signed 64 bit integer.
       * @property {number}  STRING - Array of bytes representing a string of characters.
       * @property {number}  UTF7   - Array of bytes representing a string of UTF7 encoded characters.
       * @property {number}  STRUCT - A multifield type.
       * @property {number}  MAP    - A collection type (map/associative-array/dictionary).
       * @property {number}  SET    - A collection type (unordered and without repeated values).
       * @property {number}  LIST   - A collection type (unordered).
       * @property {number}  UTF8   - Array of bytes representing a string of UTF8 encoded characters.
       * @property {number}  UTF16  - Array of bytes representing a string of UTF16 encoded characters.
       */
      Type: {
          'STOP' : 0,
          'VOID' : 1,
          'BOOL' : 2,
          'BYTE' : 3,
          'I08' : 3,
          'DOUBLE' : 4,
          'I16' : 6,
          'I32' : 8,
          'I64' : 10,
          'STRING' : 11,
          'UTF7' : 11,
          'STRUCT' : 12,
          'MAP' : 13,
          'SET' : 14,
          'LIST' : 15,
          'UTF8' : 16,
          'UTF16' : 17
      },
  
      /**
       * Thrift RPC message type string to Id mapping.
       * @readonly
       * @property {number}  CALL      - RPC call sent from client to server.
       * @property {number}  REPLY     - RPC call normal response from server to client.
       * @property {number}  EXCEPTION - RPC call exception response from server to client.
       * @property {number}  ONEWAY    - Oneway RPC call from client to server with no response.
       */
      MessageType: {
          'CALL' : 1,
          'REPLY' : 2,
          'EXCEPTION' : 3,
          'ONEWAY' : 4
      },
  
      /**
       * Utility function returning the count of an object's own properties.
       * @param {object} obj - Object to test.
       * @returns {number} number of object's own properties
       */
      objectLength: function(obj) {
          var length = 0;
          for (var k in obj) {
              if (obj.hasOwnProperty(k)) {
                  length++;
              }
          }
          return length;
      },
  
      /**
       * Utility function to establish prototype inheritance.
       * @see {@link http://javascript.crockford.com/prototypal.html|Prototypal Inheritance}
       * @param {function} constructor - Contstructor function to set as derived.
       * @param {function} superConstructor - Contstructor function to set as base.
       * @param {string} [name] - Type name to set as name property in derived prototype.
       */
      inherits: function(constructor, superConstructor, name) {
        function F() {}
        F.prototype = superConstructor.prototype;
        constructor.prototype = new F();
        constructor.prototype.name = name || "";
      }
  };
  
  /**
   * Initializes a Thrift TException instance.
   * @constructor
   * @augments Error
   * @param {string} message - The TException message (distinct from the Error message).
   * @classdesc TException is the base class for all Thrift exceptions types.
   */
  Thrift.TException = function(message) {
      this.message = message;
  };
  Thrift.inherits(Thrift.TException, Error, 'TException');
  
  /**
   * Returns the message set on the exception.
   * @readonly
   * @returns {string} exception message
   */
  Thrift.TException.prototype.getMessage = function() {
      return this.message;
  };
  
  /**
   * Thrift Application Exception type string to Id mapping.
   * @readonly
   * @property {number}  UNKNOWN                 - Unknown/undefined.
   * @property {number}  UNKNOWN_METHOD          - Client attempted to call a method unknown to the server.
   * @property {number}  INVALID_MESSAGE_TYPE    - Client passed an unknown/unsupported MessageType.
   * @property {number}  WRONG_METHOD_NAME       - Unused.
   * @property {number}  BAD_SEQUENCE_ID         - Unused in Thrift RPC, used to flag proprietary sequence number errors.
   * @property {number}  MISSING_RESULT          - Raised by a server processor if a handler fails to supply the required return result.
   * @property {number}  INTERNAL_ERROR          - Something bad happened.
   * @property {number}  PROTOCOL_ERROR          - The protocol layer failed to serialize or deserialize data.
   * @property {number}  INVALID_TRANSFORM       - Unused.
   * @property {number}  INVALID_PROTOCOL        - The protocol (or version) is not supported.
   * @property {number}  UNSUPPORTED_CLIENT_TYPE - Unused.
   */
  Thrift.TApplicationExceptionType = {
      'UNKNOWN' : 0,
      'UNKNOWN_METHOD' : 1,
      'INVALID_MESSAGE_TYPE' : 2,
      'WRONG_METHOD_NAME' : 3,
      'BAD_SEQUENCE_ID' : 4,
      'MISSING_RESULT' : 5,
      'INTERNAL_ERROR' : 6,
      'PROTOCOL_ERROR' : 7,
      'INVALID_TRANSFORM' : 8,
      'INVALID_PROTOCOL' : 9,
      'UNSUPPORTED_CLIENT_TYPE' : 10
  };
  
  /**
   * Initializes a Thrift TApplicationException instance.
   * @constructor
   * @augments Thrift.TException
   * @param {string} message - The TApplicationException message (distinct from the Error message).
   * @param {Thrift.TApplicationExceptionType} [code] - The TApplicationExceptionType code.
   * @classdesc TApplicationException is the exception class used to propagate exceptions from an RPC server back to a calling client.
  */
  Thrift.TApplicationException = function(message, code) {
      this.message = message;
      this.code = typeof code === "number" ? code : 0;
  };
  Thrift.inherits(Thrift.TApplicationException, Thrift.TException, 'TApplicationException');
  
  /**
   * Read a TApplicationException from the supplied protocol.
   * @param {object} input - The input protocol to read from.
   */
  Thrift.TApplicationException.prototype.read = function(input) {
      while (1) {
          var ret = input.readFieldBegin();
  
          if (ret.ftype == Thrift.Type.STOP) {
              break;
          }
  
          var fid = ret.fid;
  
          switch (fid) {
              case 1:
                  if (ret.ftype == Thrift.Type.STRING) {
                      ret = input.readString();
                      this.message = ret.value;
                  } else {
                      ret = input.skip(ret.ftype);
                  }
                  break;
              case 2:
                  if (ret.ftype == Thrift.Type.I32) {
                      ret = input.readI32();
                      this.code = ret.value;
                  } else {
                      ret = input.skip(ret.ftype);
                  }
                  break;
             default:
                  ret = input.skip(ret.ftype);
                  break;
          }
  
          input.readFieldEnd();
      }
  
      input.readStructEnd();
  };
  
  /**
   * Wite a TApplicationException to the supplied protocol.
   * @param {object} output - The output protocol to write to.
   */
  Thrift.TApplicationException.prototype.write = function(output) {
      output.writeStructBegin('TApplicationException');
  
      if (this.message) {
          output.writeFieldBegin('message', Thrift.Type.STRING, 1);
          output.writeString(this.getMessage());
          output.writeFieldEnd();
      }
  
      if (this.code) {
          output.writeFieldBegin('type', Thrift.Type.I32, 2);
          output.writeI32(this.code);
          output.writeFieldEnd();
      }
  
      output.writeFieldStop();
      output.writeStructEnd();
  };
  
  /**
   * Returns the application exception code set on the exception.
   * @readonly
   * @returns {Thrift.TApplicationExceptionType} exception code
   */
  Thrift.TApplicationException.prototype.getCode = function() {
      return this.code;
  };
  
  /**
   * Constructor Function for the XHR transport.
   * If you do not specify a url then you must handle XHR operations on
   * your own. This type can also be constructed using the Transport alias
   * for backward compatibility.
   * @constructor
   * @param {string} [url] - The URL to connect to.
   * @classdesc The Apache Thrift Transport layer performs byte level I/O 
   * between RPC clients and servers. The JavaScript TXHRTransport object 
   * uses Http[s]/XHR. Target servers must implement the http[s] transport
   * (see: node.js example server_http.js).
   * @example
   *     var transport = new Thrift.TXHRTransport("http://localhost:8585");
   */
  Thrift.Transport = Thrift.TXHRTransport = function(url, options) {
      this.url = url;
      this.wpos = 0;
      this.rpos = 0;
      this.useCORS = (options && options.useCORS);
      this.send_buf = '';
      this.recv_buf = '';
  };
  
  Thrift.TXHRTransport.prototype = {
      /**
       * Gets the browser specific XmlHttpRequest Object.
       * @returns {object} the browser XHR interface object
       */
      getXmlHttpRequestObject: function() {
          try { return new XMLHttpRequest(); } catch (e1) { }
          try { return new ActiveXObject('Msxml2.XMLHTTP'); } catch (e2) { }
          try { return new ActiveXObject('Microsoft.XMLHTTP'); } catch (e3) { }
  
          throw "Your browser doesn't support XHR.";
      },
  
      /**
       * Sends the current XRH request if the transport was created with a URL 
       * and the async parameter is false. If the transport was not created with
       * a URL, or the async parameter is True and no callback is provided, or 
       * the URL is an empty string, the current send buffer is returned.
       * @param {object} async - If true the current send buffer is returned.
       * @param {object} callback - Optional async completion callback 
       * @returns {undefined|string} Nothing or the current send buffer.
       * @throws {string} If XHR fails.
       */
      flush: function(async, callback) {
          var self = this;
          if ((async && !callback) || this.url === undefined || this.url === '') {
              return this.send_buf;
          }
  
          var xreq = this.getXmlHttpRequestObject();
  
          if (xreq.overrideMimeType) {
              xreq.overrideMimeType('application/json');
          }
  
          if (callback) {
              //Ignore XHR callbacks until the data arrives, then call the
              //  client's callback
              xreq.onreadystatechange = 
                (function() {
                  var clientCallback = callback;    
                  return function() {
                    if (this.readyState == 4 && this.status == 200) {
                      self.setRecvBuffer(this.responseText);
                      clientCallback();
                    }
                  };
                }());
          }
  
          xreq.open('POST', this.url, !!async);
          xreq.send(this.send_buf);
          if (async && callback) {
              return;
          }
  
          if (xreq.readyState != 4) {
              throw 'encountered an unknown ajax ready state: ' + xreq.readyState;
          }
  
          if (xreq.status != 200) {
              throw 'encountered a unknown request status: ' + xreq.status;
          }
  
          this.recv_buf = xreq.responseText;
          this.recv_buf_sz = this.recv_buf.length;
          this.wpos = this.recv_buf.length;
          this.rpos = 0;
      },
  
      /**
       * Creates a jQuery XHR object to be used for a Thrift server call.
       * @param {object} client - The Thrift Service client object generated by the IDL compiler.
       * @param {object} postData - The message to send to the server.
       * @param {function} args - The original call arguments with the success call back at the end.
       * @param {function} recv_method - The Thrift Service Client receive method for the call.
       * @returns {object} A new jQuery XHR object.
       * @throws {string} If the jQuery version is prior to 1.5 or if jQuery is not found.
       */
      jqRequest: function(client, postData, args, recv_method) {
          if (typeof jQuery === 'undefined' ||
              typeof jQuery.Deferred === 'undefined') {
              throw 'Thrift.js requires jQuery 1.5+ to use asynchronous requests';
          }
  
          var thriftTransport = this;
  
          var jqXHR = jQuery.ajax({
              url: this.url,
              data: postData,
              type: 'POST',
              cache: false,
              contentType: 'application/json',
              dataType: 'text thrift',
              converters: {
                  'text thrift' : function(responseData) {
                      thriftTransport.setRecvBuffer(responseData);
                      var value = recv_method.call(client);
                      return value;
                  }
              },
              context: client,
              success: jQuery.makeArray(args).pop()
          });
  
          return jqXHR;
      },
  
      /**
       * Sets the buffer to provide the protocol when deserializing.
       * @param {string} buf - The buffer to supply the protocol.
       */
      setRecvBuffer: function(buf) {
          this.recv_buf = buf;
          this.recv_buf_sz = this.recv_buf.length;
          this.wpos = this.recv_buf.length;
          this.rpos = 0;
      },
  
      /**
       * Returns true if the transport is open, XHR always returns true.
       * @readonly
       * @returns {boolean} Always True.
       */    
      isOpen: function() {
          return true;
      },
  
      /**
       * Opens the transport connection, with XHR this is a nop.
       */    
      open: function() {},
  
      /**
       * Closes the transport connection, with XHR this is a nop.
       */    
      close: function() {},
  
      /**
       * Returns the specified number of characters from the response
       * buffer.
       * @param {number} len - The number of characters to return.
       * @returns {string} Characters sent by the server.
       */
      read: function(len) {
          var avail = this.wpos - this.rpos;
  
          if (avail === 0) {
              return '';
          }
  
          var give = len;
  
          if (avail < len) {
              give = avail;
          }
  
          var ret = this.read_buf.substr(this.rpos, give);
          this.rpos += give;
  
          //clear buf when complete?
          return ret;
      },
  
      /**
       * Returns the entire response buffer.
       * @returns {string} Characters sent by the server.
       */
      readAll: function() {
          return this.recv_buf;
      },
  
      /**
       * Sets the send buffer to buf.
       * @param {string} buf - The buffer to send.
       */    
      write: function(buf) {
          this.send_buf = buf;
      },
  
      /**
       * Returns the send buffer.
       * @readonly
       * @returns {string} The send buffer.
       */ 
      getSendBuffer: function() {
          return this.send_buf;
      }
  
  };
  
  
  /**
   * Constructor Function for the WebSocket transport.
   * @constructor
   * @param {string} [url] - The URL to connect to.
   * @classdesc The Apache Thrift Transport layer performs byte level I/O 
   * between RPC clients and servers. The JavaScript TWebSocketTransport object 
   * uses the WebSocket protocol. Target servers must implement WebSocket.
   * (see: node.js example server_http.js).
   * @example
   *   var transport = new Thrift.TWebSocketTransport("http://localhost:8585");
   */
  Thrift.TWebSocketTransport = function(url) {
      this.__reset(url);
  };
  
  Thrift.TWebSocketTransport.prototype = {
      __reset: function(url) {
        this.url = url;             //Where to connect
        this.socket = null;         //The web socket
        this.callbacks = [];        //Pending callbacks
        this.send_pending = [];     //Buffers/Callback pairs waiting to be sent
        this.send_buf = '';         //Outbound data, immutable until sent
        this.recv_buf = '';         //Inbound data
        this.rb_wpos = 0;           //Network write position in receive buffer
        this.rb_rpos = 0;           //Client read position in receive buffer
      },
  
      /**
       * Sends the current WS request and registers callback. The async 
       * parameter is ignored (WS flush is always async) and the callback 
       * function parameter is required.
       * @param {object} async - Ignored.
       * @param {object} callback - The client completion callback.
       * @returns {undefined|string} Nothing (undefined) 
       */
      flush: function(async, callback) {
        var self = this;
        if (this.isOpen()) {
          //Send data and register a callback to invoke the client callback
          this.socket.send(this.send_buf); 
          this.callbacks.push((function() {
            var clientCallback = callback;    
            return function(msg) {
              self.setRecvBuffer(msg);
              clientCallback();
            };
          }()));
        } else {
          //Queue the send to go out __onOpen
          this.send_pending.push({
            buf: this.send_buf,
            cb:  callback
          });
        }
      },
  
      __onOpen: function() { 
         var self = this;
         if (this.send_pending.length > 0) {
            //If the user made calls before the connection was fully 
            //open, send them now
            this.send_pending.forEach(function(elem) {
               this.socket.send(elem.buf);
               this.callbacks.push((function() {
                 var clientCallback = elem.cb;    
                 return function(msg) {
                    self.setRecvBuffer(msg);
                    clientCallback();
                 };
               }()));
            });
            this.send_pending = [];
         }
      },
      
      __onClose: function(evt) { 
        this.__reset(this.url);
      },
       
      __onMessage: function(evt) {
        if (this.callbacks.length) {
          this.callbacks.shift()(evt.data);
        }
      },
       
      __onError: function(evt) { 
        console.log("Thrift WebSocket Error: " + evt.toString());
        this.socket.close();
      },
  
      /**
       * Sets the buffer to use when receiving server responses.
       * @param {string} buf - The buffer to receive server responses.
       */
      setRecvBuffer: function(buf) {
          this.recv_buf = buf;
          this.recv_buf_sz = this.recv_buf.length;
          this.wpos = this.recv_buf.length;
          this.rpos = 0;
      },
  
      /**
       * Returns true if the transport is open
       * @readonly
       * @returns {boolean} 
       */    
      isOpen: function() {
          return this.socket && this.socket.readyState == this.socket.OPEN;
      },
  
      /**
       * Opens the transport connection
       */    
      open: function() {
        //If OPEN/CONNECTING/CLOSING ignore additional opens
        if (this.socket && this.socket.readyState != this.socket.CLOSED) {
          return;
        }
        //If there is no socket or the socket is closed:
        this.socket = new WebSocket(this.url);
        this.socket.onopen = this.__onOpen.bind(this); 
        this.socket.onmessage = this.__onMessage.bind(this); 
        this.socket.onerror = this.__onError.bind(this); 
        this.socket.onclose = this.__onClose.bind(this); 
      },
  
      /**
       * Closes the transport connection
       */    
      close: function() {
        this.socket.close();
      },
  
      /**
       * Returns the specified number of characters from the response
       * buffer.
       * @param {number} len - The number of characters to return.
       * @returns {string} Characters sent by the server.
       */
      read: function(len) {
          var avail = this.wpos - this.rpos;
  
          if (avail === 0) {
              return '';
          }
  
          var give = len;
  
          if (avail < len) {
              give = avail;
          }
  
          var ret = this.read_buf.substr(this.rpos, give);
          this.rpos += give;
  
          //clear buf when complete?
          return ret;
      },
  
      /**
       * Returns the entire response buffer.
       * @returns {string} Characters sent by the server.
       */
      readAll: function() {
          return this.recv_buf;
      },
  
      /**
       * Sets the send buffer to buf.
       * @param {string} buf - The buffer to send.
       */    
      write: function(buf) {
          this.send_buf = buf;
      },
  
      /**
       * Returns the send buffer.
       * @readonly
       * @returns {string} The send buffer.
       */ 
      getSendBuffer: function() {
          return this.send_buf;
      }
  
  };
  
  /**
   * Initializes a Thrift JSON protocol instance.
   * @constructor
   * @param {Thrift.Transport} transport - The transport to serialize to/from.
   * @classdesc Apache Thrift Protocols perform serialization which enables cross 
   * language RPC. The Protocol type is the JavaScript browser implementation 
   * of the Apache Thrift TJSONProtocol.
   * @example
   *     var protocol  = new Thrift.Protocol(transport);
   */
  Thrift.TJSONProtocol = Thrift.Protocol = function(transport) {
      this.tstack = [];
      this.tpos = [];
      this.transport = transport;
  };
  
  /**
   * Thrift IDL type Id to string mapping.
   * @readonly
   * @see {@link Thrift.Type}
   */
  Thrift.Protocol.Type = {};
  Thrift.Protocol.Type[Thrift.Type.BOOL] = '"tf"';
  Thrift.Protocol.Type[Thrift.Type.BYTE] = '"i8"';
  Thrift.Protocol.Type[Thrift.Type.I16] = '"i16"';
  Thrift.Protocol.Type[Thrift.Type.I32] = '"i32"';
  Thrift.Protocol.Type[Thrift.Type.I64] = '"i64"';
  Thrift.Protocol.Type[Thrift.Type.DOUBLE] = '"dbl"';
  Thrift.Protocol.Type[Thrift.Type.STRUCT] = '"rec"';
  Thrift.Protocol.Type[Thrift.Type.STRING] = '"str"';
  Thrift.Protocol.Type[Thrift.Type.MAP] = '"map"';
  Thrift.Protocol.Type[Thrift.Type.LIST] = '"lst"';
  Thrift.Protocol.Type[Thrift.Type.SET] = '"set"';
  
  /**
   * Thrift IDL type string to Id mapping.
   * @readonly
   * @see {@link Thrift.Type}
   */
  Thrift.Protocol.RType = {};
  Thrift.Protocol.RType.tf = Thrift.Type.BOOL;
  Thrift.Protocol.RType.i8 = Thrift.Type.BYTE;
  Thrift.Protocol.RType.i16 = Thrift.Type.I16;
  Thrift.Protocol.RType.i32 = Thrift.Type.I32;
  Thrift.Protocol.RType.i64 = Thrift.Type.I64;
  Thrift.Protocol.RType.dbl = Thrift.Type.DOUBLE;
  Thrift.Protocol.RType.rec = Thrift.Type.STRUCT;
  Thrift.Protocol.RType.str = Thrift.Type.STRING;
  Thrift.Protocol.RType.map = Thrift.Type.MAP;
  Thrift.Protocol.RType.lst = Thrift.Type.LIST;
  Thrift.Protocol.RType.set = Thrift.Type.SET;
  
  /**
   * The TJSONProtocol version number.
   * @readonly
   * @const {number} Version
   * @memberof Thrift.Protocol
   */
   Thrift.Protocol.Version = 1;
  
  Thrift.Protocol.prototype = {
      /**
       * Returns the underlying transport.
       * @readonly
       * @returns {Thrift.Transport} The underlying transport.
       */ 
      getTransport: function() {
          return this.transport;
      },
  
      /**
       * Serializes the beginning of a Thrift RPC message.
       * @param {string} name - The service method to call.
       * @param {Thrift.MessageType} messageType - The type of method call.
       * @param {number} seqid - The sequence number of this call (always 0 in Apache Thrift).
       */
      writeMessageBegin: function(name, messageType, seqid) {
          this.tstack = [];
          this.tpos = [];
  
          this.tstack.push([Thrift.Protocol.Version, '"' +
              name + '"', messageType, seqid]);
      },
  
      /**
       * Serializes the end of a Thrift RPC message.
       */
      writeMessageEnd: function() {
          var obj = this.tstack.pop();
  
          this.wobj = this.tstack.pop();
          this.wobj.push(obj);
  
          this.wbuf = '[' + this.wobj.join(',') + ']';
  
          this.transport.write(this.wbuf);
       },
  
  
      /**
       * Serializes the beginning of a struct.
       * @param {string} name - The name of the struct.
       */
      writeStructBegin: function(name) {
          this.tpos.push(this.tstack.length);
          this.tstack.push({});
      },
  
      /**
       * Serializes the end of a struct.
       */
      writeStructEnd: function() {
  
          var p = this.tpos.pop();
          var struct = this.tstack[p];
          var str = '{';
          var first = true;
          for (var key in struct) {
              if (first) {
                  first = false;
              } else {
                  str += ',';
              }
  
              str += key + ':' + struct[key];
          }
  
          str += '}';
          this.tstack[p] = str;
      },
  
      /**
       * Serializes the beginning of a struct field.
       * @param {string} name - The name of the field.
       * @param {Thrift.Protocol.Type} fieldType - The data type of the field.
       * @param {number} fieldId - The field's unique identifier.
       */
      writeFieldBegin: function(name, fieldType, fieldId) {
          this.tpos.push(this.tstack.length);
          this.tstack.push({ 'fieldId': '"' +
              fieldId + '"', 'fieldType': Thrift.Protocol.Type[fieldType]
          });
  
      },
  
      /**
       * Serializes the end of a field.
       */
      writeFieldEnd: function() {
          var value = this.tstack.pop();
          var fieldInfo = this.tstack.pop();
  
          this.tstack[this.tstack.length - 1][fieldInfo.fieldId] = '{' +
              fieldInfo.fieldType + ':' + value + '}';
          this.tpos.pop();
      },
  
      /**
       * Serializes the end of the set of fields for a struct.
       */
      writeFieldStop: function() {
          //na
      },
  
      /**
       * Serializes the beginning of a map collection.
       * @param {Thrift.Type} keyType - The data type of the key.
       * @param {Thrift.Type} valType - The data type of the value.
       * @param {number} [size] - The number of elements in the map (ignored).
       */
      writeMapBegin: function(keyType, valType, size) {
          this.tpos.push(this.tstack.length);
          this.tstack.push([Thrift.Protocol.Type[keyType],
              Thrift.Protocol.Type[valType], 0]);
      },
  
      /**
       * Serializes the end of a map.
       */
      writeMapEnd: function() {
          var p = this.tpos.pop();
  
          if (p == this.tstack.length) {
              return;
          }
  
          if ((this.tstack.length - p - 1) % 2 !== 0) {
              this.tstack.push('');
          }
  
          var size = (this.tstack.length - p - 1) / 2;
  
          this.tstack[p][this.tstack[p].length - 1] = size;
  
          var map = '}';
          var first = true;
          while (this.tstack.length > p + 1) {
              var v = this.tstack.pop();
              var k = this.tstack.pop();
              if (first) {
                  first = false;
              } else {
                  map = ',' + map;
              }
  
              if (! isNaN(k)) { k = '"' + k + '"'; } //json "keys" need to be strings
              map = k + ':' + v + map;
          }
          map = '{' + map;
  
          this.tstack[p].push(map);
          this.tstack[p] = '[' + this.tstack[p].join(',') + ']';
      },
  
      /**
       * Serializes the beginning of a list collection.
       * @param {Thrift.Type} elemType - The data type of the elements.
       * @param {number} size - The number of elements in the list.
       */
      writeListBegin: function(elemType, size) {
          this.tpos.push(this.tstack.length);
          this.tstack.push([Thrift.Protocol.Type[elemType], size]);
      },
  
      /**
       * Serializes the end of a list.
       */
      writeListEnd: function() {
          var p = this.tpos.pop();
  
          while (this.tstack.length > p + 1) {
              var tmpVal = this.tstack[p + 1];
              this.tstack.splice(p + 1, 1);
              this.tstack[p].push(tmpVal);
          }
  
          this.tstack[p] = '[' + this.tstack[p].join(',') + ']';
      },
  
      /**
       * Serializes the beginning of a set collection.
       * @param {Thrift.Type} elemType - The data type of the elements.
       * @param {number} size - The number of elements in the list.
       */
      writeSetBegin: function(elemType, size) {
          this.tpos.push(this.tstack.length);
          this.tstack.push([Thrift.Protocol.Type[elemType], size]);
      },
  
      /**
       * Serializes the end of a set.
       */
      writeSetEnd: function() {
          var p = this.tpos.pop();
  
          while (this.tstack.length > p + 1) {
              var tmpVal = this.tstack[p + 1];
              this.tstack.splice(p + 1, 1);
              this.tstack[p].push(tmpVal);
          }
  
          this.tstack[p] = '[' + this.tstack[p].join(',') + ']';
      },
  
      /** Serializes a boolean */
      writeBool: function(value) {
          this.tstack.push(value ? 1 : 0);
      },
  
      /** Serializes a number */
      writeByte: function(i8) {
          this.tstack.push(i8);
      },
  
      /** Serializes a number */
      writeI16: function(i16) {
          this.tstack.push(i16);
      },
  
      /** Serializes a number */
      writeI32: function(i32) {
          this.tstack.push(i32);
      },
  
      /** Serializes a number */
      writeI64: function(i64) {
          this.tstack.push(i64);
      },
  
      /** Serializes a number */
      writeDouble: function(dbl) {
          this.tstack.push(dbl);
      },
  
      /** Serializes a string */
      writeString: function(str) {
          // We do not encode uri components for wire transfer:
          if (str === null) {
              this.tstack.push(null);
          } else {
              // concat may be slower than building a byte buffer
              var escapedString = '';
              for (var i = 0; i < str.length; i++) {
                  var ch = str.charAt(i);      // a single double quote: "
                  if (ch === '\"') {
                      escapedString += '\\\"'; // write out as: \"
                  } else if (ch === '\\') {    // a single backslash
                      escapedString += '\\\\'; // write out as double backslash 
                  } else if (ch === '\b') {    // a single backspace: invisible
                      escapedString += '\\b';  // write out as: \b"
                  } else if (ch === '\f') {    // a single formfeed: invisible
                      escapedString += '\\f';  // write out as: \f"
                  } else if (ch === '\n') {    // a single newline: invisible
                      escapedString += '\\n';  // write out as: \n"
                  } else if (ch === '\r') {    // a single return: invisible
                      escapedString += '\\r';  // write out as: \r"
                  } else if (ch === '\t') {    // a single tab: invisible
                      escapedString += '\\t';  // write out as: \t"
                  } else {
                      escapedString += ch;     // Else it need not be escaped
                  }
              }
              this.tstack.push('"' + escapedString + '"');
          }
      },
  
      /** Serializes a string */
      writeBinary: function(str) {
          this.writeString(str);
      },
  
      /**
         @class
         @name AnonReadMessageBeginReturn
         @property {string} fname - The name of the service method.
         @property {Thrift.MessageType} mtype - The type of message call.
         @property {number} rseqid - The sequence number of the message (0 in Thrift RPC).
       */
      /** 
       * Deserializes the beginning of a message. 
       * @returns {AnonReadMessageBeginReturn}
       */
      readMessageBegin: function() {
          this.rstack = [];
          this.rpos = [];
  
          if (typeof JSON !== 'undefined' && typeof JSON.parse === 'function') {
              this.robj = JSON.parse(this.transport.readAll());
          } else if (typeof jQuery !== 'undefined') {
              this.robj = jQuery.parseJSON(this.transport.readAll());
          } else {
              this.robj = eval(this.transport.readAll());
          }
  
          var r = {};
          var version = this.robj.shift();
  
          if (version != Thrift.Protocol.Version) {
              throw 'Wrong thrift protocol version: ' + version;
          }
  
          r.fname = this.robj.shift();
          r.mtype = this.robj.shift();
          r.rseqid = this.robj.shift();
  
  
          //get to the main obj
          this.rstack.push(this.robj.shift());
  
          return r;
      },
  
      /** Deserializes the end of a message. */
      readMessageEnd: function() {
      },
  
      /** 
       * Deserializes the beginning of a struct. 
       * @param {string} [name] - The name of the struct (ignored)
       * @returns {object} - An object with an empty string fname property
       */    
      readStructBegin: function(name) {
          var r = {};
          r.fname = '';
  
          //incase this is an array of structs
          if (this.rstack[this.rstack.length - 1] instanceof Array) {
              this.rstack.push(this.rstack[this.rstack.length - 1].shift());
          }
  
          return r;
      },
  
      /** Deserializes the end of a struct. */
      readStructEnd: function() {
          if (this.rstack[this.rstack.length - 2] instanceof Array) {
              this.rstack.pop();
          }
      },
  
      /**
         @class
         @name AnonReadFieldBeginReturn
         @property {string} fname - The name of the field (always '').
         @property {Thrift.Type} ftype - The data type of the field.
         @property {number} fid - The unique identifier of the field.
       */
      /** 
       * Deserializes the beginning of a field. 
       * @returns {AnonReadFieldBeginReturn}
       */
      readFieldBegin: function() {
          var r = {};
  
          var fid = -1;
          var ftype = Thrift.Type.STOP;
  
          //get a fieldId
          for (var f in (this.rstack[this.rstack.length - 1])) {
              if (f === null) {
                continue;
              }
  
              fid = parseInt(f, 10);
              this.rpos.push(this.rstack.length);
  
              var field = this.rstack[this.rstack.length - 1][fid];
  
              //remove so we don't see it again
              delete this.rstack[this.rstack.length - 1][fid];
  
              this.rstack.push(field);
  
              break;
          }
  
          if (fid != -1) {
  
              //should only be 1 of these but this is the only
              //way to match a key
              for (var i in (this.rstack[this.rstack.length - 1])) {
                  if (Thrift.Protocol.RType[i] === null) {
                      continue;
                  }
  
                  ftype = Thrift.Protocol.RType[i];
                  this.rstack[this.rstack.length - 1] =
                      this.rstack[this.rstack.length - 1][i];
              }
          }
  
          r.fname = '';
          r.ftype = ftype;
          r.fid = fid;
  
          return r;
      },
  
      /** Deserializes the end of a field. */
      readFieldEnd: function() {
          var pos = this.rpos.pop();
  
          //get back to the right place in the stack
          while (this.rstack.length > pos) {
              this.rstack.pop();
          }
  
      },
  
      /**
         @class
         @name AnonReadMapBeginReturn
         @property {Thrift.Type} ktype - The data type of the key.
         @property {Thrift.Type} vtype - The data type of the value.
         @property {number} size - The number of elements in the map.
       */
      /** 
       * Deserializes the beginning of a map. 
       * @returns {AnonReadMapBeginReturn}
       */
      readMapBegin: function() {
          var map = this.rstack.pop();
          var first = map.shift();
          if (first instanceof Array) {
            this.rstack.push(map);
            map = first;
            first = map.shift();
          }
  
          var r = {};
          r.ktype = Thrift.Protocol.RType[first];
          r.vtype = Thrift.Protocol.RType[map.shift()];
          r.size = map.shift();
  
  
          this.rpos.push(this.rstack.length);
          this.rstack.push(map.shift());
  
          return r;
      },
  
      /** Deserializes the end of a map. */
      readMapEnd: function() {
          this.readFieldEnd();
      },
  
      /**
         @class
         @name AnonReadColBeginReturn
         @property {Thrift.Type} etype - The data type of the element.
         @property {number} size - The number of elements in the collection.
       */
      /** 
       * Deserializes the beginning of a list. 
       * @returns {AnonReadColBeginReturn}
       */
      readListBegin: function() {
          var list = this.rstack[this.rstack.length - 1];
  
          var r = {};
          r.etype = Thrift.Protocol.RType[list.shift()];
          r.size = list.shift();
  
          this.rpos.push(this.rstack.length);
          this.rstack.push(list);
  
          return r;
      },
  
      /** Deserializes the end of a list. */
      readListEnd: function() {
          this.readFieldEnd();
      },
  
      /** 
       * Deserializes the beginning of a set. 
       * @returns {AnonReadColBeginReturn}
       */
      readSetBegin: function(elemType, size) {
          return this.readListBegin(elemType, size);
      },
  
      /** Deserializes the end of a set. */
      readSetEnd: function() {
          return this.readListEnd();
      },
  
      /** Returns an object with a value property set to 
       *  False unless the next number in the protocol buffer 
       *  is 1, in which case the value property is True */
      readBool: function() {
          var r = this.readI32();
  
          if (r !== null && r.value == '1') {
              r.value = true;
          } else {
              r.value = false;
          }
  
          return r;
      },
  
      /** Returns the an object with a value property set to the 
          next value found in the protocol buffer */
      readByte: function() {
          return this.readI32();
      },
  
      /** Returns the an object with a value property set to the 
          next value found in the protocol buffer */
      readI16: function() {
          return this.readI32();
      },
  
      /** Returns the an object with a value property set to the 
          next value found in the protocol buffer */
      readI32: function(f) {
          if (f === undefined) {
              f = this.rstack[this.rstack.length - 1];
          }
  
          var r = {};
  
          if (f instanceof Array) {
              if (f.length === 0) {
                  r.value = undefined;
              } else {
                  r.value = f.shift();
              }
          } else if (f instanceof Object) {
             for (var i in f) {
                  if (i === null) {
                    continue;
                  }
                  this.rstack.push(f[i]);
                  delete f[i];
  
                  r.value = i;
                  break;
             }
          } else {
              r.value = f;
              this.rstack.pop();
          }
  
          return r;
      },
  
      /** Returns the an object with a value property set to the 
          next value found in the protocol buffer */
      readI64: function() {
          return this.readI32();
      },
  
      /** Returns the an object with a value property set to the 
          next value found in the protocol buffer */
      readDouble: function() {
          return this.readI32();
      },
  
      /** Returns the an object with a value property set to the 
          next value found in the protocol buffer */
      readString: function() {
          var r = this.readI32();
          return r;
      },
  
      /** Returns the an object with a value property set to the 
          next value found in the protocol buffer */
      readBinary: function() {
          return this.readString();
      },
  
      /** 
       * Method to arbitrarily skip over data */
      skip: function(type) {
          var ret, i;
          switch (type) {
              case Thrift.Type.STOP:
                  return null;
  
              case Thrift.Type.BOOL:
                  return this.readBool();
  
              case Thrift.Type.BYTE:
                  return this.readByte();
  
              case Thrift.Type.I16:
                  return this.readI16();
  
              case Thrift.Type.I32:
                  return this.readI32();
  
              case Thrift.Type.I64:
                  return this.readI64();
  
              case Thrift.Type.DOUBLE:
                  return this.readDouble();
  
              case Thrift.Type.STRING:
                  return this.readString();
  
              case Thrift.Type.STRUCT:
                  this.readStructBegin();
                  while (true) {
                      ret = this.readFieldBegin();
                      if (ret.ftype == Thrift.Type.STOP) {
                          break;
                      }
                      this.skip(ret.ftype);
                      this.readFieldEnd();
                  }
                  this.readStructEnd();
                  return null;
  
              case Thrift.Type.MAP:
                  ret = this.readMapBegin();
                  for (i = 0; i < ret.size; i++) {
                      if (i > 0) {
                          if (this.rstack.length > this.rpos[this.rpos.length - 1] + 1) {
                              this.rstack.pop();
                          }
                      }
                      this.skip(ret.ktype);
                      this.skip(ret.vtype);
                  }
                  this.readMapEnd();
                  return null;
  
              case Thrift.Type.SET:
                  ret = this.readSetBegin();
                  for (i = 0; i < ret.size; i++) {
                      this.skip(ret.etype);
                  }
                  this.readSetEnd();
                  return null;
  
              case Thrift.Type.LIST:
                  ret = this.readListBegin();
                  for (i = 0; i < ret.size; i++) {
                      this.skip(ret.etype);
                  }
                  this.readListEnd();
                  return null;
          }
      }
  };
  
  
  /**
   * Initializes a MutilplexProtocol Implementation as a Wrapper for Thrift.Protocol
   * @constructor
   */
  Thrift.MultiplexProtocol = function (srvName, trans, strictRead, strictWrite) {
      Thrift.Protocol.call(this, trans, strictRead, strictWrite);
      this.serviceName = srvName;
  };
  Thrift.inherits(Thrift.MultiplexProtocol, Thrift.Protocol, 'multiplexProtocol');
  
  /** Override writeMessageBegin method of prototype*/
  Thrift.MultiplexProtocol.prototype.writeMessageBegin = function (name, type, seqid) {
  
      if (type === Thrift.MessageType.CALL || type === Thrift.MessageType.ONEWAY) {
          Thrift.Protocol.prototype.writeMessageBegin.call(this, this.serviceName + ":" + name, type, seqid);
      } else {
          Thrift.Protocol.prototype.writeMessageBegin.call(this, name, type, seqid);
      }
  };
  
  Thrift.Multiplexer = function () {
      this.seqid = 0;
  };
  
  /** Instantiates a multiplexed client for a specific service
   * @constructor
   * @param {String} serviceName - The transport to serialize to/from.
   * @param {Thrift.ServiceClient} SCl - The Service Client Class
   * @param {Thrift.Transport} transport - Thrift.Transport instance which provides remote host:port
   * @example
   *    var mp = new Thrift.Multiplexer();
   *    var transport = new Thrift.Transport("http://localhost:9090/foo.thrift");
   *    var protocol = new Thrift.Protocol(transport);
   *    var client = mp.createClient('AuthService', AuthServiceClient, transport);
  */
  Thrift.Multiplexer.prototype.createClient = function (serviceName, SCl, transport) {
      if (SCl.Client) {
          SCl = SCl.Client;
      }
      var self = this;
      SCl.prototype.new_seqid = function () {
          self.seqid += 1;
          return self.seqid;
      };
      var client = new SCl(new Thrift.MultiplexProtocol(serviceName, transport));
  
      return client;
  };
  
  
  
  
  // Override TXHRTransport.flush
  //
  // The 0.9.2 transport flush() method implementation only calls the callback on
  // status 200 and never invokes the client callback on HTTP status errors. This
  // replaces the implementation with one that always calls the callback,
  // including on errors and exceptions.
  
  Thrift.TXHRTransport.prototype.flush = function(async, callback) {
      var self = this;
      if ((async && !callback) || this.url === undefined || this.url === '') {
          return this.send_buf;
      }
  
      var xreq = this.getXmlHttpRequestObject();
  
      if (xreq.overrideMimeType) {
          xreq.overrideMimeType('application/json');
      }
  
      if (callback) {
          //Ignore XHR callbacks until the data arrives, then call the
          //  client's callback
          //========
          // BEGIN CODE PATCH
          //========
          /*
            xreq.onreadystatechange =
            (function() {
              var clientCallback = callback;
              return function() {
                if (this.readyState == 4 && this.status == 200) {
                  self.setRecvBuffer(this.responseText);
                  clientCallback();
                }
              };
            }());
          */
          //========
          // MODIFIED CODE
          //========
          xreq.onreadystatechange = function() {
              if (this.readyState == 4) {
                  //
                  // The incoming callback doesn't actually take an error object
                  // (another limitation of the thrift code) so there's no way
                  // to properly move the status code error back to client callback.
                  //
                  // To workaround this, short of making signficant patches to the
                  // Thrift library, we *rely on the fact that we're using a JSON
                  // protocol* and set the buffer to invalid JSON.  The true error
                  // gets lost, but at least the client is informed of *a* failure
                  // rather than radio silence.
                  //
                  var err = (this.status == 200) ? false : true;
                  self.setRecvBuffer(err ? "http_status_not_200" : this.responseText);
                  callback();
              }
          };
          //========
          // END CODE PATCH
          //========
      }
  
      xreq.open('POST', this.url, !!async);
      xreq.send(this.send_buf);
      if (async && callback) {
          return;
      }
  
      if (xreq.readyState != 4) {
          throw 'encountered an unknown ajax ready state: ' + xreq.readyState;
      }
  
      if (xreq.status != 200) {
          throw 'encountered a unknown request status: ' + xreq.status;
      }
  
      this.recv_buf = xreq.responseText;
      this.recv_buf_sz = this.recv_buf.length;
      this.wpos = this.recv_buf.length;
      this.rpos = 0;
  };
  
  module.exports.crouton_thrift = crouton_thrift;
  module.exports.Thrift = Thrift;
  })();