text: /*
   Copyright 2013 Daniel Wirtz <dcode@dcode.io>
  
   Licensed 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.
   */
  
  /**
   * @license ProtoBuf.js (c) 2013 Daniel Wirtz <dcode@dcode.io>
   * Released under the Apache License, Version 2.0
   * see: https://github.com/dcodeIO/ProtoBuf.js for details
   */
  (function(global) {
      "use strict";
      
      function loadProtoBuf(ByteBuffer) {
          if (!ByteBuffer || !ByteBuffer.zigZagEncode32) {
              throw(new Error("ProtoBuf.js requires ByteBuffer.js >=1.1.0: Get it at https://github.com/dcodeIO/ByteBuffer.js"));
          }
  
          /**
           * The ProtoBuf namespace.
           * @exports ProtoBuf
           * @namespace
           * @expose
           */
          var ProtoBuf = {};
          
          /**
           * ProtoBuf.js version.
           * @type {string}
           * @const
           * @expose
           */
          ProtoBuf.VERSION = "1.1.4";
  
          /**
           * Wire types.
           * @type {Object.<string,number>}
           * @const
           * @expose
           */
          ProtoBuf.WIRE_TYPES = {};
  
          /**
           * Varint wire type.
           * @type {number}
           * @expose
           */
          ProtoBuf.WIRE_TYPES.VARINT = 0;
  
          /**
           * Fixed 64 bits wire type.
           * @type {number}
           * @const
           * @expose
           */
          ProtoBuf.WIRE_TYPES.BITS64 = 1;
  
          /**
           * Length delimited wire type.
           * @type {number}
           * @const
           * @expose
           */
          ProtoBuf.WIRE_TYPES.LDELIM = 2;
  
          /**
           * Start group wire type.
           * @type {number}
           * @const
           * @deprecated Not supported.
           * @expose
           */
          ProtoBuf.WIRE_TYPES.STARTGROUP = 3;
  
          /**
           * End group wire type.
           * @type {number}
           * @const
           * @deprecated Not supported.
           * @expose
           */
          ProtoBuf.WIRE_TYPES.ENDGROUP = 4;
  
          /**
           * Fixed 32 bits wire type.
           * @type {number}
           * @const
           * @expose
           */
          ProtoBuf.WIRE_TYPES.BITS32 = 5;
  
          /**
           * Types.
           * @dict
           * @type {Object.<string,{name: string, wireType: number}>}
           * @const
           * @expose
           */
          ProtoBuf.TYPES = {
              // According to the protobuf spec.
              "int32": {
                  name: "int32",
                  wireType: ProtoBuf.WIRE_TYPES.VARINT
              },
              "uint32": {
                  name: "uint32",
                  wireType: ProtoBuf.WIRE_TYPES.VARINT
              },
              "sint32": {
                  name: "sint32",
                  wireType: ProtoBuf.WIRE_TYPES.VARINT
              },
              "int64": {
                  name: "int64",
                  wireType: ProtoBuf.WIRE_TYPES.VARINT
              },
              "uint64": {
                  name: "uint64",
                  wireType: ProtoBuf.WIRE_TYPES.VARINT
              },
              "sint64": {
                  name: "sint64",
                  wireType: ProtoBuf.WIRE_TYPES.VARINT
              },
              "bool": {
                  name: "bool",
                  wireType: ProtoBuf.WIRE_TYPES.VARINT
              },
              "double": {
                  name: "double",
                  wireType: ProtoBuf.WIRE_TYPES.BITS64
              },
              "string": {
                  name: "string",
                  wireType: ProtoBuf.WIRE_TYPES.LDELIM
              },
              "bytes": {
                  name: "bytes",
                  wireType: ProtoBuf.WIRE_TYPES.LDELIM
              },
              "fixed32": {
                  name: "fixed32",
                  wireType: ProtoBuf.WIRE_TYPES.BITS32
              },
              "sfixed32": {
                  name: "sfixed32",
                  wireType: ProtoBuf.WIRE_TYPES.BITS32
              },
              "fixed64": {
                  name: "fixed64",
                  wireType: ProtoBuf.WIRE_TYPES.BITS64
              },
              "sfixed64": {
                  name: "sfixed64",
                  wireType: ProtoBuf.WIRE_TYPES.BITS64
              },
              "float": {
                  name: "float",
                  wireType: ProtoBuf.WIRE_TYPES.BITS32
              },
              "enum": {
                  name: "enum",
                  wireType: ProtoBuf.WIRE_TYPES.VARINT
              },
              "message": {
                  name: "message",
                  wireType: ProtoBuf.WIRE_TYPES.LDELIM
              }
          };
  
          /**
           * @type {?Long}
           */
          ProtoBuf.Long = ByteBuffer.Long;
          
          /**
           * @alias ProtoBuf.Util
           * @expose
           */
          ProtoBuf.Util = (function() {
              "use strict";
          
              // Object.create polyfill
              // ref: https://developer.mozilla.org/de/docs/JavaScript/Reference/Global_Objects/Object/create
              if (!Object.create) {
                  /** @expose */
                  Object.create = function (o) {
                      if (arguments.length > 1) {
                          throw new Error('Object.create implementation only accepts the first parameter.');
                      }
                      function F() {}
                      F.prototype = o;
                      return new F();
                  };
              }
          
              /**
               * ProtoBuf utilities.
               * @exports ProtoBuf.Util
               * @namespace
               */
              var Util = {};
          
              /**
               * Flag if running in node or not.
               * @type {boolean}
               * @const
               * @expose
               */
              Util.IS_NODE = (typeof window == 'undefined' || !window.window) && typeof require == 'function';
              
              /**
               * Constructs a XMLHttpRequest object.
               * @return {XMLHttpRequest}
               * @throws {Error} If XMLHttpRequest is not supported
               * @expose
               */
              Util.XHR = function() {
                  // No dependencies please, ref: http://www.quirksmode.org/js/xmlhttp.html
                  var XMLHttpFactories = [
                      function () {return new XMLHttpRequest()},
                      function () {return new ActiveXObject("Msxml2.XMLHTTP")},
                      function () {return new ActiveXObject("Msxml3.XMLHTTP")},
                      function () {return new ActiveXObject("Microsoft.XMLHTTP")}
                  ];
                  /** @type {?XMLHttpRequest} */
                  var xhr = null;
                  for (var i=0;i<XMLHttpFactories.length;i++) {
                      try { xhr = XMLHttpFactories[i](); }
                      catch (e) { continue; }
                      break;
                  }
                  if (!xhr) throw(new Error("XMLHttpRequest is not supported"));
                  return xhr;
              };
          
              /**
               * Fetches a resource.
               * @param {string} path Resource path
               * @param {function(?string)=} callback Callback receiving the resource's contents. If omitted the resource will
               *   be fetched synchronously. If the request failed, contents will be null.
               * @return {?string|undefined} Resource contents if callback is omitted (null if the request failed), else undefined.
               * @expose
               */
              Util.fetch = function(path, callback) {
                  if (callback && typeof callback != 'function') callback = null;
                  if (Util.IS_NODE) {
                      if (callback) {
                          require("fs").readFile(path, function(err, data) {
                              if (err) callback(null);
                              else callback(""+data);
                          });
                      } else {
                          try {
                              return require("fs").readFileSync(path);
                          } catch (e) {
                              return null;
                          }
                      }
                  } else {
                      var xhr = Util.XHR();
                      xhr.open('GET', path, callback ? true : false);
                      xhr.setRequestHeader('User-Agent', 'XMLHTTP/1.0');
                      xhr.setRequestHeader('Accept', 'text/plain');
                      if (callback) {
                          xhr.onreadystatechange = function() {
                              if (xhr.readyState != 4) return;
                              if (xhr.status == 200) {
                                  callback(xhr.responseText);
                              } else {
                                  callback(null);
                              }
                          };
                          if (xhr.readyState == 4) return;
                          xhr.send(null);
                      } else {
                          xhr.send(null);
                          return xhr.responseText;
                      }
                  }
              };
              
              return Util;
          })();        
          /**
           * @alias ProtoBuf.Lang
           * @expose
           */
          ProtoBuf.Lang = (function() {
              "use strict";
              
              /**
               * ProtoBuf Language.
               * @exports ProtoBuf.Lang
               * @type {Object.<string,string|RegExp>}
               * @namespace
               * @private
               * @expose
               */
              var Lang = { // Look, so cute!
                  OPEN: "{",
                  CLOSE: "}",
                  OPTOPEN: "[",
                  OPTCLOSE: "]",
                  OPTEND: ",",
                  EQUAL: "=",
                  END: ";",
          
                  DELIM: /[\s\{\}=;\[\],"\(\)]/g,
                  KEYWORD: /package|option|import|message|enum|extend|service|syntax|extensions/,
                  RULE: /required|optional|repeated/,
                  TYPE: /double|float|int32|uint32|sint32|int64|uint64|sint64|fixed32|sfixed32|fixed64|sfixed64|bool|string|bytes/,
                  NAME: /[a-zA-Z][a-zA-Z_0-9]*/,
                  TYPEDEF: /[a-zA-Z](\.?[a-zA-Z_0-9])*/,
                  TYPEREF: /\.?[a-zA-Z](\.?[a-zA-Z_0-9])*/,
                  NUMBER: /^-?(?:[1-9][0-9]*|0|0x[0-9a-fA-F]+|0[0-7]+|[0-9]*\.[0-9]+)$/,
                  NUMBER_DEC: /^(?:[1-9][0-9]*|0)$/,
                  NUMBER_HEX: /^0x[0-9a-fA-F]+$/,
                  NUMBER_OCT: /^0[0-7]+$/,
                  NUMBER_FLT: /^[0-9]*\.[0-9]+$/,
                  ID: /^(?:[1-9][0-9]*|0|0x[0-9a-fA-F]+|0[0-7]+)$/,
                  NEGID: /^\-?(?:[1-9][0-9]*|0|0x[0-9a-fA-F]+|0[0-7]+)$/,
                  WHITESPACE: /\s/,
                  STRING: /"([^"\\]*(\\.[^"\\]*)*)"/g,
                  STRINGOPEN: '"',
                  STRINGCLOSE: '"',
                  COPTOPEN: '(',
                  COPTCLOSE: ')'
              };
              
              return Lang;
          })();
                  
          /**
           * @alias ProtoBuf.DotProto
           * @expose
           */
          ProtoBuf.DotProto = (function() {
              "use strict";
          
              /**
               * Utilities to parse .proto files.
               * @exports ProtoBuf.DotProto
               * @namespace
               */
              var DotProto = {};
              
              return DotProto;
          })();
                  
          /**
           * @alias ProtoBuf.DotProto.Tokenizer
           * @expose
           */
          ProtoBuf.DotProto.Tokenizer = (function(Lang) {
          
              /**
               * Constructs a new Tokenizer.
               * @exports ProtoBuf.DotProto.Tokenizer
               * @class A ProtoBuf .proto Tokenizer.
               * @param {string} proto Proto to tokenize
               * @constructor
               */
              var Tokenizer = function(proto) {
                  
                  /**
                   * Source to parse.
                   * @type {string}
                   * @expose
                   */
                  this.source = ""+proto;
                  
                  /**
                   * Current index.
                   * @type {number}
                   * @expose
                   */
                  this.index = 0;
          
                  /**
                   * Stacked values.
                   * @type {Array}
                   * @expose
                   */
                  this.stack = [];
          
                  /**
                   * Whether currently reading a string or not.
                   * @type {boolean}
                   * @expose
                   */
                  this.readingString = false;
              };
          
              /**
               * Reads a string beginning at the current index.
               * @return {string} The string
               * @throws {Error} If it's not a valid string
               * @private
               */
              Tokenizer.prototype._readString = function() {
                  Lang.STRING.lastIndex = this.index-1; // Include the open quote
                  var match;
                  if ((match = Lang.STRING.exec(this.source)) !== null) {
                      var s = match[1];
                      this.index = Lang.STRING.lastIndex;
                      this.stack.push(Lang.STRINGCLOSE);
                      return s;
                  }
                  throw(new Error("Illegal string value at index "+this.index));
              };
          
              /**
               * Gets the next token and advances by one.
               * @return {?string} Token or `null` on EOF
               * @throws {Error} If it's not a valid proto file
               * @expose
               */
              Tokenizer.prototype.next = function() {
                  if (this.stack.length > 0) {
                      return this.stack.shift();
                  }
                  if (this.index >= this.source.length) {
                      return null; // No more tokens
                  }
                  if (this.readingString) {
                      this.readingString = false;
                      return this._readString();
                  }
                  var repeat;
                  do {
                      repeat = false;
                      // Strip white spaces
                      while (Lang.WHITESPACE.test(this.source.charAt(this.index))) {
                          this.index++;
                          if (this.index == this.source.length) return null;
                      }
                      // Strip comments
                      if (this.source.charAt(this.index) == '/') {
                          if (this.source.charAt(++this.index) == '/') { // Single line
                              while (this.source.charAt(this.index) != "\n") {
                                  this.index++;
                                  if (this.index == this.source.length) return null;
                              }
                              this.index++;
                              repeat = true;
                          } else if (this.source.charAt(this.index) == '*') { /* Block */
                              var last = '';
                              while (last+(last=this.source.charAt(this.index)) != '*/') {
                                  this.index++;
                                  if (this.index == this.source.length) return null;
                              }
                              this.index++;
                              repeat = true;
                          } else {
                              throw(new Error("Invalid comment: /"+this.source.charAt(this.index)+" ('/' or '*' expected)"));
                          }
                      }
                  } while (repeat);
                  if (this.index == this.source.length) return null;
          
                  // Read the next token
                  var end = this.index;
                  Lang.DELIM.lastIndex = 0;
                  var delim = Lang.DELIM.test(this.source.charAt(end));
                  if (!delim) {
                      end++;
                      while(end < this.source.length && !Lang.DELIM.test(this.source.charAt(end))) {
                          end++;
                      }
                  } else {
                      end++;
                  }
                  var token = this.source.substring(this.index, this.index = end);
                  if (token == Lang.STRINGOPEN) {
                      this.readingString = true;
                  }
                  return token;
              };
          
              /**
               * Peeks for the next token.
               * @return {?string} Token or `null` on EOF
               * @throws {Error} If it's not a valid proto file
               * @expose
               */
              Tokenizer.prototype.peek = function() {
                  if (this.stack.length == 0) {
                      var token = this.next();
                      if (token === null) return null;
                      this.stack.push(token);
                  }
                  return this.stack[0];
              };
          
              /**
               * Returns a string representation of this object.
               * @return {string} String representation as of "Tokenizer(index/length)"
               * @expose
               */
              Tokenizer.prototype.toString = function() {
                  return "Tokenizer("+this.index+"/"+this.source.length+")";
              };
              
              return Tokenizer;
              
          })(ProtoBuf.Lang);
                  
          /**
           * @alias ProtoBuf.DotProto.Parser
           * @expose
           */
          ProtoBuf.DotProto.Parser = (function(ProtoBuf, Lang, Tokenizer) {
              "use strict";
              
              /**
               * Constructs a new Parser.
               * @exports ProtoBuf.DotProto.Parser
               * @class A ProtoBuf .proto parser.
               * @param {string} proto Protocol source
               * @constructor
               */
              var Parser = function(proto) {
          
                  /**
                   * Tokenizer.
                   * @type {ProtoBuf.DotProto.Tokenizer}
                   * @expose
                   */
                  this.tn = new Tokenizer(proto);
              };
          
              /**
               * Runs the parser.
               * @return {{package: string|null, messages: Array.<object>, enums: Array.<object>, imports: Array.<string>, options: object<string,*>}}
               * @throws {Error} If the source cannot be parsed
               * @expose
               */
              Parser.prototype.parse = function() {
                  var topLevel = {
                      "name": "[ROOT]", // temporary
                      "package": null,
                      "messages": [],
                      "enums": [],
                      "imports": [],
                      "options": {}
                  };
                  var token, header = true;
                  do {
                      token = this.tn.next();
                      if (token == null) {
                          break; // No more messages
                      }
                      if (token == 'package') {
                          if (!header) {
                              throw(new Error("Illegal package definition: Must be declared before the first message or enum"));
                          }
                          if (topLevel["package"] !== null) {
                              throw(new Error("Illegal package definition: Package already declared"));
                          }
                          topLevel["package"] = this._parsePackage(token);
                      } else if (token == 'import') {
                          if (!header) {
                              throw(new Error("Illegal import definition: Must be declared before the first message or enum"));
                          }
                          topLevel.imports.push(this._parseImport(token));
                      } else if (token == 'message') {
                          this._parseMessage(topLevel, token);
                          header = false;
                      } else if (token == 'enum') {
                          this._parseEnum(topLevel, token);
                          header = false;
                      } else if (token == 'option') {
                          if (!header) {
                              throw(new Error("Illegal option definition: Must be declared before the first message or enum"));
                          }
                          this._parseOption(topLevel, token);
                      } else if (token == 'extend' || token == 'service') {
                          this._parseIgnoredBlock(topLevel, token);
                      } else if (token == 'syntax') {
                          this._parseIgnoredStatement(topLevel, token);
                      } else {
                          throw(new Error("Illegal top level declaration: "+token));
                      }
                  } while (true);
                  delete topLevel["name"];
                  return topLevel;
              };
          
              /**
               * Parses a number value.
               * @param {string} val Number value to parse
               * @return {number} Number
               * @throws {Error} If the number value is invalid
               * @private
               */
              Parser.prototype._parseNumber = function(val) {
                  var sign = 1;
                  if (val.charAt(0) == '-') {
                      sign = -1; val = val.substring(1);
                  }
                  if (Lang.NUMBER_DEC.test(val)) {
                      return sign*parseInt(val, 10);
                  } else if (Lang.NUMBER_HEX.test(val)) {
                      return sign*parseInt(val.substring(2), 16);
                  } else if (Lang.NUMBER_OCT.test(val)) {
                      return sign*parseInt(val.substring(1), 8);
                  } else if (Lang.NUMBER_FLT.test(val)) {
                      return sign*parseFloat(val);
                  }
                  throw(new Error("Illegal number value: "+(sign < 0 ? '-' : '')+val));
              };
          
              /**
               * Parses an ID value.
               * @param {string} val ID value to parse
               * @param {boolean=} neg Whether the ID may be negative, defaults to `false`
               * @returns {number} ID
               * @throws {Error} If the ID value is invalid
               * @private
               */
              Parser.prototype._parseId = function(val, neg) {
                  var id = -1;
                  var sign = 1;
                  if (val.charAt(0) == '-') {
                      sign = -1; val = val.substring(1);
                  }
                  if (Lang.NUMBER_DEC.test(val)) {
                      id = parseInt(val);
                  } else if (Lang.NUMBER_HEX.test(val)) {
                      id = parseInt(val.substring(2), 16);
                  } else if (Lang.NUMBER_OCT.test(val)) {
                      id = parseInt(val.substring(1), 8);
                  } else {
                      throw(new Error("Illegal ID value: "+(sign < 0 ? '-' : '')+val));
                  }
                  id = (sign*id)|0; // Force to 32bit
                  if (!neg && id < 0) {
                      throw(new Error("Illegal ID range: "+(sign < 0 ? '-' : '')+val));
                  }
                  return id;
              };
          
              /**
               * Parses the package definition.
               * @param {string} token Initial token
               * @return {string} Package name
               * @throws {Error} If the package definition cannot be parsed
               * @private
               */
              Parser.prototype._parsePackage = function(token) {
                  token = this.tn.next();
                  if (!Lang.TYPEDEF.test(token)) {
                      throw(new Error("Illegal package name: "+token));
                  }
                  var pkg = token;
                  token = this.tn.next();
                  if (token != Lang.END) {
                      throw(new Error("Illegal end of package definition: "+token+" ('"+Lang.END+"' expected)"));
                  }
                  return pkg;
              };
          
              /**
               * Parses an import definition.
               * @param {string} token Initial token
               * @return {string} Import file name 
               * @throws {Error} If the import definition cannot be parsed
               * @private
               */
              Parser.prototype._parseImport = function(token) {
                  token = this.tn.next();
                  if (token == "public") {
                      token = this.tn.next();
                  }
                  if (token != Lang.STRINGOPEN) {
                      throw(new Error("Illegal begin of import value: "+token+" ('"+Lang.STRINGOPEN+"' expected)"));
                  }
                  var imported = this.tn.next();
                  token = this.tn.next();
                  if (token != Lang.STRINGCLOSE) {
                      throw(new Error("Illegal end of import value: "+token+" ('"+Lang.STRINGCLOSE+"' expected)"));
                  }
                  token = this.tn.next();
                  if (token != Lang.END) {
                      throw(new Error("Illegal end of import definition: "+token+" ('"+Lang.END+"' expected)"));
                  }
                  return imported;
              };
          
              /**
               * Parses a namespace option.
               * @param {Object} parent Parent definition
               * @param {string} token Initial token
               * @throws {Error} If the option cannot be parsed
               * @private
               */
              Parser.prototype._parseOption = function(parent, token) {
                  token = this.tn.next();
                  var custom = false;
                  if (token == Lang.COPTOPEN) {
                      custom = true;
                      token = this.tn.next();
                  }
                  if (!Lang.NAME.test(token)) {
                      throw(new Error("Illegal option name in message "+parent.name+": "+token));
                  }
                  var name = token;
                  token = this.tn.next();
                  if (custom) {
                      if (token != Lang.COPTCLOSE) {
                          throw(new Error("Illegal custom option name delimiter in message "+parent.name+", option "+name+": "+token+" ('"+Lang.COPTCLOSE+"' expected)"));
                      }
                      token = this.tn.next();
                  }
                  if (token != Lang.EQUAL) {
                      throw(new Error("Illegal option operator in message "+parent.name+", option "+name+": "+token+" ('"+Lang.EQUAL+"' expected)"));
                  }
                  var value;
                  token = this.tn.next();
                  if (token == Lang.STRINGOPEN) {
                      value = this.tn.next();
                      token = this.tn.next();
                      if (token != Lang.STRINGCLOSE) {
                          throw(new Error("Illegal end of option value in message "+parent.name+", option "+name+": "+token+" ('"+Lang.STRINGCLOSE+"' expected)"));
                      }
                  } else {
                      if (Lang.NUMBER.test(token)) {
                          value = this._parseNumber(token, true);
                      } else if (Lang.NAME.test(token)) {
                          value = token;
                      } else {
                          throw(new Error("Illegal option value in message "+parent.name+", option "+name+": "+token));
                      }
                  }
                  token = this.tn.next();
                  if (token != Lang.END) {
                      throw(new Error("Illegal end of option in message "+parent.name+", option "+name+": "+token+" ('"+Lang.END+"' expected)"));
                  }
                  parent["options"][name] = value;
              };
          
              /**
               * Parses an ignored block of the form ['keyword', 'typeref', '{' ... '}'].
               * @param {Object} parent Parent definition
               * @param {string} keyword Initial token
               * @throws {Error} If the directive cannot be parsed
               * @private
               */
              Parser.prototype._parseIgnoredBlock = function(parent, keyword) {
                  var token = this.tn.next();
                  if (!Lang.TYPEREF.test(token)) {
                      throw(new Error("Illegal "+keyword+" type in "+parent.name+": "+token));
                  }
                  var name = token;
                  token = this.tn.next();
                  if (token != Lang.OPEN) {
                      throw(new Error("Illegal OPEN in "+parent.name+" after "+keyword+" "+name+": "+token));
                  }
                  var depth = 1;
                  do {
                      token = this.tn.next();
                      if (token === null) {
                          throw(new Error("Unexpected EOF in "+parent.name+", "+keyword+" (ignored), "+name));
                      }
                      if (token == Lang.OPEN) {
                          depth++;
                      } else if (token == Lang.CLOSE) {
                          token = this.tn.peek();
                          if (token == Lang.END) this.tn.next();
                          depth--;
                          if (depth == 0) {
                              break;
                          }
                      }
                  } while(true);
              };
          
              /**
               * Parses an ignored statement of the form ['keyword', ..., ';'].
               * @param {Object} parent Parent definition
               * @param {string} keyword Initial token
               * @throws {Error} If the directive cannot be parsed
               * @private
               */
              Parser.prototype._parseIgnoredStatement = function(parent, keyword) {
                  do {
                      var token = this.tn.next();
                      if (token === null) {
                          throw(new Error("Unexpected EOF in "+parent.name+", "+keyword+" (ignored)"));
                      }
                      if (token == Lang.END) break;
                  } while (true);
              };
          
              /**
               * Parses a message.
               * @param {Object} parent Parent definition
               * @param {string} token First token
               * @return {Object}
               * @throws {Error} If the message cannot be parsed
               * @private
               */
              Parser.prototype._parseMessage = function(parent, token) {
                  /** @dict */
                  var msg = {}; // Note: At some point we might want to exclude the parser, so we need a dict.
                  token = this.tn.next();
                  if (!Lang.NAME.test(token)) {
                      throw(new Error("Illegal message name"+(parent ? " in message "+parent["name"] : "")+": "+token));
                  }
                  msg["name"] = token;
                  token = this.tn.next();
                  if (token != Lang.OPEN) {
                      throw(new Error("Illegal OPEN after message "+msg.name+": "+token+" ('"+Lang.OPEN+"' expected)"));
                  }
                  msg["fields"] = []; // Note: Using arrays to support also browser that cannot preserve order of object keys.
                  msg["enums"] = [];
                  msg["messages"] = [];
                  msg["options"] = {};
                  do {
                      token = this.tn.next();
                      if (token == Lang.CLOSE) {
                          token = this.tn.peek();
                          if (token == Lang.END) this.tn.next();
                          break;
                      } else if (Lang.RULE.test(token)) {
                          this._parseMessageField(msg, token);
                      } else if (token == "enum") {
                          this._parseEnum(msg, token);
                      } else if (token == "message") {
                          this._parseMessage(msg, token);
                      } else if (token == "option") {
                          this._parseOption(msg, token);
                      } else if (token == "extensions") {
                          this._parseIgnoredStatement(msg, token);
                      } else {
                          throw(new Error("Illegal token in message "+msg.name+": "+token+" (type or '"+Lang.CLOSE+"' expected)"));
                      }
                  } while (true);
                  parent["messages"].push(msg);
                  return msg;
              };
          
              /**
               * Parses a message field.
               * @param {Object} msg Message definition
               * @param {string} token Initial token
               * @throws {Error} If the message field cannot be parsed
               * @private
               */
              Parser.prototype._parseMessageField = function(msg, token) {
                  /** @dict */
                  var fld = {};
                  fld["rule"] = token;
                  token = this.tn.next();
                  if (!Lang.TYPE.test(token) && !Lang.TYPEREF.test(token)) {
                      throw(new Error("Illegal field type in message "+msg.name+": "+token));
                  }
                  fld["type"] = token;
                  token = this.tn.next();
                  if (!Lang.NAME.test(token)) {
                      throw(new Error("Illegal field name in message "+msg.name+": "+token));
                  }
                  fld["name"] = token;
                  token = this.tn.next();
                  if (token != Lang.EQUAL) {
                      throw(new Error("Illegal field number operator in message "+msg.name+"#"+fld.name+": "+token+" ('"+Lang.EQUAL+"' expected)"));
                  }
                  token = this.tn.next();
                  try {
                      fld["id"] = this._parseId(token);
                  } catch (e) {
                      throw(new Error("Illegal field id in message "+msg.name+"#"+fld.name+": "+token));
                  }
                  /** @dict */
                  fld["options"] = {};
                  token = this.tn.next();
                  if (token == Lang.OPTOPEN) {
                      this._parseFieldOptions(msg, fld, token);
                      token = this.tn.next();
                  }
                  if (token != Lang.END) {
                      throw(new Error("Illegal field delimiter in message "+msg.name+"#"+fld.name+": "+token+" ('"+Lang.END+"' expected)"));
                  }
                  msg["fields"].push(fld);
              };
          
              /**
               * Parses a set of field option definitions.
               * @param {Object} msg Message definition
               * @param {Object} fld Field definition
               * @param {string} token Initial token
               * @throws {Error} If the message field options cannot be parsed
               * @private
               */
              Parser.prototype._parseFieldOptions = function(msg, fld, token) {
                  var first = true;
                  do {
                      token = this.tn.next();
                      if (token == Lang.OPTCLOSE) {
                          break;
                      } else if (token == Lang.OPTEND) {
                          if (first) {
                              throw(new Error("Illegal start of message field options in message "+msg.name+"#"+fld.name+": "+token));
                          }
                          token = this.tn.next();
                      }
                      this._parseFieldOption(msg, fld, token);
                      first = false;
                  } while (true);
              };
          
              /**
               * Parses a single field option.
               * @param {Object} msg Message definition
               * @param {Object} fld Field definition
               * @param {string} token Initial token
               * @throws {Error} If the mesage field option cannot be parsed
               * @private
               */
              Parser.prototype._parseFieldOption = function(msg, fld, token) {
                  var custom = false;
                  if (token == Lang.COPTOPEN) {
                      token = this.tn.next();
                      custom = true;
                  }
                  if (!Lang.NAME.test(token)) {
                      throw(new Error("Illegal field option in message "+msg.name+"#"+fld.name+": "+token));
                  }
                  var name = token;
                  token = this.tn.next();
                  if (custom) {
                      if (token != Lang.COPTCLOSE) {
                          throw(new Error("Illegal custom field option name delimiter in message "+msg.name+"#"+fld.name+": "+token+" (')' expected)"));
                      }
                      token = this.tn.next();
                  }
                  if (token != Lang.EQUAL) {
                      throw(new Error("Illegal field option operation in message "+msg.name+"#"+fld.name+": "+token+" ('=' expected)"));
                  }
                  var value;
                  token = this.tn.next();
                  if (token == Lang.STRINGOPEN) {
                      value = this.tn.next();
                      token = this.tn.next();
                      if (token != Lang.STRINGCLOSE) {
                          throw(new Error("Illegal end of field value in message "+msg.name+"#"+fld.name+", option "+name+": "+token+" ('"+Lang.STRINGCLOSE+"' expected)"));
                      }
                  } else if (Lang.NUMBER.test(token, true)) {
                      value = this._parseNumber(token, true);
                  } else if (Lang.TYPEREF.test(token)) {
                      value = token; // TODO: Resolve?
                  } else {
                      throw(new Error("Illegal field option value in message "+msg.name+"#"+fld.name+", option "+name+": "+token));
                  }
                  fld["options"][name] = value;
              };
          
              /**
               * Parses an enum.
               * @param {Object} msg Message definition
               * @param {string} token Initial token
               * @throws {Error} If the enum cannot be parsed
               * @private
               */
              Parser.prototype._parseEnum = function(msg, token) {
                  /** @dict */
                  var enm = {};
                  token = this.tn.next();
                  if (!Lang.NAME.test(token)) {
                      throw(new Error("Illegal enum name in message "+msg.name+": "+token));
                  }
                  enm["name"] = token;
                  token = this.tn.next();
                  if (token != Lang.OPEN) {
                      throw(new Error("Illegal OPEN after enum "+enm.name+": "+token));
                  }
                  enm["values"] = [];
                  enm["options"] = {};
                  do {
                      token = this.tn.next();
                      if (token == Lang.CLOSE) {
                          token = this.tn.peek();
                          if (token == Lang.END) this.tn.next();
                          break;
                      }
                      if (token == 'option') {
                          this._parseOption(enm, token);
                      } else {
                          if (!Lang.NAME.test(token)) {
                              throw(new Error("Illegal enum value name in enum "+enm.name+": "+token));
                          }
                          this._parseEnumValue(enm, token);
                      }
                  } while (true);
                  msg["enums"].push(enm);
              };
          
              /**
               * Parses an enum value.
               * @param {Object} enm Enum definition
               * @param {string} token Initial token
               * @throws {Error} If the enum value cannot be parsed
               * @private
               */
              Parser.prototype._parseEnumValue = function(enm, token) {
                  /** @dict */
                  var val = {};
                  val["name"] = token;
                  token = this.tn.next();
                  if (token != Lang.EQUAL) {
                      throw(new Error("Illegal enum value operator in enum "+enm.name+": "+token+" ('"+Lang.EQUAL+"' expected)"));
                  }
                  token = this.tn.next();
                  try {
                      val["id"] = this._parseId(token, true);
                  } catch (e) {
                      throw(new Error("Illegal enum value id in enum "+enm.name+": "+token));
                  }
                  enm["values"].push(val);
                  token = this.tn.next();
                  if (token == Lang.OPTOPEN) {
                      var opt = { 'options' : {} }; // TODO: Actually expose them somehow.
                      this._parseFieldOptions(enm, opt, token);
                      token = this.tn.next();
                  }
                  if (token != Lang.END) {
                      throw(new Error("Illegal enum value delimiter in enum "+enm.name+": "+token+" ('"+Lang.END+"' expected)"));
                  }
              };
          
              /**
               * Returns a string representation of this object.
               * @returns {string} String representation as of "Parser"
               */
              Parser.prototype.toString = function() {
                  return "Parser";
              };
              
              return Parser;
              
          })(ProtoBuf, ProtoBuf.Lang, ProtoBuf.DotProto.Tokenizer);
                  
          /**
           * @alias ProtoBuf.Reflect
           * @expose
           */
          ProtoBuf.Reflect = (function(ProtoBuf) {
              "use strict";
              
              /**
               * @exports ProtoBuf.Reflect
               * @namespace
               */
              var Reflect = {};
          
              /**
               * Constructs a Reflect base class.
               * @exports ProtoBuf.Reflect.T
               * @constructor
               * @param {ProtoBuf.Reflect.T} parent Parent object
               * @param {string} name Object name
               */
              var T = function(parent, name) {
                  /**
                   * Parent object.
                   * @type {ProtoBuf.Reflect.T|null}
                   * @expose
                   */
                  this.parent = parent;
          
                  /**
                   * Object name in namespace.
                   * @type {string}
                   * @expose
                   */
                  this.name = name;
              };
          
              /**
               * Returns a string representation of this Reflect object (its fully qualified name).
               * @param {boolean=} includeClass Set to true to include the class name. Defaults to false.
               * @return String representation
               * @expose
               */
              T.prototype.toString = function(includeClass) {
                  var name = this.name;
                  var ptr = this;
                  do {
                      ptr = ptr.parent;
                      if (ptr == null) break;
                      name = ptr.name+"."+name;
                  } while (true);
                  if (includeClass) {
                      if (this instanceof Reflect.Message) {
                          name = "Message "+name;
                      } else if (this instanceof Message.Field) {
                          name = "Message.Field "+name;
                      } else if (this instanceof Enum) {
                          name = "Enum "+name;
                      } else if (this instanceof Enum.Value) {
                          name = "Enum.Value "+name;
                      } else if (this instanceof Namespace) {
                          name = "Namespace "+name;
                      }
                  }
                  return name;
              };
          
              /**
               * Builds this type.
               * @throws {Error} If this type cannot be built directly
               * @expose
               */
              T.prototype.build = function() {
                  throw(new Error(this.toString(true)+" cannot be built directly"));
              };
          
              /**
               * @alias ProtoBuf.Reflect.T
               * @expose
               */
              Reflect.T = T;
          
              /**
               * Constructs a new Namespace.
               * @exports ProtoBuf.Reflect.Namespace
               * @param {ProtoBuf.Reflect.Namespace|null} parent Namespace parent
               * @param {string} name Namespace name
               * @param {Object.<string,*>} options Namespace options
               * @constructor
               * @extends ProtoBuf.Reflect.T
               */
              var Namespace = function(parent, name, options) {
                  T.call(this, parent, name);
          
                  /**
                   * Children inside the namespace.
                   * @type {Array.<ProtoBuf.Reflect.T>}
                   */
                  this.children = [];
          
                  /**
                   * Options.
                   * @type {Object.<string, *>}
                   */
                  this.options = options || {};
              };
          
              // Extends T
              Namespace.prototype = Object.create(T.prototype);
          
              /**
               * Returns an array of the namespace's children.
               * @param {ProtoBuf.Reflect.T=} type Filter type (returns instances of this type only). Defaults to null (all children).
               * @return {Array.<ProtoBuf.Reflect.T>}
               * @expose
               */
              Namespace.prototype.getChildren = function(type) {
                  type = type || null;
                  if (type == null) {
                      return this.children.slice();
                  }
                  var children = [];
                  for (var i=0; i<this.children.length; i++) {
                      if (this.children[i] instanceof type) {
                          children.push(this.children[i]);
                      }
                  }
                  return children;
              };
          
              /**
               * Adds a child to the namespace.
               * @param {ProtoBuf.Reflect.T} child Child
               * @throws {Error} If the child cannot be added (duplicate)
               * @expose
               */
              Namespace.prototype.addChild = function(child) {
                  if (this.hasChild(child.name)) {
                      throw(new Error("Duplicate name in namespace "+this.toString(true)+": "+child.name));
                  }
                  this.children.push(child);
              };
          
              /**
               * Tests if this namespace has a child with the specified name.
               * @param {string|number} nameOrId Child name or id
               * @returns {boolean} true if there is one, else false
               * @expose
               */
              Namespace.prototype.hasChild = function(nameOrId) {
                  var i;
                  if (typeof nameOrId == 'number') {
                      for (i=0; i<this.children.length; i++) if (this.children[i] instanceof Message.Field && this.children[i].id == nameOrId) return true;
                  } else {
                      for (i=0; i<this.children.length; i++) if (this.children[i].name == nameOrId) return true;
                  }
                  return false;
              };
          
              /**
               * Gets a child by its name.
               * @param {string|number} nameOrId Child name or id
               * @return {?ProtoBuf.Reflect.T} The child or null if not found
               * @expose
               */
              Namespace.prototype.getChild = function(nameOrId) {
                  var i;
                  if (typeof nameOrId == 'number') {
                      for (i=0; i<this.children.length; i++) if (this.children[i] instanceof Message.Field && this.children[i].id == nameOrId) return this.children[i];
                  } else {
                      for (i=0; i<this.children.length; i++) if (this.children[i].name == nameOrId) return this.children[i];
                  }
                  return null;
              };
          
              /**
               * Resolves a reflect object inside of this namespace.
               * @param {string} qn Qualified name to resolve
               * @return {ProtoBuf.Reflect.Namespace|null} The resolved type or null if not found
               * @expose
               */
              Namespace.prototype.resolve = function(qn) {
                  var part = qn.split(".");
                  var ptr = this, i=0;
                  if (part[i] == "") { // Fully qualified name, e.g. ".My.Message'
                      while (ptr.parent != null) {
                          ptr = ptr.parent;
                      }
                      i++;
                  }
                  var child;
                  do {
                      do {
                          child = ptr.getChild(part[i]);
                          if (!child || !(child instanceof Reflect.T)) {
                              ptr = null;
                              break;
                          }
                          ptr = child; i++;
                      } while (i < part.length);
                      if (ptr != null) break; // Found
                      // Else search the parent
                      if (this.parent !== null) {
                          return this.parent.resolve(qn);
                      }
                  } while (ptr != null);
                  return ptr;
              };
          
              /**
               * Builds the namespace and returns the runtime counterpart.
               * @return {Object.<string,Function|Object>} Runtime namespace
               * @expose
               */
              Namespace.prototype.build = function() {
                  /** @dict */
                  var ns = {};
                  var children = this.getChildren(), child;
                  for (var i=0; i<children.length; i++) {
                      child = children[i];
                      if (child instanceof Namespace) {
                          ns[child.name] = child.build();
                      }
                  }
                  if (Object.defineProperty) {
                      Object.defineProperty(ns, "$options", {
                          "value": this.buildOpt(),
                          "enumerable": false,
                          "configurable": false,
                          "writable": false
                      });
                  }
                  return ns;
              };
          
              /**
               * Builds the namespace's 'opt' property.
               * @return {Object.<string,*>}
               */
              Namespace.prototype.buildOpt = function() {
                  var opt = {};
                  var keys = Object.keys(this.options);
                  for (var i=0; i<keys.length; i++) {
                      var key = keys[i];
                      var val = this.options[keys[i]];
                      // TODO: Options are not resolved, yet.
                      // if (val instanceof Namespace) {
                      //     opt[key] = val.build();
                      // } else {
                          opt[key] = val;
                      // }
                  }
                  return opt;
              };
          
              /**
               * Gets the value assigned to the option with the specified name.
               * @param {string=} name Returns the option value if specified, otherwise all options are returned.
               * @return {*|Object.<string,*>}null} Option value or NULL if there is no such option
               */
              Namespace.prototype.getOption = function(name) {
                  if (typeof name == 'undefined') {
                      return this.options;
                  }
                  return typeof this.options[name] != 'undefined' ? this.options[name] : null;
              };
          
              /**
               * @alias ProtoBuf.Reflect.Namespace
               * @expose
               */
              Reflect.Namespace = Namespace;
          
              /**
               * Constructs a new Message.
               * @exports ProtoBuf.Reflect.Message
               * @param {ProtoBuf.Reflect.Namespace} parent Parent message or namespace
               * @param {string} name Message name
               * @param {Object.<string,*>} options Message options
               * @constructor
               * @extends ProtoBuf.Reflect.Namespace
               */
              var Message = function(parent, name, options) {
                  Namespace.call(this, parent, name, options);
          
                  /**
                   * Runtime message class.
                   * @type {ProtoBuf.Builder.Message|null}
                   * @expose
                   */
                  this.clazz = null;
              };
          
              // Extends Namespace
              Message.prototype = Object.create(Namespace.prototype);
          
              /**
               * Builds the message and returns the runtime counterpart, which is a fully functional class.
               * @see ProtoBuf.Builder.Message
               * @return {ProtoBuf.Reflect.Message} Message class
               * @throws {Error} If the message cannot be built
               * @expose
               */
              Message.prototype.build = function() {
                  // We need to create a prototyped Message class in an isolated scope
                  var clazz = (function(Reflect, T) {
                      var fields = T.getChildren(Reflect.Message.Field);
          
                      /**
                       * Constructs a new runtime Message.
                       * @name ProtoBuf.Builder.Message
                       * @class Barebone of all runtime messages.
                       * @param {Object.<string,*>} values Preset values
                       * @constructor
                       * @throws {Error} If the message cannot be created
                       */
          
                      /**
                       * @type {!Function}
                       */
                      var Message = eval("0, (function "+T.name+"() { ProtoBuf.Builder.Message.call(this); this.__construct.apply(this, arguments); })");
                      // Any better way to create a named function? This is so much nicer for debugging with util.inspect()
                      
                      // Extends ProtoBuf.Builder.Message
                      Message.prototype = Object.create(ProtoBuf.Builder.Message.prototype);
                      
                      /**
                       * @expose
                       */
                      Message.prototype.__construct = function(values) {                
                          var i, field;
          
                          // Create fields on the object itself to allow setting and getting through Message#fieldname
                          for (i=0; i<fields.length; i++) {
                              field = fields[i];
                              this[field.name] = (field.repeated) ? [] : null;
                          }
                          // Set the default values
                          for (i=0; i<fields.length; i++) {
                              field = fields[i];
                              if (typeof field.options['default'] != 'undefined') {
                                  try {
                                      this.set(field.name, field.options['default']); // Should not throw
                                  } catch (e) {
                                      throw(new Error("[INTERNAL ERROR] "+e));
                                  }
                              }
                          }
                          // Set field values from a values object
                          if (arguments.length == 1 && typeof values == 'object' &&
                              /* not another Message */ typeof values.encode != 'function' &&
                              /* not a repeated field */ !(values instanceof Array) &&
                              /* not a ByteBuffer */ !(values instanceof ByteBuffer) &&
                              /* not an ArrayBuffer */ !(values instanceof ArrayBuffer) &&
                              /* not a Long */ !(ProtoBuf.Long && values instanceof ProtoBuf.Long)) {
                              var keys = Object.keys(values);
                              for (i=0; i<keys.length; i++) {
                                  this.set(keys[i], values[keys[i]]); // May throw
                              }
                              // Else set field values from arguments, in correct order
                          } else {
                              for (i=0; i<arguments.length; i++) {
                                  if (i<fields.length) {
                                      this.set(fields[i].name, arguments[i]); // May throw
                                  }
                              }
                          }
                      };
          
                      /**
                       * Adds a value to a repeated field.
                       * @name ProtoBuf.Builder.Message#add
                       * @function
                       * @param {string} key Field name
                       * @param {*} value Value to add
                       * @throws {Error} If the value cannot be added
                       * @expose
                       */
                      Message.prototype.add = function(key, value) {
                          var field = T.getChild(key);
                          if (!field) {
                              throw(new Error(this+"#"+key+" is undefined"));
                          }
                          if (!(field instanceof Reflect.Message.Field)) {
                              throw(new Error(this+"#"+key+" is not a field: "+field.toString(true))); // May throw if it's an enum or embedded message
                          }
                          if (!field.repeated) {
                              throw(new Error(this+"#"+key+" is not a repeated field"));
                          }
                          if (this[field.name] === null) this[field.name] = [];
                          this[field.name].push(field.verifyValue(value, true));
                      };
          
                      /**
                       * Sets a field value.
                       * @name ProtoBuf.Builder.Message#set
                       * @function
                       * @param {string} key Key
                       * @param {*} value Value to set
                       * @throws {Error} If the value cannot be set
                       * @expose
                       */
                      Message.prototype.set = function(key, value) {
                          var field = T.getChild(key);
                          if (!field) {
                              throw(new Error(this+"#"+key+" is not a field: undefined"));
                          }
                          if (!(field instanceof Reflect.Message.Field)) {
                              throw(new Error(this+"#"+key+" is not a field: "+field.toString(true)));
                          }
                          this[field.name] = field.verifyValue(value); // May throw
                      };
          
                      /**
                       * Gets a value.
                       * @name ProtoBuf.Builder.Message#get
                       * @function
                       * @param {string} key Key
                       * @return {*} Value
                       * @throws {Error} If there is no such field
                       * @expose
                       */
                      Message.prototype.get = function(key) {
                          var field = T.getChild(key);
                          if (!field || !(field instanceof Reflect.Message.Field)) {
                              throw(new Error(this+"#"+key+" is not a field: undefined"));
                          }
                          if (!(field instanceof Reflect.Message.Field)) {
                              throw(new Error(this+"#"+key+" is not a field: "+field.toString(true)));
                          }
                          return this[field.name];
                      };
          
                      // Getters and setters
          
                      for (var i=0; i<fields.length; i++) {
                          var field = fields[i];
                          
                          (function(field) {
                              // set/get[SomeValue]
                              var Name = field.name.replace(/(_[a-zA-Z])/g,
                                  function(match) {
                                      return match.toUpperCase().replace('_','');
                                  }
                              );
                              Name = Name.substring(0,1).toUpperCase()+Name.substring(1);
              
                              // set/get_[some_value]
                              var name = field.name.replace(/([A-Z])/g,
                                  function(match) {
                                      return "_"+match;
                                  }
                              );
              
                              /**
                               * Sets a value. This method is present for each field, but only if there is no name conflict with
                               * another field.
                               * @name ProtoBuf.Builder.Message#set[SomeField]
                               * @function
                               * @param {*} value Value to set
                               * @abstract
                               * @throws {Error} If the value cannot be set
                               */
                              if (!T.hasChild("set"+Name)) {
                                  Message.prototype["set"+Name] = function(value) {
                                      this.set(field.name, value);
                                  }
                              }
              
                              /**
                               * Sets a value. This method is present for each field, but only if there is no name conflict with
                               * another field.
                               * @name ProtoBuf.Builder.Message#set_[some_field]
                               * @function
                               * @param {*} value Value to set
                               * @abstract
                               * @throws {Error} If the value cannot be set
                               */
                              if (!T.hasChild("set_"+name)) {
                                  Message.prototype["set_"+name] = function(value) {
                                      this.set(field.name, value);
                                  };
                              }
              
                              /**
                               * Gets a value. This method is present for each field, but only if there is no name conflict with
                               * another field.
                               * @name ProtoBuf.Builder.Message#get[SomeField]
                               * @function
                               * @abstract
                               * @return {*} The value
                               */
                              if (!T.hasChild("get"+Name)) {
                                  Message.prototype["get"+Name] = function() {
                                      return this.get(field.name); // Does not throw, field exists
                                  }
                              }
              
                              /**
                               * Gets a value. This method is present for each field, but only if there is no name conflict with
                               * another field.
                               * @name ProtoBuf.Builder.Message#get_[some_field]
                               * @function
                               * @return {*} The value
                               * @abstract
                               */
                              if (!T.hasChild("get_"+name)) {
                                  Message.prototype["get_"+name] = function() {
                                      return this.get(field.name); // Does not throw, field exists
                                  };
                              }
                              
                          })(field);
                      }
          
                      // En-/decoding
          
                      /**
                       * Encodes the message.
                       * @name ProtoBuf.Builder.Message#encode
                       * @function
                       * @param {ByteBuffer=} buffer ByteBuffer to encode to. Will create a new one if omitted.
                       * @return {ByteBuffer} Encoded message
                       * @throws {Error} If the message cannot be encoded
                       * @expose
                       */
                      Message.prototype.encode = function(buffer) {
                          buffer = buffer || new ByteBuffer();
                          var le = buffer.littleEndian;
                          try {
                              var bb = T.encode(this, buffer.LE()).flip();
                              buffer.littleEndian = le;
                              return bb;
                          } catch (e) {
                              buffer.littleEndian = le;
                              throw(e);
                          }
                      };
          
                      /**
                       * Directly encodes the message to an ArrayBuffer.
                       * @name ProtoBuf.Builder.Message#toArrayBuffer
                       * @function
                       * @return {ArrayBuffer} Encoded message as ArrayBuffer
                       * @throws {Error} If the message cannot be encoded
                       * @expose
                       */
                      Message.prototype.toArrayBuffer = function() {
                          return this.encode().toArrayBuffer();
                      };
          
                      /**
                       * Directly encodes the message to a node Buffer.
                       * @name ProtoBuf.Builder.Message#toBuffer
                       * @function
                       * @return {!Buffer}
                       * @throws {Error} If the message cannot be encoded or not running under node.js
                       * @expose
                       */
                      Message.prototype.toBuffer = function() {
                          return this.encode().toBuffer();
                      };
          
                      /**
                       * Decodes the message from the specified ByteBuffer.
                       * @name ProtoBuf.Builder.Message.decode
                       * @function
                       * @param {!ByteBuffer|!ArrayBuffer|!Buffer} buffer ByteBuffer to decode from
                       * @return {!ProtoBuf.Builder.Message} Decoded message
                       * @throws {Error} If the message cannot be decoded
                       * @expose
                       */
                      Message.decode = function(buffer) {
                          buffer = buffer ? (buffer instanceof ByteBuffer ? buffer : ByteBuffer.wrap(buffer)) : new ByteBuffer();
                          var le = buffer.littleEndian;
                          try {
                              var msg = T.decode(buffer.LE());
                              buffer.littleEndian = le;
                              return msg;
                          } catch (e) {
                              buffer.littleEndian = le;
                              throw(e);
                          }
                      };
          
                      // Utility
          
                      /**
                       * Returns a string representation of this Message.
                       * @name ProtoBuf.Builder.Message#toString
                       * @function
                       * @return {string} String representation as of ".Fully.Qualified.MessageName"
                       * @expose
                       */
                      Message.prototype.toString = function() {
                          return T.toString();
                      };
          
                      // Static
                      
                      /**
                       * Options.
                       * @name ProtoBuf.Builder.Message.$options
                       * @type {Object.<string,*>}
                       * @expose
                       */
                      var O_o; // for cc
                      
                      if (Object.defineProperty) {
                          Object.defineProperty(Message, '$options', {
                              'value': T.buildOpt(),
                              'enumerable': false,
                              'configurable': false,
                              'writable': false
                          });
                      }
                      
                      return Message;
          
                  })(Reflect, this);
          
                  // Static enums and prototyped sub-messages
                  var children = this.getChildren();
                  for (var i=0; i<children.length; i++) {
                      if (children[i] instanceof Enum) {
                          clazz[children[i]['name']] = children[i].build();
                      } else if (children[i] instanceof Message) {
                          clazz[children[i]['name']] = children[i].build();
                      } else if (children[i] instanceof Message.Field) {
                          // Ignore
                      } else {
                          throw(new Error("Illegal reflect child of "+this.toString(true)+": "+children[i].toString(true)));
                      }
                  }
                  return this.clazz = clazz;
              };
          
              /**
               * Encodes a runtime message's contents to the specified buffer.
               * @param {ProtoBuf.Builder.Message} message Runtime message to encode
               * @param {ByteBuffer} buffer ByteBuffer to write to
               * @return {ByteBuffer} The ByteBuffer for chaining
               * @throws {string} If the message cannot be encoded
               * @expose
               */
              Message.prototype.encode = function(message, buffer) {
                  var fields = this.getChildren(Message.Field);
                  for (var i=0; i<fields.length; i++) {
                      fields[i].encode(message.get(fields[i].name), buffer);
                  }
                  return buffer;
              };
          
              /**
               * Decodes an encoded message and returns the decoded message.
               * @param {ByteBuffer} buffer ByteBuffer to decode from
               * @param {number=} length Message length. Defaults to decode all the available data.
               * @return {ProtoBuf.Builder.Message} Decoded message
               * @throws {Error} If the message cannot be decoded
               * @expose
               */
              Message.prototype.decode = function(buffer, length) {
                  length = typeof length === 'number' ? length : -1;
                  var start = buffer.offset;
                  var msg = new (this.clazz)();
                  while (buffer.offset < start+length || (length == -1 && buffer.remaining() > 0)) {
                      var tag = buffer.readVarint32();
                      var wireType = tag & 0x07,
                          id = tag >> 3;
                      var field = this.getChild(id); // Message.Field only
                      if (!field) {
                          // "messages created by your new code can be parsed by your old code: old binaries simply ignore the new field when parsing."
                          switch (wireType) {
                              case ProtoBuf.WIRE_TYPES.VARINT:
                                  buffer.readVarint32();
                                  break;
                              case ProtoBuf.WIRE_TYPES.BITS32:
                                  buffer.offset += 4;
                                  break;
                              case ProtoBuf.WIRE_TYPES.BITS64:
                                  buffer.offset += 8;
                                  break;
                              case ProtoBuf.WIRE_TYPES.LDELIM:
                                  var len = buffer.readVarint32();
                                  buffer.offset += len;
                                  break;
                              default:
                                  throw(new Error("Illegal wire type of unknown field "+id+" in "+this.toString(true)+"#decode: "+wireType));
                          }
                          continue;
                      }
                      if (field.repeated && !field.options["packed"]) {
                          msg.add(field.name, field.decode(wireType, buffer));
                      } else {
                          msg.set(field.name, field.decode(wireType, buffer));
                      }
                  }
                  // Check if all required fields are present
                  var fields = this.getChildren(Reflect.Field);
                  for (var i=0; i<fields.length; i++) {
                      if (fields[i].required && msg[fields[i].name] === null) {
                          var err = new Error("Missing field "+fields[i].toString(true)+" in "+this.toString(true)+"#decode");
                          err.msg = msg;
                          throw(err);
                      }
                  }
                  return msg;
              };
          
              /**
               * @alias ProtoBuf.Reflect.Message
               * @expose
               */
              Reflect.Message = Message;
          
              /**
               * Constructs a new Message Field.
               * @exports ProtoBuf.Reflect.Message.Field
               * @param {ProtoBuf.Reflect.Message} message Message reference
               * @param {string} rule Rule, one of requried, optional, repeated
               * @param {string} type Data type, e.g. int32
               * @param {string} name Field name
               * @param {number} id Unique field id
               * @param {Object.<string.*>=} options Options
               * @constructor
               * @extends ProtoBuf.Reflect.T
               */
              var Field = function(message, rule, type, name, id, options) {
                  T.call(this, message, name);
          
                  /**
                   * Message field required flag.
                   * @type {boolean}
                   * @expose
                   */
                  this.required = rule == "required";
          
                  /**
                   * Message field repeated flag.
                   * @type {boolean}
                   * @expose
                   */
                  this.repeated = rule == "repeated";
          
                  /**
                   * Message field type. Type reference string if unresolved, protobuf type if resolved.
                   * @type {string|{name: string, wireType: number}
                   * @expose
                   */
                  this.type = type;
          
                  /**
                   * Resolved type reference inside the global namespace.
                   * @type {ProtoBuf.Reflect.T|null}
                   * @expose
                   */
                  this.resolvedType = null;
          
                  /**
                   * Unique message field id.
                   * @type {number}
                   * @expose
                   */
                  this.id = id;
          
                  /**
                   * Message field options.
                   * @type {!Object.<string,*>}
                   * @dict
                   * @expose
                   */
                  this.options = options || {};
              };
          
              // Extends T
              Field.prototype = Object.create(T.prototype);
          
              /**
               * Checks if the given value can be set for this field.
               * @param {*} value Value to check
               * @param {boolean=} skipRepeated Whether to skip the repeated value check or not. Defaults to false.
               * @return {*} Verified, maybe adjusted, value
               * @throws {Error} If the value cannot be set for this field
               * @expose
               */
              Field.prototype.verifyValue = function(value, skipRepeated) {
                  skipRepeated = skipRepeated || false;
                  if (value === null) { // NULL values for optional fields
                      if (this.required) {
                          throw(new Error("Illegal value for "+this.toString(true)+": "+value+" (required)"));
                      }
                      return null;
                  }
                  var i;
                  if (this.repeated && !skipRepeated) { // Repeated values as arrays
                      if (!(value instanceof Array)) {
                          value = [value];
                      }
                      var res = [];
                      for (i=0; i<value.length; i++) {
                          res.push(this.verifyValue(value[i], true));
                      }
                      return res;
                  }
                  // All non-repeated fields expect no array
                  if (!this.repeated && value instanceof Array) {
                      throw(new Error("Illegal value for "+this.toString(true)+": "+value+" (no array expected)"));
                  }
                  // Signed 32bit
                  if (this.type == ProtoBuf.TYPES["int32"] || this.type == ProtoBuf.TYPES["sint32"] || this.type == ProtoBuf.TYPES["sfixed32"]) {
                      return parseInt(value, 10) | 0;
                  }
                  // Unsigned 32bit
                  if (this.type == ProtoBuf.TYPES["uint32"] || this.type == ProtoBuf.TYPES["fixed32"]) {
                      return parseInt(value, 10) >>> 0;
                  }
                  if (ProtoBuf.Long) {
                      // Signed 64bit
                      if (this.type == ProtoBuf.TYPES["int64"] || this.type == ProtoBuf.TYPES["sint64"] || this.type == ProtoBuf.TYPES["sfixed64"]) {
                          if (!(typeof value == 'object' && value instanceof ProtoBuf.Long)) {
                              return ProtoBuf.Long.fromNumber(value, false);
                          }
                          return value.unsigned ? value.toSigned() : value;
                      }
                      // Unsigned 64bit
                      if (this.type == ProtoBuf.TYPES["uint64"] || this.type == ProtoBuf.TYPES["fixed64"]) {
                          if (!(typeof value == 'object' && value instanceof ProtoBuf.Long)) {
                              return ProtoBuf.Long.fromNumber(value, true);
                          }
                          return value.unsigned ? value : value.toUnsigned();
                      }
                  }
                  // Bool
                  if (this.type == ProtoBuf.TYPES["bool"]) {
                      return !!value;
                  }
                  // 64bit float
                  if (this.type == ProtoBuf.TYPES["float"] || this.type == ProtoBuf.TYPES["double"]) {
                      return parseFloat(value);
                  }
                  // Length-delimited string
                  if (this.type == ProtoBuf.TYPES["string"]) {
                      return ""+value;
                  }
                  // Length-delimited bytes
                  if (this.type == ProtoBuf.TYPES["bytes"]) {
                      if (typeof value == 'object' && value instanceof ByteBuffer) {
                          return value;
                      }
                      return ByteBuffer.wrap(value);
                  }
                  // Constant enum value
                  if (this.type == ProtoBuf.TYPES["enum"]) {
                      var values = this.resolvedType.getChildren(Enum.Value);
                      for (i=0; i<values.length; i++) {
                          if (values[i].name == value) {
                              return values[i].id;
                          } else if (values[i].id == value) {
                              return values[i].id;
                          }
                      }
                      throw(new Error("Illegal value for "+this.toString(true)+": "+value+" (not a valid enum value)"));
                  }
                  // Embedded message
                  if (this.type == ProtoBuf.TYPES["message"]) {
                      if (typeof value != 'object') {
                          throw(new Error("Illegal value for "+this.toString(true)+": "+value+" (object expected)"));
                      }
                      if (value instanceof this.resolvedType.clazz) {
                          return value;
                      }
                      // Else let's try to construct one from a key-value object
                      return new (this.resolvedType.clazz)(value); // May throw for a hundred of reasons
                  }
                  // We should never end here
                  throw(new Error("[INTERNAL ERROR] Illegal value for "+this.toString(true)+": "+value+" (undefined type "+this.type+")"));
              };
          
              /**
               * Encodes the specified field value to the specified buffer.
               * @param {*} value Field value
               * @param {ByteBuffer} buffer ByteBuffer to encode to
               * @return {ByteBuffer} The ByteBuffer for chaining
               * @throws {Error} If the field cannot be encoded
               * @expose
               */
              Field.prototype.encode = function(value, buffer) {
                  value = this.verifyValue(value); // May throw
                  if (this.type == null || typeof this.type != 'object') {
                      throw(new Error("[INTERNAL ERROR] Unresolved type in "+this.toString(true)+": "+this.type));
                  }
                  if (value === null || (this.repeated && value.length == 0)) return buffer; // Optional omitted
                  try {
                      if (this.repeated) {
                          var i;
                          if (this.options["packed"]) {
                              // "All of the elements of the field are packed into a single key-value pair with wire type 2
                              // (length-delimited). Each element is encoded the same way it would be normally, except without a
                              // tag preceding it." 
                              buffer.writeVarint32((this.id << 3) | ProtoBuf.WIRE_TYPES.LDELIM);
                              buffer.ensureCapacity(buffer.offset += 1); // We do not know the length yet, so let's assume a varint of length 1
                              var start = buffer.offset; // Remember where the contents begin
                              for (i=0; i<value.length; i++) {
                                  this.encodeValue(value[i], buffer);
                              }
                              var len = buffer.offset-start;
                              var varintLen = ByteBuffer.calculateVarint32(len);
                              if (varintLen > 1) { // We need to move the contents
                                  var contents = buffer.slice(start, buffer.offset);
                                  start += varintLen-1;
                                  buffer.offset = start;
                                  buffer.append(contents);
                              }
                              buffer.writeVarint32(len, start-varintLen);
                          } else {
                              // "If your message definition has repeated elements (without the [packed=true] option), the encoded
                              // message has zero or more key-value pairs with the same tag number"
                              for (i=0; i<value.length; i++) {
                                  buffer.writeVarint32((this.id << 3) | this.type.wireType);
                                  this.encodeValue(value[i], buffer);
                              }
                          }
                      } else {
                          buffer.writeVarint32((this.id << 3) | this.type.wireType);
                          this.encodeValue(value, buffer);
                      }
                  } catch (e) {
                      throw(new Error("Illegal value for "+this.toString(true)+": "+value+" ("+e+")"));
                  }
                  return buffer;
              };
          
              /**
               * Encodes a value to the specified buffer. Does not encode the key.
               * @param {*} value Field value
               * @param {ByteBuffer} buffer ByteBuffer to encode to
               * @return {ByteBuffer} The ByteBuffer for chaining
               * @throws {Error} If the value cannot be encoded
               * @expose
               */
              Field.prototype.encodeValue = function(value, buffer) {
                  if (value === null) return; // Nothing to encode
                  // Tag has already been written
                  
                  // 32bit varint as-is
                  if (this.type == ProtoBuf.TYPES["int32"] || this.type == ProtoBuf.TYPES["uint32"]) {
                      buffer.writeVarint32(value);
                      
                  // 32bit varint zig-zag
                  } else if (this.type == ProtoBuf.TYPES["sint32"]) {
                      buffer.writeZigZagVarint32(value);
                      
                  // Fixed unsigned 32bit
                  } else if (this.type == ProtoBuf.TYPES["fixed32"]) {
                      buffer.writeUint32(value);
                      
                  // Fixed signed 32bit
                  } else if (this.type == ProtoBuf.TYPES["sfixed32"]) {
                      buffer.writeInt32(value);
                  
                  // 64bit varint as-is
                  } else if (this.type == ProtoBuf.TYPES["int64"] || this.type == ProtoBuf.TYPES["uint64"]) {
                      buffer.writeVarint64(value); // throws
                      
                  // 64bit varint zig-zag
                  } else if (this.type == ProtoBuf.TYPES["sint64"]) {
                      buffer.writeZigZagVarint64(value); // throws
                      
                  // Fixed unsigned 64bit
                  } else if (this.type == ProtoBuf.TYPES["fixed64"]) {
                      buffer.writeUint64(value); // throws
                      
                  // Fixed signed 64bit
                  } else if (this.type == ProtoBuf.TYPES["sfixed64"]) {
                      buffer.writeInt64(value); // throws
                      
                  // Bool
                  } else if (this.type == ProtoBuf.TYPES["bool"]) {
                      buffer.writeVarint32(value ? 1 : 0);
                      
                  // Constant enum value
                  } else if (this.type == ProtoBuf.TYPES["enum"]) {
                      buffer.writeVarint32(value);
                      
                  // 32bit float
                  } else if (this.type == ProtoBuf.TYPES["float"]) {
                      buffer.writeFloat32(value);
                      
                  // 64bit float
                  } else if (this.type == ProtoBuf.TYPES["double"]) {
                      buffer.writeFloat64(value);
                      
                  // Length-delimited string
                  } else if (this.type == ProtoBuf.TYPES["string"]) {
                      buffer.writeVString(value);
                      
                  // Length-delimited bytes
                  } else if (this.type == ProtoBuf.TYPES["bytes"]) {
                      if (value.offset > value.length) { // Forgot to flip?
                          buffer = buffer.clone().flip();
                      }
                      buffer.writeVarint32(value.remaining());
                      buffer.append(value);
                      
                  // Embedded message
                  } else if (this.type == ProtoBuf.TYPES["message"]) {
                      var bb = new ByteBuffer().LE();
                      this.resolvedType.encode(value, bb);
                      buffer.writeVarint32(bb.offset);
                      buffer.append(bb.flip());
                  } else {
                      // We should never end here
                      throw(new Error("[INTERNAL ERROR] Illegal value to encode in "+this.toString(true)+": "+value+" (unknown type)"));
                  }
                  return buffer;
              };
          
              /**
               * Decode the field value from the specified buffer.
               * @param {number} wireType Leading wire type
               * @param {ByteBuffer} buffer ByteBuffer to decode from
               * @param {boolean=} skipRepeated Whether to skip the repeated check or not. Defaults to false.
               * @return {*} Decoded value
               * @throws {Error} If the field cannot be decoded
               * @expose
               */
              Field.prototype.decode = function(wireType, buffer, skipRepeated) {
                  var value, nBytes;
                  if (wireType != this.type.wireType && (skipRepeated || (wireType != ProtoBuf.WIRE_TYPES.LDELIM || !this.repeated))) {
                      throw(new Error("Illegal wire type for field "+this.toString(true)+": "+wireType+" ("+this.type.wireType+" expected)"));
                  }
                  if (wireType == ProtoBuf.WIRE_TYPES.LDELIM && this.repeated && this.options["packed"]) {
                      if (!skipRepeated) {
                          nBytes = buffer.readVarint32();
                          nBytes = buffer.offset + nBytes; // Limit
                          var values = [];
                          while (buffer.offset < nBytes) {
                              values.push(this.decode(this.type.wireType, buffer, true));
                          }
                          return values;
                      }
                      // Read the next value otherwise...
                      
                  }
                  // 32bit signed varint
                  if (this.type == ProtoBuf.TYPES["int32"]) {
                      return buffer.readVarint32() | 0;
                  }
                  
                  // 32bit unsigned varint
                  if (this.type == ProtoBuf.TYPES["uint32"]) {
                      return buffer.readVarint32() >>> 0;
                  }
                  
                  // 32bit signed varint zig-zag
                  if (this.type == ProtoBuf.TYPES["sint32"]) {
                      return buffer.readZigZagVarint32() | 0;
                  }
                  
                  // Fixed 32bit unsigned
                  if (this.type == ProtoBuf.TYPES["fixed32"]) {
                      return buffer.readUint32() >>> 0;
                  }
                  
                  // Fixed 32bit signed
                  if (this.type == ProtoBuf.TYPES["sfixed32"]) {
                      return buffer.readInt32() | 0;
                  }
                  
                  // 64bit signed varint
                  if (this.type == ProtoBuf.TYPES["int64"]) {
                      return buffer.readVarint64();
                  }
                  
                  // 64bit unsigned varint
                  if (this.type == ProtoBuf.TYPES["uint64"]) {
                      return buffer.readVarint64().toUnsigned();
                  }
                  
                  // 64bit signed varint zig-zag
                  if (this.type == ProtoBuf.TYPES["sint64"]) {
                      return buffer.readZigZagVarint64();
                  }
          
                  // Fixed 64bit unsigned
                  if (this.type == ProtoBuf.TYPES["fixed64"]) {
                      return buffer.readUint64();
                  }
                  
                  // Fixed 64bit signed
                  if (this.type == ProtoBuf.TYPES["sfixed64"]) {
                      return buffer.readInt64();
                  }
                  
                  // Bool varint
                  if (this.type == ProtoBuf.TYPES["bool"]) {
                      return !!buffer.readVarint32();
                  }
                  
                  // Constant enum value varint)
                  if (this.type == ProtoBuf.TYPES["enum"]) {
                      return buffer.readVarint32(); // The following Builder.Message#set will already throw
                  }
                  
                  // 32bit float
                  if (this.type == ProtoBuf.TYPES["float"]) {
                      return buffer.readFloat();
                  }
                  // 64bit float
                  if (this.type == ProtoBuf.TYPES["double"]) {
                      return buffer.readDouble();
                  }
                  
                  // Length-delimited string
                  if (this.type == ProtoBuf.TYPES["string"]){
                      return buffer.readVString();
                  }
                  
                  // Length-delimited bytes
                  if (this.type == ProtoBuf.TYPES["bytes"]) {
                      nBytes = buffer.readVarint32();
                      value = buffer.clone(); // Offset already set
                      value.length = value.offset+nBytes;
                      buffer.offset += nBytes;
                      return value;
                  }
                  
                  // Length-delimited embedded message
                  if (this.type == ProtoBuf.TYPES["message"]) {
                      nBytes = buffer.readVarint32();
                      return this.resolvedType.decode(buffer, nBytes);
                  }
                  
                  // We should never end here
                  throw(new Error("[INTERNAL ERROR] Illegal wire type for "+this.toString(true)+": "+wireType));
              };
          
              /**
               * @alias ProtoBuf.Reflect.Message.Field
               * @expose
               */
              Reflect.Message.Field = Field;
          
              /**
               * Constructs a new Enum.
               * @exports ProtoBuf.Reflect.Enum
               * @param {!ProtoBuf.Reflect.T} parent Parent Reflect object
               * @param {string} name Enum name
               * @param {Object.<string.*>=} options Enum options
               * @constructor
               * @extends ProtoBuf.Reflect.Namespace
               */
              var Enum = function(parent, name, options) {
                  Namespace.call(this, parent, name, options);
          
                  /**
                   * Runtime enum object.
                   * @type {Object.<string,number>|null}
                   * @expose
                   */
                  this.object = null;
              };
          
              // Extends Namespace
              Enum.prototype = Object.create(Namespace.prototype);
          
              /**
               * Builds this enum and returns the runtime counterpart.
               * @return {Object<string,*>}
               * @expose
               */
              Enum.prototype.build = function() {
                  var enm = {};
                  var values = this.getChildren(Enum.Value);
                  for (var i=0; i<values.length; i++) {
                      enm[values[i]['name']] = values[i]['id'];
                  }
                  if (Object.defineProperty) {
                      Object.defineProperty(enm, '$options', {
                          'value': this.buildOpt(),
                          'enumerable': false,
                          'configurable': false,
                          'writable': false
                      });
                  }
                  return this.object = enm;
              };
          
              /**
               * @alias ProtoBuf.Reflect.Enum
               * @expose
               */
              Reflect.Enum = Enum;
          
              /**
               * Constructs a new Enum Value.
               * @exports ProtoBuf.Reflect.Enum.Value
               * @param {!ProtoBuf.Reflect.Enum} enm Enum reference
               * @param {string} name Field name
               * @param {number} id Unique field id
               * @constructor
               * @extends ProtoBuf.Reflect.T
               */
              var Value = function(enm, name, id) {
                  T.call(this, enm, name);
          
                  /**
                   * Unique enum value id.
                   * @type {number}
                   * @expose
                   */
                  this.id = id;
              };
          
              // Extends T
              Value.prototype = Object.create(T.prototype);
          
              /**
               * @alias ProtoBuf.Reflect.Enum.Value
               * @expose
               */
              Reflect.Enum.Value = Value;
          
              return Reflect;
          })(ProtoBuf);
                  
          /**
           * @alias ProtoBuf.Builder
           * @expose
           */
          ProtoBuf.Builder = (function(ProtoBuf, Lang, Reflect) {
              "use strict";
              
              /**
               * Constructs a new Builder.
               * @exports ProtoBuf.Builder
               * @class Provides the functionality to build protocol messages.
               * @constructor
               */
              var Builder = function() {
          
                  /**
                   * Namespace.
                   * @type {ProtoBuf.Reflect.Namespace}
                   * @expose
                   */
                  this.ns = new Reflect.Namespace(null, ""); // Global namespace
          
                  /**
                   * Namespace pointer.
                   * @type {ProtoBuf.Reflect.T}
                   * @expose
                   */
                  this.ptr = this.ns;
          
                  /**
                   * Resolved flag.
                   * @type {boolean}
                   * @expose
                   */
                  this.resolved = false;
          
                  /**
                   * The current building result.
                   * @type {Object.<string,ProtoBuf.Builder.Message|Object>|null}
                   * @expose
                   */
                  this.result = null;
              };
          
              /**
               * Resets the pointer to the global namespace.
               * @expose
               */
              Builder.prototype.reset = function() {
                  this.ptr = this.ns;
              };
          
              /**
               * Defines a package on top of the current pointer position and places the pointer on it.
               * @param {string} pkg
               * @param {Object.<string,*>=} options
               * @return {ProtoBuf.Builder} this
               * @throws {Error} If the package name is invalid
               * @expose
               */
              Builder.prototype.define = function(pkg, options) {
                  if (typeof pkg != 'string' || !Lang.TYPEDEF.test(pkg)) {
                      throw(new Error("Illegal package name: "+pkg));
                  }
                  var part = pkg.split("."), i;
                  for (i=0; i<part.length; i++) { // To be absolutely sure
                      if (!Lang.NAME.test(part[i])) {
                          throw(new Error("Illegal package name: "+part[i]));
                      }
                  }
                  for (i=0; i<part.length; i++) {
                      if (!this.ptr.hasChild(part[i])) { // Keep existing namespace
                          this.ptr.addChild(new Reflect.Namespace(this.ptr, part[i], options));
                      }
                      this.ptr = this.ptr.getChild(part[i]);
                  }
                  return this;
              };
          
              /**
               * Tests if a definition is a valid message definition.
               * @param {Object.<string,*>} def Definition
               * @return {boolean} true if valid, else false
               * @expose
               */
              Builder.isValidMessage = function(def) {
                  // Messages require a string name
                  if (typeof def["name"] != 'string' || !Lang.NAME.test(def["name"])) {
                      return false;
                  }
                  // Messages must not contain values (that'd be an enum)
                  if (typeof def["values"] != 'undefined') {
                      return false;
                  }
                  // Fields, enums and messages are arrays if provided
                  var i;
                  if (typeof def["fields"] != 'undefined') {
                      if (!(def["fields"] instanceof Array)) {
                          return false;
                      }
                      var ids = [], id; // IDs must be unique
                      for (i=0; i<def["fields"].length; i++) {
                          if (!Builder.isValidMessageField(def["fields"][i])) {
                              return false;
                          }
                          id = parseInt(def["id"], 10);
                          if (ids.indexOf(id) >= 0) {
                              return false;
                          }
                          ids.push(id);
                      }
                      ids = null;
                  }
                  if (typeof def["enums"] != 'undefined') {
                      if (!(def["enums"] instanceof Array)) {
                          return false;
                      }
                      for (i=0; i<def["enums"].length; i++) {
                          if (!Builder.isValidEnum(def["enums"][i])) {
                              return false;
                          }
                      }
                  }
                  if (typeof def["messages"] != 'undefined') {
                      if (!(def["messages"] instanceof Array)) {
                          return false;
                      }
                      for (i=0; i<def["messages"].length; i++) {
                          if (!Builder.isValidMessage(def["messages"][i])) {
                              return false;
                          }
                      }
                  }
                  return true;
              };
          
              /**
               * Tests if a definition is a valid message field definition.
               * @param {Object} def Definition
               * @return {boolean} true if valid, else false
               * @expose
               */
              Builder.isValidMessageField = function(def) {
                  // Message fields require a string rule, name and type and an id
                  if (typeof def["rule"] != 'string' || typeof def["name"] != 'string' || typeof def["type"] != 'string' || typeof def["id"] == 'undefined') {
                      return false;
                  }
                  if (!Lang.RULE.test(def["rule"]) || !Lang.NAME.test(def["name"]) || !Lang.TYPEREF.test(def["type"]) || !Lang.ID.test(""+def["id"])) {
                      return false;
                  }
                  if (typeof def["options"] != 'undefined') {
                      // Options are objects
                      if (typeof def["options"] != 'object') {
                          return false;
                      }
                      // Options are <string,*>
                      var keys = Object.keys(def["options"]);
                      for (var i=0; i<keys.length; i++) {
                          if (!Lang.NAME.test(keys[i]) || (typeof def["options"][keys[i]] != 'string' && typeof def["options"][keys[i]] != 'number')) {
                              return false;
                          }
                      }
                  }
                  return true;
              };
          
              /**
               * Tests if a definition is a valid enum definition.
               * @param {Object} def Definition
               * @return {boolean} true if valid, else false
               * @expose
               */
              Builder.isValidEnum = function(def) {
                  // Enums require a string name
                  if (typeof def["name"] != 'string' || !Lang.NAME.test(def["name"])) {
                      return false;
                  }
                  // Enums require at least one value
                  if (typeof def["values"] == 'undefined' || !(def["values"] instanceof Array) || def["values"].length == 0) {
                      return false;
                  }
                  for (var i=0; i<def["values"].length; i++) {
                      // Values are objects
                      if (typeof def["values"][i] != "object") {
                          return false;
                      }
                      // Values require a string name and an id
                      if (typeof def["values"][i]["name"] != 'string' || typeof def["values"][i]["id"] == 'undefined') {
                          return false;
                      }
                      if (!Lang.NAME.test(def["values"][i]["name"]) || !Lang.NEGID.test(""+def["values"][i]["id"])) {
                          return false;
                      }
                  }
                  // It's not important if there are other fields because ["values"] is already unique
                  return true;
              };
          
              /**
               * Creates ths specified protocol types at the current pointer position.
               * @param {Array.<Object.<string,*>>} messages Messages or enums to create
               * @return {ProtoBuf.Builder} this
               * @throws {Error} If a message definition is invalid
               * @expose
               */
              Builder.prototype.create = function(messages) {
                  if (!messages) return; // Nothing to create
                  if (!(messages instanceof Array)) {
                      messages = [messages];
                  }
                  if (messages.length == 0) return;
          
                  // It's quite hard to keep track of scopes and memory here, so let's do this iteratively.
                  var stack = [], defs, def, obj, subObj, i, j;
                  stack.push(messages); // One level [a, b, c]
                  while (stack.length > 0) {
                      defs = stack.pop();
                      if (defs instanceof Array) { // Stack always contains entire namespaces
                          while (defs.length > 0) {
                              def = defs.shift(); // Namespace always contains an array of messages and enums
                              if (Builder.isValidMessage(def)) {
                                  obj = new Reflect.Message(this.ptr, def["name"], def["options"]);
                                  // Create fields
                                  if (def["fields"] && def["fields"].length > 0) {
                                      for (i=0; i<def["fields"].length; i++) { // i=Fields
                                          if (!Builder.isValidMessageField(def["fields"][i])) {
                                              throw(new Error("Not a valid message field definition in message "+obj.name+": "+JSON.stringify(def["fields"][i])));
                                          }
                                          if (obj.hasChild(def['fields'][i]['id'])) {
                                              throw(new Error("Duplicate field id in message "+obj.name+": "+def['fields'][i]['id']));
                                          }
                                          if (def["fields"][i]["options"]) {
                                              subObj = Object.keys(def["fields"][i]["options"]);
                                              for (j=0; j<subObj.length; j++) { // j=Option names
                                                  if (!Lang.NAME.test(subObj[j])) {
                                                      throw(new Error("Illegal field option name in message "+obj.name+"#"+def["fields"][i]["name"]+": "+subObj[j]));
                                                  }
                                                  if (typeof def["fields"][i]["options"][subObj[j]] != 'string' && typeof def["fields"][i]["options"][subObj[j]] != 'number') {
                                                      throw(new Error("Illegal field option value in message "+obj.name+"#"+def["fields"][i]["name"]+"#"+subObj[j]+": "+def["fields"][i]["options"][subObj[j]]));
                                                  }
                                              }
                                              subObj = null;
                                          }
                                          obj.addChild(new Reflect.Message.Field(obj, def["fields"][i]["rule"], def["fields"][i]["type"], def["fields"][i]["name"], def["fields"][i]["id"], def["fields"][i]["options"]));
                                      }
                                  }
                                  // Push enums and messages to stack
                                  subObj = [];
                                  if (typeof def["enums"] != 'undefined' && def['enums'].length > 0) {
                                      for (i=0; i<def["enums"].length; i++) {
                                          subObj.push(def["enums"][i]);
                                      }
                                  }
                                  if (def["messages"] && def["messages"].length > 0) {
                                      for (i=0; i<def["messages"].length; i++) {
                                          subObj.push(def["messages"][i]);
                                      }
                                  }
                                  this.ptr.addChild(obj); // Add to current namespace
                                  if (subObj.length > 0) {
                                      stack.push(defs); // Push the current level back
                                      defs = subObj; // Continue processing sub level
                                      subObj = null;
                                      this.ptr = obj; // And move the pointer to this namespace
                                      obj = null;
                                      continue;
                                  }
                                  subObj = null;
                                  obj = null;
                              } else if (Builder.isValidEnum(def)) {
                                  obj = new Reflect.Enum(this.ptr, def["name"], def["options"]);
                                  for (i=0; i<def["values"].length; i++) {
                                      obj.addChild(new Reflect.Enum.Value(obj, def["values"][i]["name"], def["values"][i]["id"]));
                                  }
                                  this.ptr.addChild(obj);
                                  obj = null;
                              } else {
                                  throw(new Error("Not a valid message or enum definition: "+JSON.stringify(def)));
                              }
                              def = null;
                          }
                          // Break goes here
                      } else {
                          throw(new Error("Not a valid namespace definition: "+JSON.stringify(defs)));
                      }
                      defs = null;
                      this.ptr = this.ptr.parent; // This namespace is s done
                  }
                  this.resolved = false; // Require re-resolve
                  this.result = null; // Require re-build
                  return this;
              };
          
              /**
               * Tests if the specified file is a valid import.
               * @param {string} filename
               * @returns {boolean} true if valid, false if it should be skipped
               * @expose
               */
              Builder.isValidImport = function(filename) {
                  // Ignore google/protobuf/descriptor.proto (for example) as it makes use of low-level
                  // bootstrapping directives that are not required and therefore cannot be parsed by ProtoBuf.js.
                  return !(/google\/protobuf\//.test(filename));
              };
          
              /**
               * Imported files.
               * @type {Array.<string>}
               * @expose
               */
              Builder.prototype.files = [];
          
              /**
               * Imports another definition into this builder.
               * @param {Object.<string,*>} parsed Parsed import
               * @param {string=} filename Imported file name
               * @return {ProtoBuf.Builder} this
               * @throws {Error} If the definition or file cannot be imported
               * @expose
               */
              Builder.prototype["import"] = function(parsed, filename) {
                  if (typeof filename === 'string') {
                      if (ProtoBuf.Util.IS_NODE) {
                          var path = require("path");
                          filename = path.resolve(filename);
                      }
                      if (!!this.files[filename]) {
                          this.reset();
                          return this; // Skip duplicate imports
                      }
                      this.files[filename] = true;
                  }
                  if (!!parsed['package']) {
                      this.define(parsed['package'], parsed["options"]);
                  }
                  if (!!parsed['messages']) {
                      this.create(parsed['messages']);
                  }
                  this.reset();
          
                  if (!!parsed['package']) {
                      this.define(parsed['package'], parsed["options"]);
                  }
                  if (!!parsed['enums']) {
                      this.create(parsed['enums']);
                  }
                  this.reset();
          
                  if (!!parsed['imports'] && parsed['imports'].length > 0) {
                      if (!filename) {
                          throw(new Error("Cannot determine import root: File name is unknown"));
                      }
                      var importRoot = filename.replace(/[\/\\][^\/\\]*$/, "");
                      for (var i=0; i<parsed['imports'].length; i++) {
                          var importFilename = importRoot+"/"+parsed['imports'][i];
                          if (/\.json$/i.test(importFilename)) { // Always possible
                              var json = ProtoBuf.Util.fetch(importFilename);
                              if (json === null) {
                                  throw(new Error("Failed to import '"+importFilename+"' in '"+filename+"': File not found"));
                              }
                              this["import"](JSON.parse(json), importFilename); // Throws on its own
                          } else {
                              if (!Builder.isValidImport(importFilename)) continue; // e.g. google/protobuf/*
                              var proto = ProtoBuf.Util.fetch(importFilename);
                              if (proto === null) {
                                  throw(new Error("Failed to import '"+importFilename+"' in '"+filename+"': File not found"));
                              }
                              var parser = new ProtoBuf.DotProto.Parser(proto+"");
                              this["import"](parser.parse(), importFilename); // Throws on its own                    
                          }
                      }
                  }
                  return this;
              };
          
              /**
               * Resolves all namespace objects.
               * @throws {Error} If a type cannot be resolved
               * @expose
               */
              Builder.prototype.resolveAll = function() {
                  // Resolve all reflected objects
                  if (this.ptr == null || typeof this.ptr.type == 'object') return; // Done (already resolved)
                  if (this.ptr instanceof Reflect.Namespace) {
                      // Build all children
                      var children = this.ptr.getChildren();
                      for (var i=0; i<children.length; i++) {
                          this.ptr = children[i];
                          this.resolveAll();
                      }
                  } else if (this.ptr instanceof Reflect.Message.Field) {
                      if (!Lang.TYPE.test(this.ptr.type)) { // Resolve type...
                          if (!Lang.TYPEREF.test(this.ptr.type)) {
                              throw(new Error("Illegal type reference in "+this.ptr.toString(true)+": "+this.ptr.type));
                          }
                          var res = this.ptr.parent.resolve(this.ptr.type);
                          if (!res) {
                              throw(new Error("Unresolvable type reference in "+this.ptr.toString(true)+": "+this.ptr.type));
                          }
                          this.ptr.resolvedType = res;
                          if (res instanceof Reflect.Enum) {
                              this.ptr.type = ProtoBuf.TYPES["enum"];
                          } else if (res instanceof Reflect.Message) {
                              this.ptr.type = ProtoBuf.TYPES["message"];
                          } else {
                              throw(new Error("Illegal type reference in "+this.ptr.toString(true)+": "+this.ptr.type));
                          }
                      } else {
                          this.ptr.type = ProtoBuf.TYPES[this.ptr.type];
                      }
                  } else if (this.ptr instanceof ProtoBuf.Reflect.Enum.Value) {
                      // No need to build enum values (built in enum)
                  } else {
                      throw(new Error("Illegal object type in namespace: "+typeof(this.ptr)+":"+this.ptr));
                  }
                  this.reset();
              };
          
              /**
               * Builds the protocol. This will first try to resolve all definitions and, if this has been successful,
               * return the built package.
               * @param {string=} path Specifies what to return. If omitted, the entire namespace will be returned.
               * @return {ProtoBuf.Builder.Message|Object.<string,*>}
               * @throws {Error} If a type could not be resolved
               * @expose
               */
              Builder.prototype.build = function(path) {
                  this.reset();
                  if (!this.resolved) {
                      this.resolveAll();
                      this.resolved = true;
                      this.result = null; // Require re-build
                  }
                  if (this.result == null) { // (Re-)Build
                      this.result = this.ns.build();
                  }
                  if (!path) {
                      return this.result;
                  } else {
                      var part = path.split(".");
                      var ptr = this.result; // Build namespace pointer (no hasChild etc.)
                      for (var i=0; i<part.length; i++) {
                          if (ptr[part[i]]) {
                              ptr = ptr[part[i]];
                          } else {
                              ptr = null;
                              break;
                          }
                      }
                      return ptr;
                  }
              };
          
              /**
               * Similar to {@link ProtoBuf.Builder#build}, but looks up the internal reflection descriptor.
               * @param {string=} path Specifies what to return. If omitted, the entire namespace wiil be returned.
               * @return {ProtoBuf.Reflect.T} Reflection descriptor or `null` if not found
               */
              Builder.prototype.lookup = function(path) {
                  return path ? this.ns.resolve(path) : this.ns;
              };
          
              /**
               * Returns a string representation of this object.
               * @return {string} String representation as of "Builder"
               * @expose
               */
              Builder.prototype.toString = function() {
                  return "Builder";
              };
          
              // Pseudo type documented in Reflect.js.
              // Exists for the sole purpose of being able to "... instanceof ProtoBuf.Builder.Message".
              Builder.Message = function() {};
              
              return Builder;
              
          })(ProtoBuf, ProtoBuf.Lang, ProtoBuf.Reflect);
                  
          /**
           * Builds a .proto definition and returns the Builder.
           * @param {string} proto .proto file contents
           * @param {(ProtoBuf.Builder|string)=} builder Builder to append to. Will create a new one if omitted.
           * @param {string=} filename The corresponding file name if known. Must be specified for imports.
           * @return {ProtoBuf.Builder} Builder to create new messages
           * @throws {Error} If the definition cannot be parsed or built
           * @expose
           */
          ProtoBuf.protoFromString = function(proto, builder, filename) {
              if (typeof builder == 'string') {
                  filename = builder;
                  builder = null;
              }
              var parser = new ProtoBuf.DotProto.Parser(proto+"");
              var parsed = parser.parse();
              var builder = typeof builder == 'object' ? builder : new ProtoBuf.Builder();
              if (parsed['package'] !== null) builder.define(parsed['package'], parsed["options"]);
              builder.create(parsed['messages']);
              builder.reset();
              if (parsed['package'] !== null) builder.define(parsed['package'], parsed["options"]);
              builder.create(parsed['enums']);
              builder.reset();
              if (filename && parsed['imports'].length > 0) {
                  builder["import"]({
                      "imports": parsed["imports"]
                  }, filename);
              }
              builder.resolveAll();
              builder.build();
              return builder;
          };
  
          /**
           * Builds a .proto file and returns the Builder.
           * @param {string} filename Path to proto filename
           * @param {function(ProtoBuf.Builder)=} callback Callback that will receive the Builder as its first argument.
           *   If the request has failed, builder will be NULL. If omitted, the file will be read synchronously and this
           *   function will return the Builder or NULL if the request has failed.
           * @param {ProtoBuf.Builder=} builder Builder to append to. Will create a new one if omitted.
           * @return {?ProtoBuf.Builder|undefined} The Builder if synchronous (no callback specified, will be NULL if the
           *   request has failed), else undefined
           * @expose
           */
          ProtoBuf.protoFromFile = function(filename, callback, builder) {
              if (callback && typeof callback == 'object') {
                  builder = callback;
                  callback = null;
              } else if (!callback || typeof callback != 'function') {
                  callback = null;
              }
              if (callback) {
                  ProtoBuf.Util.fetch(filename, function(contents) {
                      callback(ProtoBuf.protoFromString(contents, builder, filename));
                  });
              } else {
                  var contents = ProtoBuf.Util.fetch(filename);
                  return contents !== null ? ProtoBuf.protoFromString(contents, builder, filename) : null;
              }
          };
  
          /**
           * Constructs a new Builder with the specified package defined.
           * @param {string=} pkg Package name as fully qualified name, e.g. "My.Game". If no package is specified, the
           * builder will only contain a global namespace.
           * @param {Object.<string,*>=} options Top level options
           * @return {ProtoBuf.Builder} New Builder
           * @expose
           */
          ProtoBuf.newBuilder = function(pkg, options) {
              var builder = new ProtoBuf.Builder();
              if (typeof pkg != 'undefined') {
                  builder.define(pkg, options);
              }
              return builder;
          };
  
          return ProtoBuf;
      }
  
      // Enable module loading if available
      if (typeof module != 'undefined' && module["exports"]) { // CommonJS
          module["exports"] = loadProtoBuf(require("bytebuffer"));
      } else if (typeof define != 'undefined' && define["amd"]) { // AMD
          define("ProtoBuf", ["ByteBuffer"], loadProtoBuf);
      } else { // Shim
          if (!global["dcodeIO"]) {
              global["dcodeIO"] = {};
          }
          global["dcodeIO"]["ProtoBuf"] = loadProtoBuf(global["dcodeIO"]["ByteBuffer"]);
      }
  
  })(this);