text: /* jshint esversion: 6 */
  /* eslint "indent": [ "error", 4, { "SwitchCase": 1 } ] */
  
  var npu = npu || {};
  var base = base || require('./base');
  
  
  npu.ModelFactory = class {
  
      match(context) {
          const identifier = context.identifier.toLowerCase();
          if (identifier.endsWith('.npumodel')) {
              const stream = context.stream;
              stream.peek(-32);
              const buffer = stream.read(32);
              stream.seek(0);
              const view = new npu.BinaryReader(buffer);
              let text = view.getStr(32);
  
              text = text.substring(0, Math.min(text.length, 32));
              if (text.search('#') != -1) {
                  this.version = text.split('#').shift().trim();
                  this.chip_no = text.split('#', 2)[1].substring(0,2);
              }
              else {
                  this.version = text.substring(0,15);
              }
              if (this.version === '2020-06-09V0.08' || this.version === '2019-08-07V0.04' || this.version.startsWith('2020-10-25V1.1') || this.version.startsWith('2021-12-31V1.2') || this.version.startsWith('2022-02-03V1.4') || this.version.startsWith('2022-02-03V1.5')) {
                  return true;
              }
              else {
                  throw new npu.Error('Unsupport npumodel version:' + this.version);
              }
          }
  
          return false;
      }
  
      open(context) {
          return npu.Metadata.open(context, this.version).then((metadata) => {
              const identifier = context.identifier.toLowerCase();
              try {
                  return new npu.Model(metadata, context, this.version);
              }
              catch (error) {
                  const message = error && error.message ? error.message : error.toString();
                  throw new npu.Error(message.replace(/\.$/, '') + " in '" + identifier + "'.");
              }
          });
      }
  };
  
  npu.Model = class {
  
      constructor(metadata, context, version) {
          this._format = 'npumodel';
          this._graphs = [];
          this.version = version;
          this._graphs.push(new npu.Graph(metadata, context, version));
      }
  
      get format() {
          return 'npu';
      }
  
      get graphs() {
          return this._graphs;
      }
  };
  
  npu.Graph = class {
  
      constructor(metadata, context, version) {
          this._inputs = [];
          this._outputs = [];
          this._nodes = [];
          this.version = version;
          var model;
  
          const stream = context.stream;
          //stream.peek(-32);
          const buffer = stream.read();
          stream.seek(0);
  
          if (version === '2019-08-07V0.04') { //vc718
              model = new npu.Binary718v4Reader(metadata, buffer, this);
          }
          else if (version === '2020-06-09V0.08') { //vc768
              model = new npu.Binary768v8Reader(metadata, buffer, this);
          }
          else if (version.startsWith('2020-10-25V1.1') || version.startsWith('2021-12-31V1.2')) {// vc768
              model = new npu.Binary768v11Reader(metadata, buffer, this);
          }
          else if (version.startsWith('2022-02-03V1.4') || version.startsWith('2022-02-03V1.5')) { //vc768
              model = new npu.Binary768v14Reader(metadata, buffer, this);
          }
  
          let lastLayer = null;
          let lastTop = null;
          for (let i = 1; i <= model.Layer_num; i++) {
              var node = model.getLayer(metadata);
              var input_name = {};
              input_name = node.inputs[0].arguments[0].name;
              var output_name = {};
              output_name = node.outputs[0].arguments[0].name;
              if (input_name == output_name && input_name == lastTop && lastLayer) { //inplace
                  lastLayer.chain = lastLayer.chain || [];
                  lastLayer.chain.push(node);
              }
              else {
                  lastLayer = node;
                  lastTop = node.outputs[0].arguments[0].name;
                  this._nodes.push(node);
              }
          }
      }
  
      get inputs() {
          return this._inputs;
      }
  
      get outputs() {
          return this._outputs;
      }
  
      get nodes() {
          return this._nodes;
      }
  };
  
  npu.Parameter = class {
  
      constructor(name, visible, args) {
          this._name = name;
          this._visible = visible;
          this._arguments = args;
      }
  
      get name() {
          return this._name;
      }
  
      get visible() {
          return this._visible;
      }
  
      get arguments() {
          return this._arguments;
      }
  };
  
  npu.Argument = class {
  
      constructor(name, type, shape, description) {
          if (typeof name !== 'string') {
              throw new npu.Error("Invalid argument identifier '" + JSON.stringify(name) + "'.");
          }
          this._name = name;
          this._type = type || null;
          this._initializer = null;
          this._shape = shape;
          this._description = description;
          this._ioflag = false;
      }
  
      set description(input_str) {
          this._description = input_str;
      }
      get description() {
          return this._description;
      }
  
      get name() {
          return this._name;
      }
  
      set type(input_str) {
          this._type = input_str;
      }
      get type() {
          return this._type;
      }
  
      set shape(input_arr) {
          this._shape = input_arr;
      }
      get shape() {
          return this._shape;
      }
  
      set ioflag(input_bool) {
          this._ioflag = input_bool;
      }
      get ioflag() {
          return this._ioflag;
      }
  
      set initializer(input_obj) {
          this._initializer = input_obj;
      }
      get initializer() {
          return this._initializer;
      }
  };
  
  npu.Node = class {
  
      constructor(metadata) {
          this._metadata = metadata;
          this._inputs = [];
          this._outputs = [];
          this._attributes = [];
          this._type = {};
          this._name = '';
          this._iflag = false;
          this._oflag = false;
      }
  
      get type() {
          return this._type;
      }
      set type(input_str) {
          this._type = input_str;
      }
  
      get name() {
          return this._name;
      }
      set name(input_str) {
          this._name = input_str;
      }
  
      set iflag(input_bool) {
          this._iflag = input_bool;
      }
      get iflag() {
          return this._iflag;
      }
  
      set oflag(input_bool) {
          this._oflag = input_bool;
      }
      get oflag() {
          return this._oflag;
      }
  
      get metadata() {
          return this._metadata.type(this._type);
      }
  
      get attributes() {
          return this._attributes;
      }
      append_attributes(input_obj) {
          if (input_obj) {
              this._attributes.push(input_obj);
          }
      }
  
      get inputs() {
          return this._inputs;
      }
      append_inputs(input_obj) {
          if (input_obj) {
              this._inputs.push(input_obj);
          }
      }
  
      get outputs() {
          return this._outputs;
      }
      append_outputs(input_obj) {
          if (input_obj) {
              this._outputs.push(input_obj);
          }
      }
  };
  
  npu.Attribute = class {
  
      constructor(schema, reader) {
          this._type = '';
          this._name = '';
          this._value = -1;
          if (schema) {
              this._name = schema.name;
              if (schema.type) {
                  this._type = schema.type;
              }
              switch (this._type) {
                  case 'bit16':
                      this._value = reader.getBit16(schema.mask);
                      break;
                  case 'bit32':
                      this._value = reader.getBit32(schema.mask);
                      break;
                  case 'uint16':
                      this._value = reader.getInt16(false);
                      break;
                  case 'int16':
                      this._value = reader.getInt16(true);
                      break;
                  case 'uint32':
                      this._value = reader.getInt32(false);
                      break;
                  case 'int32':
                      this._value = reader.getInt32(true);
                      break;
                  case 'float32':
                      this._value = reader.getFloat32();
                      break;
                  default:
                      break;
              }
              if (Object.prototype.hasOwnProperty.call(schema, 'visible') && !schema.visible) {
                  this._visible = false;
              }
              else if (Object.prototype.hasOwnProperty.call(schema, 'default')) {
                  if (this._value == schema.default || (this._value && this._value.toString() == schema.default.toString())) {
                      this._visible = false;
                  }
              }
          }
      }
  
      get type() {
          return this._type;
      }
      set type(input_str) {
          this._type = input_str;
      }
  
      get name() {
          return this._name;
      }
      set name(input_str) {
          this._name = input_str;
      }
  
      get value() {
          return this._value;
      }
      set value(input_num) {
          this._value = input_num;
      }
  
      get visible() {
          return this._visible == false ? false : true;
      }
      set visible(input_bool) {
          this._visible = input_bool;
      }
  };
  
  npu.Tensor = class {
  
      constructor(name, type, shape, data) {
          this._name = name;
          this._type = type;
          this._shape = shape;
          this._data = data;
      }
  
      set kind(input_str) {
          this._kind = input_str;
      }
      get kind() {
          return this._kind;
      }
  
      get name() {
          return this._name;
      }
  
      get type() {
          return this._type;
      }
  
      get state() {
          return this._state || null;
      }
      set state(input_str) {
          this._state = input_str;
      }
  
      get value() {
          const context = this._context();
          if (context.state) {
              return null;
          }
          context.limit = Number.MAX_SAFE_INTEGER;
          return this._decode(context, 0);
      }
  
      toString() {
          const context = this._context();
          if (context.state) {
              return '';
          }
          context.limit = 10000;
          const value = this._decode(context, 0);
          return JSON.stringify(value, null, 4);
      }
  
      _context() {
          const context = {};
          context.index = 0;
          context.count = 0;
          context.state = null;
  
          if (this._type.dataType == '?') {
              context.state = 'Tensor has unknown data type.';
              return context;
          }
          if (!this._type.shape) {
              context.state = 'Tensor has no dimensions.';
              return context;
          }
  
          if (!this._data) {
              context.state = 'Tensor data is empty.';
              return context;
          }
  
          switch (this._type.dataType) {
              case 'float16':
              case 'float32':
                  context.data = new DataView(this._data.buffer, this._data.byteOffset, this._data.byteLength);
                  break;
              default:
                  context.state = 'Tensor data type is not implemented.';
                  break;
          }
  
          context.dataType = this._type.dataType;
          context.shape = this._type.shape.dimensions;
          return context;
      }
  
      _decode(context, dimension) {
          const shape = context.shape.length !== 0 ? context.shape : [ 1 ];
          const results = [];
          const size = shape[dimension];
          if (dimension == shape.length - 1) {
              for (let i = 0; i < size; i++) {
                  if (context.count > context.limit) {
                      results.push('...');
                      return results;
                  }
                  switch (this._type.dataType) {
                      case 'float32':
                          results.push(context.data.getFloat32(context.index, true));
                          context.index += 4;
                          context.count++;
                          break;
                      case 'float16':
                          results.push(context.data.getFloat16(context.index, true));
                          context.index += 2;
                          context.count++;
                          break;
                      default:
                          break;
                  }
              }
          }
          else {
              for (let j = 0; j < size; j++) {
                  if (context.count > context.limit) {
                      results.push('...');
                      return results;
                  }
                  results.push(this._decode(context, dimension + 1));
              }
          }
          if (context.shape.length == 0) {
              return results[0];
          }
          return results;
      }
  };
  
  npu.TensorType = class {
  
      constructor(dataType, shape) {
          this._dataType = dataType || '?';
          this._shape = shape;
      }
  
      get dataType() {
          return this._dataType;
      }
  
      get shape() {
          return this._shape;
      }
  
      toString() {
          return this._dataType + ' Shape:' + this._shape.toString();
      }
  };
  
  npu.TensorShape = class {
  
      constructor(dimensions) {
          this._dimensions = dimensions;
      }
  
      get dimensions() {
          return this._dimensions;
      }
  
      toString() {
          return this._dimensions ? ('[' + this._dimensions.map((dimension) => dimension ? dimension.toString() : '?').join(',') + ']') : '';
      }
  };
  
  npu.Metadata = class {
  
      static open(context, version) {
          let json_url = 'npu-metadata';
          if (version.startsWith('2019-08-07V0.04')) {
              json_url = json_url + '718v4.json';
          }
          else if (version.startsWith('2020-06-09V0.08')) {
              json_url = json_url + '768v8.json';
          }
          else if (version.startsWith('2020-10-25V1.1')) {
              json_url = json_url + '768v11.json';
          }
          else if (version.startsWith('2021-12-31V1.2')) {
              json_url = json_url + '768v11.json';
          }
          else if (version.startsWith('2022-02-03V1.4')) {
              json_url = json_url + '768v14.json';
          }
          else if (version.startsWith('2022-02-03V1.5')) {
              json_url = json_url + '768v14.json';
          }
  
          if (npu.Metadata._metadata) {
              return Promise.resolve(npu.Metadata._metadata);
          }
  
          return context.request(json_url, 'utf-8', null).then((data) => {
              npu.Metadata._metadata = new npu.Metadata(data);
              return npu.Metadata._metadata;
          }).catch(() => {
              npu.Metadata._metadata = new npu.Metadata(null);
              return npu.Metadata._metadatas;
          });
      }
  
      constructor(data) {
          this._operatorMap = new Map();
          this._map = new Map();
          this._attributeCache = new Map();
  
          if (data) {
              const items = JSON.parse(data);
              if (items) {
                  for (const item of items) {
                      if (item.name && item.schema) {
                          item.schema.name = item.name;
                          this._map.set(item.name, item.schema);
                          if (Object.prototype.hasOwnProperty.call(item.schema, 'Opera')) {
                              this._operatorMap.set(item.schema.Opera, item.name);
                          }
                      }
                  }
              }
          }
      }
  
      operator(code) {
          return this._operatorMap.get(code);
      }
  
      type(name) {
          return this._map.get(name);
      }
  
      attribute(type, name) {
          const key = type + ':' + name;
          if (!this._attributeCache.has(key)) {
              const schema = this.type(type);
              if (schema && schema.attributes && schema.attributes.length > 0) {
                  for (const attribute of schema.attributes) {
                      this._attributeCache.set(type + ':' + attribute.name, attribute);
                  }
              }
              if (!this._attributeCache.has(key)) {
                  this._attributeCache.set(key, null);
              }
          }
          return this._attributeCache.get(key);
      }
  };
  
  npu.Binary718v4Reader = class {
      constructor(metadata, buffer, graph) {
          this._graph = graph;
          this.reader = new npu.BinaryReader(buffer);
          this.Version = this.reader.getStr(32);
          this.Name = this.reader.getStr(32);
          this.Layer_num = this.reader.getInt32(false);
          this.HwCmdBaseAddr = this.reader.getInt32(false);
          this.HwCmdBaseVaddr = this.reader.getInt32(false);
          this.reader.skip(4);
          this.StartLayer = this.reader.getInt32(false);
          this.reader.skip(4*31);
          this.EndLayer = this.reader.getInt32(false);
          this.reader.skip(4*31);
          this.Hardware_Layer_num = this.reader.getInt32(false);
          this.Hardware_Start_Layer = this.reader.getInt32(false);
          this.Hardware_Exec_Layer = this.reader.getInt32(false);
          this.Hardware_Command_Reg_Addr = this.reader.getInt32(false);
  
          console.log('Version:' + this.Version.split('#').shift().trim());
          console.log('Name:'+this.Name);
          console.log(this.Layer_num + ' layers, ' + this.Hardware_Layer_num + ' hardware layers.');
          console.log('StartLayer: ' + this.StartLayer + ' EndLayer: ' + this.EndLayer);
          console.log('Hardware_Layer_num: ' + this.Hardware_Start_Layer + ' Hardware_Exec_Layer: ' + this.Hardware_Exec_Layer);
          console.log('HwCmdRegAddr:'+ this.Hardware_Command_Reg_Addr.toString(16));
      }
  
      getLayer(metadata) {
          const data_length = 96;
          const longest_param = 64;
          var node = new npu.Node(metadata);
          var in_num = this.reader.getInt32(false);
          var out_num = this.reader.getInt32(false);
          this.reader.skip(8);
  
          var inputs = [];
          var outputs = [];
  
          for (let i = 1; i <= 4; i++) {
              if (i <= in_num) {
                  const blob_reader = new npu.BlobReader718v4(this.reader);
                  inputs.push(blob_reader.getBlob());
              }
              else {
                  inputs.push(null);
                  this.reader.skip(data_length);
              }
          }
  
          for (let o = 1; o <= 2; o++) {
              if (o <= out_num) {
                  const blob_reader = new npu.BlobReader718v4(this.reader);
                  outputs.push(blob_reader.getBlob());
              }
              else {
                  outputs.push(null);
                  this.reader.skip(data_length);
              }
          }
  
          var opera_code = this.reader.getInt32(false);
          if ((opera_code & 0x2) && (opera_code != 0x2)) {
              opera_code = opera_code & ~(opera_code & 0x2);
          }
          this.reader.skip(3*4);
          node.name = this.reader.getStr(32);
  
          var operator = metadata.operator(opera_code);
          node.type = metadata.type(operator);
  
          var blob;
          const meta_input_blobs = metadata.type(operator).inputs;
          for (const meta_input_blob of meta_input_blobs) {
              blob = inputs.shift();
              if (blob !== null) {
                  if (meta_input_blob.name !== 'input') {
                      blob.initializer = new npu.Tensor(blob.name, new npu.TensorType(blob.data_type, new npu.TensorShape(blob.shape)), null);
                      blob.initializer.kind = meta_input_blob.name;
                  }
                  else {
                      blob.initializer = null;
                  }
                  if (blob.ioflag && !node.iflag) {
                      node.name = node.name + '-<input>';
                      node.iflag = true;
                      this._graph._inputs.push(new npu.Parameter(meta_input_blob.name, true, [blob]));
                  }
                  node.append_inputs(new npu.Parameter(meta_input_blob.name, true, [blob]));
              }
          }
  
          const meta_output_blobs = metadata.type(operator).outputs;
          for (const meta_output_blob of meta_output_blobs) {
              blob = outputs.shift();
              if (blob !== null) {
                  if (meta_output_blob.name !== 'output') {
                      blob.initializer = new npu.Tensor(blob.name, new npu.TensorType(blob.data_type, new npu.TensorShape(blob.shape)), null);
                      blob.initializer.kind = meta_output_blob.name;
                  }
                  else {
                      blob.initializer = null;
                  }
                  if (blob.ioflag && !node.oflag) {
                      node.name = node.name + '-<output>';
                      node.oflag = true;
                      this._graph._outputs.push(new npu.Parameter(meta_output_blob.name, true, [blob]));
                  }
                  node.append_outputs(new npu.Parameter(meta_output_blob.name, true, [blob]));
              }
          }
  
          const schema = metadata.type(operator);
          const attributeMetadata = schema && schema.attributes ? schema && schema.attributes : [];
          var current_param_length = 0;
          for (const attribute of attributeMetadata) {
              node.append_attributes(new npu.Attribute(attribute, this.reader));
              switch (attribute.type) {
                  case 'bit16':
                  case 'bit32':
                      break;
                  case 'uint16':
                  case 'int16':
                      current_param_length = current_param_length + 2;
                      break;
                  case 'uint32':
                  case 'int32':
                  case 'float32':
                      current_param_length = current_param_length + 4;
                      break;
                  default:
                      break;
              }
          }
          this.reader.skip(longest_param - current_param_length);
  
          return node;
      }
  };
  
  npu.Binary768v8Reader = class {
      constructor(metadata, buffer, graph) {
          this._graph = graph;
          this.reader = new npu.BinaryReader(buffer);
          this.Version = this.reader.getStr(32);
          this.Name = this.reader.getStr(32);
          this.Layer_num = this.reader.getInt32(false);
          this.StartLayer = this.reader.getInt32(false);
          this.EndLayer = this.reader.getInt32(false);
          this.Hardware_Layer_num = this.reader.getInt32(false);
          this.Hardware_Start_Layer = this.reader.getInt32(false);
          this.Hardware_Exec_Layer = this.reader.getInt32(false);
          this.Hardware_Command_Base_Addr = this.reader.getInt32(false);
          this.Hardware_Command_Reg_Addr = this.reader.getInt32(false);
          this.Hardware_Command_base_Vaddr = this.reader.getInt64(false);
  
          console.log('Version:' + this.Version.split('#').shift().trim());
          console.log('Name:'+this.Name);
          console.log(this.Layer_num + ' layers, ' + this.Hardware_Layer_num + ' hardware layers.');
          console.log('StartLayer: ' + this.StartLayer + ' EndLayer: ' + this.EndLayer);
          console.log('Hardware_Layer_num: ' + this.Hardware_Start_Layer + ' Hardware_Exec_Layer: ' + this.Hardware_Exec_Layer);
          console.log('HwCmdBaseAddr: ' + this.Hardware_Command_Base_Addr.toString(16) + ' HwCmdRegAddr:'+
              this.Hardware_Command_Reg_Addr.toString(16) + ' HwCmdBaseVaddr:' + this.Hardware_Command_base_Vaddr.toString(16));
      }
  
      getLayer(metadata) {
          const data_length = 96;
          const longest_param = 28;//24;
          var node = new npu.Node(metadata);
          var in_num = this.reader.getInt32(false);
          var out_num = this.reader.getInt32(false);
          this.reader.skip(8);
  
          var inputs = [];
          var outputs = [];
          for (let i = 1; i <= 4; i++) {
              if (i <= in_num) {
                  const blob_reader = new npu.BlobReader768v8(this.reader);
                  inputs.push(blob_reader.getBlob());
              }
              else {
                  inputs.push(null);
                  this.reader.skip(data_length);
              }
          }
  
          for (let o = 1; o <= 2; o++) {
              if (o <= out_num) {
                  const blob_reader = new npu.BlobReader768v8(this.reader);
                  outputs.push(blob_reader.getBlob());
              }
              else {
                  outputs.push(null);
                  this.reader.skip(data_length);
              }
          }
  
          node.name = this.reader.getStr(32);
          var opera_code = this.reader.getInt32(false);
  
          var Round = new npu.Attribute(null, null);
          Round.name = 'Round';
          Round.type = 'uint32';
          Round.value = this.reader.getInt32(false);
          node.append_attributes(Round);
  
          if ((opera_code & 0x2) && (opera_code != 0x2)) {
              opera_code = opera_code & ~(opera_code & 0x2);
              var ReluThres = new npu.Attribute(null, null);
              ReluThres.name = 'ReluThres';
              ReluThres.type = 'float32';
              ReluThres.value = this.reader.getFloat32();
              node.append_attributes(ReluThres);
              this.reader.skip(8); // f32PReluNegK s32PrePReluOutShift
          }
          else if ((opera_code & 0x100) && (opera_code != 0x100)) {
              opera_code = opera_code & ~(opera_code & 0x100);
              this.reader.skip(4); // f32ReluxThres
              var PReluNegK = new npu.Attribute(null, null);
              PReluNegK.name = 'PReluNegK';
              PReluNegK.type = 'float32';
              PReluNegK.value = this.reader.getFloat32();
              node.append_attributes(PReluNegK);
  
              var PrePReluOutShift =  new npu.Attribute(null, null);
              PrePReluOutShift.name = 'PrePReluOutShift';
              PrePReluOutShift.type = 'int32';
              PrePReluOutShift.value = this.reader.getInt32(true);
              node.append_attributes(PrePReluOutShift);
          }
          else {
              this.reader.skip(12);// f32ReluxThres f32PReluNegK s32PrePReluOutShift
          }
  
          var operator = metadata.operator(opera_code);
          node.type = metadata.type(operator);
  
          const meta_input_blobs = metadata.type(operator).inputs;
          for (const meta_input_blob of meta_input_blobs) {
              var inblob = inputs.shift();
              if (inblob !== null) {
                  if (meta_input_blob.name !== 'input') {
                      inblob.initializer = new npu.Tensor(inblob.name, new npu.TensorType(inblob.data_type, new npu.TensorShape(inblob.shape)), null);
                      inblob.initializer.kind = meta_input_blob.name;
                  }
                  else {
                      inblob.initializer = null;
                  }
                  if (inblob.ioflag && !node.iflag) {
                      node.name = node.name + '-<input>';
                      node.iflag = true;
                      this._graph._inputs.push(new npu.Parameter(meta_input_blob.name, true, [inblob]));
                  }
                  node.append_inputs(new npu.Parameter(meta_input_blob.name, true, [inblob]));
              }
          }
  
          const meta_output_blobs = metadata.type(operator).outputs;
          for (const meta_output_blob of meta_output_blobs) {
              var outblob = outputs.shift();
              if (outblob !== null) {
                  if (meta_output_blob.name !== 'output') {
                      outblob.initializer = new npu.Tensor(outblob.name, new npu.TensorType(outblob.data_type, new npu.TensorShape(outblob.shape)), null);
                      outblob.initializer.kind = meta_output_blob.name;
                  }
                  else {
                      outblob.initializer = null;
                  }
                  if (outblob.ioflag && !node.oflag) {
                      node.name = node.name + '-<output>';
                      node.oflag = true;
                      this._graph._outputs.push(new npu.Parameter(meta_output_blob.name, true, [outblob]));
                  }
                  node.append_outputs(new npu.Parameter(meta_output_blob.name, true, [outblob]));
              }
          }
  
          const schema = metadata.type(operator);
          const attributeMetadata = schema && schema.attributes ? schema && schema.attributes : [];
          var current_param_length = 0;
          for (const attribute of attributeMetadata) {
              node.append_attributes(new npu.Attribute(attribute, this.reader));
              switch (attribute.type) {
                  case 'uint16':
                  case 'int16':
                      current_param_length = current_param_length + 2;
                      break;
                  case 'uint32':
                  case 'int32':
                  case 'float32':
                      current_param_length = current_param_length + 4;
                      break;
                  default:
                      break;
              }
          }
          this.reader.skip(longest_param - current_param_length);
  
          return node;
      }
  };
  
  npu.Binary768v11Reader = class {
      constructor(metadata, buffer, graph) {
          this._graph = graph;
          this.reader = new npu.BinaryReader(buffer);
          this.Version = this.reader.getStr(32);
          if (this.Version === '2020-10-25V1.1') {
              this.Name = this.reader.getStr(32);
          }
          else if (this.Version === '2021-12-31V1.2') {
              this.Name = this.reader.getStr(64);
          }
          this.Layer_num = this.reader.getInt32(false);
          this.StartLayer = this.reader.getInt32(false);
          this.reader.skip(31*4); // u32ReservedS[31]
          this.EndLayer = this.reader.getInt32(false);
          this.reader.skip(31*4); // u32ReservedE[31]
          this.Hardware_Layer_num = this.reader.getInt32(false);
          this.Hardware_Start_Layer = this.reader.getInt32(false);
          this.Hardware_Exec_Layer = this.reader.getInt32(false);
          this.Hardware_Command_Base_Addr = this.reader.getInt32(false);
          this.Hardware_Command_Reg_Addr = this.reader.getInt32(false);
          this.Hardware_Command_base_Vaddr = this.reader.getInt64(false);
  
          console.log('Version:' + this.Version.split('#').shift().trim());
          console.log('Name:'+this.Name);
          console.log(this.Layer_num + ' layers, ' + this.Hardware_Layer_num + ' hardware layers.');
          console.log('StartLayer: ' + this.StartLayer + ' EndLayer: ' + this.EndLayer);
          console.log('Hardware_Layer_num: ' + this.Hardware_Start_Layer + ' Hardware_Exec_Layer: ' + this.Hardware_Exec_Layer);
          console.log('HwCmdBaseAddr: ' + this.Hardware_Command_Base_Addr.toString(16) + ' HwCmdRegAddr:'+
              this.Hardware_Command_Reg_Addr.toString(16) + ' HwCmdBaseVaddr:' + this.Hardware_Command_base_Vaddr.toString(16));
      }
  
      getLayer(metadata) {
          const data_length = 96;
          const longest_param = 28;//24;
          var node = new npu.Node(metadata);
          var in_num = this.reader.getInt32(false);
          var out_num = this.reader.getInt32(false);
          this.reader.skip(6*4); // u32HwStartLayer u32HwEndLayer u32Reserved[4]
  
          var inputs = [];
          var outputs = [];
          for (let i = 1; i <= 4; i++) {
              if (i <= in_num) {
                  const blob_reader = new npu.BlobReader768v8(this.reader);
                  inputs.push(blob_reader.getBlob());
              }
              else {
                  inputs.push(null);
                  this.reader.skip(data_length);
              }
          }
  
          for (let o = 1; o <= 2; o++) {
              if (o <= out_num) {
                  const blob_reader = new npu.BlobReader768v8(this.reader);
                  outputs.push(blob_reader.getBlob());
              }
              else {
                  outputs.push(null);
                  this.reader.skip(data_length);
              }
          }
  
          if (this.Version === '2020-10-25V1.1') {
              node.name = this.reader.getStr(32);
          }
          else if (this.Version === '2021-12-31V1.2') {
              node.name = this.reader.getStr(64);
          }
  
          var opera_code = this.reader.getInt32(false);
  
          var layer_flags = this.reader.getInt32(false);
  
          var Round = new npu.Attribute(null, null);
          Round.name = 'Round';
          Round.type = 'uint32';
          Round.value = (layer_flags & 0x80000000) >>> 31;
          node.append_attributes(Round);
  
          var layer_cal_mode = new npu.Attribute(null, null);
          var value = (layer_flags & 0x70000000) >>> 28;
          layer_cal_mode.name = 'Runing Mode';
          layer_cal_mode.type = 'string';
          if (value === 0) {
              layer_cal_mode.value = 'NPU';
          }
          else if (value === 1) {
              layer_cal_mode.value = 'CPU';
          }
          node.append_attributes(layer_cal_mode);
  
          if ((opera_code & 0x2) && (opera_code != 0x2)) {
              opera_code = opera_code & ~(opera_code & 0x2);
              var ReluThres = new npu.Attribute(null, null);
              ReluThres.name = 'ReluThres';
              ReluThres.type = 'float32';
              ReluThres.value = this.reader.getFloat32();
              node.append_attributes(ReluThres);
              this.reader.skip(8); // f32PReluNegK s32PrePReluOutShift
          }
          else if ((opera_code & 0x100) && (opera_code != 0x100)) {
              opera_code = opera_code & ~(opera_code & 0x100);
              this.reader.skip(4); // f32ReluxThres
              var PReluNegK = new npu.Attribute(null, null);
              PReluNegK.name = 'PReluNegK';
              PReluNegK.type = 'float32';
              PReluNegK.value = this.reader.getFloat32();
              node.append_attributes(PReluNegK);
  
              var PrePReluOutShift =  new npu.Attribute(null, null);
              PrePReluOutShift.name = 'PrePReluOutShift';
              PrePReluOutShift.type = 'int32';
              PrePReluOutShift.value = this.reader.getInt32(true);
              node.append_attributes(PrePReluOutShift);
          }
          else {
              this.reader.skip(12);// f32ReluxThres f32PReluNegK s32PrePReluOutShift
          }
  
          var operator = metadata.operator(opera_code);
          node.type = metadata.type(operator);
  
          const meta_input_blobs = metadata.type(operator).inputs;
          var blob;
          for (const meta_input_blob of meta_input_blobs) {
              blob = inputs.shift();
              if (blob !== null) {
                  if (meta_input_blob.name !== 'input') {
                      blob.initializer = new npu.Tensor(blob.name, new npu.TensorType(blob.data_type, new npu.TensorShape(blob.shape)), null);
                      blob.initializer.kind = meta_input_blob.name;
                  }
                  else {
                      blob.initializer = null;
                  }
                  if (blob.ioflag && !node.iflag) {
                      node.name = node.name + '-<input>';
                      node.iflag = true;
                      this._graph._inputs.push(new npu.Parameter(meta_input_blob.name, true, [blob]));
                  }
                  node.append_inputs(new npu.Parameter(meta_input_blob.name, true, [blob]));
              }
          }
  
          const meta_output_blobs = metadata.type(operator).outputs;
          for (const meta_output_blob of meta_output_blobs) {
              blob = outputs.shift();
              if (blob !== null) {
                  if (meta_output_blob.name !== 'output') {
                      blob.initializer = new npu.Tensor(blob.name, new npu.TensorType(blob.data_type, new npu.TensorShape(blob.shape)), null);
                      blob.initializer.kind = meta_output_blob.name;
                  }
                  else {
                      blob.initializer = null;
                  }
                  if (blob.ioflag && !node.oflag) {
                      node.name = node.name + '-<output>';
                      node.oflag = true;
                      this._graph._outputs.push(new npu.Parameter(meta_output_blob.name, true, [blob]));
                  }
                  node.append_outputs(new npu.Parameter(meta_output_blob.name, true, [blob]));
              }
          }
  
          const schema = metadata.type(operator);
          const attributeMetadata = schema && schema.attributes ? schema && schema.attributes : [];
          var current_param_length = 0;
          for (const attribute of attributeMetadata) {
              node.append_attributes(new npu.Attribute(attribute, this.reader));
              switch (attribute.type) {
                  case 'uint16':
                  case 'int16':
                      current_param_length = current_param_length + 2;
                      break;
                  case 'uint32':
                  case 'int32':
                  case 'float32':
                      current_param_length = current_param_length + 4;
                      break;
                  default:
                      break;
              }
          }
          this.reader.skip(longest_param - current_param_length);
  
          return node;
      }
  };
  
  npu.Binary768v14Reader = class {
      constructor(metadata, buffer, graph) {
          this._graph = graph;
          this.reader = new npu.BinaryReader(buffer);
          this.Version = this.reader.getStr(32);
          if (this.Version === '2022-02-03V1.4') {
              this.Name = this.reader.getStr(64);
          }
          else if (this.Version === '2022-02-03V1.5') {
              this.Name = this.reader.getStr(128);
          }
  
          this.Layer_num = this.reader.getInt32(false);
          this.StartLayer = this.reader.getInt32(false);
          this.reader.skip(31*4); // u32ReservedS[31]
          this.EndLayer = this.reader.getInt32(false);
          this.reader.skip(31*4); // u32ReservedE[31]
          this.Hardware_Layer_num = this.reader.getInt32(false);
          this.Hardware_Start_Layer = this.reader.getInt32(false);
          this.Hardware_Exec_Layer = this.reader.getInt32(false);
          this.Hardware_Command_Base_Addr = this.reader.getInt32(false);
          this.Hardware_Command_Reg_Addr = this.reader.getInt32(false);
          this.Hardware_Command_base_Vaddr = this.reader.getInt64(false);
  
          console.log('Version:' + this.Version.split('#').shift().trim());
          console.log('Name:'+this.Name);
          console.log(this.Layer_num + ' layers, ' + this.Hardware_Layer_num + ' hardware layers.');
          console.log('StartLayer: ' + this.StartLayer + ' EndLayer: ' + this.EndLayer);
          console.log('Hardware_Layer_num: ' + this.Hardware_Start_Layer + ' Hardware_Exec_Layer: ' + this.Hardware_Exec_Layer);
          console.log('HwCmdBaseAddr: ' + this.Hardware_Command_Base_Addr.toString(16) + ' HwCmdRegAddr:'+
              this.Hardware_Command_Reg_Addr.toString(16) + ' HwCmdBaseVaddr:' + this.Hardware_Command_base_Vaddr.toString(16));
      }
  
      getLayer(metadata) {
          const data_length = 96 + 4 + 4*5;
          const longest_param = 28;
          var node = new npu.Node(metadata);
          var in_num = this.reader.getInt32(false);
          var out_num = this.reader.getInt32(false);
          this.reader.skip(6*4); // u32HwStartLayer u32HwEndLayer u32Reserved[3] u16Reserved0 u16BatchFlag
  
          var inputs = [];
          var outputs = [];
          for (let i = 1; i <= 4; i++) {
              if (i <= in_num) {
                  const blob_reader = new npu.BlobReader768v14(this.reader);
                  inputs.push(blob_reader.getBlob());
              }
              else {
                  inputs.push(null);
                  this.reader.skip(data_length);
              }
          }
  
          for (let o = 1; o <= 2; o++) {
              if (o <= out_num) {
                  const blob_reader = new npu.BlobReader768v14(this.reader);
                  outputs.push(blob_reader.getBlob());
              }
              else {
                  outputs.push(null);
                  this.reader.skip(data_length);
              }
          }
          if (this.Version === '2022-02-03V1.4') {
              node.name = this.reader.getStr(64); // u8Name[NAME_LEN];
          }
          else if (this.Version === '2022-02-03V1.5') {
              node.name = this.reader.getStr(128); // u8Name[NAME_LEN];
          }
  
          var opera_code = this.reader.getInt32(false); // enOpera
  
          var layer_flags = this.reader.getInt32(false); // u32LayerFlags
  
          var Round = new npu.Attribute(null, null);
          Round.name = 'Round';
          Round.type = 'uint32';
          Round.value = (layer_flags & 0x80000000) >>> 31;
          node.append_attributes(Round);
  
          var layer_cal_mode = new npu.Attribute(null, null);
          var value = (layer_flags & 0x70000000) >>> 28;
          layer_cal_mode.name = 'Runing Mode';
          layer_cal_mode.type = 'string';
          if (value === 0) {
              layer_cal_mode.value = 'NPU';
          }
          else if (value === 1) {
              layer_cal_mode.value = 'CPU';
          }
          node.append_attributes(layer_cal_mode);
  
          if ((opera_code & 0x2) && (opera_code != 0x2)) {
              opera_code = opera_code & ~(opera_code & 0x2);
              var ReluThres = new npu.Attribute(null, null);
              ReluThres.name = 'ReluThres';
              ReluThres.type = 'float32';
              ReluThres.value = this.reader.getFloat32();
              node.append_attributes(ReluThres);
              this.reader.skip(8); // f32PReluNegK s32PrePReluOutShift
              this.reader.skip(4*6); // s32Reserve[6]
          }
          else if ((opera_code & 0x100) && (opera_code != 0x100)) {
              opera_code = opera_code & ~(opera_code & 0x100);
              this.reader.skip(4); // f32ReluxThres
              var PReluNegK = new npu.Attribute(null, null);
              PReluNegK.name = 'PReluNegK';
              PReluNegK.type = 'float32';
              PReluNegK.value = this.reader.getFloat32();
              node.append_attributes(PReluNegK);
  
              var PrePReluOutShift =  new npu.Attribute(null, null);
              PrePReluOutShift.name = 'PrePReluOutShift';
              PrePReluOutShift.type = 'int32';
              PrePReluOutShift.value = this.reader.getInt32(true);
              node.append_attributes(PrePReluOutShift);
              this.reader.skip(4*6); // s32Reserve[6]
          }
          else {
              this.reader.skip(4+4+4+4*6);// f32ReluxThres f32PReluNegK s32PrePReluOutShift s32Reserve[6]
          }
  
          var operator = metadata.operator(opera_code);
          node.type = metadata.type(operator);
  
          const meta_input_blobs = metadata.type(operator).inputs;
  
          for (const meta_input_blob of meta_input_blobs) {
              var inblob = inputs.shift();
              if (inblob !== null) {
                  if (meta_input_blob.name !== 'input') {
                      inblob.initializer = new npu.Tensor(inblob.name, new npu.TensorType(inblob.data_type, new npu.TensorShape(inblob.shape)), null);
                      inblob.initializer.kind = meta_input_blob.name;
                  }
                  else {
                      inblob.initializer = null;
                  }
  
                  if (inblob.ioflag && !node.iflag) {
                      node.name = node.name + '-<input>';
                      node.iflag = true;
                      this._graph._inputs.push(new npu.Parameter(meta_input_blob.name, true, [inblob]));
                  }
                  node.append_inputs(new npu.Parameter(meta_input_blob.name, true, [inblob]));
              }
          }
  
          const meta_output_blobs = metadata.type(operator).outputs;
          for (const meta_output_blob of meta_output_blobs) {
              var outblob = outputs.shift();
              if (outblob !== null) {
                  if (meta_output_blob.name !== 'output') {
                      outblob.initializer = new npu.Tensor(outblob.name, new npu.TensorType(outblob.data_type, new npu.TensorShape(outblob.shape)), null);
                      outblob.initializer.kind = meta_output_blob.name;
                  }
                  else {
                      outblob.initializer = null;
                  }
                  if (outblob.ioflag && !node.oflag) {
                      node.name = node.name + '-<output>';
                      node.oflag = true;
                      this._graph._outputs.push(new npu.Parameter(meta_output_blob.name, true, [outblob]));
                  }
                  node.append_outputs(new npu.Parameter(meta_output_blob.name, true, [outblob]));
              }
          }
  
          const schema = metadata.type(operator);
          const attributeMetadata = schema && schema.attributes ? schema && schema.attributes : [];
          var current_param_length = 0;
          for (const attribute of attributeMetadata) {
              node.append_attributes(new npu.Attribute(attribute, this.reader));
              switch (attribute.type) {
                  case 'uint16':
                  case 'int16':
                      current_param_length = current_param_length + 2;
                      break;
                  case 'uint32':
                  case 'int32':
                  case 'float32':
                      current_param_length = current_param_length + 4;
                      break;
                  default:
                      break;
              }
          }
  
          this.reader.skip(longest_param - current_param_length);
  
          return node;
      }
  };
  
  
  npu.BlobReader718v4 = class {
  
      constructor(buffer) {
          this._buffer = buffer;
      }
  
      getBlob() {
          this._buffer.skip(4); //addr
          var h = this._buffer.getInt32(false);
          var w = this._buffer.getInt32(false);
          var c = this._buffer.getInt32(false);
          var BitWidth = this._buffer.getInt32(false);
          var ShiftBits = this._buffer.getInt32(true);
          var pm = this._buffer.getInt32(false);
          var PadMode;
          switch (pm) {
              case 0:
                  PadMode = 'AcrossChannel';
                  break;
              case 1:
                  PadMode = 'WithinChannel';
                  break;
              case 2:
                  PadMode = 'Butt';
                  break;
              default:
                  PadMode = pm;
          }
          var PadTop = this._buffer.getInt32(false);
          var PadBottom = this._buffer.getInt32(false);
          var PadLeft = this._buffer.getInt32(false);
          var PadRight = this._buffer.getInt32(false);
          this._buffer.skip(4); // var Align = this._buffer.getInt32(false);
          var BufId = this._buffer.getInt32(false);
          var FileOffset = this._buffer.getInt32(false);
          var Offset = this._buffer.getInt32(false);
          var InOutFlag = this._buffer.getInt32(false);
          this._buffer.skip(4);
          this._buffer.skip(4); //var BufSize = this._buffer.getInt32(false);
          this._buffer.skip(4*6);
  
          var data_type = '';
          switch (BitWidth) {
              case 0:
                  data_type = 'S8Bit';
                  break;
              case 1:
                  data_type = 'U8Bit';
                  break;
              case 2:
                  data_type = 'S16Bit';
                  break;
              case 3:
                  data_type = 'U16Bit';
                  break;
              default:
                  break;
          }
          data_type = data_type + ', ShiftBit:' + ShiftBits;
          var type = data_type + ', Shape:[' + [c,h,w] + ']';
  
          var description = '<b>Pad('+ PadMode + '):[' + PadTop + ',' + PadBottom + ',' + PadLeft + ',' + PadRight + ']<br/>';
          description = description + 'FileOffset: 0x' + FileOffset.toString(16) + '<br/>';
          description = description + 'Offset: 0x' + Offset.toString(16) + '<br/>';
          description = description + 'InOutFlag:' + InOutFlag + '<b/>';
  
          var name = (InOutFlag == 1) ? BufId.toString() + '-io' : BufId.toString();
          var blob = new npu.Argument(name, type, [c,h,w], description);
          blob.ioflag = (InOutFlag == 1) ? true : false;
          blob.initiallizer = null;
  
          return blob;
      }
  };
  
  npu.BlobReader768v8 = class {
  
      constructor(buffer) {
          this._buffer = buffer;
      }
  
      getBlob() {
          var n = this._buffer.getInt16(false);
          var c = this._buffer.getInt16(false);
          var h = this._buffer.getInt16(false);
          var w = this._buffer.getInt16(false);
          var pt = this._buffer.getInt16(false);
          var PadType;
          switch (pt) {
              case 0:
                  PadType = 'Top&Bottom';
                  break;
              case 1:
                  PadType = 'FourDir';
                  break;
              case 2:
                  PadType = 'Butt';
                  break;
              default:
                  PadType = pt;
          }
          var PadTop = this._buffer.getInt16(false);
          var PadBottom = this._buffer.getInt16(false);
          var PadLeft = this._buffer.getInt16(false);
          var PadRight = this._buffer.getInt16(false);
          this._buffer.skip(2); // var MaxPadTop = this._buffer.getInt16(false);
          this._buffer.skip(2); // var MaxPadBottom = this._buffer.getInt16(false);
          var BitWidth = this._buffer.getInt16(false);
          var Transposed = this._buffer.getInt16(false);
          var Align = this._buffer.getInt16(false);
          this._buffer.skip(16); // bSparsed u16IdxBits u16LutBitWidth s16Reserved0 s16Flags u16AlignInBytes u32SparseColSize
          var ShiftBits = this._buffer.getInt32(true);
          var Scale = this._buffer.getFloat32();
          this._buffer.skip(4); //var Stride = this._buffer.getInt32(false);
          var BufId = this._buffer.getInt32(false);
          var FileOffset = this._buffer.getInt32(false);
          var Offset = this._buffer.getInt32(false);
          var InOutFlag = this._buffer.getInt32(false);
          var BufSize = this._buffer.getInt32(false);
          this._buffer.skip(20); // u32PhyAddr u32UsrVirAddr u32KerVirAddr
  
          var data_type = '';
          switch (BitWidth) {
              case 0:
                  data_type = 'S8Bit';
                  break;
              case 1:
                  data_type = 'U8Bit';
                  break;
              case 2:
                  data_type = 'S16Bit';
                  break;
              case 3:
                  data_type = 'U16Bit';
                  break;
              default:
                  break;
          }
          data_type = data_type + ', ShiftBit:' + ShiftBits;
          var type = data_type + ', Shape:[' + [n,c,h,w] + ']';
  
          var description = '<b>Pad('+ PadType + '):[' + PadTop + ',' + PadBottom + ',' + PadLeft + ',' + PadRight + ']<br/>';
          description = description + 'Scale:' + Scale + '<br/>';
          description = description + 'FileOffset: 0x' + FileOffset.toString(16) + '<br/>';
          description = description + 'Offset: 0x' + Offset.toString(16) + '<br/>';
          description = description + 'InOutFlag:' + InOutFlag + '<b/>';
          description = description + 'BufSize:' + BufSize + '<b/>';
          description = description + 'Transposed:' + Transposed + '<b/>';
          description = description + 'Align:' + Align + '<b/>';
  
          var name = (InOutFlag == 1) ? BufId.toString() + '-io' : BufId.toString();
          var blob = new npu.Argument(name, type, [n,c,h,w], description);
          blob.ioflag = (InOutFlag == 1) ? true : false;
          blob.initiallizer = null;
  
          return blob;
      }
  };
  
  npu.BlobReader768v14 = class {
  
      constructor(buffer) {
          this._buffer = buffer;
      }
  
      getBlob() {
          var n = this._buffer.getInt16(false);
          var c = this._buffer.getInt16(false);
          var h = this._buffer.getInt16(false);
          var w = this._buffer.getInt16(false);
          var pt = this._buffer.getInt16(false);
          var PadType;
          switch (pt) {
              case 0:
                  PadType = 'Top&Bottom';
                  break;
              case 1:
                  PadType = 'FourDir';
                  break;
              case 2:
                  PadType = 'Butt';
                  break;
              default:
                  PadType = pt;
          }
          var PadTop = this._buffer.getInt16(false);
          var PadBottom = this._buffer.getInt16(false);
          var PadLeft = this._buffer.getInt16(false);
          var PadRight = this._buffer.getInt16(false);
          this._buffer.skip(2); //var MaxPadTop = this._buffer.getInt16(false);
          this._buffer.skip(2); //var MaxPadBottom = this._buffer.getInt16(false);
          var BitWidth = this._buffer.getInt16(false);
          var Transposed = this._buffer.getInt16(false);
          var Align = this._buffer.getInt16(false);
          this._buffer.skip(16); // bSparsed u16IdxBits u16LutBitWidth s16Reserved0 s16Flags u16AlignInBytes u32SparseColSize
          var ShiftBits = this._buffer.getInt32(true);
          var Scale = this._buffer.getFloat32();
          this._buffer.skip(4); //var Stride = this._buffer.getInt32(false);
          var BufId = this._buffer.getInt32(false);
          var FileOffset = this._buffer.getInt32(false);
          var Offset = this._buffer.getInt32(false);
          var InOutFlag = this._buffer.getInt32(false);
          var BufSize = this._buffer.getInt32(false);
          this._buffer.skip(4+8+8+4+4*5); // u32PhyAddr u32UsrVirAddr u32KerVirAddr u32OffsetInBuf u32Reserved[5]
  
          var data_type = '';
          switch (BitWidth) {
              case 0:
                  data_type = 'S8Bit';
                  break;
              case 1:
                  data_type = 'U8Bit';
                  break;
              case 2:
                  data_type = 'S16Bit';
                  break;
              case 3:
                  data_type = 'U16Bit';
                  break;
              default:
                  break;
          }
          data_type = data_type + ', ShiftBit:' + ShiftBits;
          var type = data_type + ', Shape:[' + [n,c,h,w] + ']';
  
          var description = '<b>Pad('+ PadType + '):[' + PadTop + ',' + PadBottom + ',' + PadLeft + ',' + PadRight + ']<br/>';
          description = description + 'Scale:' + Scale + '<br/>';
          description = description + 'FileOffset: 0x' + FileOffset.toString(16) + '<br/>';
          description = description + 'Offset: 0x' + Offset.toString(16) + '<br/>';
          description = description + 'InOutFlag:' + InOutFlag + '<br/>';
          description = description + 'BufSize:' + BufSize + '<br/>';
          description = description + 'Transposed:' + Transposed + '<br/>';
          description = description + 'Align:' + Align + '<b/>';
  
          var name = (InOutFlag == 1) ? BufId.toString() + '-io' : BufId.toString();
          var blob = new npu.Argument(name, type, [n,c,h,w], description);
          blob.ioflag = (InOutFlag == 1) ? true : false;
          blob.initiallizer = null;
  
          return blob;
      }
  };
  
  DataView.prototype.getString = function(offset, length) {
      var end = typeof length == 'number' ? offset + length : this.byteLength;
      var text = '';
      var val = -1;
  
      while (offset < this.byteLength && offset < end) {
          val = this.getUint8(offset++);
          if (val == 0) {
              break;
          }
          text += String.fromCharCode(val);
      }
  
      return text;
  };
  
  npu.BinaryReader = class {
  
      constructor(buffer) {
          this._buffer = buffer;
          this._dataView = new DataView(buffer.buffer, buffer.byteOffset, buffer.byteLength);
          this._position = 0;
      }
  
      skip(size) {
          this._position += size;
          if (this._position > this._buffer.length) {
              throw new npu.Error('Expected ' + (this._position - this._buffer.length) + ' more bytes. The file might be corrupted. Unexpected end of file.');
          }
      }
  
      back(size) {
          this._position = this._position - size;
          if (this._position < 0) {
              throw new npu.Error('Expected ' + this._position + ' bytes out of file. The file might be corrupted. Unexpected end of file.');
          }
      }
  
      getBit16(mask) {
          this.skip(2);
          this._dataView.set;
          var ret = this._dataView.getInt16(this._position, true) | mask;
          this.back(2);
  
          return ret;
      }
  
      getBit32(mask) {
          this.skip(4);
          this._dataView.set;
          var ret = this._dataView.getInt32(this._position, true) | mask;
          this.back(4);
  
          return ret;
      }
  
      getInt16(signed) {
          const position = this._position;
          this.skip(2);
          this._dataView.set;
          if (signed) {
              return this._dataView.getInt16(position, true);
          }
          else{
              return this._dataView.getUint16(position, true);
          }
      }
  
      getInt32(signed) {
          const position = this._position;
          this.skip(4);
          this._dataView.set;
          if (signed) {
              return this._dataView.getInt32(position, true);
          }
          else{
              return this._dataView.getUint32(position, true);
          }
      }
  
      getInt64(signed) {
          const position = this._position;
          this.skip(8);
          this._dataView.set;
          if (signed) {
              return this._dataView.getBigInt64(position, true);
          }
          else {
              return this._dataView.getBigUint64(position, true);
          }
      }
  
      getFloat32() {
          const position = this._position;
          this.skip(4);
          this._dataView.set;
          return this._dataView.getFloat32(position, true);
      }
  
      getStr(len) {
          const position = this._position;
          this.skip(len);
          this._dataView.set;
          return this._dataView.getString(position);
      }
  };
  
  npu.Error = class extends Error {
  
      constructor(message) {
          super(message);
          this.name = 'Error loading npu model.';
      }
  };
  
  if (typeof module !== 'undefined' && typeof module.exports === 'object') {
      module.exports.ModelFactory = npu.ModelFactory;
  }
  