UNPKG

@kubectl/caminojs

Version:
392 lines 44.9 kB
"use strict"; var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; var desc = Object.getOwnPropertyDescriptor(m, k); if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { desc = { enumerable: true, get: function() { return m[k]; } }; } Object.defineProperty(o, k2, desc); }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; })); var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { Object.defineProperty(o, "default", { enumerable: true, value: v }); }) : function(o, v) { o["default"] = v; }); var __importStar = (this && this.__importStar) || function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); __setModuleDefault(result, mod); return result; }; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); /** * @packageDocumentation * @module Utils-BinTools */ const bn_js_1 = __importDefault(require("bn.js")); const buffer_1 = require("buffer/"); const create_hash_1 = __importDefault(require("create-hash")); const bech32 = __importStar(require("bech32")); const base58_1 = require("./base58"); const errors_1 = require("../utils/errors"); const ethers_1 = require("ethers"); /** * A class containing tools useful in interacting with binary data cross-platform using * nodejs & javascript. * * This class should never be instantiated directly. Instead, * invoke the "BinTools.getInstance()" static * function to grab the singleton * instance of the tools. * * Everything in this library uses * the {@link https://github.com/feross/buffer|feross's Buffer class}. * * ```js * const bintools: BinTools = BinTools.getInstance(); * const b58str: = bintools.bufferToB58(Buffer.from("Wubalubadubdub!")); * ``` */ class BinTools { constructor() { /** * Returns true if meets requirements to parse as an address as Bech32 on X-Chain or P-Chain, otherwise false * @param address the string to verify is address */ this.isPrimaryBechAddress = (address) => { const parts = address.trim().split("-"); if (parts.length !== 2) { return false; } try { bech32.bech32.fromWords(bech32.bech32.decode(parts[1]).words); } catch (err) { return false; } return true; }; /** * Produces a string from a {@link https://github.com/feross/buffer|Buffer} * representing a string. ONLY USED IN TRANSACTION FORMATTING, ASSUMED LENGTH IS PREPENDED. * * @param buff The {@link https://github.com/feross/buffer|Buffer} to convert to a string */ this.bufferToString = (buff) => this.copyFrom(buff, 2).toString("utf8"); /** * Produces a {@link https://github.com/feross/buffer|Buffer} from a string. ONLY USED IN TRANSACTION FORMATTING, LENGTH IS PREPENDED. * * @param str The string to convert to a {@link https://github.com/feross/buffer|Buffer} */ this.stringToBuffer = (str) => { const buff = buffer_1.Buffer.alloc(2 + str.length); buff.writeUInt16BE(str.length, 0); buff.write(str, 2, str.length, "utf8"); return buff; }; /** * Makes a copy (no reference) of a {@link https://github.com/feross/buffer|Buffer} * over provided indecies. * * @param buff The {@link https://github.com/feross/buffer|Buffer} to copy * @param start The index to start the copy * @param end The index to end the copy */ this.copyFrom = (buff, start = 0, end = undefined) => { if (end === undefined) { end = buff.length; } return buffer_1.Buffer.from(Uint8Array.prototype.slice.call(buff.slice(start, end))); }; /** * Takes a {@link https://github.com/feross/buffer|Buffer} and returns a base-58 string of * the {@link https://github.com/feross/buffer|Buffer}. * * @param buff The {@link https://github.com/feross/buffer|Buffer} to convert to base-58 */ this.bufferToB58 = (buff) => this.b58.encode(buff); /** * Takes a base-58 string and returns a {@link https://github.com/feross/buffer|Buffer}. * * @param b58str The base-58 string to convert * to a {@link https://github.com/feross/buffer|Buffer} */ this.b58ToBuffer = (b58str) => this.b58.decode(b58str); /** * Takes a {@link https://github.com/feross/buffer|Buffer} and returns an ArrayBuffer. * * @param buff The {@link https://github.com/feross/buffer|Buffer} to * convert to an ArrayBuffer */ this.fromBufferToArrayBuffer = (buff) => { const ab = new ArrayBuffer(buff.length); const view = new Uint8Array(ab); for (let i = 0; i < buff.length; ++i) { view[`${i}`] = buff[`${i}`]; } return view; }; /** * Takes an ArrayBuffer and converts it to a {@link https://github.com/feross/buffer|Buffer}. * * @param ab The ArrayBuffer to convert to a {@link https://github.com/feross/buffer|Buffer} */ this.fromArrayBufferToBuffer = (ab) => { const buf = buffer_1.Buffer.alloc(ab.byteLength); for (let i = 0; i < ab.byteLength; ++i) { buf[`${i}`] = ab[`${i}`]; } return buf; }; /** * Takes a {@link https://github.com/feross/buffer|Buffer} and converts it * to a {@link https://github.com/indutny/bn.js/|BN}. * * @param buff The {@link https://github.com/feross/buffer|Buffer} to convert * to a {@link https://github.com/indutny/bn.js/|BN} */ this.fromBufferToBN = (buff) => { if (typeof buff === "undefined") { return undefined; } return new bn_js_1.default(buff.toString("hex"), 16, "be"); }; /** * Takes a {@link https://github.com/indutny/bn.js/|BN} and converts it * to a {@link https://github.com/feross/buffer|Buffer}. * * @param bn The {@link https://github.com/indutny/bn.js/|BN} to convert * to a {@link https://github.com/feross/buffer|Buffer} * @param length The zero-padded length of the {@link https://github.com/feross/buffer|Buffer} */ this.fromBNToBuffer = (bn, length) => { if (typeof bn === "undefined") { return undefined; } const newarr = bn.toArray("be"); /** * CKC: Still unsure why bn.toArray with a "be" and a length do not work right. Bug? */ if (length) { // bn toArray with the length parameter doesn't work correctly, need this. const x = length - newarr.length; for (let i = 0; i < x; i++) { newarr.unshift(0); } } return buffer_1.Buffer.from(newarr); }; /** * Takes a {@link https://github.com/feross/buffer|Buffer} and adds a checksum, returning * a {@link https://github.com/feross/buffer|Buffer} with the 4-byte checksum appended. * * @param buff The {@link https://github.com/feross/buffer|Buffer} to append a checksum */ this.addChecksum = (buff) => { const hashslice = buffer_1.Buffer.from((0, create_hash_1.default)("sha256").update(buff).digest().slice(28)); return buffer_1.Buffer.concat([buff, hashslice]); }; /** * Takes a {@link https://github.com/feross/buffer|Buffer} with an appended 4-byte checksum * and returns true if the checksum is valid, otherwise false. * * @param b The {@link https://github.com/feross/buffer|Buffer} to validate the checksum */ this.validateChecksum = (buff) => { const checkslice = buff.slice(buff.length - 4); const hashslice = buffer_1.Buffer.from((0, create_hash_1.default)("sha256") .update(buff.slice(0, buff.length - 4)) .digest() .slice(28)); return checkslice.toString("hex") === hashslice.toString("hex"); }; /** * Takes a {@link https://github.com/feross/buffer|Buffer} and returns a base-58 string with * checksum as per the cb58 standard. * * @param bytes A {@link https://github.com/feross/buffer|Buffer} to serialize * * @returns A serialized base-58 string of the Buffer. */ this.cb58Encode = (bytes) => { const x = this.addChecksum(bytes); return this.bufferToB58(x); }; /** * Takes a cb58 serialized {@link https://github.com/feross/buffer|Buffer} or base-58 string * and returns a {@link https://github.com/feross/buffer|Buffer} of the original data. Throws on error. * * @param bytes A cb58 serialized {@link https://github.com/feross/buffer|Buffer} or base-58 string */ this.cb58Decode = (bytes) => { if (typeof bytes === "string") { bytes = this.b58ToBuffer(bytes); } if (this.validateChecksum(bytes)) { return this.copyFrom(bytes, 0, bytes.length - 4); } throw new errors_1.ChecksumError("Error - BinTools.cb58Decode: invalid checksum"); }; this.cb58DecodeWithChecksum = (bytes) => { if (typeof bytes === "string") { bytes = this.b58ToBuffer(bytes); } if (this.validateChecksum(bytes)) { return `0x${this.copyFrom(bytes, 0, bytes.length).toString("hex")}`; } throw new errors_1.ChecksumError("Error - BinTools.cb58Decode: invalid checksum"); }; this.addressToString = (hrp, chainid, bytes) => `${chainid}-${bech32.bech32.encode(hrp, bech32.bech32.toWords(bytes))}`; this.stringToAddress = (address, hrp) => { if (address.substring(0, 2) === "0x") { // ETH-style address if (ethers_1.utils.isAddress(address)) { return buffer_1.Buffer.from(address.substring(2), "hex"); } else { throw new errors_1.HexError("Error - Invalid address"); } } // Bech32 addresses const parts = address.trim().split("-"); if (parts.length < 2) { throw new errors_1.Bech32Error("Error - Valid address should include -"); } if (parts[0].length < 1) { throw new errors_1.Bech32Error("Error - Valid address must have prefix before -"); } const split = parts[1].lastIndexOf("1"); if (split < 0) { throw new errors_1.Bech32Error("Error - Valid address must include separator (1)"); } const humanReadablePart = parts[1].slice(0, split); if (humanReadablePart.length < 1) { throw new errors_1.Bech32Error("Error - HRP should be at least 1 character"); } if (humanReadablePart !== "avax" && humanReadablePart !== "fuji" && humanReadablePart != "local" && humanReadablePart != "columbus" && humanReadablePart != "camino" && humanReadablePart != "custom" && humanReadablePart != hrp) { throw new errors_1.Bech32Error("Error - Invalid HRP"); } return buffer_1.Buffer.from(bech32.bech32.fromWords(bech32.bech32.decode(parts[1]).words)); }; /** * Takes an address and returns its {@link https://github.com/feross/buffer|Buffer} * representation if valid. A more strict version of stringToAddress. * * @param addr A string representation of the address * @param blockchainID A cb58 encoded string representation of the blockchainID * @param alias A chainID alias, if any, that the address can also parse from. * @param addrlen VMs can use any addressing scheme that they like, so this is the appropriate number of address bytes. Default 20. * * @returns A {@link https://github.com/feross/buffer|Buffer} for the address if valid, * undefined if not valid. */ this.parseAddress = (addr, blockchainID, alias = undefined, addrlen = 20) => { const abc = addr.split("-"); if (abc.length === 2 && ((alias && abc[0] === alias) || (blockchainID && abc[0] === blockchainID))) { const addrbuff = this.stringToAddress(addr); if ((addrlen && addrbuff.length === addrlen) || !addrlen) { return addrbuff; } } return undefined; }; this.b58 = base58_1.Base58.getInstance(); } /** * Retrieves the BinTools singleton. */ static getInstance() { if (!BinTools.instance) { BinTools.instance = new BinTools(); } return BinTools.instance; } /** * Returns true if base64, otherwise false * @param str the string to verify is Base64 */ isBase64(str) { if (str === "" || str.trim() === "") { return false; } try { let b64 = buffer_1.Buffer.from(str, "base64"); return b64.toString("base64") === str; } catch (err) { return false; } } /** * Returns true if cb58, otherwise false * @param cb58 the string to verify is cb58 */ isCB58(cb58) { return this.isBase58(cb58); } /** * Returns true if base58, otherwise false * @param base58 the string to verify is base58 */ isBase58(base58) { if (base58 === "" || base58.trim() === "") { return false; } try { return this.b58.encode(this.b58.decode(base58)) === base58; } catch (err) { return false; } } /** * Returns true if hexidecimal, otherwise false * @param hex the string to verify is hexidecimal */ isHex(hex) { if (hex === "" || hex.trim() === "") { return false; } const startsWith0x = hex.startsWith("0x"); const matchResult = startsWith0x ? hex.slice(2).match(/[0-9A-Fa-f]/g) : hex.match(/[0-9A-Fa-f]/g); if ((startsWith0x && hex.length - 2 == matchResult.length) || hex.length == matchResult.length) { return true; } else { return false; } } /** * Returns true if decimal, otherwise false * @param str the string to verify is hexidecimal */ isDecimal(str) { if (str === "" || str.trim() === "") { return false; } try { return new bn_js_1.default(str, 10).toString(10) === str.trim(); } catch (err) { return false; } } } exports.default = BinTools; //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYmludG9vbHMuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi9zcmMvdXRpbHMvYmludG9vbHMudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7OztBQUFBOzs7R0FHRztBQUNILGtEQUFzQjtBQUN0QixvQ0FBZ0M7QUFDaEMsOERBQW9DO0FBQ3BDLCtDQUFnQztBQUNoQyxxQ0FBaUM7QUFDakMsNENBQXNFO0FBQ3RFLG1DQUE4QjtBQUU5Qjs7Ozs7Ozs7Ozs7Ozs7O0dBZUc7QUFDSCxNQUFxQixRQUFRO0lBRzNCO1FBNEZBOzs7V0FHRztRQUNILHlCQUFvQixHQUFHLENBQUMsT0FBZSxFQUFXLEVBQUU7WUFDbEQsTUFBTSxLQUFLLEdBQWEsT0FBTyxDQUFDLElBQUksRUFBRSxDQUFDLEtBQUssQ0FBQyxHQUFHLENBQUMsQ0FBQTtZQUNqRCxJQUFJLEtBQUssQ0FBQyxNQUFNLEtBQUssQ0FBQyxFQUFFO2dCQUN0QixPQUFPLEtBQUssQ0FBQTthQUNiO1lBQ0QsSUFBSTtnQkFDRixNQUFNLENBQUMsTUFBTSxDQUFDLFNBQVMsQ0FBQyxNQUFNLENBQUMsTUFBTSxDQUFDLE1BQU0sQ0FBQyxLQUFLLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxLQUFLLENBQUMsQ0FBQTthQUM5RDtZQUFDLE9BQU8sR0FBRyxFQUFFO2dCQUNaLE9BQU8sS0FBSyxDQUFBO2FBQ2I7WUFDRCxPQUFPLElBQUksQ0FBQTtRQUNiLENBQUMsQ0FBQTtRQUVEOzs7OztXQUtHO1FBQ0gsbUJBQWMsR0FBRyxDQUFDLElBQVksRUFBVSxFQUFFLENBQ3hDLElBQUksQ0FBQyxRQUFRLENBQUMsSUFBSSxFQUFFLENBQUMsQ0FBQyxDQUFDLFFBQVEsQ0FBQyxNQUFNLENBQUMsQ0FBQTtRQUV6Qzs7OztXQUlHO1FBQ0gsbUJBQWMsR0FBRyxDQUFDLEdBQVcsRUFBVSxFQUFFO1lBQ3ZDLE1BQU0sSUFBSSxHQUFXLGVBQU0sQ0FBQyxLQUFLLENBQUMsQ0FBQyxHQUFHLEdBQUcsQ0FBQyxNQUFNLENBQUMsQ0FBQTtZQUNqRCxJQUFJLENBQUMsYUFBYSxDQUFDLEdBQUcsQ0FBQyxNQUFNLEVBQUUsQ0FBQyxDQUFDLENBQUE7WUFDakMsSUFBSSxDQUFDLEtBQUssQ0FBQyxHQUFHLEVBQUUsQ0FBQyxFQUFFLEdBQUcsQ0FBQyxNQUFNLEVBQUUsTUFBTSxDQUFDLENBQUE7WUFDdEMsT0FBTyxJQUFJLENBQUE7UUFDYixDQUFDLENBQUE7UUFFRDs7Ozs7OztXQU9HO1FBQ0gsYUFBUSxHQUFHLENBQ1QsSUFBWSxFQUNaLFFBQWdCLENBQUMsRUFDakIsTUFBYyxTQUFTLEVBQ2YsRUFBRTtZQUNWLElBQUksR0FBRyxLQUFLLFNBQVMsRUFBRTtnQkFDckIsR0FBRyxHQUFHLElBQUksQ0FBQyxNQUFNLENBQUE7YUFDbEI7WUFDRCxPQUFPLGVBQU0sQ0FBQyxJQUFJLENBQUMsVUFBVSxDQUFDLFNBQVMsQ0FBQyxLQUFLLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxLQUFLLENBQUMsS0FBSyxFQUFFLEdBQUcsQ0FBQyxDQUFDLENBQUMsQ0FBQTtRQUM3RSxDQUFDLENBQUE7UUFFRDs7Ozs7V0FLRztRQUNILGdCQUFXLEdBQUcsQ0FBQyxJQUFZLEVBQVUsRUFBRSxDQUFDLElBQUksQ0FBQyxHQUFHLENBQUMsTUFBTSxDQUFDLElBQUksQ0FBQyxDQUFBO1FBRTdEOzs7OztXQUtHO1FBQ0gsZ0JBQVcsR0FBRyxDQUFDLE1BQWMsRUFBVSxFQUFFLENBQUMsSUFBSSxDQUFDLEdBQUcsQ0FBQyxNQUFNLENBQUMsTUFBTSxDQUFDLENBQUE7UUFFakU7Ozs7O1dBS0c7UUFDSCw0QkFBdUIsR0FBRyxDQUFDLElBQVksRUFBZSxFQUFFO1lBQ3RELE1BQU0sRUFBRSxHQUFHLElBQUksV0FBVyxDQUFDLElBQUksQ0FBQyxNQUFNLENBQUMsQ0FBQTtZQUN2QyxNQUFNLElBQUksR0FBRyxJQUFJLFVBQVUsQ0FBQyxFQUFFLENBQUMsQ0FBQTtZQUMvQixLQUFLLElBQUksQ0FBQyxHQUFXLENBQUMsRUFBRSxDQUFDLEdBQUcsSUFBSSxDQUFDLE1BQU0sRUFBRSxFQUFFLENBQUMsRUFBRTtnQkFDNUMsSUFBSSxDQUFDLEdBQUcsQ0FBQyxFQUFFLENBQUMsR0FBRyxJQUFJLENBQUMsR0FBRyxDQUFDLEVBQUUsQ0FBQyxDQUFBO2FBQzVCO1lBQ0QsT0FBTyxJQUFJLENBQUE7UUFDYixDQUFDLENBQUE7UUFFRDs7OztXQUlHO1FBQ0gsNEJBQXVCLEdBQUcsQ0FBQyxFQUFlLEVBQVUsRUFBRTtZQUNwRCxNQUFNLEdBQUcsR0FBRyxlQUFNLENBQUMsS0FBSyxDQUFDLEVBQUUsQ0FBQyxVQUFVLENBQUMsQ0FBQTtZQUN2QyxLQUFLLElBQUksQ0FBQyxHQUFXLENBQUMsRUFBRSxDQUFDLEdBQUcsRUFBRSxDQUFDLFVBQVUsRUFBRSxFQUFFLENBQUMsRUFBRTtnQkFDOUMsR0FBRyxDQUFDLEdBQUcsQ0FBQyxFQUFFLENBQUMsR0FBRyxFQUFFLENBQUMsR0FBRyxDQUFDLEVBQUUsQ0FBQyxDQUFBO2FBQ3pCO1lBQ0QsT0FBTyxHQUFHLENBQUE7UUFDWixDQUFDLENBQUE7UUFFRDs7Ozs7O1dBTUc7UUFDSCxtQkFBYyxHQUFHLENBQUMsSUFBWSxFQUFNLEVBQUU7WUFDcEMsSUFBSSxPQUFPLElBQUksS0FBSyxXQUFXLEVBQUU7Z0JBQy9CLE9BQU8sU0FBUyxDQUFBO2FBQ2pCO1lBQ0QsT0FBTyxJQUFJLGVBQUUsQ0FBQyxJQUFJLENBQUMsUUFBUSxDQUFDLEtBQUssQ0FBQyxFQUFFLEVBQUUsRUFBRSxJQUFJLENBQUMsQ0FBQTtRQUMvQyxDQUFDLENBQUE7UUFDRDs7Ozs7OztXQU9HO1FBQ0gsbUJBQWMsR0FBRyxDQUFDLEVBQU0sRUFBRSxNQUFlLEVBQVUsRUFBRTtZQUNuRCxJQUFJLE9BQU8sRUFBRSxLQUFLLFdBQVcsRUFBRTtnQkFDN0IsT0FBTyxTQUFTLENBQUE7YUFDakI7WUFDRCxNQUFNLE1BQU0sR0FBRyxFQUFFLENBQUMsT0FBTyxDQUFDLElBQUksQ0FBQyxDQUFBO1lBQy9COztlQUVHO1lBQ0gsSUFBSSxNQUFNLEVBQUU7Z0JBQ1YsMEVBQTBFO2dCQUMxRSxNQUFNLENBQUMsR0FBRyxNQUFNLEdBQUcsTUFBTSxDQUFDLE1BQU0sQ0FBQTtnQkFDaEMsS0FBSyxJQUFJLENBQUMsR0FBVyxDQUFDLEVBQUUsQ0FBQyxHQUFHLENBQUMsRUFBRSxDQUFDLEVBQUUsRUFBRTtvQkFDbEMsTUFBTSxDQUFDLE9BQU8sQ0FBQyxDQUFDLENBQUMsQ0FBQTtpQkFDbEI7YUFDRjtZQUNELE9BQU8sZUFBTSxDQUFDLElBQUksQ0FBQyxNQUFNLENBQUMsQ0FBQTtRQUM1QixDQUFDLENBQUE7UUFFRDs7Ozs7V0FLRztRQUNILGdCQUFXLEdBQUcsQ0FBQyxJQUFZLEVBQVUsRUFBRTtZQUNyQyxNQUFNLFNBQVMsR0FBVyxlQUFNLENBQUMsSUFBSSxDQUNuQyxJQUFBLHFCQUFVLEVBQUMsUUFBUSxDQUFDLENBQUMsTUFBTSxDQUFDLElBQUksQ0FBQyxDQUFDLE1BQU0sRUFBRSxDQUFDLEtBQUssQ0FBQyxFQUFFLENBQUMsQ0FDckQsQ0FBQTtZQUNELE9BQU8sZUFBTSxDQUFDLE1BQU0sQ0FBQyxDQUFDLElBQUksRUFBRSxTQUFTLENBQUMsQ0FBQyxDQUFBO1FBQ3pDLENBQUMsQ0FBQTtRQUVEOzs7OztXQUtHO1FBQ0gscUJBQWdCLEdBQUcsQ0FBQyxJQUFZLEVBQVcsRUFBRTtZQUMzQyxNQUFNLFVBQVUsR0FBVyxJQUFJLENBQUMsS0FBSyxDQUFDLElBQUksQ0FBQyxNQUFNLEdBQUcsQ0FBQyxDQUFDLENBQUE7WUFDdEQsTUFBTSxTQUFTLEdBQVcsZUFBTSxDQUFDLElBQUksQ0FDbkMsSUFBQSxxQkFBVSxFQUFDLFFBQVEsQ0FBQztpQkFDakIsTUFBTSxDQUFDLElBQUksQ0FBQyxLQUFLLENBQUMsQ0FBQyxFQUFFLElBQUksQ0FBQyxNQUFNLEdBQUcsQ0FBQyxDQUFDLENBQUM7aUJBQ3RDLE1BQU0sRUFBRTtpQkFDUixLQUFLLENBQUMsRUFBRSxDQUFDLENBQ2IsQ0FBQTtZQUNELE9BQU8sVUFBVSxDQUFDLFFBQVEsQ0FBQyxLQUFLLENBQUMsS0FBSyxTQUFTLENBQUMsUUFBUSxDQUFDLEtBQUssQ0FBQyxDQUFBO1FBQ2pFLENBQUMsQ0FBQTtRQUVEOzs7Ozs7O1dBT0c7UUFDSCxlQUFVLEdBQUcsQ0FBQyxLQUFhLEVBQVUsRUFBRTtZQUNyQyxNQUFNLENBQUMsR0FBVyxJQUFJLENBQUMsV0FBVyxDQUFDLEtBQUssQ0FBQyxDQUFBO1lBQ3pDLE9BQU8sSUFBSSxDQUFDLFdBQVcsQ0FBQyxDQUFDLENBQUMsQ0FBQTtRQUM1QixDQUFDLENBQUE7UUFFRDs7Ozs7V0FLRztRQUNILGVBQVUsR0FBRyxDQUFDLEtBQXNCLEVBQVUsRUFBRTtZQUM5QyxJQUFJLE9BQU8sS0FBSyxLQUFLLFFBQVEsRUFBRTtnQkFDN0IsS0FBSyxHQUFHLElBQUksQ0FBQyxXQUFXLENBQUMsS0FBSyxDQUFDLENBQUE7YUFDaEM7WUFDRCxJQUFJLElBQUksQ0FBQyxnQkFBZ0IsQ0FBQyxLQUFLLENBQUMsRUFBRTtnQkFDaEMsT0FBTyxJQUFJLENBQUMsUUFBUSxDQUFDLEtBQUssRUFBRSxDQUFDLEVBQUUsS0FBSyxDQUFDLE1BQU0sR0FBRyxDQUFDLENBQUMsQ0FBQTthQUNqRDtZQUNELE1BQU0sSUFBSSxzQkFBYSxDQUFDLCtDQUErQyxDQUFDLENBQUE7UUFDMUUsQ0FBQyxDQUFBO1FBRUQsMkJBQXNCLEdBQUcsQ0FBQyxLQUFzQixFQUFVLEVBQUU7WUFDMUQsSUFBSSxPQUFPLEtBQUssS0FBSyxRQUFRLEVBQUU7Z0JBQzdCLEtBQUssR0FBRyxJQUFJLENBQUMsV0FBVyxDQUFDLEtBQUssQ0FBQyxDQUFBO2FBQ2hDO1lBQ0QsSUFBSSxJQUFJLENBQUMsZ0JBQWdCLENBQUMsS0FBSyxDQUFDLEVBQUU7Z0JBQ2hDLE9BQU8sS0FBSyxJQUFJLENBQUMsUUFBUSxDQUFDLEtBQUssRUFBRSxDQUFDLEVBQUUsS0FBSyxDQUFDLE1BQU0sQ0FBQyxDQUFDLFFBQVEsQ0FBQyxLQUFLLENBQUMsRUFBRSxDQUFBO2FBQ3BFO1lBQ0QsTUFBTSxJQUFJLHNCQUFhLENBQUMsK0NBQStDLENBQUMsQ0FBQTtRQUMxRSxDQUFDLENBQUE7UUFFRCxvQkFBZSxHQUFHLENBQUMsR0FBVyxFQUFFLE9BQWUsRUFBRSxLQUFhLEVBQVUsRUFBRSxDQUN4RSxHQUFHLE9BQU8sSUFBSSxNQUFNLENBQUMsTUFBTSxDQUFDLE1BQU0sQ0FBQyxHQUFHLEVBQUUsTUFBTSxDQUFDLE1BQU0sQ0FBQyxPQUFPLENBQUMsS0FBSyxDQUFDLENBQUMsRUFBRSxDQUFBO1FBRXpFLG9CQUFlLEdBQUcsQ0FBQyxPQUFlLEVBQUUsR0FBWSxFQUFVLEVBQUU7WUFDMUQsSUFBSSxPQUFPLENBQUMsU0FBUyxDQUFDLENBQUMsRUFBRSxDQUFDLENBQUMsS0FBSyxJQUFJLEVBQUU7Z0JBQ3BDLG9CQUFvQjtnQkFDcEIsSUFBSSxjQUFLLENBQUMsU0FBUyxDQUFDLE9BQU8sQ0FBQyxFQUFFO29CQUM1QixPQUFPLGVBQU0sQ0FBQyxJQUFJLENBQUMsT0FBTyxDQUFDLFNBQVMsQ0FBQyxDQUFDLENBQUMsRUFBRSxLQUFLLENBQUMsQ0FBQTtpQkFDaEQ7cUJBQU07b0JBQ0wsTUFBTSxJQUFJLGlCQUFRLENBQUMseUJBQXlCLENBQUMsQ0FBQTtpQkFDOUM7YUFDRjtZQUNELG1CQUFtQjtZQUNuQixNQUFNLEtBQUssR0FBYSxPQUFPLENBQUMsSUFBSSxFQUFFLENBQUMsS0FBSyxDQUFDLEdBQUcsQ0FBQyxDQUFBO1lBRWpELElBQUksS0FBSyxDQUFDLE1BQU0sR0FBRyxDQUFDLEVBQUU7Z0JBQ3BCLE1BQU0sSUFBSSxvQkFBVyxDQUFDLHdDQUF3QyxDQUFDLENBQUE7YUFDaEU7WUFFRCxJQUFJLEtBQUssQ0FBQyxDQUFDLENBQUMsQ0FBQyxNQUFNLEdBQUcsQ0FBQyxFQUFFO2dCQUN2QixNQUFNLElBQUksb0JBQVcsQ0FBQyxpREFBaUQsQ0FBQyxDQUFBO2FBQ3pFO1lBRUQsTUFBTSxLQUFLLEdBQVcsS0FBSyxDQUFDLENBQUMsQ0FBQyxDQUFDLFdBQVcsQ0FBQyxHQUFHLENBQUMsQ0FBQTtZQUMvQyxJQUFJLEtBQUssR0FBRyxDQUFDLEVBQUU7Z0JBQ2IsTUFBTSxJQUFJLG9CQUFXLENBQUMsa0RBQWtELENBQUMsQ0FBQTthQUMxRTtZQUVELE1BQU0saUJBQWlCLEdBQVcsS0FBSyxDQUFDLENBQUMsQ0FBQyxDQUFDLEtBQUssQ0FBQyxDQUFDLEVBQUUsS0FBSyxDQUFDLENBQUE7WUFDMUQsSUFBSSxpQkFBaUIsQ0FBQyxNQUFNLEdBQUcsQ0FBQyxFQUFFO2dCQUNoQyxNQUFNLElBQUksb0JBQVcsQ0FBQyw0Q0FBNEMsQ0FBQyxDQUFBO2FBQ3BFO1lBRUQsSUFDRSxpQkFBaUIsS0FBSyxNQUFNO2dCQUM1QixpQkFBaUIsS0FBSyxNQUFNO2dCQUM1QixpQkFBaUIsSUFBSSxPQUFPO2dCQUM1QixpQkFBaUIsSUFBSSxVQUFVO2dCQUMvQixpQkFBaUIsSUFBSSxRQUFRO2dCQUM3QixpQkFBaUIsSUFBSSxRQUFRO2dCQUM3QixpQkFBaUIsSUFBSSxHQUFHLEVBQ3hCO2dCQUNBLE1BQU0sSUFBSSxvQkFBVyxDQUFDLHFCQUFxQixDQUFDLENBQUE7YUFDN0M7WUFFRCxPQUFPLGVBQU0sQ0FBQyxJQUFJLENBQ2hCLE1BQU0sQ0FBQyxNQUFNLENBQUMsU0FBUyxDQUFDLE1BQU0sQ0FBQyxNQUFNLENBQUMsTUFBTSxDQUFDLEtBQUssQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLEtBQUssQ0FBQyxDQUM5RCxDQUFBO1FBQ0gsQ0FBQyxDQUFBO1FBRUQ7Ozs7Ozs7Ozs7O1dBV0c7UUFDSCxpQkFBWSxHQUFHLENBQ2IsSUFBWSxFQUNaLFlBQW9CLEVBQ3BCLFFBQWdCLFNBQVMsRUFDekIsVUFBa0IsRUFBRSxFQUNaLEVBQUU7WUFDVixNQUFNLEdBQUcsR0FBYSxJQUFJLENBQUMsS0FBSyxDQUFDLEdBQUcsQ0FBQyxDQUFBO1lBQ3JDLElBQ0UsR0FBRyxDQUFDLE1BQU0sS0FBSyxDQUFDO2dCQUNoQixDQUFDLENBQUMsS0FBSyxJQUFJLEdBQUcsQ0FBQyxDQUFDLENBQUMsS0FBSyxLQUFLLENBQUMsSUFBSSxDQUFDLFlBQVksSUFBSSxHQUFHLENBQUMsQ0FBQyxDQUFDLEtBQUssWUFBWSxDQUFDLENBQUMsRUFDMUU7Z0JBQ0EsTUFBTSxRQUFRLEdBQUcsSUFBSSxDQUFDLGVBQWUsQ0FBQyxJQUFJLENBQUMsQ0FBQTtnQkFDM0MsSUFBSSxDQUFDLE9BQU8sSUFBSSxRQUFRLENBQUMsTUFBTSxLQUFLLE9BQU8sQ0FBQyxJQUFJLENBQUMsT0FBTyxFQUFFO29CQUN4RCxPQUFPLFFBQVEsQ0FBQTtpQkFDaEI7YUFDRjtZQUNELE9BQU8sU0FBUyxDQUFBO1FBQ2xCLENBQUMsQ0FBQTtRQTNYQyxJQUFJLENBQUMsR0FBRyxHQUFHLGVBQU0sQ0FBQyxXQUFXLEVBQUUsQ0FBQTtJQUNqQyxDQUFDO0lBSUQ7O09BRUc7SUFDSCxNQUFNLENBQUMsV0FBVztRQUNoQixJQUFJLENBQUMsUUFBUSxDQUFDLFFBQVEsRUFBRTtZQUN0QixRQUFRLENBQUMsUUFBUSxHQUFHLElBQUksUUFBUSxFQUFFLENBQUE7U0FDbkM7UUFDRCxPQUFPLFFBQVEsQ0FBQyxRQUFRLENBQUE7SUFDMUIsQ0FBQztJQUVEOzs7T0FHRztJQUNILFFBQVEsQ0FBQyxHQUFXO1FBQ2xCLElBQUksR0FBRyxLQUFLLEVBQUUsSUFBSSxHQUFHLENBQUMsSUFBSSxFQUFFLEtBQUssRUFBRSxFQUFFO1lBQ25DLE9BQU8sS0FBSyxDQUFBO1NBQ2I7UUFDRCxJQUFJO1lBQ0YsSUFBSSxHQUFHLEdBQVcsZUFBTSxDQUFDLElBQUksQ0FBQyxHQUFHLEVBQUUsUUFBUSxDQUFDLENBQUE7WUFDNUMsT0FBTyxHQUFHLENBQUMsUUFBUSxDQUFDLFFBQVEsQ0FBQyxLQUFLLEdBQUcsQ0FBQTtTQUN0QztRQUFDLE9BQU8sR0FBRyxFQUFFO1lBQ1osT0FBTyxLQUFLLENBQUE7U0FDYjtJQUNILENBQUM7SUFFRDs7O09BR0c7SUFDSCxNQUFNLENBQUMsSUFBWTtRQUNqQixPQUFPLElBQUksQ0FBQyxRQUFRLENBQUMsSUFBSSxDQUFDLENBQUE7SUFDNUIsQ0FBQztJQUVEOzs7T0FHRztJQUNILFFBQVEsQ0FBQyxNQUFjO1FBQ3JCLElBQUksTUFBTSxLQUFLLEVBQUUsSUFBSSxNQUFNLENBQUMsSUFBSSxFQUFFLEtBQUssRUFBRSxFQUFFO1lBQ3pDLE9BQU8sS0FBSyxDQUFBO1NBQ2I7UUFDRCxJQUFJO1lBQ0YsT0FBTyxJQUFJLENBQUMsR0FBRyxDQUFDLE1BQU0sQ0FBQyxJQUFJLENBQUMsR0FBRyxDQUFDLE1BQU0sQ0FBQyxNQUFNLENBQUMsQ0FBQyxLQUFLLE1BQU0sQ0FBQTtTQUMzRDtRQUFDLE9BQU8sR0FBRyxFQUFFO1lBQ1osT0FBTyxLQUFLLENBQUE7U0FDYjtJQUNILENBQUM7SUFFRDs7O09BR0c7SUFDSCxLQUFLLENBQUMsR0FBVztRQUNmLElBQUksR0FBRyxLQUFLLEVBQUUsSUFBSSxHQUFHLENBQUMsSUFBSSxFQUFFLEtBQUssRUFBRSxFQUFFO1lBQ25DLE9BQU8sS0FBSyxDQUFBO1NBQ2I7UUFDRCxNQUFNLFlBQVksR0FBRyxHQUFHLENBQUMsVUFBVSxDQUFDLElBQUksQ0FBQyxDQUFBO1FBQ3pDLE1BQU0sV0FBVyxHQUFHLFlBQVk7WUFDOUIsQ0FBQyxDQUFDLEdBQUcsQ0FBQyxLQUFLLENBQUMsQ0FBQyxDQUFDLENBQUMsS0FBSyxDQUFDLGNBQWMsQ0FBQztZQUNwQyxDQUFDLENBQUMsR0FBRyxDQUFDLEtBQUssQ0FBQyxjQUFjLENBQUMsQ0FBQTtRQUM3QixJQUNFLENBQUMsWUFBWSxJQUFJLEdBQUcsQ0FBQyxNQUFNLEdBQUcsQ0FBQyxJQUFJLFdBQVcsQ0FBQyxNQUFNLENBQUM7WUFDdEQsR0FBRyxDQUFDLE1BQU0sSUFBSSxXQUFXLENBQUMsTUFBTSxFQUNoQztZQUNBLE9BQU8sSUFBSSxDQUFBO1NBQ1o7YUFBTTtZQUNMLE9BQU8sS0FBSyxDQUFBO1NBQ2I7SUFDSCxDQUFDO0lBRUQ7OztPQUdHO0lBQ0gsU0FBUyxDQUFDLEdBQVc7UUFDbkIsSUFBSSxHQUFHLEtBQUssRUFBRSxJQUFJLEdBQUcsQ0FBQyxJQUFJLEVBQUUsS0FBSyxFQUFFLEVBQUU7WUFDbkMsT0FBTyxLQUFLLENBQUE7U0FDYjtRQUNELElBQUk7WUFDRixPQUFPLElBQUksZUFBRSxDQUFDLEdBQUcsRUFBRSxFQUFFLENBQUMsQ0FBQyxRQUFRLENBQUMsRUFBRSxDQUFDLEtBQUssR0FBRyxDQUFDLElBQUksRUFBRSxDQUFBO1NBQ25EO1FBQUMsT0FBTyxHQUFHLEVBQUU7WUFDWixPQUFPLEtBQUssQ0FBQTtTQUNiO0lBQ0gsQ0FBQztDQW1TRjtBQWhZRCwyQkFnWUMiLCJzb3VyY2VzQ29udGVudCI6WyIvKipcbiAqIEBwYWNrYWdlRG9jdW1lbnRhdGlvblxuICogQG1vZHVsZSBVdGlscy1CaW5Ub29sc1xuICovXG5pbXBvcnQgQk4gZnJvbSBcImJuLmpzXCJcbmltcG9ydCB7IEJ1ZmZlciB9IGZyb20gXCJidWZmZXIvXCJcbmltcG9ydCBjcmVhdGVIYXNoIGZyb20gXCJjcmVhdGUtaGFzaFwiXG5pbXBvcnQgKiBhcyBiZWNoMzIgZnJvbSBcImJlY2gzMlwiXG5pbXBvcnQgeyBCYXNlNTggfSBmcm9tIFwiLi9iYXNlNThcIlxuaW1wb3J0IHsgQmVjaDMyRXJyb3IsIENoZWNrc3VtRXJyb3IsIEhleEVycm9yIH0gZnJvbSBcIi4uL3V0aWxzL2Vycm9yc1wiXG5pbXBvcnQgeyB1dGlscyB9IGZyb20gXCJldGhlcnNcIlxuXG4vKipcbiAqIEEgY2xhc3MgY29udGFpbmluZyB0b29scyB1c2VmdWwgaW4gaW50ZXJhY3Rpbmcgd2l0aCBiaW5hcnkgZGF0YSBjcm9zcy1wbGF0Zm9ybSB1c2luZ1xuICogbm9kZWpzICYgamF2YXNjcmlwdC5cbiAqXG4gKiBUaGlzIGNsYXNzIHNob3VsZCBuZXZlciBiZSBpbnN0YW50aWF0ZWQgZGlyZWN0bHkuIEluc3RlYWQsXG4gKiBpbnZva2UgdGhlIFwiQmluVG9vbHMuZ2V0SW5zdGFuY2UoKVwiIHN0YXRpYyAqIGZ1bmN0aW9uIHRvIGdyYWIgdGhlIHNpbmdsZXRvblxuICogaW5zdGFuY2Ugb2YgdGhlIHRvb2xzLlxuICpcbiAqIEV2ZXJ5dGhpbmcgaW4gdGhpcyBsaWJyYXJ5IHVzZXNcbiAqIHRoZSB7QGxpbmsgaHR0cHM6Ly9naXRodWIuY29tL2Zlcm9zcy9idWZmZXJ8ZmVyb3NzJ3MgQnVmZmVyIGNsYXNzfS5cbiAqXG4gKiBgYGBqc1xuICogY29uc3QgYmludG9vbHM6IEJpblRvb2xzID0gQmluVG9vbHMuZ2V0SW5zdGFuY2UoKTtcbiAqIGNvbnN0IGI1OHN0cjogID0gYmludG9vbHMuYnVmZmVyVG9CNTgoQnVmZmVyLmZyb20oXCJXdWJhbHViYWR1YmR1YiFcIikpO1xuICogYGBgXG4gKi9cbmV4cG9ydCBkZWZhdWx0IGNsYXNzIEJpblRvb2xzIHtcbiAgcHJpdmF0ZSBzdGF0aWMgaW5zdGFuY2U6IEJpblRvb2xzXG5cbiAgcHJpdmF0ZSBjb25zdHJ1Y3RvcigpIHtcbiAgICB0aGlzLmI1OCA9IEJhc2U1OC5nZXRJbnN0YW5jZSgpXG4gIH1cblxuICBwcml2YXRlIGI1ODogQmFzZTU4XG5cbiAgLyoqXG4gICAqIFJldHJpZXZlcyB0aGUgQmluVG9vbHMgc2luZ2xldG9uLlxuICAgKi9cbiAgc3RhdGljIGdldEluc3RhbmNlKCk6IEJpblRvb2xzIHtcbiAgICBpZiAoIUJpblRvb2xzLmluc3RhbmNlKSB7XG4gICAgICBCaW5Ub29scy5pbnN0YW5jZSA9IG5ldyBCaW5Ub29scygpXG4gICAgfVxuICAgIHJldHVybiBCaW5Ub29scy5pbnN0YW5jZVxuICB9XG5cbiAgLyoqXG4gICAqIFJldHVybnMgdHJ1ZSBpZiBiYXNlNjQsIG90aGVyd2lzZSBmYWxzZVxuICAgKiBAcGFyYW0gc3RyIHRoZSBzdHJpbmcgdG8gdmVyaWZ5IGlzIEJhc2U2NFxuICAgKi9cbiAgaXNCYXNlNjQoc3RyOiBzdHJpbmcpIHtcbiAgICBpZiAoc3RyID09PSBcIlwiIHx8IHN0ci50cmltKCkgPT09IFwiXCIpIHtcbiAgICAgIHJldHVybiBmYWxzZVxuICAgIH1cbiAgICB0cnkge1xuICAgICAgbGV0IGI2NDogQnVmZmVyID0gQnVmZmVyLmZyb20oc3RyLCBcImJhc2U2NFwiKVxuICAgICAgcmV0dXJuIGI2NC50b1N0cmluZyhcImJhc2U2NFwiKSA9PT0gc3RyXG4gICAgfSBjYXRjaCAoZXJyKSB7XG4gICAgICByZXR1cm4gZmFsc2VcbiAgICB9XG4gIH1cblxuICAvKipcbiAgICogUmV0dXJucyB0cnVlIGlmIGNiNTgsIG90aGVyd2lzZSBmYWxzZVxuICAgKiBAcGFyYW0gY2I1OCB0aGUgc3RyaW5nIHRvIHZlcmlmeSBpcyBjYjU4XG4gICAqL1xuICBpc0NCNTgoY2I1ODogc3RyaW5nKTogYm9vbGVhbiB7XG4gICAgcmV0dXJuIHRoaXMuaXNCYXNlNTgoY2I1OClcbiAgfVxuXG4gIC8qKlxuICAgKiBSZXR1cm5zIHRydWUgaWYgYmFzZTU4LCBvdGhlcndpc2UgZmFsc2VcbiAgICogQHBhcmFtIGJhc2U1OCB0aGUgc3RyaW5nIHRvIHZlcmlmeSBpcyBiYXNlNThcbiAgICovXG4gIGlzQmFzZTU4KGJhc2U1ODogc3RyaW5nKTogYm9vbGVhbiB7XG4gICAgaWYgKGJhc2U1OCA9PT0gXCJcIiB8fCBiYXNlNTgudHJpbSgpID09PSBcIlwiKSB7XG4gICAgICByZXR1cm4gZmFsc2VcbiAgICB9XG4gICAgdHJ5IHtcbiAgICAgIHJldHVybiB0aGlzLmI1OC5lbmNvZGUodGhpcy5iNTguZGVjb2RlKGJhc2U1OCkpID09PSBiYXNlNThcbiAgICB9IGNhdGNoIChlcnIpIHtcbiAgICAgIHJldHVybiBmYWxzZVxuICAgIH1cbiAgfVxuXG4gIC8qKlxuICAgKiBSZXR1cm5zIHRydWUgaWYgaGV4aWRlY2ltYWwsIG90aGVyd2lzZSBmYWxzZVxuICAgKiBAcGFyYW0gaGV4IHRoZSBzdHJpbmcgdG8gdmVyaWZ5IGlzIGhleGlkZWNpbWFsXG4gICAqL1xuICBpc0hleChoZXg6IHN0cmluZyk6IGJvb2xlYW4ge1xuICAgIGlmIChoZXggPT09IFwiXCIgfHwgaGV4LnRyaW0oKSA9PT0gXCJcIikge1xuICAgICAgcmV0dXJuIGZhbHNlXG4gICAgfVxuICAgIGNvbnN0IHN0YXJ0c1dpdGgweCA9IGhleC5zdGFydHNXaXRoKFwiMHhcIilcbiAgICBjb25zdCBtYXRjaFJlc3VsdCA9IHN0YXJ0c1dpdGgweFxuICAgICAgPyBoZXguc2xpY2UoMikubWF0Y2goL1swLTlBLUZhLWZdL2cpXG4gICAgICA6IGhleC5tYXRjaCgvWzAtOUEtRmEtZl0vZylcbiAgICBpZiAoXG4gICAgICAoc3RhcnRzV2l0aDB4ICYmIGhleC5sZW5ndGggLSAyID09IG1hdGNoUmVzdWx0Lmxlbmd0aCkgfHxcbiAgICAgIGhleC5sZW5ndGggPT0gbWF0Y2hSZXN1bHQubGVuZ3RoXG4gICAgKSB7XG4gICAgICByZXR1cm4gdHJ1ZVxuICAgIH0gZWxzZSB7XG4gICAgICByZXR1cm4gZmFsc2VcbiAgICB9XG4gIH1cblxuICAvKipcbiAgICogUmV0dXJucyB0cnVlIGlmIGRlY2ltYWwsIG90aGVyd2lzZSBmYWxzZVxuICAgKiBAcGFyYW0gc3RyIHRoZSBzdHJpbmcgdG8gdmVyaWZ5IGlzIGhleGlkZWNpbWFsXG4gICAqL1xuICBpc0RlY2ltYWwoc3RyOiBzdHJpbmcpIHtcbiAgICBpZiAoc3RyID09PSBcIlwiIHx8IHN0ci50cmltKCkgPT09IFwiXCIpIHtcbiAgICAgIHJldHVybiBmYWxzZVxuICAgIH1cbiAgICB0cnkge1xuICAgICAgcmV0dXJuIG5ldyBCTihzdHIsIDEwKS50b1N0cmluZygxMCkgPT09IHN0ci50cmltKClcbiAgICB9IGNhdGNoIChlcnIpIHtcbiAgICAgIHJldHVybiBmYWxzZVxuICAgIH1cbiAgfVxuXG4gIC8qKlxuICAgKiBSZXR1cm5zIHRydWUgaWYgbWVldHMgcmVxdWlyZW1lbnRzIHRvIHBhcnNlIGFzIGFuIGFkZHJlc3MgYXMgQmVjaDMyIG9uIFgtQ2hhaW4gb3IgUC1DaGFpbiwgb3RoZXJ3aXNlIGZhbHNlXG4gICAqIEBwYXJhbSBhZGRyZXNzIHRoZSBzdHJpbmcgdG8gdmVyaWZ5IGlzIGFkZHJlc3NcbiAgICovXG4gIGlzUHJpbWFyeUJlY2hBZGRyZXNzID0gKGFkZHJlc3M6IHN0cmluZyk6IGJvb2xlYW4gPT4ge1xuICAgIGNvbnN0IHBhcnRzOiBzdHJpbmdbXSA9IGFkZHJlc3MudHJpbSgpLnNwbGl0KFwiLVwiKVxuICAgIGlmIChwYXJ0cy5sZW5ndGggIT09IDIpIHtcbiAgICAgIHJldHVybiBmYWxzZVxuICAgIH1cbiAgICB0cnkge1xuICAgICAgYmVjaDMyLmJlY2gzMi5mcm9tV29yZHMoYmVjaDMyLmJlY2gzMi5kZWNvZGUocGFydHNbMV0pLndvcmRzKVxuICAgIH0gY2F0Y2ggKGVycikge1xuICAgICAgcmV0dXJuIGZhbHNlXG4gICAgfVxuICAgIHJldHVybiB0cnVlXG4gIH1cblxuICAvKipcbiAgICogUHJvZHVjZXMgYSBzdHJpbmcgZnJvbSBhIHtAbGluayBodHRwczovL2dpdGh1Yi5jb20vZmVyb3NzL2J1ZmZlcnxCdWZmZXJ9XG4gICAqIHJlcHJlc2VudGluZyBhIHN0cmluZy4gT05MWSBVU0VEIElOIFRSQU5TQUNUSU9OIEZPUk1BVFRJTkcsIEFTU1VNRUQgTEVOR1RIIElTIFBSRVBFTkRFRC5cbiAgICpcbiAgICogQHBhcmFtIGJ1ZmYgVGhlIHtAbGluayBodHRwczovL2dpdGh1Yi5jb20vZmVyb3NzL2J1ZmZlcnxCdWZmZXJ9IHRvIGNvbnZlcnQgdG8gYSBzdHJpbmdcbiAgICovXG4gIGJ1ZmZlclRvU3RyaW5nID0gKGJ1ZmY6IEJ1ZmZlcik6IHN0cmluZyA9PlxuICAgIHRoaXMuY29weUZyb20oYnVmZiwgMikudG9TdHJpbmcoXCJ1dGY4XCIpXG5cbiAgLyoqXG4gICAqIFByb2R1Y2VzIGEge0BsaW5rIGh0dHBzOi8vZ2l0aHViLmNvbS9mZXJvc3MvYnVmZmVyfEJ1ZmZlcn0gZnJvbSBhIHN0cmluZy4gT05MWSBVU0VEIElOIFRSQU5TQUNUSU9OIEZPUk1BVFRJTkcsIExFTkdUSCBJUyBQUkVQRU5ERUQuXG4gICAqXG4gICAqIEBwYXJhbSBzdHIgVGhlIHN0cmluZyB0byBjb252ZXJ0IHRvIGEge0BsaW5rIGh0dHBzOi8vZ2l0aHViLmNvbS9mZXJvc3MvYnVmZmVyfEJ1ZmZlcn1cbiAgICovXG4gIHN0cmluZ1RvQnVmZmVyID0gKHN0cjogc3RyaW5nKTogQnVmZmVyID0+IHtcbiAgICBjb25zdCBidWZmOiBCdWZmZXIgPSBCdWZmZXIuYWxsb2MoMiArIHN0ci5sZW5ndGgpXG4gICAgYnVmZi53cml0ZVVJbnQxNkJFKHN0ci5sZW5ndGgsIDApXG4gICAgYnVmZi53cml0ZShzdHIsIDIsIHN0ci5sZW5ndGgsIFwidXRmOFwiKVxuICAgIHJldHVybiBidWZmXG4gIH1cblxuICAvKipcbiAgICogTWFrZXMgYSBjb3B5IChubyByZWZlcmVuY2UpIG9mIGEge0BsaW5rIGh0dHBzOi8vZ2l0aHViLmNvbS9mZXJvc3MvYnVmZmVyfEJ1ZmZlcn1cbiAgICogb3ZlciBwcm92aWRlZCBpbmRlY2llcy5cbiAgICpcbiAgICogQHBhcmFtIGJ1ZmYgVGhlIHtAbGluayBodHRwczovL2dpdGh1Yi5jb20vZmVyb3NzL2J1ZmZlcnxCdWZmZXJ9IHRvIGNvcHlcbiAgICogQHBhcmFtIHN0YXJ0IFRoZSBpbmRleCB0byBzdGFydCB0aGUgY29weVxuICAgKiBAcGFyYW0gZW5kIFRoZSBpbmRleCB0byBlbmQgdGhlIGNvcHlcbiAgICovXG4gIGNvcHlGcm9tID0gKFxuICAgIGJ1ZmY6IEJ1ZmZlcixcbiAgICBzdGFydDogbnVtYmVyID0gMCxcbiAgICBlbmQ6IG51bWJlciA9IHVuZGVmaW5lZFxuICApOiBCdWZmZXIgPT4ge1xuICAgIGlmIChlbmQgPT09IHVuZGVmaW5lZCkge1xuICAgICAgZW5kID0gYnVmZi5sZW5ndGhcbiAgICB9XG4gICAgcmV0dXJuIEJ1ZmZlci5mcm9tKFVpbnQ4QXJyYXkucHJvdG90eXBlLnNsaWNlLmNhbGwoYnVmZi5zbGljZShzdGFydCwgZW5kKSkpXG4gIH1cblxuICAvKipcbiAgICogVGFrZXMgYSB7QGxpbmsgaHR0cHM6Ly9naXRodWIuY29tL2Zlcm9zcy9idWZmZXJ8QnVmZmVyfSBhbmQgcmV0dXJucyBhIGJhc2UtNTggc3RyaW5nIG9mXG4gICAqIHRoZSB7QGxpbmsgaHR0cHM6Ly9naXRodWIuY29tL2Zlcm9zcy9idWZmZXJ8QnVmZmVyfS5cbiAgICpcbiAgICogQHBhcmFtIGJ1ZmYgVGhlIHtAbGluayBodHRwczovL2dpdGh1Yi5jb20vZmVyb3NzL2J1ZmZlcnxCdWZmZXJ9IHRvIGNvbnZlcnQgdG8gYmFzZS01OFxuICAgKi9cbiAgYnVmZmVyVG9CNTggPSAoYnVmZjogQnVmZmVyKTogc3RyaW5nID0+IHRoaXMuYjU4LmVuY29kZShidWZmKVxuXG4gIC8qKlxuICAgKiBUYWtlcyBhIGJhc2UtNTggc3RyaW5nIGFuZCByZXR1cm5zIGEge0BsaW5rIGh0dHBzOi8vZ2l0aHViLmNvbS9mZXJvc3MvYnVmZmVyfEJ1ZmZlcn0uXG4gICAqXG4gICAqIEBwYXJhbSBiNThzdHIgVGhlIGJhc2UtNTggc3RyaW5nIHRvIGNvbnZlcnRcbiAgICogdG8gYSB7QGxpbmsgaHR0cHM6Ly9naXRodWIuY29tL2Zlcm9zcy9idWZmZXJ8QnVmZmVyfVxuICAgKi9cbiAgYjU4VG9CdWZmZXIgPSAoYjU4c3RyOiBzdHJpbmcpOiBCdWZmZXIgPT4gdGhpcy5iNTguZGVjb2RlKGI1OHN0cilcblxuICAvKipcbiAgICogVGFrZXMgYSB7QGxpbmsgaHR0cHM6Ly9naXRodWIuY29tL2Zlcm9zcy9idWZmZXJ8QnVmZmVyfSBhbmQgcmV0dXJucyBhbiBBcnJheUJ1ZmZlci5cbiAgICpcbiAgICogQHBhcmFtIGJ1ZmYgVGhlIHtAbGluayBodHRwczovL2dpdGh1Yi5jb20vZmVyb3NzL2J1ZmZlcnxCdWZmZXJ9IHRvXG4gICAqIGNvbnZlcnQgdG8gYW4gQXJyYXlCdWZmZXJcbiAgICovXG4gIGZyb21CdWZmZXJUb0FycmF5QnVmZmVyID0gKGJ1ZmY6IEJ1ZmZlcik6IEFycmF5QnVmZmVyID0+IHtcbiAgICBjb25zdCBhYiA9IG5ldyBBcnJheUJ1ZmZlcihidWZmLmxlbmd0aClcbiAgICBjb25zdCB2aWV3ID0gbmV3IFVpbnQ4QXJyYXkoYWIpXG4gICAgZm9yIChsZXQgaTogbnVtYmVyID0gMDsgaSA8IGJ1ZmYubGVuZ3RoOyArK2kpIHtcbiAgICAgIHZpZXdbYCR7aX1gXSA9IGJ1ZmZbYCR7aX1gXVxuICAgIH1cbiAgICByZXR1cm4gdmlld1xuICB9XG5cbiAgLyoqXG4gICAqIFRha2VzIGFuIEFycmF5QnVmZmVyIGFuZCBjb252ZXJ0cyBpdCB0byBhIHtAbGluayBodHRwczovL2dpdGh1Yi5jb20vZmVyb3NzL2J1ZmZlcnxCdWZmZXJ9LlxuICAgKlxuICAgKiBAcGFyYW0gYWIgVGhlIEFycmF5QnVmZmVyIHRvIGNvbnZlcnQgdG8gYSB7QGxpbmsgaHR0cHM6Ly9naXRodWIuY29tL2Zlcm9zcy9idWZmZXJ8QnVmZmVyfVxuICAgKi9cbiAgZnJvbUFycmF5QnVmZmVyVG9CdWZmZXIgPSAoYWI6IEFycmF5QnVmZmVyKTogQnVmZmVyID0+IHtcbiAgICBjb25zdCBidWYgPSBCdWZmZXIuYWxsb2MoYWIuYnl0ZUxlbmd0aClcbiAgICBmb3IgKGxldCBpOiBudW1iZXIgPSAwOyBpIDwgYWIuYnl0ZUxlbmd0aDsgKytpKSB7XG4gICAgICBidWZbYCR7aX1gXSA9IGFiW2Ake2l9YF1cbiAgICB9XG4gICAgcmV0dXJuIGJ1ZlxuICB9XG5cbiAgLyoqXG4gICAqIFRha2VzIGEge0BsaW5rIGh0dHBzOi8vZ2l0aHViLmNvbS9mZXJvc3MvYnVmZmVyfEJ1ZmZlcn0gYW5kIGNvbnZlcnRzIGl0XG4gICAqIHRvIGEge0BsaW5rIGh0dHBzOi8vZ2l0aHViLmNvbS9pbmR1dG55L2JuLmpzL3xCTn0uXG4gICAqXG4gICAqIEBwYXJhbSBidWZmIFRoZSB7QGxpbmsgaHR0cHM6Ly9naXRodWIuY29tL2Zlcm9zcy9idWZmZXJ8QnVmZmVyfSB0byBjb252ZXJ0XG4gICAqIHRvIGEge0BsaW5rIGh0dHBzOi8vZ2l0aHViLmNvbS9pbmR1dG55L2JuLmpzL3xCTn1cbiAgICovXG4gIGZyb21CdWZmZXJUb0JOID0gKGJ1ZmY6IEJ1ZmZlcik6IEJOID0+IHtcbiAgICBpZiAodHlwZW9mIGJ1ZmYgPT09IFwidW5kZWZpbmVkXCIpIHtcbiAgICAgIHJldHVybiB1bmRlZmluZWRcbiAgICB9XG4gICAgcmV0dXJuIG5ldyBCTihidWZmLnRvU3RyaW5nKFwiaGV4XCIpLCAxNiwgXCJiZVwiKVxuICB9XG4gIC8qKlxuICAgKiBUYWtlcyBhIHtAbGluayBodHRwczovL2dpdGh1Yi5jb20vaW5kdXRueS9ibi5qcy98Qk59IGFuZCBjb252ZXJ0cyBpdFxuICAgKiB0byBhIHtAbGluayBodHRwczovL2dpdGh1Yi5jb20vZmVyb3NzL2J1ZmZlcnxCdWZmZXJ9LlxuICAgKlxuICAgKiBAcGFyYW0gYm4gVGhlIHtAbGluayBodHRwczovL2dpdGh1Yi5jb20vaW5kdXRueS9ibi5qcy98Qk59IHRvIGNvbnZlcnRcbiAgICogdG8gYSB7QGxpbmsgaHR0cHM6Ly9naXRodWIuY29tL2Zlcm9zcy9idWZmZXJ8QnVmZmVyfVxuICAgKiBAcGFyYW0gbGVuZ3RoIFRoZSB6ZXJvLXBhZGRlZCBsZW5ndGggb2YgdGhlIHtAbGluayBodHRwczovL2dpdGh1Yi5jb20vZmVyb3NzL2J1ZmZlcnxCdWZmZXJ9XG4gICAqL1xuICBmcm9tQk5Ub0J1ZmZlciA9IChibjogQk4sIGxlbmd0aD86IG51bWJlcik6IEJ1ZmZlciA9PiB7XG4gICAgaWYgKHR5cGVvZiBibiA9PT0gXCJ1bmRlZmluZWRcIikge1xuICAgICAgcmV0dXJuIHVuZGVmaW5lZFxuICAgIH1cbiAgICBjb25zdCBuZXdhcnIgPSBibi50b0FycmF5KFwiYmVcIilcbiAgICAvKipcbiAgICAgKiBDS0M6IFN0aWxsIHVuc3VyZSB3aHkgYm4udG9BcnJheSB3aXRoIGEgXCJiZVwiIGFuZCBhIGxlbmd0aCBkbyBub3Qgd29yayByaWdodC4gQnVnP1xuICAgICAqL1xuICAgIGlmIChsZW5ndGgpIHtcbiAgICAgIC8vIGJuIHRvQXJyYXkgd2l0aCB0aGUgbGVuZ3RoIHBhcmFtZXRlciBkb2Vzbid0IHdvcmsgY29ycmVjdGx5LCBuZWVkIHRoaXMuXG4gICAgICBjb25zdCB4ID0gbGVuZ3RoIC0gbmV3YXJyLmxlbmd0aFxuICAgICAgZm9yIChsZXQgaTogbnVtYmVyID0gMDsgaSA8IHg7IGkrKykge1xuICAgICAgICBuZXdhcnIudW5zaGlmdCgwKVxuICAgICAgfVxuICAgIH1cbiAgICByZXR1cm4gQnVmZmVyLmZyb20obmV3YXJyKVxuICB9XG5cbiAgLyoqXG4gICAqIFRha2VzIGEge0BsaW5rIGh0dHBzOi8vZ2l0aHViLmNvbS9mZXJvc3MvYnVmZmVyfEJ1ZmZlcn0gYW5kIGFkZHMgYSBjaGVja3N1bSwgcmV0dXJuaW5nXG4gICAqIGEge0BsaW5rIGh0dHBzOi8vZ2l0aHViLmNvbS9mZXJvc3MvYnVmZmVyfEJ1ZmZlcn0gd2l0aCB0aGUgNC1ieXRlIGNoZWNrc3VtIGFwcGVuZGVkLlxuICAgKlxuICAgKiBAcGFyYW0gYnVmZiBUaGUge0BsaW5rIGh0dHBzOi8vZ2l0aHViLmNvbS9mZXJvc3MvYnVmZmVyfEJ1ZmZlcn0gdG8gYXBwZW5kIGEgY2hlY2tzdW1cbiAgICovXG4gIGFkZENoZWNrc3VtID0gKGJ1ZmY6IEJ1ZmZlcik6IEJ1ZmZlciA9PiB7XG4gICAgY29uc3QgaGFzaHNsaWNlOiBCdWZmZXIgPSBCdWZmZXIuZnJvbShcbiAgICAgIGNyZWF0ZUhhc2goXCJzaGEyNTZcIikudXBkYXRlKGJ1ZmYpLmRpZ2VzdCgpLnNsaWNlKDI4KVxuICAgIClcbiAgICByZXR1cm4gQnVmZmVyLmNvbmNhdChbYnVmZiwgaGFzaHNsaWNlXSlcbiAgfVxuXG4gIC8qKlxuICAgKiBUYWtlcyBhIHtAbGluayBodHRwczovL2dpdGh1Yi5jb20vZmVyb3NzL2J1ZmZlcnxCdWZmZXJ9IHdpdGggYW4gYXBwZW5kZWQgNC1ieXRlIGNoZWNrc3VtXG4gICAqIGFuZCByZXR1cm5zIHRydWUgaWYgdGhlIGNoZWNrc3VtIGlzIHZhbGlkLCBvdGhlcndpc2UgZmFsc2UuXG4gICAqXG4gICAqIEBwYXJhbSBiIFRoZSB7QGxpbmsgaHR0cHM6Ly9naXRodWIuY29tL2Zlcm9zcy9idWZmZXJ8QnVmZmVyfSB0byB2YWxpZGF0ZSB0aGUgY2hlY2tzdW1cbiAgICovXG4gIHZhbGlkYXRlQ2hlY2tzdW0gPSAoYnVmZjogQnVmZmVyKTogYm9vbGVhbiA9PiB7XG4gICAgY29uc3QgY2hlY2tzbGljZTogQnVmZmVyID0gYnVmZi5zbGljZShidWZmLmxlbmd0aCAtIDQpXG4gICAgY29uc3QgaGFzaHNsaWNlOiBCdWZmZXIgPSBCdWZmZXIuZnJvbShcbiAgICAgIGNyZWF0ZUhhc2goXCJzaGEyNTZcIilcbiAgICAgICAgLnVwZGF0ZShidWZmLnNsaWNlKDAsIGJ1ZmYubGVuZ3RoIC0gNCkpXG4gICAgICAgIC5kaWdlc3QoKVxuICAgICAgICAuc2xpY2UoMjgpXG4gICAgKVxuICAgIHJldHVybiBjaGVja3NsaWNlLnRvU3RyaW5nKFwiaGV4XCIpID09PSBoYXNoc2xpY2UudG9TdHJpbmcoXCJoZXhcIilcbiAgfVxuXG4gIC8qKlxuICAgKiBUYWtlcyBhIHtAbGluayBodHRwczovL2dpdGh1Yi5jb20vZmVyb3NzL2J1ZmZlcnxCdWZmZXJ9IGFuZCByZXR1cm5zIGEgYmFzZS01OCBzdHJpbmcgd2l0aFxuICAgKiBjaGVja3N1bSBhcyBwZXIgdGhlIGNiNTggc3RhbmRhcmQuXG4gICAqXG4gICAqIEBwYXJhbSBieXRlcyBBIHtAbGluayBodHRwczovL2dpdGh1Yi5jb20vZmVyb3NzL2J1ZmZlcnxCdWZmZXJ9IHRvIHNlcmlhbGl6ZVxuICAgKlxuICAgKiBAcmV0dXJucyBBIHNlcmlhbGl6ZWQgYmFzZS01OCBzdHJpbmcgb2YgdGhlIEJ1ZmZlci5cbiAgICovXG4gIGNiNThFbmNvZGUgPSAoYnl0ZXM6IEJ1ZmZlcik6IHN0cmluZyA9PiB7XG4gICAgY29uc3QgeDogQnVmZmVyID0gdGhpcy5hZGRDaGVja3N1bShieXRlcylcbiAgICByZXR1cm4gdGhpcy5idWZmZXJUb0I1OCh4KVxuICB9XG5cbiAgLyoqXG4gICAqIFRha2VzIGEgY2I1OCBzZXJpYWxpemVkIHtAbGluayBodHRwczovL2dpdGh1Yi5jb20vZmVyb3NzL2J1ZmZlcnxCdWZmZXJ9IG9yIGJhc2UtNTggc3RyaW5nXG4gICAqIGFuZCByZXR1cm5zIGEge0BsaW5rIGh0dHBzOi8vZ2l0aHViLmNvbS9mZXJvc3MvYnVmZmVyfEJ1ZmZlcn0gb2YgdGhlIG9yaWdpbmFsIGRhdGEuIFRocm93cyBvbiBlcnJvci5cbiAgICpcbiAgICogQHBhcmFtIGJ5dGVzIEEgY2I1OCBzZXJpYWxpemVkIHtAbGluayBodHRwczovL2dpdGh1Yi5jb20vZmVyb3NzL2J1ZmZlcnxCdWZmZXJ9IG9yIGJhc2UtNTggc3RyaW5nXG4gICAqL1xuICBjYjU4RGVjb2RlID0gKGJ5dGVzOiBCdWZmZXIgfCBzdHJpbmcpOiBCdWZmZXIgPT4ge1xuICAgIGlmICh0eXBlb2YgYnl0ZXMgPT09IFwic3RyaW5nXCIpIHtcbiAgICAgIGJ5dGVzID0gdGhpcy5iNThUb0J1ZmZlcihieXRlcylcbiAgICB9XG4gICAgaWYgKHRoaXMudmFsaWRhdGVDaGVja3N1bShieXRlcykpIHtcbiAgICAgIHJldHVybiB0aGlzLmNvcHlGcm9tKGJ5dGVzLCAwLCBieXRlcy5sZW5ndGggLSA0KVxuICAgIH1cbiAgICB0aHJvdyBuZXcgQ2hlY2tzdW1FcnJvcihcIkVycm9yIC0gQmluVG9vbHMuY2I1OERlY29kZTogaW52YWxpZCBjaGVja3N1bVwiKVxuICB9XG5cbiAgY2I1OERlY29kZVdpdGhDaGVja3N1bSA9IChieXRlczogQnVmZmVyIHwgc3RyaW5nKTogc3RyaW5nID0+IHtcbiAgICBpZiAodHlwZW9mIGJ5dGVzID09PSBcInN0cmluZ1wiKSB7XG4gICAgICBieXRlcyA9IHRoaXMuYjU4VG9CdWZmZXIoYnl0ZXMpXG4gICAgfVxuICAgIGlmICh0aGlzLnZhbGlkYXRlQ2hlY2tzdW0oYnl0ZXMpKSB7XG4gICAgICByZXR1cm4gYDB4JHt0aGlzLmNvcHlGcm9tKGJ5dGVzLCAwLCBieXRlcy5sZW5ndGgpLnRvU3RyaW5nKFwiaGV4XCIpfWBcbiAgICB9XG4gICAgdGhyb3cgbmV3IENoZWNrc3VtRXJyb3IoXCJFcnJvciAtIEJpblRvb2xzLmNiNThEZWNvZGU6IGludmFsaWQgY2hlY2tzdW1cIilcbiAgfVxuXG4gIGFkZHJlc3NUb1N0cmluZyA9IChocnA6IHN0cmluZywgY2hhaW5pZDogc3RyaW5nLCBieXRlczogQnVmZmVyKTogc3RyaW5nID0+XG4gICAgYCR7Y2hhaW5pZH0tJHtiZWNoMzIuYmVjaDMyLmVuY29kZShocnAsIGJlY2gzMi5iZWNoMzIudG9Xb3JkcyhieXRlcykpfWBcblxuICBzdHJpbmdUb0FkZHJlc3MgPSAoYWRkcmVzczogc3RyaW5nLCBocnA/OiBzdHJpbmcpOiBCdWZmZXIgPT4ge1xuICAgIGlmIChhZGRyZXNzLnN1YnN0cmluZygwLCAyKSA9PT0gXCIweFwiKSB7XG4gICAgICAvLyBFVEgtc3R5bGUgYWRkcmVzc1xuICAgICAgaWYgKHV0aWxzLmlzQWRkcmVzcyhhZGRyZXNzKSkge1xuICAgICAgICByZXR1cm4gQnVmZmVyLmZyb20oYWRkcmVzcy5zdWJzdHJpbmcoMiksIFwiaGV4XCIpXG4gICAgICB9IGVsc2Uge1xuICAgICAgICB0aHJvdyBuZXcgSGV4RXJyb3IoXCJFcnJvciAtIEludmFsaWQgYWRkcmVzc1wiKVxuICAgICAgfVxuICAgIH1cbiAgICAvLyBCZWNoMzIgYWRkcmVzc2VzXG4gICAgY29uc3QgcGFydHM6IHN0cmluZ1tdID0gYWRkcmVzcy50cmltKCkuc3BsaXQoXCItXCIpXG5cbiAgICBpZiAocGFydHMubGVuZ3RoIDwgMikge1xuICAgICAgdGhyb3cgbmV3IEJlY2gzMkVycm9yKFwiRXJyb3IgLSBWYWxpZCBhZGRyZXNzIHNob3VsZCBpbmNsdWRlIC1cIilcbiAgICB9XG5cbiAgICBpZiAocGFydHNbMF0ubGVuZ3RoIDwgMSkge1xuICAgICAgdGhyb3cgbmV3IEJlY2gzMkVycm9yKFwiRXJyb3IgLSBWYWxpZCBhZGRyZXNzIG11c3QgaGF2ZSBwcmVmaXggYmVmb3JlIC1cIilcbiAgICB9XG5cbiAgICBjb25zdCBzcGxpdDogbnVtYmVyID0gcGFydHNbMV0ubGFzdEluZGV4T2YoXCIxXCIpXG4gICAgaWYgKHNwbGl0IDwgMCkge1xuICAgICAgdGhyb3cgbmV3IEJlY2gzMkVycm9yKFwiRXJyb3IgLSBWYWxpZCBhZGRyZXNzIG11c3QgaW5jbHVkZSBzZXBhcmF0b3IgKDEpXCIpXG4gICAgfVxuXG4gICAgY29uc3QgaHVtYW5SZWFkYWJsZVBhcnQ6IHN0cmluZyA9IHBhcnRzWzFdLnNsaWNlKDAsIHNwbGl0KVxuICAgIGlmIChodW1hblJlYWRhYmxlUGFydC5sZW5ndGggPCAxKSB7XG4gICAgICB0aHJvdyBuZXcgQmVjaDMyRXJyb3IoXCJFcnJvciAtIEhSUCBzaG91bGQgYmUgYXQgbGVhc3QgMSBjaGFyYWN0ZXJcIilcbiAgICB9XG5cbiAgICBpZiAoXG4gICAgICBodW1hblJlYWRhYmxlUGFydCAhPT0gXCJhdmF4XCIgJiZcbiAgICAgIGh1bWFuUmVhZGFibGVQYXJ0ICE9PSBcImZ1amlcIiAmJlxuICAgICAgaHVtYW5SZWFkYWJsZVBhcnQgIT0gXCJsb2NhbFwiICYmXG4gICAgICBodW1hblJlYWRhYmxlUGFydCAhPSBcImNvbHVtYnVzXCIgJiZcbiAgICAgIGh1bWFuUmVhZGFibGVQYXJ0ICE9IFwiY2FtaW5vXCIgJiZcbiAgICAgIGh1bWFuUmVhZGFibGVQYXJ0ICE9IFwiY3VzdG9tXCIgJiZcbiAgICAgIGh1bWFuUmVhZGFibGVQYXJ0ICE9IGhycFxuICAgICkge1xuICAgICAgdGhyb3cgbmV3IEJlY2gzMkVycm9yKFwiRXJyb3IgLSBJbnZhbGlkIEhSUFwiKVxuICAgIH1cblxuICAgIHJldHVybiBCdWZmZXIuZnJvbShcbiAgICAgIGJlY2gzMi5iZWNoMzIuZnJvbVdvcmRzKGJlY2gzMi5iZWNoMzIuZGVjb2RlKHBhcnRzWzFdKS53b3JkcylcbiAgICApXG4gIH1cblxuICAvKipcbiAgICogVGFrZXMgYW4gYWRkcmVzcyBhbmQgcmV0dXJucyBpdHMge0BsaW5rIGh0dHBzOi8vZ2l0aHViLmNvbS9mZXJvc3MvYnVmZmVyfEJ1ZmZlcn1cbiAgICogcmVwcmVzZW50YXRpb24gaWYgdmFsaWQuIEEgbW9yZSBzdHJpY3QgdmVyc2lvbiBvZiBzdHJpbmdUb0FkZHJlc3MuXG4gICAqXG4gICAqIEBwYXJhbSBhZGRyIEEgc3RyaW5nIHJlcHJlc2VudGF0aW9uIG9mIHRoZSBhZGRyZXNzXG4gICAqIEBwYXJhbSBibG9ja2NoYWluSUQgQSBjYjU4IGVuY29kZWQgc3RyaW5nIHJlcHJlc2VudGF0aW9uIG9mIHRoZSBibG9ja2NoYWluSURcbiAgICogQHBhcmFtIGFsaWFzIEEgY2hhaW5JRCBhbGlhcywgaWYgYW55LCB0aGF0IHRoZSBhZGRyZXNzIGNhbiBhbHNvIHBhcnNlIGZyb20uXG4gICAqIEBwYXJhbSBhZGRybGVuIFZNcyBjYW4gdXNlIGFueSBhZGRyZXNzaW5nIHNjaGVtZSB0aGF0IHRoZXkgbGlrZSwgc28gdGhpcyBpcyB0aGUgYXBwcm9wcmlhdGUgbnVtYmVyIG9mIGFkZHJlc3MgYnl0ZXMuIERlZmF1bHQgMjAuXG4gICAqXG4gICAqIEByZXR1cm5zIEEge0BsaW5rIGh0dHBzOi8vZ2l0aHViLmNvbS9mZXJvc3MvYnVmZmVyfEJ1ZmZlcn0gZm9yIHRoZSBhZGRyZXNzIGlmIHZhbGlkLFxuICAgKiB1bmRlZmluZWQgaWYgbm90IHZhbGlkLlxuICAgKi9cbiAgcGFyc2VBZGRyZXNzID0gKFxuICAgIGFkZHI6IHN0cmluZyxcbiAgICBibG9ja2NoYWluSUQ6IHN0cmluZyxcbiAgICBhbGlhczogc3RyaW5nID0gdW5kZWZpbmVkLFxuICAgIGFkZHJsZW46IG51bWJlciA9IDIwXG4gICk6IEJ1ZmZlciA9PiB7XG4gICAgY29uc3QgYWJjOiBzdHJpbmdbXSA9IGFkZHIuc3BsaXQoXCItXCIpXG4gICAgaWYgKFxuICAgICAgYWJjLmxlbmd0aCA9PT0gMiAmJlxuICAgICAgKChhbGlhcyAmJiBhYmNbMF0gPT09IGFsaWFzKSB8fCAoYmxvY2tjaGFpbklEICYmIGFiY1swXSA9PT0gYmxvY2tjaGFpbklEKSlcbiAgICApIHtcbiAgICAgIGNvbnN0IGFkZHJidWZmID0gdGhpcy5zdHJpbmdUb0FkZHJlc3MoYWRkcilcbiAgICAgIGlmICgoYWRkcmxlbiAmJiBhZGRyYnVmZi5sZW5ndGggPT09IGFkZHJsZW4pIHx8ICFhZGRybGVuKSB7XG4gICAgICAgIHJldHVybiBhZGRyYnVmZlxuICAgICAgfVxuICAgIH1cbiAgICByZXR1cm4gdW5kZWZpbmVkXG4gIH1cbn1cbiJdfQ==