text: // Low-level types that make up operations
  
  import v from "./SerializerValidation";
  import fp from "./FastParser";
  
  import ChainTypes from "./ChainTypes";
  import ObjectId from "./ObjectId";
  
  import { PublicKey, Address, getAddressPrefix } from "x4tdex-ecc";
  
  import ByteBuffer from "bytebuffer";
  const Buffer = require("safe-buffer").Buffer;
  
  var Types = {};
  
  const HEX_DUMP = process.env.npm_config__graphene_serializer_hex_dump;
  
  Types.uint8 = {
    fromByteBuffer(b) {
      return b.readUint8();
    },
    appendByteBuffer(b, object) {
      v.require_range(0, 0xff, object, `uint8 ${object}`);
      b.writeUint8(object);
      return;
    },
    fromObject(object) {
      v.require_range(0, 0xff, object, `uint8 ${object}`);
      return object;
    },
    toObject(object, debug = {}) {
      if (debug.use_default && object === undefined) {
        return 0;
      }
      v.require_range(0, 0xff, object, `uint8 ${object}`);
      return parseInt(object);
    }
  };
  
  Types.uint16 = {
    fromByteBuffer(b) {
      return b.readUint16();
    },
    appendByteBuffer(b, object) {
      v.require_range(0, 0xffff, object, `uint16 ${object}`);
      b.writeUint16(object);
      return;
    },
    fromObject(object) {
      v.require_range(0, 0xffff, object, `uint16 ${object}`);
      return object;
    },
    toObject(object, debug = {}) {
      if (debug.use_default && object === undefined) {
        return 0;
      }
      v.require_range(0, 0xffff, object, `uint16 ${object}`);
      return parseInt(object);
    }
  };
  
  Types.uint32 = {
    fromByteBuffer(b) {
      return b.readUint32();
    },
    appendByteBuffer(b, object) {
      v.require_range(0, 0xffffffff, object, `uint32 ${object}`);
      b.writeUint32(object);
      return;
    },
    fromObject(object) {
      v.require_range(0, 0xffffffff, object, `uint32 ${object}`);
      return object;
    },
    toObject(object, debug = {}) {
      if (debug.use_default && object === undefined) {
        return 0;
      }
      v.require_range(0, 0xffffffff, object, `uint32 ${object}`);
      return parseInt(object);
    }
  };
  
  var MIN_SIGNED_32 = -1 * Math.pow(2, 31);
  var MAX_SIGNED_32 = Math.pow(2, 31) - 1;
  
  Types.varint32 = {
    fromByteBuffer(b) {
      return b.readVarint32();
    },
    appendByteBuffer(b, object) {
      v.require_range(MIN_SIGNED_32, MAX_SIGNED_32, object, `uint32 ${object}`);
      b.writeVarint32(object);
      return;
    },
    fromObject(object) {
      v.require_range(MIN_SIGNED_32, MAX_SIGNED_32, object, `uint32 ${object}`);
      return object;
    },
    toObject(object, debug = {}) {
      if (debug.use_default && object === undefined) {
        return 0;
      }
      v.require_range(MIN_SIGNED_32, MAX_SIGNED_32, object, `uint32 ${object}`);
      return parseInt(object);
    }
  };
  
  Types.int64 = {
    fromByteBuffer(b) {
      return b.readInt64();
    },
    appendByteBuffer(b, object) {
      v.required(object);
      b.writeInt64(v.to_long(object));
      return;
    },
    fromObject(object) {
      v.required(object);
      return v.to_long(object);
    },
    toObject(object, debug = {}) {
      if (debug.use_default && object === undefined) {
        return "0";
      }
      v.required(object);
      return v.to_long(object).toString();
    }
  };
  
  Types.uint64 = {
    fromByteBuffer(b) {
      return b.readUint64();
    },
    appendByteBuffer(b, object) {
      b.writeUint64(v.to_long(v.unsigned(object), undefined, true));
      return;
    },
    fromObject(object) {
      return v.to_long(v.unsigned(object), undefined, true);
    },
    toObject(object, debug = {}) {
      if (debug.use_default && object === undefined) {
        return "0";
      }
      return v.to_long(object, undefined, true).toString();
    }
  };
  
  Types.string = {
    fromByteBuffer(b) {
      var b_copy;
      var len = b.readVarint32();
      (b_copy = b.copy(b.offset, b.offset + len)), b.skip(len);
      return Buffer.from(b_copy.toBinary(), "binary");
    },
    appendByteBuffer(b, object) {
      v.required(object);
      b.writeVarint32(object.length);
      b.append(object.toString("binary"), "binary");
      return;
    },
    fromObject(object) {
      v.required(object);
      return Buffer.from(object);
    },
    toObject(object, debug = {}) {
      if (debug.use_default && object === undefined) {
        return "";
      }
      return object.toString();
    }
  };
  
  Types.bytes = function(size) {
    return {
      fromByteBuffer(b) {
        if (size === undefined) {
          var b_copy;
          var len = b.readVarint32();
          (b_copy = b.copy(b.offset, b.offset + len)), b.skip(len);
          return Buffer.from(b_copy.toBinary(), "binary");
        } else {
          (b_copy = b.copy(b.offset, b.offset + size)), b.skip(size);
          return Buffer.from(b_copy.toBinary(), "binary");
        }
      },
      appendByteBuffer(b, object) {
        v.required(object);
        if (typeof object === "string") object = Buffer.from(object, "hex");
  
        if (size === undefined) {
          b.writeVarint32(object.length);
        }
        b.append(object.toString("binary"), "binary");
        return;
      },
      fromObject(object) {
        v.required(object);
        if (Buffer.isBuffer(object)) return object;
  
        return Buffer.from(object, "hex");
      },
      toObject(object, debug = {}) {
        if (debug.use_default && object === undefined) {
          var zeros = function(num) {
            return new Array(num).join("00");
          };
          return zeros(size);
        }
        v.required(object);
        return object.toString("hex");
      }
    };
  };
  
  Types.bool = {
    fromByteBuffer(b) {
      return b.readUint8() === 1;
    },
    appendByteBuffer(b, object) {
      // supports boolean or integer
      b.writeUint8(JSON.parse(object) ? 1 : 0);
      return;
    },
    fromObject(object) {
      return JSON.parse(object) ? true : false;
    },
    toObject(object, debug = {}) {
      if (debug.use_default && object === undefined) {
        return false;
      }
      return JSON.parse(object) ? true : false;
    }
  };
  
  Types.void = {
    fromByteBuffer(b) {
      throw new Error("(void) undefined type");
    },
    appendByteBuffer(b, object) {
      throw new Error("(void) undefined type");
    },
    fromObject(object) {
      throw new Error("(void) undefined type");
    },
    toObject(object, debug = {}) {
      if (debug.use_default && object === undefined) {
        return undefined;
      }
      throw new Error("(void) undefined type");
    }
  };
  
  Types.array = function(st_operation) {
    return {
      fromByteBuffer(b) {
        var size = b.readVarint32();
        if (HEX_DUMP) {
          console.log("varint32 size = " + size.toString(16));
        }
        var result = [];
        for (var i = 0; 0 < size ? i < size : i > size; 0 < size ? i++ : i++) {
          result.push(st_operation.fromByteBuffer(b));
        }
        return sortOperation(result, st_operation);
      },
      appendByteBuffer(b, object) {
        v.required(object);
        object = sortOperation(object, st_operation);
        b.writeVarint32(object.length);
        for (var i = 0, o; i < object.length; i++) {
          o = object[i];
          st_operation.appendByteBuffer(b, o);
        }
      },
      fromObject(object) {
        v.required(object);
        object = sortOperation(object, st_operation);
        var result = [];
        for (var i = 0, o; i < object.length; i++) {
          o = object[i];
          result.push(st_operation.fromObject(o));
        }
        return result;
      },
      toObject(object, debug = {}) {
        if (debug.use_default && object === undefined) {
          return [st_operation.toObject(object, debug)];
        }
        v.required(object);
        object = sortOperation(object, st_operation);
  
        var result = [];
        for (var i = 0, o; i < object.length; i++) {
          o = object[i];
          result.push(st_operation.toObject(o, debug));
        }
        return result;
      }
    };
  };
  
  Types.time_point_sec = {
    fromByteBuffer(b) {
      return b.readUint32();
    },
    appendByteBuffer(b, object) {
      if (typeof object !== "number")
        object = Types.time_point_sec.fromObject(object);
  
      b.writeUint32(object);
      return;
    },
    fromObject(object) {
      v.required(object);
  
      if (typeof object === "number") return object;
  
      if (object.getTime) return Math.floor(object.getTime() / 1000);
  
      if (typeof object !== "string")
        throw new Error("Unknown date type: " + object);
  
      if (/T[0-2][0-9]:[0-5][0-9]:[0-5][0-9]$/.test(object))
        object = object + "Z";
  
      return Math.floor(new Date(object).getTime() / 1000);
    },
    toObject(object, debug = {}) {
      if (debug.use_default && object === undefined)
        return new Date(0).toISOString().split(".")[0];
  
      v.required(object);
  
      if (typeof object === "string") return object;
  
      if (object.getTime) return object.toISOString().split(".")[0];
  
      var int = parseInt(object);
      v.require_range(0, 0xffffffff, int, `uint32 ${object}`);
      return new Date(int * 1000).toISOString().split(".")[0];
    }
  };
  
  Types.set = function(st_operation) {
    return {
      validate(array) {
        var dup_map = {};
        for (var i = 0, o; i < array.length; i++) {
          o = array[i];
          var ref;
          if (((ref = typeof o), ["string", "number"].indexOf(ref) >= 0)) {
            if (dup_map[o] !== undefined) {
              throw new Error("duplicate (set)");
            }
            dup_map[o] = true;
          }
        }
        return sortOperation(array, st_operation);
      },
      fromByteBuffer(b) {
        var size = b.readVarint32();
        if (HEX_DUMP) {
          console.log("varint32 size = " + size.toString(16));
        }
        return this.validate(
          (() => {
            var result = [];
            for (
              var i = 0;
              0 < size ? i < size : i > size;
              0 < size ? i++ : i++
            ) {
              result.push(st_operation.fromByteBuffer(b));
            }
            return result;
          })()
        );
      },
      appendByteBuffer(b, object) {
        if (!object) {
          object = [];
        }
        b.writeVarint32(object.length);
        var iterable = this.validate(object);
        for (var i = 0, o; i < iterable.length; i++) {
          o = iterable[i];
          st_operation.appendByteBuffer(b, o);
        }
        return;
      },
      fromObject(object) {
        if (!object) {
          object = [];
        }
        return this.validate(
          (() => {
            var result = [];
            for (var i = 0, o; i < object.length; i++) {
              o = object[i];
              result.push(st_operation.fromObject(o));
            }
            return result;
          })()
        );
      },
      toObject(object, debug = {}) {
        if (debug.use_default && object === undefined) {
          return [st_operation.toObject(object, debug)];
        }
        if (!object) {
          object = [];
        }
        return this.validate(
          (() => {
            var result = [];
            for (var i = 0, o; i < object.length; i++) {
              o = object[i];
              result.push(st_operation.toObject(o, debug));
            }
            return result;
          })()
        );
      }
    };
  };
  
  // global_parameters_update_operation current_fees
  Types.fixed_array = function(count, st_operation) {
    return {
      fromByteBuffer: function(b) {
        var i, j, ref, results;
        results = [];
        for (i = j = 0, ref = count; j < ref; i = j += 1) {
          results.push(st_operation.fromByteBuffer(b));
        }
        return sortOperation(results, st_operation);
      },
      appendByteBuffer: function(b, object) {
        var i, j, ref;
        if (count !== 0) {
          v.required(object);
          object = sortOperation(object, st_operation);
        }
        for (i = j = 0, ref = count; j < ref; i = j += 1) {
          st_operation.appendByteBuffer(b, object[i]);
        }
      },
      fromObject: function(object) {
        var i, j, ref, results;
        if (count !== 0) {
          v.required(object);
        }
        results = [];
        for (i = j = 0, ref = count; j < ref; i = j += 1) {
          results.push(st_operation.fromObject(object[i]));
        }
        return results;
      },
      toObject: function(object, debug) {
        var i, j, k, ref, ref1, results, results1;
        if (debug == null) {
          debug = {};
        }
        if (debug.use_default && object === void 0) {
          results = [];
          for (i = j = 0, ref = count; j < ref; i = j += 1) {
            results.push(st_operation.toObject(void 0, debug));
          }
          return results;
        }
        if (count !== 0) {
          v.required(object);
        }
        results1 = [];
        for (i = k = 0, ref1 = count; k < ref1; i = k += 1) {
          results1.push(st_operation.toObject(object[i], debug));
        }
        return results1;
      }
    };
  };
  
  /* Supports instance numbers (11) or object types (1.2.11).  Object type
  Validation is enforced when an object type is used. */
  var id_type = function(reserved_spaces, object_type) {
    v.required(reserved_spaces, "reserved_spaces");
    v.required(object_type, "object_type");
    return {
      fromByteBuffer(b) {
        return b.readVarint32();
      },
      appendByteBuffer(b, object) {
        v.required(object);
        if (object.resolve !== undefined) {
          object = object.resolve;
        }
        // convert 1.2.n into just n
        if (/^[0-9]+\.[0-9]+\.[0-9]+$/.test(object)) {
          object = v.get_instance(reserved_spaces, object_type, object);
        }
        b.writeVarint32(v.to_number(object));
        return;
      },
      fromObject(object) {
        v.required(object);
        if (object.resolve !== undefined) {
          object = object.resolve;
        }
        if (v.is_digits(object)) {
          return v.to_number(object);
        }
        return v.get_instance(reserved_spaces, object_type, object);
      },
      toObject(object, debug = {}) {
        var object_type_id = ChainTypes.object_type[object_type];
        if (debug.use_default && object === undefined) {
          return `${reserved_spaces}.${object_type_id}.0`;
        }
        v.required(object);
        if (object.resolve !== undefined) {
          object = object.resolve;
        }
        if (/^[0-9]+\.[0-9]+\.[0-9]+$/.test(object)) {
          object = v.get_instance(reserved_spaces, object_type, object);
        }
  
        return `${reserved_spaces}.${object_type_id}.` + object;
      }
    };
  };
  
  Types.protocol_id_type = function(name) {
    v.required(name, "name");
    return id_type(ChainTypes.reserved_spaces.protocol_ids, name);
  };
  
  Types.object_id_type = {
    fromByteBuffer(b) {
      return ObjectId.fromByteBuffer(b);
    },
    appendByteBuffer(b, object) {
      v.required(object);
      if (object.resolve !== undefined) {
        object = object.resolve;
      }
      object = ObjectId.fromString(object);
      object.appendByteBuffer(b);
      return;
    },
    fromObject(object) {
      v.required(object);
      if (object.resolve !== undefined) {
        object = object.resolve;
      }
      return ObjectId.fromString(object);
    },
    toObject(object, debug = {}) {
      if (debug.use_default && object === undefined) {
        return "0.0.0";
      }
      v.required(object);
      if (object.resolve !== undefined) {
        object = object.resolve;
      }
      object = ObjectId.fromString(object);
      return object.toString();
    }
  };
  
  Types.vote_id = {
    TYPE: 0x000000ff,
    ID: 0xffffff00,
    fromByteBuffer(b) {
      var value = b.readUint32();
      return {
        type: value & this.TYPE,
        id: value & this.ID
      };
    },
    appendByteBuffer(b, object) {
      v.required(object);
      if (object === "string") object = Types.vote_id.fromObject(object);
  
      var value = (object.id << 8) | object.type;
      b.writeUint32(value);
      return;
    },
    fromObject(object) {
      v.required(object, "(type vote_id)");
      if (typeof object === "object") {
        v.required(object.type, "type");
        v.required(object.id, "id");
        return object;
      }
      v.require_test(/^[0-9]+:[0-9]+$/, object, `vote_id format ${object}`);
      var [type, id] = object.split(":");
      v.require_range(0, 0xff, type, `vote type ${object}`);
      v.require_range(0, 0xffffff, id, `vote id ${object}`);
      return { type, id };
    },
    toObject(object, debug = {}) {
      if (debug.use_default && object === undefined) {
        return "0:0";
      }
      v.required(object);
      if (typeof object === "string") object = Types.vote_id.fromObject(object);
  
      return object.type + ":" + object.id;
    },
    compare(a, b) {
      if (typeof a !== "object") a = Types.vote_id.fromObject(a);
      if (typeof b !== "object") b = Types.vote_id.fromObject(b);
      return parseInt(a.id) - parseInt(b.id);
    }
  };
  
  Types.optional = function(st_operation) {
    v.required(st_operation, "st_operation");
    return {
      fromByteBuffer(b) {
        if (!(b.readUint8() === 1)) {
          return undefined;
        }
        return st_operation.fromByteBuffer(b);
      },
      appendByteBuffer(b, object) {
        if (object !== null && object !== undefined) {
          b.writeUint8(1);
          st_operation.appendByteBuffer(b, object);
        } else {
          b.writeUint8(0);
        }
        return;
      },
      fromObject(object) {
        if (object === undefined) {
          return undefined;
        }
        return st_operation.fromObject(object);
      },
      toObject(object, debug = {}) {
        // toObject is only null save if use_default is true
        var result_object = (() => {
          if (!debug.use_default && object === undefined) {
            return undefined;
          } else {
            return st_operation.toObject(object, debug);
          }
        })();
  
        if (debug.annotate) {
          if (typeof result_object === "object") {
            result_object.__optional = "parent is optional";
          } else {
            result_object = { __optional: result_object };
          }
        }
        return result_object;
      }
    };
  };
  
  Types.extension = function(fields_def) {
    // fields_def is an array
    v.require_array(fields_def, r => {
      v.string(r.name);
      v.required(r.type, "st_operation");
    });
    //v.required(st_operation, "st_operation");
    return {
      fromByteBuffer(b) {
        let count = b.readVarint32();
        if (count === 0) {
          return undefined;
        }
        let o = {};
        if (count > fields_def.length) {
          throw new Error("two many fields");
        }
        while (count > 0) {
          let index = b.readVarint32();
          if (index >= fields_def.length) {
            throw new Error("index out of range");
          }
          let operation = fields_def[index];
          o[operation.name] = operation.type.fromByteBuffer(b);
          count--;
        }
        return o;
        // return st_operation.fromByteBuffer(b);
      },
      appendByteBuffer(b, object) {
        //let tempBuffer = new Buffer([]);
        let tempBuffer = new ByteBuffer(
          ByteBuffer.DEFAULT_CAPACITY,
          ByteBuffer.LITTLE_ENDIAN
        );
        var count = 0;
        if (object) {
          fields_def.forEach((f, i) => {
            if (object[f.name] !== undefined && object[f.name] !== null) {
              tempBuffer.writeVarint32(i);
              f.type.appendByteBuffer(tempBuffer, object[f.name]);
              count++;
            }
          });
        }
        b.writeVarint32(count);
        tempBuffer.flip();
        b.append(tempBuffer);
  
        return;
      },
      fromObject(object) {
        if (object === undefined) {
          return undefined;
        }
        /*
              return st_operation.fromObject(object);
              */
        var result = {};
        fields_def.forEach(f => {
          if (object[f.name] !== undefined && object[f.name] !== null) {
            result[f.name] = f.type.fromObject(object[f.name]);
          }
        });
        return result;
      },
      toObject(object, debug = {}) {
        // toObject is only null save if use_default is true
        var result_object = (() => {
          if (object === undefined) {
            return undefined;
          } else {
            // return st_operation.toObject(object, debug);
            let result = {};
            fields_def.forEach(f => {
              if (object[f.name] !== undefined && object[f.name] !== null) {
                result[f.name] = f.type.toObject(object[f.name], debug);
              }
            });
            return result;
          }
        })();
  
        if (debug.annotate) {
          if (typeof result_object === "object") {
            result_object.__optional = "parent is optional";
          } else {
            result_object = { __optional: result_object };
          }
        }
        return result_object;
      }
    };
  };
  
  Types.static_variant = function(_st_operations) {
    return {
      nosort: true,
      st_operations: _st_operations,
      fromByteBuffer(b) {
        var type_id = b.readVarint32();
        var st_operation = this.st_operations[type_id];
        if (HEX_DUMP) {
          console.error(
            `static_variant id 0x${type_id.toString(16)} (${type_id})`
          );
        }
        v.required(st_operation, `operation ${type_id}`);
        return [type_id, st_operation.fromByteBuffer(b)];
      },
      appendByteBuffer(b, object) {
        v.required(object);
        var type_id = object[0];
        var st_operation = this.st_operations[type_id];
        v.required(st_operation, `operation ${type_id}`);
        b.writeVarint32(type_id);
        st_operation.appendByteBuffer(b, object[1]);
        return;
      },
      fromObject(object) {
        v.required(object);
        var type_id = object[0];
        var st_operation = this.st_operations[type_id];
        v.required(st_operation, `operation ${type_id}`);
        return [type_id, st_operation.fromObject(object[1])];
      },
      toObject(object, debug = {}) {
        if (debug.use_default && object === undefined) {
          return [0, this.st_operations[0].toObject(undefined, debug)];
        }
        v.required(object);
        var type_id = object[0];
        var st_operation = this.st_operations[type_id];
        v.required(st_operation, `operation ${type_id}`);
        return [type_id, st_operation.toObject(object[1], debug)];
      }
    };
  };
  
  Types.map = function(key_st_operation, value_st_operation) {
    return {
      validate(array) {
        if (!Array.isArray(array)) {
          throw new Error("expecting array");
        }
        var dup_map = {};
        for (var i = 0, o; i < array.length; i++) {
          o = array[i];
          var ref;
          if (!(o.length === 2)) {
            throw new Error("expecting two elements");
          }
          if (((ref = typeof o[0]), ["number", "string"].indexOf(ref) >= 0)) {
            if (dup_map[o[0]] !== undefined) {
              throw new Error("duplicate (map)");
            }
            dup_map[o[0]] = true;
          }
        }
        return sortOperation(array, key_st_operation);
      },
  
      fromByteBuffer(b) {
        var result = [];
        var end = b.readVarint32();
        for (var i = 0; 0 < end ? i < end : i > end; 0 < end ? i++ : i++) {
          result.push([
            key_st_operation.fromByteBuffer(b),
            value_st_operation.fromByteBuffer(b)
          ]);
        }
        return this.validate(result);
      },
  
      appendByteBuffer(b, object) {
        this.validate(object);
        b.writeVarint32(object.length);
        for (var i = 0, o; i < object.length; i++) {
          o = object[i];
          key_st_operation.appendByteBuffer(b, o[0]);
          value_st_operation.appendByteBuffer(b, o[1]);
        }
        return;
      },
      fromObject(object) {
        v.required(object);
        var result = [];
        for (var i = 0, o; i < object.length; i++) {
          o = object[i];
          result.push([
            key_st_operation.fromObject(o[0]),
            value_st_operation.fromObject(o[1])
          ]);
        }
        return this.validate(result);
      },
      toObject(object, debug = {}) {
        if (debug.use_default && object === undefined) {
          return [
            [
              key_st_operation.toObject(undefined, debug),
              value_st_operation.toObject(undefined, debug)
            ]
          ];
        }
        v.required(object);
        object = this.validate(object);
        var result = [];
        for (var i = 0, o; i < object.length; i++) {
          o = object[i];
          result.push([
            key_st_operation.toObject(o[0], debug),
            value_st_operation.toObject(o[1], debug)
          ]);
        }
        return result;
      }
    };
  };
  
  Types.public_key = {
    toPublic(object) {
      if (object.resolve !== undefined) {
        object = object.resolve;
      }
      return object == null
        ? object
        : object.Q
        ? object
        : PublicKey.fromStringOrThrow(object);
    },
    fromByteBuffer(b) {
      return fp.public_key(b);
    },
    appendByteBuffer(b, object) {
      v.required(object);
      fp.public_key(b, Types.public_key.toPublic(object));
      return;
    },
    fromObject(object) {
      v.required(object);
      if (object.Q) {
        return object;
      }
      return Types.public_key.toPublic(object);
    },
    toObject(object, debug = {}) {
      if (debug.use_default && object === undefined) {
        return (
          getAddressPrefix() +
          "859gxfnXyUriMgUeThh1fWv3oqcpLFyHa3TfFYC4PK2HqhToVM"
        );
      }
      v.required(object);
      return object.toString();
    },
    compare(a, b) {
      return Types.public_key
        .fromObject(a)
        .toBlockchainAddress()
        .compare(Types.public_key.fromObject(b).toBlockchainAddress());
    }
  };
  
  Types.address = {
    _to_address(object) {
      v.required(object);
      if (object.addy) {
        return object;
      }
      return Address.fromString(object);
    },
    fromByteBuffer(b) {
      return new Address(fp.ripemd160(b));
    },
    appendByteBuffer(b, object) {
      fp.ripemd160(b, Types.address._to_address(object).toBuffer());
      return;
    },
    fromObject(object) {
      return Types.address._to_address(object);
    },
    toObject(object, debug = {}) {
      if (debug.use_default && object === undefined) {
        return getAddressPrefix() + "664KmHxSuQyDsfwo4WEJvWpzg1QKdg67S";
      }
      return Types.address._to_address(object).toString();
    },
    compare(a, b) {
      return strCmp(a.toString(), b.toString());
    }
  };
  
  let strCmp = (a, b) => (a > b ? 1 : a < b ? -1 : 0);
  let firstEl = el => (Array.isArray(el) ? el[0] : el);
  let sortOperation = (array, st_operation) =>
    st_operation.nosort
      ? array
      : st_operation.compare
      ? array.sort((a, b) => st_operation.compare(firstEl(a), firstEl(b))) // custom compare operation
      : array.sort((a, b) =>
          typeof firstEl(a) === "number" && typeof firstEl(b) === "number"
            ? firstEl(a) - firstEl(b)
            : // A binary string compare does not work. Performanance is very good so HEX is used..  localeCompare is another option.
            Buffer.isBuffer(firstEl(a)) && Buffer.isBuffer(firstEl(b))
            ? strCmp(firstEl(a).toString("hex"), firstEl(b).toString("hex"))
            : strCmp(firstEl(a).toString(), firstEl(b).toString())
        );
  
  export default Types;
  