UNPKG

@c4tplatform/caminojs

Version:
546 lines 72.2 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.StandardUTXOSet = exports.StandardUTXO = void 0; /** * @packageDocumentation * @module Common-UTXOs */ const buffer_1 = require("buffer/"); const bintools_1 = __importDefault(require("../utils/bintools")); const bn_js_1 = __importDefault(require("bn.js")); const output_1 = require("./output"); const helperfunctions_1 = require("../utils/helperfunctions"); const serialization_1 = require("../utils/serialization"); const errors_1 = require("../utils/errors"); /** * @ignore */ const bintools = bintools_1.default.getInstance(); const serialization = serialization_1.Serialization.getInstance(); /** * Class for representing a single StandardUTXO. */ class StandardUTXO extends serialization_1.Serializable { serialize(encoding = "hex") { let fields = super.serialize(encoding); return Object.assign(Object.assign({}, fields), { codecID: serialization.encoder(this.codecID, encoding, "Buffer", "decimalString"), txid: serialization.encoder(this.txid, encoding, "Buffer", "cb58"), outputidx: serialization.encoder(this.outputidx, encoding, "Buffer", "decimalString"), assetID: serialization.encoder(this.assetID, encoding, "Buffer", "cb58"), output: this.output.serialize(encoding) }); } deserialize(fields, encoding = "hex") { super.deserialize(fields, encoding); this.codecID = serialization.decoder(fields["codecID"], encoding, "decimalString", "Buffer", 2); this.txid = serialization.decoder(fields["txid"], encoding, "cb58", "Buffer", 32); this.outputidx = serialization.decoder(fields["outputidx"], encoding, "decimalString", "Buffer", 4); this.assetID = serialization.decoder(fields["assetID"], encoding, "cb58", "Buffer", 32); } /** * Returns a {@link https://github.com/feross/buffer|Buffer} representation of the [[StandardUTXO]]. */ toBuffer() { const outbuff = this.output.toBuffer(); const outputidbuffer = buffer_1.Buffer.alloc(4); outputidbuffer.writeUInt32BE(this.output.getOutputID(), 0); const barr = [ this.codecID, this.txid, this.outputidx, this.assetID, outputidbuffer, outbuff ]; return buffer_1.Buffer.concat(barr, this.codecID.length + this.txid.length + this.outputidx.length + this.assetID.length + outputidbuffer.length + outbuff.length); } /** * Class for representing a single StandardUTXO. * * @param codecID Optional number which specifies the codeID of the UTXO. Default 0 * @param txID Optional {@link https://github.com/feross/buffer|Buffer} of transaction ID for the StandardUTXO * @param txidx Optional {@link https://github.com/feross/buffer|Buffer} or number for the index of the transaction's [[Output]] * @param assetID Optional {@link https://github.com/feross/buffer|Buffer} of the asset ID for the StandardUTXO * @param outputid Optional {@link https://github.com/feross/buffer|Buffer} or number of the output ID for the StandardUTXO */ constructor(codecID = 0, txID = undefined, outputidx = undefined, assetID = undefined, output = undefined) { super(); this._typeName = "StandardUTXO"; this._typeID = undefined; this.codecID = buffer_1.Buffer.alloc(2); this.txid = buffer_1.Buffer.alloc(32); this.outputidx = buffer_1.Buffer.alloc(4); this.assetID = buffer_1.Buffer.alloc(32); this.output = undefined; /** * Returns the numeric representation of the CodecID. */ this.getCodecID = () => this.codecID.readUInt8(0); /** * Returns the {@link https://github.com/feross/buffer|Buffer} representation of the CodecID */ this.getCodecIDBuffer = () => this.codecID; /** * Returns a {@link https://github.com/feross/buffer|Buffer} of the TxID. */ this.getTxID = () => this.txid; /** * Returns a {@link https://github.com/feross/buffer|Buffer} of the OutputIdx. */ this.getOutputIdx = () => this.outputidx; /** * Returns the assetID as a {@link https://github.com/feross/buffer|Buffer}. */ this.getAssetID = () => this.assetID; /** * Returns the UTXOID as a base-58 string (UTXOID is a string ) */ this.getUTXOID = () => bintools.bufferToB58(buffer_1.Buffer.concat([this.getTxID(), this.getOutputIdx()])); /** * Returns a reference to the output */ this.getOutput = () => this.output; if (typeof codecID !== "undefined") { this.codecID.writeUInt8(codecID, 0); } if (typeof txID !== "undefined") { this.txid = txID; } if (typeof outputidx === "number") { this.outputidx.writeUInt32BE(outputidx, 0); } else if (outputidx instanceof buffer_1.Buffer) { this.outputidx = outputidx; } if (typeof assetID !== "undefined") { this.assetID = assetID; } if (typeof output !== "undefined") { this.output = output; } } } exports.StandardUTXO = StandardUTXO; /** * Class representing a set of [[StandardUTXO]]s. */ class StandardUTXOSet extends serialization_1.Serializable { constructor() { super(...arguments); this._typeName = "StandardUTXOSet"; this._typeID = undefined; this.utxos = {}; this.addressUTXOs = {}; // maps address to utxoids:locktime /** * Returns true if the [[StandardUTXO]] is in the StandardUTXOSet. * * @param utxo Either a [[StandardUTXO]] a cb58 serialized string representing a StandardUTXO */ this.includes = (utxo) => { let utxoX = undefined; let utxoid = undefined; try { utxoX = this.parseUTXO(utxo); utxoid = utxoX.getUTXOID(); } catch (e) { if (e instanceof Error) { console.log(e.message); } else { console.log(e); } return false; } return utxoid in this.utxos; }; /** * Removes a [[StandardUTXO]] from the [[StandardUTXOSet]] if it exists. * * @param utxo Either a [[StandardUTXO]] an cb58 serialized string representing a StandardUTXO * * @returns A [[StandardUTXO]] if it was removed and undefined if nothing was removed. */ this.remove = (utxo) => { let utxovar = undefined; try { utxovar = this.parseUTXO(utxo); } catch (e) { if (e instanceof Error) { console.log(e.message); } else { console.log(e); } return undefined; } const utxoid = utxovar.getUTXOID(); if (!(utxoid in this.utxos)) { return undefined; } delete this.utxos[`${utxoid}`]; const addresses = Object.keys(this.addressUTXOs); for (let i = 0; i < addresses.length; i++) { if (utxoid in this.addressUTXOs[addresses[`${i}`]]) { delete this.addressUTXOs[addresses[`${i}`]][`${utxoid}`]; } } return utxovar; }; /** * Removes an array of [[StandardUTXO]]s to the [[StandardUTXOSet]]. * * @param utxo Either a [[StandardUTXO]] an cb58 serialized string representing a StandardUTXO * @param overwrite If true, if the UTXOID already exists, overwrite it... default false * * @returns An array of UTXOs which were removed. */ this.removeArray = (utxos) => { const removed = []; for (let i = 0; i < utxos.length; i++) { const result = this.remove(utxos[`${i}`]); if (typeof result !== "undefined") { removed.push(result); } } return removed; }; /** * Gets a [[StandardUTXO]] from the [[StandardUTXOSet]] by its UTXOID. * * @param utxoid String representing the UTXOID * * @returns A [[StandardUTXO]] if it exists in the set. */ this.getUTXO = (utxoid) => this.utxos[`${utxoid}`]; /** * Gets all the [[StandardUTXO]]s, optionally that match with UTXOIDs in an array * * @param utxoids An optional array of UTXOIDs, returns all [[StandardUTXO]]s if not provided * * @returns An array of [[StandardUTXO]]s. */ this.getAllUTXOs = (utxoids = undefined) => { let results = []; if (typeof utxoids !== "undefined" && Array.isArray(utxoids)) { results = utxoids .filter((utxoid) => this.utxos[`${utxoid}`]) .map((utxoid) => this.utxos[`${utxoid}`]); } else { results = Object.values(this.utxos); } return results; }; /** * Gets all the [[StandardUTXO]]s as strings, optionally that match with UTXOIDs in an array. * * @param utxoids An optional array of UTXOIDs, returns all [[StandardUTXO]]s if not provided * * @returns An array of [[StandardUTXO]]s as cb58 serialized strings. */ this.getAllUTXOStrings = (utxoids = undefined) => { const results = []; const utxos = Object.keys(this.utxos); if (typeof utxoids !== "undefined" && Array.isArray(utxoids)) { for (let i = 0; i < utxoids.length; i++) { if (utxoids[`${i}`] in this.utxos) { results.push(this.utxos[utxoids[`${i}`]].toString()); } } } else { for (const u of utxos) { results.push(this.utxos[`${u}`].toString()); } } return results; }; /** * Given an address or array of addresses, returns all the UTXOIDs for those addresses * * @param address An array of address {@link https://github.com/feross/buffer|Buffer}s * @param spendable If true, only retrieves UTXOIDs whose locktime has passed * * @returns An array of addresses. */ this.getUTXOIDs = (addresses = undefined, spendable = true) => { if (typeof addresses !== "undefined") { const results = []; const now = (0, helperfunctions_1.UnixNow)(); for (let i = 0; i < addresses.length; i++) { if (addresses[`${i}`].toString("hex") in this.addressUTXOs) { const entries = Object.entries(this.addressUTXOs[addresses[`${i}`].toString("hex")]); for (const [utxoid, locktime] of entries) { if ((results.indexOf(utxoid) === -1 && spendable && locktime.lte(now)) || !spendable) { results.push(utxoid); } } } } return results; } return Object.keys(this.utxos); }; /** * Gets the addresses in the [[StandardUTXOSet]] and returns an array of {@link https://github.com/feross/buffer|Buffer}. */ this.getAddresses = () => Object.keys(this.addressUTXOs).map((k) => buffer_1.Buffer.from(k, "hex")); /** * Returns the balance of a set of addresses in the StandardUTXOSet. * * @param addresses An array of addresses * @param assetID Either a {@link https://github.com/feross/buffer|Buffer} or an cb58 serialized representation of an AssetID * @param asOf The timestamp to verify the transaction against as a {@link https://github.com/indutny/bn.js/|BN} * * @returns Returns the total balance as a {@link https://github.com/indutny/bn.js/|BN}. */ this.getBalance = (addresses, assetID, asOf = undefined) => { const utxoids = this.getUTXOIDs(addresses); const utxos = this.getAllUTXOs(utxoids); let spend = new bn_js_1.default(0); let asset; if (typeof assetID === "string") { asset = bintools.cb58Decode(assetID); } else { asset = assetID; } for (let i = 0; i < utxos.length; i++) { if (utxos[`${i}`].getOutput() instanceof output_1.StandardAmountOutput && utxos[`${i}`].getAssetID().toString("hex") === asset.toString("hex") && utxos[`${i}`].getOutput().meetsThreshold(addresses, asOf)) { spend = spend.add(utxos[`${i}`].getOutput().getAmount()); } } return spend; }; /** * Gets all the Asset IDs, optionally that match with Asset IDs in an array * * @param utxoids An optional array of Addresses as string or Buffer, returns all Asset IDs if not provided * * @returns An array of {@link https://github.com/feross/buffer|Buffer} representing the Asset IDs. */ this.getAssetIDs = (addresses = undefined) => { const results = new Set(); let utxoids = []; if (typeof addresses !== "undefined") { utxoids = this.getUTXOIDs(addresses); } else { utxoids = this.getUTXOIDs(); } for (let i = 0; i < utxoids.length; i++) { if (utxoids[`${i}`] in this.utxos && !(utxoids[`${i}`] in results)) { results.add(this.utxos[utxoids[`${i}`]].getAssetID()); } } return [...results]; }; /** * Returns a new set with copy of UTXOs in this and set parameter. * * @param utxoset The [[StandardUTXOSet]] to merge with this one * @param hasUTXOIDs Will subselect a set of [[StandardUTXO]]s which have the UTXOIDs provided in this array, defults to all UTXOs * * @returns A new StandardUTXOSet that contains all the filtered elements. */ this.merge = (utxoset, hasUTXOIDs = undefined) => { const results = this.create(); const utxos1 = this.getAllUTXOs(hasUTXOIDs); const utxos2 = utxoset.getAllUTXOs(hasUTXOIDs); const process = (utxo) => { results.add(utxo); }; utxos1.forEach(process); utxos2.forEach(process); return results; }; /** * Set intersetion between this set and a parameter. * * @param utxoset The set to intersect * * @returns A new StandardUTXOSet containing the intersection */ this.intersection = (utxoset) => { const us1 = this.getUTXOIDs(); const us2 = utxoset.getUTXOIDs(); const results = us1.filter((utxoid) => us2.includes(utxoid)); return this.merge(utxoset, results); }; /** * Set difference between this set and a parameter. * * @param utxoset The set to difference * * @returns A new StandardUTXOSet containing the difference */ this.difference = (utxoset) => { const us1 = this.getUTXOIDs(); const us2 = utxoset.getUTXOIDs(); const results = us1.filter((utxoid) => !us2.includes(utxoid)); return this.merge(utxoset, results); }; /** * Set symmetrical difference between this set and a parameter. * * @param utxoset The set to symmetrical difference * * @returns A new StandardUTXOSet containing the symmetrical difference */ this.symDifference = (utxoset) => { const us1 = this.getUTXOIDs(); const us2 = utxoset.getUTXOIDs(); const results = us1 .filter((utxoid) => !us2.includes(utxoid)) .concat(us2.filter((utxoid) => !us1.includes(utxoid))); return this.merge(utxoset, results); }; /** * Set union between this set and a parameter. * * @param utxoset The set to union * * @returns A new StandardUTXOSet containing the union */ this.union = (utxoset) => this.merge(utxoset); /** * Merges a set by the rule provided. * * @param utxoset The set to merge by the MergeRule * @param mergeRule The [[MergeRule]] to apply * * @returns A new StandardUTXOSet containing the merged data * * @remarks * The merge rules are as follows: * * "intersection" - the intersection of the set * * "differenceSelf" - the difference between the existing data and new set * * "differenceNew" - the difference between the new data and the existing set * * "symDifference" - the union of the differences between both sets of data * * "union" - the unique set of all elements contained in both sets * * "unionMinusNew" - the unique set of all elements contained in both sets, excluding values only found in the new set * * "unionMinusSelf" - the unique set of all elements contained in both sets, excluding values only found in the existing set */ this.mergeByRule = (utxoset, mergeRule) => { let uSet; switch (mergeRule) { case "intersection": return this.intersection(utxoset); case "differenceSelf": return this.difference(utxoset); case "differenceNew": return utxoset.difference(this); case "symDifference": return this.symDifference(utxoset); case "union": return this.union(utxoset); case "unionMinusNew": uSet = this.union(utxoset); return uSet.difference(utxoset); case "unionMinusSelf": uSet = this.union(utxoset); return uSet.difference(this); default: throw new errors_1.MergeRuleError("Error - StandardUTXOSet.mergeByRule: bad MergeRule"); } }; } serialize(encoding = "hex") { let fields = super.serialize(encoding); let utxos = {}; for (let utxoid in this.utxos) { let utxoidCleaned = serialization.encoder(utxoid, encoding, "base58", "base58"); utxos[`${utxoidCleaned}`] = this.utxos[`${utxoid}`].serialize(encoding); } let addressUTXOs = {}; for (let address in this.addressUTXOs) { let addressCleaned = serialization.encoder(address, encoding, "hex", "cb58"); let utxobalance = {}; for (let utxoid in this.addressUTXOs[`${address}`]) { let utxoidCleaned = serialization.encoder(utxoid, encoding, "base58", "base58"); utxobalance[`${utxoidCleaned}`] = serialization.encoder(this.addressUTXOs[`${address}`][`${utxoid}`], encoding, "BN", "decimalString"); } addressUTXOs[`${addressCleaned}`] = utxobalance; } return Object.assign(Object.assign({}, fields), { utxos, addressUTXOs }); } /** * Adds a [[StandardUTXO]] to the StandardUTXOSet. * * @param utxo Either a [[StandardUTXO]] an cb58 serialized string representing a StandardUTXO * @param overwrite If true, if the UTXOID already exists, overwrite it... default false * * @returns A [[StandardUTXO]] if one was added and undefined if nothing was added. */ add(utxo, overwrite = false) { let utxovar = undefined; try { utxovar = this.parseUTXO(utxo); } catch (e) { if (e instanceof Error) { console.log(e.message); } else { console.log(e); } return undefined; } const utxoid = utxovar.getUTXOID(); if (!(utxoid in this.utxos) || overwrite === true) { this.utxos[`${utxoid}`] = utxovar; const addresses = utxovar.getOutput().getAddresses(); const locktime = utxovar.getOutput().getLocktime(); for (let i = 0; i < addresses.length; i++) { const address = addresses[`${i}`].toString("hex"); if (!(address in this.addressUTXOs)) { this.addressUTXOs[`${address}`] = {}; } this.addressUTXOs[`${address}`][`${utxoid}`] = locktime; } return utxovar; } return undefined; } /** * Adds an array of [[StandardUTXO]]s to the [[StandardUTXOSet]]. * * @param utxo Either a [[StandardUTXO]] an cb58 serialized string representing a StandardUTXO * @param overwrite If true, if the UTXOID already exists, overwrite it... default false * * @returns An array of StandardUTXOs which were added. */ addArray(utxos, overwrite = false) { const added = []; for (let i = 0; i < utxos.length; i++) { let result = this.add(utxos[`${i}`], overwrite); if (typeof result !== "undefined") { added.push(result); } } return added; } filter(args, lambda) { let newset = this.clone(); let utxos = this.getAllUTXOs(); for (let i = 0; i < utxos.length; i++) { if (lambda(utxos[`${i}`], ...args) === false) { newset.remove(utxos[`${i}`]); } } return newset; } } exports.StandardUTXOSet = StandardUTXOSet; //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidXR4b3MuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvY29tbW9uL3V0eG9zLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7Ozs7OztBQUFBOzs7R0FHRztBQUNILG9DQUFnQztBQUNoQyxpRUFBd0M7QUFDeEMsa0RBQXNCO0FBQ3RCLHFDQUEyRDtBQUMzRCw4REFBa0Q7QUFFbEQsMERBSStCO0FBQy9CLDRDQUFnRDtBQUVoRDs7R0FFRztBQUNILE1BQU0sUUFBUSxHQUFhLGtCQUFRLENBQUMsV0FBVyxFQUFFLENBQUE7QUFDakQsTUFBTSxhQUFhLEdBQWtCLDZCQUFhLENBQUMsV0FBVyxFQUFFLENBQUE7QUFFaEU7O0dBRUc7QUFDSCxNQUFzQixZQUFhLFNBQVEsNEJBQVk7SUFJckQsU0FBUyxDQUFDLFdBQStCLEtBQUs7UUFDNUMsSUFBSSxNQUFNLEdBQVcsS0FBSyxDQUFDLFNBQVMsQ0FBQyxRQUFRLENBQUMsQ0FBQTtRQUM5Qyx1Q0FDSyxNQUFNLEtBQ1QsT0FBTyxFQUFFLGFBQWEsQ0FBQyxPQUFPLENBQzVCLElBQUksQ0FBQyxPQUFPLEVBQ1osUUFBUSxFQUNSLFFBQVEsRUFDUixlQUFlLENBQ2hCLEVBQ0QsSUFBSSxFQUFFLGFBQWEsQ0FBQyxPQUFPLENBQUMsSUFBSSxDQUFDLElBQUksRUFBRSxRQUFRLEVBQUUsUUFBUSxFQUFFLE1BQU0sQ0FBQyxFQUNsRSxTQUFTLEVBQUUsYUFBYSxDQUFDLE9BQU8sQ0FDOUIsSUFBSSxDQUFDLFNBQVMsRUFDZCxRQUFRLEVBQ1IsUUFBUSxFQUNSLGVBQWUsQ0FDaEIsRUFDRCxPQUFPLEVBQUUsYUFBYSxDQUFDLE9BQU8sQ0FBQyxJQUFJLENBQUMsT0FBTyxFQUFFLFFBQVEsRUFBRSxRQUFRLEVBQUUsTUFBTSxDQUFDLEVBQ3hFLE1BQU0sRUFBRSxJQUFJLENBQUMsTUFBTSxDQUFDLFNBQVMsQ0FBQyxRQUFRLENBQUMsSUFDeEM7SUFDSCxDQUFDO0lBQ0QsV0FBVyxDQUFDLE1BQWMs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LEtBQUssQ0FBQyxHQUFHLENBQUMsRUFBRSxDQUFDLENBQUMsQ0FBQTthQUM3QjtTQUNGO1FBQ0QsT0FBTyxNQUFNLENBQUE7SUFDZixDQUFDO0NBc0hGO0FBamVELDBDQWllQyIsInNvdXJjZXNDb250ZW50IjpbIi8qKlxuICogQHBhY2thZ2VEb2N1bWVudGF0aW9uXG4gKiBAbW9kdWxlIENvbW1vbi1VVFhPc1xuICovXG5pbXBvcnQgeyBCdWZmZXIgfSBmcm9tIFwiYnVmZmVyL1wiXG5pbXBvcnQgQmluVG9vbHMgZnJvbSBcIi4uL3V0aWxzL2JpbnRvb2xzXCJcbmltcG9ydCBCTiBmcm9tIFwiYm4uanNcIlxuaW1wb3J0IHsgQmFzZU91dHB1dCwgU3RhbmRhcmRBbW91bnRPdXRwdXQgfSBmcm9tIFwiLi9vdXRwdXRcIlxuaW1wb3J0IHsgVW5peE5vdyB9IGZyb20gXCIuLi91dGlscy9oZWxwZXJmdW5jdGlvbnNcIlxuaW1wb3J0IHsgTWVyZ2VSdWxlIH0gZnJvbSBcIi4uL3V0aWxzL2NvbnN0YW50c1wiXG5pbXBvcnQge1xuICBTZXJpYWxpemFibGUsXG4gIFNlcmlhbGl6YXRpb24sXG4gIFNlcmlhbGl6ZWRFbmNvZGluZ1xufSBmcm9tIFwiLi4vdXRpbHMvc2VyaWFsaXphdGlvblwiXG5pbXBvcnQgeyBNZXJnZVJ1bGVFcnJvciB9IGZyb20gXCIuLi91dGlscy9lcnJvcnNcIlxuXG4vKipcbiAqIEBpZ25vcmVcbiAqL1xuY29uc3QgYmludG9vbHM6IEJpblRvb2xzID0gQmluVG9vbHMuZ2V0SW5zdGFuY2UoKVxuY29uc3Qgc2VyaWFsaXphdGlvbjogU2VyaWFsaXphdGlvbiA9IFNlcmlhbGl6YXRpb24uZ2V0SW5zdGFuY2UoKVxuXG4vKipcbiAqIENsYXNzIGZvciByZXByZXNlbnRpbmcgYSBzaW5nbGUgU3RhbmRhcmRVVFhPLlxuICovXG5leHBvcnQgYWJzdHJhY3QgY2xhc3MgU3RhbmRhcmRVVFhPIGV4dGVuZHMgU2VyaWFsaXphYmxlIHtcbiAgcHJvdGVjdGVkIF90eXBlTmFtZSA9IFwiU3RhbmRhcmRVVFhPXCJcbiAgcHJvdGVjdGVkIF90eXBlSUQgPSB1bmRlZmluZWRcblxuICBzZXJpYWxpemUoZW5jb2Rpbmc6IFNlcmlhbGl6ZWRFbmNvZGluZyA9IFwiaGV4XCIpOiBvYmplY3Qge1xuICAgIGxldCBmaWVsZHM6IG9iamVjdCA9IHN1cGVyLnNlcmlhbGl6ZShlbmNvZGluZylcbiAgICByZXR1cm4ge1xuICAgICAgLi4uZmllbGRzLFxuICAgICAgY29kZWNJRDogc2VyaWFsaXphdGlvbi5lbmNvZGVyKFxuICAgICAgICB0aGlzLmNvZGVjSUQsXG4gICAgICAgIGVuY29kaW5nLFxuICAgICAgICBcIkJ1ZmZlclwiLFxuICAgICAgICBcImRlY2ltYWxTdHJpbmdcIlxuICAgICAgKSxcbiAgICAgIHR4aWQ6IHNlcmlhbGl6YXRpb24uZW5jb2Rlcih0aGlzLnR4aWQsIGVuY29kaW5nLCBcIkJ1ZmZlclwiLCBcImNiNThcIiksXG4gICAgICBvdXRwdXRpZHg6IHNlcmlhbGl6YXRpb24uZW5jb2RlcihcbiAgICAgICAgdGhpcy5vdXRwdXRpZHgsXG4gICAgICAgIGVuY29kaW5nLFxuICAgICAgICBcIkJ1ZmZlclwiLFxuICAgICAgICBcImRlY2ltYWxTdHJpbmdcIlxuICAgICAgKSxcbiAgICAgIGFzc2V0SUQ6IHNlcmlhbGl6YXRpb24uZW5jb2Rlcih0aGlzLmFzc2V0SUQsIGVuY29kaW5nLCBcIkJ1ZmZlclwiLCBcImNiNThcIiksXG4gICAgICBvdXRwdXQ6IHRoaXMub3V0cHV0LnNlcmlhbGl6ZShlbmNvZGluZylcbiAgICB9XG4gIH1cbiAgZGVzZXJpYWxpemUoZmllbGRzOiBvYmplY3QsIGVuY29kaW5nOiBTZXJpYWxpemVkRW5jb2RpbmcgPSBcImhleFwiKSB7XG4gICAgc3VwZXIuZGVzZXJpYWxpemUoZmllbGRzLCBlbmNvZGluZylcbiAgICB0aGlzLmNvZGVjSUQgPSBzZXJpYWxpemF0aW9uLmRlY29kZXIoXG4gICAgICBmaWVsZHNbXCJjb2RlY0lEXCJdLFxuICAgICAgZW5jb2RpbmcsXG4gICAgICBcImRlY2ltYWxTdHJpbmdcIixcbiAgICAgIFwiQnVmZmVyXCIsXG4gICAgICAyXG4gICAgKVxuICAgIHRoaXMudHhpZCA9IHNlcmlhbGl6YXRpb24uZGVjb2RlcihcbiAgICAgIGZpZWxkc1tcInR4aWRcIl0sXG4gICAgICBlbmNvZGluZyxcbiAgICAgIFwiY2I1OFwiLFxuICAgICAgXCJCdWZmZXJcIixcbiAgICAgIDMyXG4gICAgKVxuICAgIHRoaXMub3V0cHV0aWR4ID0gc2VyaWFsaXphdGlvbi5kZWNvZGVyKFxuICAgICAgZmllbGRzW1wib3V0cHV0aWR4XCJdLFxuICAgICAgZW5jb2RpbmcsXG4gICAgICBcImRlY2ltYWxTdHJpbmdcIixcbiAgICAgIFwiQnVmZmVyXCIsXG4gICAgICA0XG4gICAgKVxuICAgIHRoaXMuYXNzZXRJRCA9IHNlcmlhbGl6YXRpb24uZGVjb2RlcihcbiAgICAgIGZpZWxkc1tcImFzc2V0SURcIl0sXG4gICAgICBlbmNvZGluZyxcbiAgICAgIFwiY2I1OFwiLFxuICAgICAgXCJCdWZmZXJcIixcbiAgICAgIDMyXG4gICAgKVxuICB9XG5cbiAgcHJvdGVjdGVkIGNvZGVjSUQ6IEJ1ZmZlciA9IEJ1ZmZlci5hbGxvYygyKVxuICBwcm90ZWN0ZWQgdHhpZDogQnVmZmVyID0gQnVmZmVyLmFsbG9jKDMyKVxuICBwcm90ZWN0ZWQgb3V0cHV0aWR4OiBCdWZmZXIgPSBCdWZmZXIuYWxsb2MoNClcbiAgcHJvdGVjdGVkIGFzc2V0SUQ6IEJ1ZmZlciA9IEJ1ZmZlci5hbGxvYygzMilcbiAgcHJvdGVjdGVkIG91dHB1dDogQmFzZU91dHB1dCA9IHVuZGVmaW5lZFxuXG4gIC8qKlxuICAgKiBSZXR1cm5zIHRoZSBudW1lcmljIHJlcHJlc2VudGF0aW9uIG9mIHRoZSBDb2RlY0lELlxuICAgKi9cbiAgZ2V0Q29kZWNJRCA9ICgpOiAvKiBpc3RhbmJ1bCBpZ25vcmUgbmV4dCAqLyBudW1iZXIgPT5cbiAgICB0aGlzLmNvZGVjSUQucmVhZFVJbnQ4KDApXG5cbiAgLyoqXG4gICAqIFJldHVybnMgdGhlIHtAbGluayBodHRwczovL2dpdGh1Yi5jb20vZmVyb3NzL2J1ZmZlcnxCdWZmZXJ9IHJlcHJlc2VudGF0aW9uIG9mIHRoZSBDb2RlY0lEXG4gICAqL1xuICBnZXRDb2RlY0lEQnVmZmVyID0gKCk6IEJ1ZmZlciA9PiB0aGlzLmNvZGVjSURcblxuICAvKipcbiAgICogUmV0dXJucyBhIHtAbGluayBodHRwczovL2dpdGh1Yi5jb20vZmVyb3NzL2J1ZmZlcnxCdWZmZXJ9IG9mIHRoZSBUeElELlxuICAgKi9cbiAgZ2V0VHhJRCA9ICgpOiAvKiBpc3RhbmJ1bCBpZ25vcmUgbmV4dCAqLyBCdWZmZXIgPT4gdGhpcy50eGlkXG5cbiAgLyoqXG4gICAqIFJldHVybnMgYSB7QGxpbmsgaHR0cHM6Ly9naXRodWIuY29tL2Zlcm9zcy9idWZmZXJ8QnVmZmVyfSAgb2YgdGhlIE91dHB1dElkeC5cbiAgICovXG4gIGdldE91dHB1dElkeCA9ICgpOiAvKiBpc3RhbmJ1bCBpZ25vcmUgbmV4dCAqLyBCdWZmZXIgPT4gdGhpcy5vdXRwdXRpZHhcblxuICAvKipcbiAgICogUmV0dXJucyB0aGUgYXNzZXRJRCBhcyBhIHtAbGluayBodHRwczovL2dpdGh1Yi5jb20vZmVyb3NzL2J1ZmZlcnxCdWZmZXJ9LlxuICAgKi9cbiAgZ2V0QXNzZXRJRCA9ICgpOiBCdWZmZXIgPT4gdGhpcy5hc3NldElEXG5cbiAgLyoqXG4gICAqIFJldHVybnMgdGhlIFVUWE9JRCBhcyBhIGJhc2UtNTggc3RyaW5nIChVVFhPSUQgaXMgYSBzdHJpbmcgKVxuICAgKi9cbiAgZ2V0VVRYT0lEID0gKCk6IC8qIGlzdGFuYnVsIGlnbm9yZSBuZXh0ICovIHN0cmluZyA9PlxuICAgIGJpbnRvb2xzLmJ1ZmZlclRvQjU4KEJ1ZmZlci5jb25jYXQoW3RoaXMuZ2V0VHhJRCgpLCB0aGlzLmdldE91dHB1dElkeCgpXSkpXG5cbiAgLyoqXG4gICAqIFJldHVybnMgYSByZWZlcmVuY2UgdG8gdGhlIG91dHB1dFxuICAgKi9cbiAgZ2V0T3V0cHV0ID0gKCk6IEJhc2VPdXRwdXQgPT4gdGhpcy5vdXRwdXRcblxuICAvKipcbiAgICogVGFrZXMgYSB7QGxpbmsgaHR0cHM6Ly9naXRodWIuY29tL2Zlcm9zcy9idWZmZXJ8QnVmZmVyfSBjb250YWluaW5nIGFuIFtbU3RhbmRhcmRVVFhPXV0sIHBhcnNlcyBpdCwgcG9wdWxhdGVzIHRoZSBjbGFzcywgYW5kIHJldHVybnMgdGhlIGxlbmd0aCBvZiB0aGUgU3RhbmRhcmRVVFhPIGluIGJ5dGVzLlxuICAgKlxuICAgKiBAcGFyYW0gYnl0ZXMgQSB7QGxpbmsgaHR0cHM6Ly9naXRodWIuY29tL2Zlcm9zcy9idWZmZXJ8QnVmZmVyfSBjb250YWluaW5nIGEgcmF3IFtbU3RhbmRhcmRVVFhPXV1cbiAgICovXG4gIGFic3RyYWN0IGZyb21CdWZmZXIoYnl0ZXM6IEJ1ZmZlciwgb2Zmc2V0PzogbnVtYmVyKTogbnVtYmVyXG5cbiAgLyoqXG4gICAqIFJldHVybnMgYSB7QGxpbmsgaHR0cHM6Ly9naXRodWIuY29tL2Zlcm9zcy9idWZmZXJ8QnVmZmVyfSByZXByZXNlbnRhdGlvbiBvZiB0aGUgW1tTdGFuZGFyZFVUWE9dXS5cbiAgICovXG4gIHRvQnVmZmVyKCk6IEJ1ZmZlciB7XG4gICAgY29uc3Qgb3V0YnVmZjogQnVmZmVyID0gdGhpcy5vdXRwdXQudG9CdWZmZXIoKVxuICAgIGNvbnN0IG91dHB1dGlkYnVmZmVyOiBCdWZmZXIgPSBCdWZmZXIuYWxsb2MoNClcbiAgICBvdXRwdXRpZGJ1ZmZlci53cml0ZVVJbnQzMkJFKHRoaXMub3V0cHV0LmdldE91dHB1dElEKCksIDApXG4gICAgY29uc3QgYmFycjogQnVmZmVyW10gPSBbXG4gICAgICB0aGlzLmNvZGVjSUQsXG4gICAgICB0aGlzLnR4aWQsXG4gICAgICB0aGlzLm91dHB1dGlkeCxcbiAgICAgIHRoaXMuYXNzZXRJRCxcbiAgICAgIG91dHB1dGlkYnVmZmVyLFxuICAgICAgb3V0YnVmZlxuICAgIF1cbiAgICByZXR1cm4gQnVmZmVyLmNvbmNhdChcbiAgICAgIGJhcnIsXG4gICAgICB0aGlzLmNvZGVjSUQubGVuZ3RoICtcbiAgICAgICAgdGhpcy50eGlkLmxlbmd0aCArXG4gICAgICAgIHRoaXMub3V0cHV0aWR4Lmxlbmd0aCArXG4gICAgICAgIHRoaXMuYXNzZXRJRC5sZW5ndGggK1xuICAgICAgICBvdXRwdXRpZGJ1ZmZlci5sZW5ndGggK1xuICAgICAgICBvdXRidWZmLmxlbmd0aFxuICAgIClcbiAgfVxuXG4gIGFic3RyYWN0IGZyb21TdHJpbmcoc2VyaWFsaXplZDogc3RyaW5nKTogbnVtYmVyXG5cbiAgYWJzdHJhY3QgdG9TdHJpbmcoKTogc3RyaW5nXG5cbiAgYWJzdHJhY3QgY2xvbmUoKTogdGhpc1xuXG4gIGFic3RyYWN0IGNyZWF0ZShcbiAgICBjb2RlY0lEPzogbnVtYmVyLFxuICAgIHR4aWQ/OiBCdWZmZXIsXG4gICAgb3V0cHV0aWR4PzogQnVmZmVyIHwgbnVtYmVyLFxuICAgIGFzc2V0SUQ/OiBCdWZmZXIsXG4gICAgb3V0cHV0PzogQmFzZU91dHB1dFxuICApOiB0aGlzXG5cbiAgLyoqXG4gICAqIENsYXNzIGZvciByZXByZXNlbnRpbmcgYSBzaW5nbGUgU3RhbmRhcmRVVFhPLlxuICAgKlxuICAgKiBAcGFyYW0gY29kZWNJRCBPcHRpb25hbCBudW1iZXIgd2hpY2ggc3BlY2lmaWVzIHRoZSBjb2RlSUQgb2YgdGhlIFVUWE8uIERlZmF1bHQgMFxuICAgKiBAcGFyYW0gdHhJRCBPcHRpb25hbCB7QGxpbmsgaHR0cHM6Ly9naXRodWIuY29tL2Zlcm9zcy9idWZmZXJ8QnVmZmVyfSBvZiB0cmFuc2FjdGlvbiBJRCBmb3IgdGhlIFN0YW5kYXJkVVRYT1xuICAgKiBAcGFyYW0gdHhpZHggT3B0aW9uYWwge0BsaW5rIGh0dHBzOi8vZ2l0aHViLmNvbS9mZXJvc3MvYnVmZmVyfEJ1ZmZlcn0gb3IgbnVtYmVyIGZvciB0aGUgaW5kZXggb2YgdGhlIHRyYW5zYWN0aW9uJ3MgW1tPdXRwdXRdXVxuICAgKiBAcGFyYW0gYXNzZXRJRCBPcHRpb25hbCB7QGxpbmsgaHR0cHM6Ly9naXRodWIuY29tL2Zlcm9zcy9idWZmZXJ8QnVmZmVyfSBvZiB0aGUgYXNzZXQgSUQgZm9yIHRoZSBTdGFuZGFyZFVUWE9cbiAgICogQHBhcmFtIG91dHB1dGlkIE9wdGlvbmFsIHtAbGluayBodHRwczovL2dpdGh1Yi5jb20vZmVyb3NzL2J1ZmZlcnxCdWZmZXJ9IG9yIG51bWJlciBvZiB0aGUgb3V0cHV0IElEIGZvciB0aGUgU3RhbmRhcmRVVFhPXG4gICAqL1xuICBjb25zdHJ1Y3RvcihcbiAgICBjb2RlY0lEOiBudW1iZXIgPSAwLFxuICAgIHR4SUQ6IEJ1ZmZlciA9IHVuZGVmaW5lZCxcbiAgICBvdXRwdXRpZHg6IEJ1ZmZlciB8IG51bWJlciA9IHVuZGVmaW5lZCxcbiAgICBhc3NldElEOiBCdWZmZXIgPSB1bmRlZmluZWQsXG4gICAgb3V0cHV0OiBCYXNlT3V0cHV0ID0gdW5kZWZpbmVkXG4gICkge1xuICAgIHN1cGVyKClcbiAgICBpZiAodHlwZW9mIGNvZGVjSUQgIT09IFwidW5kZWZpbmVkXCIpIHtcbiAgICAgIHRoaXMuY29kZWNJRC53cml0ZVVJbnQ4KGNvZGVjSUQsIDApXG4gICAgfVxuICAgIGlmICh0eXBlb2