text: /* jshint esversion: 6 */
  
  // Experimental
  
  var weka = weka || {};
  var json = json || require('./json');
  var java = {};
  
  weka.ModelFactory = class {
  
      match(context) {
          try {
              const reader = new java.io.InputObjectStream(context.stream);
              const obj = reader.read();
              if (obj && obj.$class && obj.$class.name) {
                  return true;
              }
          }
          catch (err) {
              // continue regardless of error
          }
          return false;
      }
  
      open(context /*, host */) {
          return Promise.resolve().then(() => {
              const reader = new java.io.InputObjectStream(context.stream);
              const obj = reader.read();
              throw new weka.Error("Unsupported type '" + obj.$class.name + "'.");
          });
      }
  };
  
  weka.Error = class extends Error {
  
      constructor(message) {
          super(message);
          this.name = 'Error loading Weka model.';
      }
  };
  
  java.io = {};
  
  java.io.InputObjectStream = class {
  
      constructor(stream) {
          // Object Serialization Stream Protocol
          // https://www.cis.upenn.edu/~bcpierce/courses/629/jdkdocs/guide/serialization/spec/protocol.doc.html
          if (stream.length < 5) {
              throw new java.io.Error('Invalid stream size');
          }
          const signature = [ 0xac, 0xed ];
          if (!stream.peek(2).every((value, index) => value === signature[index])) {
              throw new java.io.Error('Invalid stream size');
          }
          this._reader = new java.io.InputObjectStream.BinaryReader(stream.peek());
          this._references = [];
          this._reader.skip(2);
          const version = this._reader.uint16();
          if (version !== 0x0005) {
              throw new java.io.Error("Unsupported version '" + version + "'.");
          }
      }
  
      read() {
          return this._object();
      }
  
      _object() {
          const code = this._reader.byte();
          switch (code) {
              case 0x73: { // TC_OBJECT
                  const obj = {};
                  obj.$class = this._classDesc();
                  this._newHandle(obj);
                  this._classData(obj);
                  return obj;
              }
              case 0x74: { // TC_STRING
                  return this._newString(false);
              }
          }
          throw new java.io.Error("Unsupported code '" + code + "'.");
      }
  
      _classDesc() {
          const code = this._reader.byte();
          switch (code) {
              case 0x72: // TC_CLASSDESC
                  this._reader.skip(-1);
                  return this._newClassDesc();
              case 0x71: // TC_REFERENCE
                  return this._references[this._reader.uint32() - 0x7e0000];
              case 0x70: // TC_NULL
                  this._reader.byte();
                  return null;
          }
          throw new java.io.Error("Unsupported code '" + code + "'.");
      }
  
      _newClassDesc() {
          const code = this._reader.byte();
          switch (code) {
              case 0x72: { // TC_CLASSDESC
                  const classDesc = {};
                  classDesc.name = this._reader.string(),
                  classDesc.id = this._reader.uint64().toString();
                  this._newHandle(classDesc);
                  classDesc.flags = this._reader.byte();
                  classDesc.fields = [];
                  const count = this._reader.uint16();
                  for (let i = 0; i < count; i++) {
                      const field = {};
                      field.type = String.fromCharCode(this._reader.byte());
                      field.name = this._reader.string();
                      if (field.type === '[' || field.type === 'L') {
                          field.classname = this._object();
                      }
                      classDesc.fields.push(field);
                  }
                  if (this._reader.byte() !== 0x78) {
                      throw new java.io.Error('Expected TC_ENDBLOCKDATA.');
                  }
                  classDesc.superClass = this._classDesc();
                  return classDesc;
              }
              case 0x7D: // TC_PROXYCLASSDESC
                  break;
          }
          throw new java.io.Error("Unsupported code '" + code + "'.");
      }
  
      _classData(/* obj */) {
          /*
          const classname = obj.$class.name;
          let flags = obj.$class.flags;
          let superClass = obj.$class.superClass;
          while (superClass) {
              flags |= superClass.flags;
              superClass = superClass.superClass;
          }
          if (flags & 0x02) { // SC_SERIALIZABLE
              debugger;
              var customObject = objects[classname];
              var hasReadObjectMethod = customObject && customObject.readObject;
              if (flags & 0x01) { // SC_WRITE_METHOD
                  if (!hasReadObjectMethod) {
                      throw new Error('Class "'+ classname + '" dose not implement readObject()');
                  }
                  customObject.readObject(this, obj);
                  if (this._reader.byte() !== 0x78) { // TC_ENDBLOCKDATA
                      throw new java.io.Error('Expected TC_ENDBLOCKDATA.');
                  }
              }
              else {
                  if (hasReadObjectMethod) {
                      customObject.readObject(this, obj);
                      if (this._reader.byte() !== 0x78) { // TC_ENDBLOCKDATA
                          throw new java.io.Error('Expected TC_ENDBLOCKDATA.');
                      }
                  }
                  else {
                      this._nowrclass(obj);
                  }
              }
          }
          else if (flags & 0x04) { // SC_EXTERNALIZABLE
              if (flags & 0x08) { // SC_BLOCK_DATA
                  this._objectAnnotation(obj);
              }
              else {
                  this._externalContents();
              }
          }
          else {
              throw new Error('Illegal flags: ' + flags);
          }
          */
      }
  
      _newString(long) {
          const value = this._reader.string(long);
          this._newHandle(value);
          return value;
      }
  
      _newHandle(obj) {
          this._references.push(obj);
      }
  };
  
  java.io.InputObjectStream.BinaryReader = class {
  
      constructor(buffer) {
          this._buffer = buffer;
          this._position = 0;
          this._length = buffer.length;
          this._view = new DataView(buffer.buffer, buffer.byteOffset, buffer.byteLength);
          this._decoder = new TextDecoder('utf-8');
      }
  
      skip(offset) {
          this._position += offset;
          if (this._position > this._end) {
              throw new java.io.Error('Expected ' + (this._position - this._end) + ' more bytes. The file might be corrupted. Unexpected end of file.');
          }
      }
  
      byte() {
          const position = this._position;
          this.skip(1);
          return this._buffer[position];
      }
  
      uint16() {
          const position = this._position;
          this.skip(2);
          return this._view.getUint16(position, false);
      }
  
      uint32() {
          const position = this._position;
          this.skip(4);
          return this._view.getUint32(position, false);
      }
  
      uint64() {
          const position = this._position;
          this.skip(8);
          return this._view.getUint64(position, false);
      }
  
      string(long) {
          const size = long ? this.uint64().toNumber() : this.uint16();
          const position = this._position;
          this.skip(size);
          return this._decoder.decode(this._buffer.subarray(position, this._position));
      }
  };
  
  java.io.Error = class extends Error {
  
      constructor(message) {
          super(message);
          this.name = 'Error loading Object Serialization Stream Protocol.';
      }
  };
  
  if (typeof module !== 'undefined' && typeof module.exports === 'object') {
      module.exports.ModelFactory = weka.ModelFactory;
  }