UNPKG

@nebulae/angular-ble

Version:

A Web Bluetooth (Bluetooth Low Energy) module for angular (v2+)

531 lines (530 loc) 46.1 kB
/** * @fileoverview added by tsickle * @suppress {checkTypes,extraRequire,uselessCode} checked by tsc */ import * as aes from 'aes-js'; import { Injectable } from '@angular/core'; import * as i0 from "@angular/core"; var CypherAesService = /** @class */ (function () { function CypherAesService() { this.masterKey = []; this.initialVector = []; this.encryptMethod = 'CBC'; this.isStaticInitialVector = true; this.isConfigExecuted = false; } /** * Initial config used to initalice all required params * @param masterKey key used to encrypt and decrypt * @param initialVector vector used to encrypt abd decrypt except when ECB encrypt method is used * @param encryptMethod type of encrypt method is used, the possible options are: CBC, CTR, CFB, OFB, ECB * @param additionalEncryptMethodParams configuration params used by the selected encrypt method. * Note: if the method CTR or CFB is used this param is required otherwise is an optinal param. * By CTR require the param counter and by CFB require the param segmentSize * @param isStaticInitialVector defines if the initial vector is changed or not when the data are encrypted or not */ /** * Initial config used to initalice all required params * @param {?} masterKey key used to encrypt and decrypt * @param {?=} initialVector vector used to encrypt abd decrypt except when ECB encrypt method is used * @param {?=} encryptMethod type of encrypt method is used, the possible options are: CBC, CTR, CFB, OFB, ECB * @param {?=} additionalEncryptMethodParams configuration params used by the selected encrypt method. * Note: if the method CTR or CFB is used this param is required otherwise is an optinal param. * By CTR require the param counter and by CFB require the param segmentSize * @param {?=} isStaticInitialVector defines if the initial vector is changed or not when the data are encrypted or not * @return {?} */ CypherAesService.prototype.config = /** * Initial config used to initalice all required params * @param {?} masterKey key used to encrypt and decrypt * @param {?=} initialVector vector used to encrypt abd decrypt except when ECB encrypt method is used * @param {?=} encryptMethod type of encrypt method is used, the possible options are: CBC, CTR, CFB, OFB, ECB * @param {?=} additionalEncryptMethodParams configuration params used by the selected encrypt method. * Note: if the method CTR or CFB is used this param is required otherwise is an optinal param. * By CTR require the param counter and by CFB require the param segmentSize * @param {?=} isStaticInitialVector defines if the initial vector is changed or not when the data are encrypted or not * @return {?} */ function (masterKey, initialVector, encryptMethod, additionalEncryptMethodParams, isStaticInitialVector) { if (initialVector === void 0) { initialVector = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]; } if (encryptMethod === void 0) { encryptMethod = 'CBC'; } if (additionalEncryptMethodParams === void 0) { additionalEncryptMethodParams = {}; } if (isStaticInitialVector === void 0) { isStaticInitialVector = true; } this.isConfigExecuted = true; this.masterKey = masterKey; this.initialVector = initialVector; this.encryptMethod = encryptMethod; this.isStaticInitialVector = isStaticInitialVector; this.additionalEncryptMethodParams = additionalEncryptMethodParams; if (!isStaticInitialVector) { this.enctrypMethodInstance = this.generateEncryptMethodInstance(); } }; /** * Encrypt the data using the encrypt method previously configured * @param dataArrayBuffer data to encrypt */ /** * Encrypt the data using the encrypt method previously configured * @param {?} dataArrayBuffer data to encrypt * @return {?} */ CypherAesService.prototype.encrypt = /** * Encrypt the data using the encrypt method previously configured * @param {?} dataArrayBuffer data to encrypt * @return {?} */ function (dataArrayBuffer) { if (!this.isConfigExecuted) { throw new Error('Must configurate cypher-aes before call this method, use the method config()'); } if (this.encryptMethod === 'CBC' || this.encryptMethod === 'ECB') { dataArrayBuffer = this.addPadding(dataArrayBuffer); } return this.isStaticInitialVector ? this.generateEncryptMethodInstance().encrypt(dataArrayBuffer) : this.enctrypMethodInstance.encrypt(dataArrayBuffer); }; /** * Decrypt the data using the encrypt method previously configured * @param dataArrayBuffer data to decrypt */ /** * Decrypt the data using the encrypt method previously configured * @param {?} dataArrayBuffer data to decrypt * @return {?} */ CypherAesService.prototype.decrypt = /** * Decrypt the data using the encrypt method previously configured * @param {?} dataArrayBuffer data to decrypt * @return {?} */ function (dataArrayBuffer) { if (!this.isConfigExecuted) { throw new Error('Must configurate cypher-aes before call this method, use the method config()'); } return this.isStaticInitialVector ? this.generateEncryptMethodInstance().decrypt(dataArrayBuffer) : this.enctrypMethodInstance.decrypt(dataArrayBuffer); }; /** * Change the current initalVector * @param initialVector new initalVector */ /** * Change the current initalVector * @param {?} initialVector new initalVector * @return {?} */ CypherAesService.prototype.changeInitialVector = /** * Change the current initalVector * @param {?} initialVector new initalVector * @return {?} */ function (initialVector) { if (!this.isStaticInitialVector) { this.enctrypMethodInstance = this.generateEncryptMethodInstance(); } this.initialVector = initialVector; }; /** * Change the current encyptMethod * @param encryptMethod new encryptMethod */ /** * Change the current encyptMethod * @param {?} encryptMethod new encryptMethod * @return {?} */ CypherAesService.prototype.changeEncryptMethod = /** * Change the current encyptMethod * @param {?} encryptMethod new encryptMethod * @return {?} */ function (encryptMethod) { if (!this.isStaticInitialVector) { this.enctrypMethodInstance = this.generateEncryptMethodInstance(); } this.encryptMethod = encryptMethod; }; /** * Change the current isStaticInitialVector * @param isStaticInitialVector new isStaticInitalVector */ /** * Change the current isStaticInitialVector * @param {?} isStaticInitialVector new isStaticInitalVector * @return {?} */ CypherAesService.prototype.changeStaticInitialVector = /** * Change the current isStaticInitialVector * @param {?} isStaticInitialVector new isStaticInitalVector * @return {?} */ function (isStaticInitialVector) { if (!isStaticInitialVector) { this.enctrypMethodInstance = this.generateEncryptMethodInstance(); } this.isStaticInitialVector = isStaticInitialVector; }; /** * Change the current masterKey * @param masterKey new masterKey */ /** * Change the current masterKey * @param {?} masterKey new masterKey * @return {?} */ CypherAesService.prototype.changeMasterKey = /** * Change the current masterKey * @param {?} masterKey new masterKey * @return {?} */ function (masterKey) { if (!this.isStaticInitialVector) { this.enctrypMethodInstance = this.generateEncryptMethodInstance(); } this.masterKey = masterKey; }; /** * Add padding to the list * @param {?} arrayBuffer * @return {?} */ CypherAesService.prototype.addPadding = /** * Add padding to the list * @param {?} arrayBuffer * @return {?} */ function (arrayBuffer) { /** @type {?} */ var paddingLength = Math.ceil(Array.from(arrayBuffer).length / 16) * 16; /** @type {?} */ var paddingList = new Array(paddingLength - Array.from(arrayBuffer).length).fill(0); return new Uint8Array(Array.from(arrayBuffer).concat(paddingList)); }; /** * generate a instance of the encrypt method using the current method configured * @return {?} */ CypherAesService.prototype.generateEncryptMethodInstance = /** * generate a instance of the encrypt method using the current method configured * @return {?} */ function () { /** @type {?} */ var enctrypMethodInstance; switch (this.encryptMethod) { case 'CBC': enctrypMethodInstance = new aes.ModeOfOperation.cbc(this.masterKey, this.initialVector); break; case 'CTR': if (!this.additionalEncryptMethodParams.counter) { throw new Error('additionalEncryptMethodParams.counter is required to use encrypt method CTR'); } enctrypMethodInstance = new aes.ModeOfOperation.ctr(this.masterKey, this.initialVector, new aes.Counter(this.additionalEncryptMethodParams.counter)); break; case 'CFB': if (!this.additionalEncryptMethodParams.segmentSize) { throw new Error('additionalEncryptMethodParams.segmentSize is required to use encrypt method CFB'); } enctrypMethodInstance = new aes.ModeOfOperation.cfb(this.masterKey, this.initialVector, this.additionalEncryptMethodParams.segmentSize); break; case 'OFB': enctrypMethodInstance = new aes.ModeOfOperation.ofb(this.masterKey, this.initialVector); break; case 'ECB': enctrypMethodInstance = new aes.ModeOfOperation.ecb(this.masterKey); break; } return enctrypMethodInstance; }; // #region UTILS /** * Convert the text to bytes * @param text Text to convert */ /** * Convert the text to bytes * @param {?} text Text to convert * @return {?} */ CypherAesService.prototype.textToBytes = /** * Convert the text to bytes * @param {?} text Text to convert * @return {?} */ function (text) { return aes.utils.utf8.toBytes(text); }; /** * Convert the bytes to text * @param bytes Bytes to convert */ /** * Convert the bytes to text * @param {?} bytes Bytes to convert * @return {?} */ CypherAesService.prototype.bytesToText = /** * Convert the bytes to text * @param {?} bytes Bytes to convert * @return {?} */ function (bytes) { return aes.utils.utf8.fromBytes(bytes); }; /** * Convert the bytes to hex * @param bytes bytes to convert */ /** * Convert the bytes to hex * @param {?} bytes bytes to convert * @return {?} */ CypherAesService.prototype.bytesTohex = /** * Convert the bytes to hex * @param {?} bytes bytes to convert * @return {?} */ function (bytes) { return aes.utils.hex.fromBytes(bytes); }; /** * Convert the hex to bytes * @param hex Hex to convert */ /** * Convert the hex to bytes * @param {?} hex Hex to convert * @return {?} */ CypherAesService.prototype.hexToBytes = /** * Convert the hex to bytes * @param {?} hex Hex to convert * @return {?} */ function (hex) { return aes.utils.hex.toBytes(hex); }; // #endregion /** * @param {?} key * @return {?} */ CypherAesService.prototype.generateSubkeys = /** * @param {?} key * @return {?} */ function (key) { /** @type {?} */ var const_Zero = new Uint8Array(16); /** @type {?} */ var const_Rb = new Buffer('00000000000000000000000000000087', 'hex'); /** @type {?} */ var enctrypMethodInstance = new aes.ModeOfOperation.cbc(key, new Uint8Array(16)); /** @type {?} */ var lEncrypted = enctrypMethodInstance.encrypt(const_Zero); /** @type {?} */ var l = new Buffer(this.bytesTohex(lEncrypted), 'hex'); /** @type {?} */ var subkey1 = this.bitShiftLeft(l); // tslint:disable-next-line:no-bitwise if (l[0] & 0x80) { subkey1 = this.xor(subkey1, const_Rb); } /** @type {?} */ var subkey2 = this.bitShiftLeft(subkey1); // tslint:disable-next-line:no-bitwise if (subkey1[0] & 0x80) { subkey2 = this.xor(subkey2, const_Rb); } return { subkey1: subkey1, subkey2: subkey2 }; }; /** * @param {?} key * @param {?} message * @return {?} */ CypherAesService.prototype.aesCmac = /** * @param {?} key * @param {?} message * @return {?} */ function (key, message) { console.log('INICIA CIFRADO!!!!!!!!!!!!!!!!'); /** @type {?} */ var subkeys = this.generateSubkeys(key); /** @type {?} */ var blockCount = Math.ceil(message.length / 16); /** @type {?} */ var lastBlockCompleteFlag; /** @type {?} */ var lastBlock; /** @type {?} */ var lastBlockIndex; if (blockCount === 0) { blockCount = 1; lastBlockCompleteFlag = false; } else { lastBlockCompleteFlag = message.length % 16 === 0; } lastBlockIndex = blockCount - 1; if (lastBlockCompleteFlag) { lastBlock = this.xor(this.getMessageBlock(message, lastBlockIndex), subkeys.subkey1); } else { lastBlock = this.xor(this.getPaddedMessageBlock(message, lastBlockIndex), subkeys.subkey2); } /** @type {?} */ var x = new Buffer('00000000000000000000000000000000', 'hex'); /** @type {?} */ var y; /** @type {?} */ var enctrypMethodInstance; for (var index = 0; index < lastBlockIndex; index++) { enctrypMethodInstance = new aes.ModeOfOperation.cbc(key, new Uint8Array(16)); y = this.xor(x, this.getMessageBlock(message, index)); /** @type {?} */ var xEncrypted = enctrypMethodInstance.encrypt(y); console.log('X normal ===============> ', this.bytesTohex(y)); console.log('X encrypted ==============> ', this.bytesTohex(xEncrypted)); x = new Buffer(this.bytesTohex(xEncrypted), 'hex'); } y = this.xor(lastBlock, x); enctrypMethodInstance = new aes.ModeOfOperation.cbc(key, new Uint8Array(16)); /** @type {?} */ var yEncrypted = enctrypMethodInstance.encrypt(y); console.log('Y normal ==============> ', this.bytesTohex(y)); console.log('Y encrypted ==============> ', this.bytesTohex(yEncrypted)); return yEncrypted; }; /** * @param {?} message * @param {?} blockIndex * @return {?} */ CypherAesService.prototype.getMessageBlock = /** * @param {?} message * @param {?} blockIndex * @return {?} */ function (message, blockIndex) { /** @type {?} */ var block = new Buffer(16); /** @type {?} */ var start = blockIndex * 16; /** @type {?} */ var end = start + 16; /** @type {?} */ var blockI = 0; for (var i = start; i < end; i++) { block[blockI] = message[i]; blockI++; } return block; }; /** * @param {?} message * @param {?} blockIndex * @return {?} */ CypherAesService.prototype.getPaddedMessageBlock = /** * @param {?} message * @param {?} blockIndex * @return {?} */ function (message, blockIndex) { /** @type {?} */ var block = new Buffer(16); /** @type {?} */ var start = blockIndex * 16; /** @type {?} */ var end = message.length; block.fill(0); /** @type {?} */ var blockI = 0; for (var i = start; i < end; i++) { block[blockI] = message[i]; blockI++; } block[end - start] = 0x80; return block; }; /** * @param {?} buffer * @return {?} */ CypherAesService.prototype.bitShiftLeft = /** * @param {?} buffer * @return {?} */ function (buffer) { /** @type {?} */ var shifted = new Buffer(buffer.length); /** @type {?} */ var last = buffer.length - 1; for (var index = 0; index < last; index++) { // tslint:disable-next-line:no-bitwise shifted[index] = buffer[index] << 1; // tslint:disable-next-line:no-bitwise if (buffer[index + 1] & 0x80) { shifted[index] += 0x01; } } // tslint:disable-next-line:no-bitwise shifted[last] = buffer[last] << 1; return shifted; }; /** * @param {?} bufferA * @param {?} bufferB * @return {?} */ CypherAesService.prototype.xor = /** * @param {?} bufferA * @param {?} bufferB * @return {?} */ function (bufferA, bufferB) { /** @type {?} */ var length = Math.min(bufferA.length, bufferB.length); /** @type {?} */ var output = new Buffer(length); for (var index = 0; index < length; index++) { // tslint:disable-next-line:no-bitwise output[index] = bufferA[index] ^ bufferB[index]; } return output; }; CypherAesService.decorators = [ { type: Injectable, args: [{ providedIn: 'root' },] }, ]; /** @nocollapse */ CypherAesService.ctorParameters = function () { return []; }; /** @nocollapse */ CypherAesService.ngInjectableDef = i0.defineInjectable({ factory: function CypherAesService_Factory() { return new CypherAesService(); }, token: CypherAesService, providedIn: "root" }); return CypherAesService; }()); export { CypherAesService }; if (false) { /** @type {?} */ CypherAesService.prototype.masterKey; /** @type {?} */ CypherAesService.prototype.initialVector; /** @type {?} */ CypherAesService.prototype.encryptMethod; /** @type {?} */ CypherAesService.prototype.isStaticInitialVector; /** @type {?} */ CypherAesService.prototype.enctrypMethodInstance; /** @type {?} */ CypherAesService.prototype.isConfigExecuted; /** @type {?} */ CypherAesService.prototype.additionalEncryptMethodParams; } //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY3lwaGVyLWFlcy5zZXJ2aWNlLmpzIiwic291cmNlUm9vdCI6Im5nOi8vQG5lYnVsYWUvYW5ndWxhci1ibGUvIiwic291cmNlcyI6WyJsaWIvY3lwaGVyL2N5cGhlci1hZXMuc2VydmljZS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7O0FBQ0EsT0FBTyxLQUFLLEdBQUcsTUFBTSxRQUFRLENBQUM7QUFDOUIsT0FBTyxFQUFFLFVBQVUsRUFBRSxNQUFNLGVBQWUsQ0FBQzs7O0lBYXpDO3lCQVBvQixFQUFFOzZCQUNFLEVBQUU7NkJBQ0YsS0FBSztxQ0FDRyxJQUFJO2dDQUVULEtBQUs7S0FFaEI7SUFDaEI7Ozs7Ozs7OztPQVNHOzs7Ozs7Ozs7Ozs7SUFDSCxpQ0FBTTs7Ozs7Ozs7Ozs7SUFBTixVQUNFLFNBQVMsRUFDVCxhQUFnRSxFQUNoRSxhQUFxQixFQUNyQiw2QkFBa0MsRUFDbEMscUJBQTRCO1FBSDVCLDhCQUFBLEVBQUEsaUJBQWlCLENBQUMsRUFBRSxDQUFDLEVBQUUsQ0FBQyxFQUFFLENBQUMsRUFBRSxDQUFDLEVBQUUsQ0FBQyxFQUFFLENBQUMsRUFBRSxDQUFDLEVBQUUsQ0FBQyxFQUFFLENBQUMsRUFBRSxDQUFDLEVBQUUsQ0FBQyxFQUFFLENBQUMsRUFBRSxDQUFDLEVBQUUsQ0FBQyxFQUFFLENBQUMsQ0FBQztRQUNoRSw4QkFBQSxFQUFBLHFCQUFxQjtRQUNyQiw4Q0FBQSxFQUFBLGtDQUFrQztRQUNsQyxzQ0FBQSxFQUFBLDRCQUE0QjtRQUU1QixJQUFJLENBQUMsZ0JBQWdCLEdBQUcsSUFBSSxDQUFDO1FBQzdCLElBQUksQ0FBQyxTQUFTLEdBQUcsU0FBUyxDQUFDO1FBQzNCLElBQUksQ0FBQyxhQUFhLEdBQUcsYUFBYSxDQUFDO1FBQ25DLElBQUksQ0FBQyxhQUFhLEdBQUcsYUFBYSxDQUFDO1FBQ25DLElBQUksQ0FBQyxxQkFBcUIsR0FBRyxxQkFBcUIsQ0FBQztRQUNuRCxJQUFJLENBQUMsNkJBQTZCLEdBQUcsNkJBQTZCLENBQUM7UUFDbkUsRUFBRSxDQUFDLENBQUMsQ0FBQyxxQkFBcUIsQ0FBQyxDQUFDLENBQUM7WUFDM0IsSUFBSSxDQUFDLHFCQUFxQixHQUFHLElBQUksQ0FBQyw2QkFBNkIsRUFBRSxDQUFDO1NBQ25FO0tBQ0Y7SUFDRDs7O09BR0c7Ozs7OztJQUNILGtDQUFPOzs7OztJQUFQLFVBQVEsZUFBdUQ7UUFDN0QsRUFBRSxDQUFDLENBQUMsQ0FBQyxJQUFJLENBQUMsZ0JBQWdCLENBQUMsQ0FBQyxDQUFDO1lBQzNCLE1BQU0sSUFBSSxLQUFLLENBQ2IsOEVBQThFLENBQy9FLENBQUM7U0FDSDtRQUNELEVBQUUsQ0FBQyxDQUFDLElBQUksQ0FBQyxhQUFhLEtBQUssS0FBSyxJQUFJLElBQUksQ0FBQyxhQUFhLEtBQUssS0FBSyxDQUFDLENBQUMsQ0FBQztZQUNqRSxlQUFlLEdBQUcsSUFBSSxDQUFDLFVBQVUsQ0FBQyxlQUFlLENBQUMsQ0FBQztTQUNwRDtRQUNELE1BQU0sQ0FBQyxJQUFJLENBQUMscUJBQXFCO1lBQy9CLENBQUMsQ0FBQyxJQUFJLENBQUMsNkJBQTZCLEVBQUUsQ0FBQyxPQUFPLENBQUMsZUFBZSxDQUFDO1lBQy9ELENBQUMsQ0FBQyxJQUFJLENBQUMscUJBQXFCLENBQUMsT0FBTyxDQUFDLGVBQWUsQ0FBQyxDQUFDO0tBQ3pEO0lBQ0Q7OztPQUdHOzs7Ozs7SUFDSCxrQ0FBTzs7Ozs7SUFBUCxVQUFRLGVBQXVEO1FBQzdELEVBQUUsQ0FBQyxDQUFDLENBQUMsSUFBSSxDQUFDLGdCQUFnQixDQUFDLENBQUMsQ0FBQztZQUMzQixNQUFNLElBQUksS0FBSyxDQUNiLDhFQUE4RSxDQUMvRSxDQUFDO1NBQ0g7UUFDRCxNQUFNLENBQUMsSUFBSSxDQUFDLHFCQUFxQjtZQUMvQixDQUFDLENBQUMsSUFBSSxDQUFDLDZCQUE2QixFQUFFLENBQUMsT0FBTyxDQUFDLGVBQWUsQ0FBQztZQUMvRCxDQUFDLENBQUMsSUFBSSxDQUFDLHFCQUFxQixDQUFDLE9BQU8sQ0FBQyxlQUFlLENBQUMsQ0FBQztLQUN6RDtJQUNEOzs7T0FHRzs7Ozs7O0lBQ0gsOENBQW1COzs7OztJQUFuQixVQUFvQixhQUFhO1FBQy9CLEVBQUUsQ0FBQyxDQUFDLENBQUMsSUFBSSxDQUFDLHFCQUFxQixDQUFDLENBQUMsQ0FBQztZQUNoQyxJQUFJLENBQUMscUJBQXFCLEdBQUcsSUFBSSxDQUFDLDZCQUE2QixFQUFFLENBQUM7U0FDbkU7UUFDRCxJQUFJLENBQUMsYUFBYSxHQUFHLGFBQWEsQ0FBQztLQUNwQztJQUVEOzs7T0FHRzs7Ozs7O0lBQ0gsOENBQW1COzs7OztJQUFuQixVQUFvQixhQUFhO1FBQy9CLEVBQUUsQ0FBQyxDQUFDLENBQUMsSUFBSSxDQUFDLHFCQUFxQixDQUFDLENBQUMsQ0FBQztZQUNoQyxJQUFJLENBQUMscUJBQXFCLEdBQUcsSUFBSSxDQUFDLDZCQUE2QixFQUFFLENBQUM7U0FDbkU7UUFDRCxJQUFJLENBQUMsYUFBYSxHQUFHLGFBQWEsQ0FBQztLQUNwQztJQUVEOzs7T0FHRzs7Ozs7O0lBQ0gsb0RBQXlCOzs7OztJQUF6QixVQUEwQixxQkFBcUI7UUFDN0MsRUFBRSxDQUFDLENBQUMsQ0FBQyxxQkFBcUIsQ0FBQyxDQUFDLENBQUM7WUFDM0IsSUFBSSxDQUFDLHFCQUFxQixHQUFHLElBQUksQ0FBQyw2QkFBNkIsRUFBRSxDQUFDO1NBQ25FO1FBQ0QsSUFBSSxDQUFDLHFCQUFxQixHQUFHLHFCQUFxQixDQUFDO0tBQ3BEO0lBQ0Q7OztPQUdHOzs7Ozs7SUFDSCwwQ0FBZTs7Ozs7SUFBZixVQUFnQixTQUFTO1FBQ3ZCLEVBQUUsQ0FBQyxDQUFDLENBQUMsSUFBSSxDQUFDLHFCQUFxQixDQUFDLENBQUMsQ0FBQztZQUNoQyxJQUFJLENBQUMscUJBQXFCLEdBQUcsSUFBSSxDQUFDLDZCQUE2QixFQUFFLENBQUM7U0FDbkU7UUFDRCxJQUFJLENBQUMsU0FBUyxHQUFHLFNBQVMsQ0FBQztLQUM1Qjs7Ozs7O0lBS08scUNBQVU7Ozs7O2NBQUMsV0FBbUQ7O1FBQ3BFLElBQU0sYUFBYSxHQUFHLElBQUksQ0FBQyxJQUFJLENBQUMsS0FBSyxDQUFDLElBQUksQ0FBQyxXQUFXLENBQUMsQ0FBQyxNQUFNLEdBQUcsRUFBRSxDQUFDLEdBQUcsRUFBRSxDQUFDOztRQUMxRSxJQUFNLFdBQVcsR0FBRyxJQUFJLEtBQUssQ0FDM0IsYUFBYSxHQUFHLEtBQUssQ0FBQyxJQUFJLENBQUMsV0FBVyxDQUFDLENBQUMsTUFBTSxDQUMvQyxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUMsQ0FBQztRQUNWLE1BQU0sQ0FBQyxJQUFJLFVBQVUsQ0FBQyxLQUFLLENBQUMsSUFBSSxDQUFDLFdBQVcsQ0FBQyxDQUFDLE1BQU0sQ0FBQyxXQUFXLENBQUMsQ0FBQyxDQUFDOzs7Ozs7SUFLN0Qsd0RBQTZCOzs7Ozs7UUFDbkMsSUFBSSxxQkFBcUIsQ0FBQztRQUMxQixNQUFNLENBQUMsQ0FBQyxJQUFJLENBQUMsYUFBYSxDQUFDLENBQUMsQ0FBQztZQUMzQixLQUFLLEtBQUs7Z0JBQ1IscUJBQXFCLEdBQUcsSUFBSSxHQUFHLENBQUMsZUFBZSxDQUFDLEdBQUcsQ0FDakQsSUFBSSxDQUFDLFNBQVMsRUFDZCxJQUFJLENBQUMsYUFBYSxDQUNuQixDQUFDO2dCQUNGLEtBQUssQ0FBQztZQUNSLEtBQUssS0FBSztnQkFDUixFQUFFLENBQUMsQ0FBQyxDQUFDLElBQUksQ0FBQyw2QkFBNkIsQ0FBQyxPQUFPLENBQUMsQ0FBQyxDQUFDO29CQUNoRCxNQUFNLElBQUksS0FBSyxDQUNiLDZFQUE2RSxDQUM5RSxDQUFDO2lCQUNIO2dCQUNELHFCQUFxQixHQUFHLElBQUksR0FBRyxDQUFDLGVBQWUsQ0FBQyxHQUFHLENBQ2pELElBQUksQ0FBQyxTQUFTLEVBQ2QsSUFBSSxDQUFDLGFBQWEsRUFDbEIsSUFBSSxHQUFHLENBQUMsT0FBTyxDQUFDLElBQUksQ0FBQyw2QkFBNkIsQ0FBQyxPQUFPLENBQUMsQ0FDNUQsQ0FBQztnQkFDRixLQUFLLENBQUM7WUFDUixLQUFLLEtBQUs7Z0JBQ1IsRUFBRSxDQUFDLENBQUMsQ0FBQyxJQUFJLENBQUMsNkJBQTZCLENBQUMsV0FBVyxDQUFDLENBQUMsQ0FBQztvQkFDcEQsTUFBTSxJQUFJLEtBQUssQ0FDYixpRkFBaUYsQ0FDbEYsQ0FBQztpQkFDSDtnQkFDRCxxQkFBcUIsR0FBRyxJQUFJLEdBQUcsQ0FBQyxlQUFlLENBQUMsR0FBRyxDQUNqRCxJQUFJLENBQUMsU0FBUyxFQUNkLElBQUksQ0FBQyxhQUFhLEVBQ2xCLElBQUksQ0FBQyw2QkFBNkIsQ0FBQyxXQUFXLENBQy9DLENBQUM7Z0JBQ0YsS0FBSyxDQUFDO1lBQ1IsS0FBSyxLQUFLO2dCQUNSLHFCQUFxQixHQUFHLElBQUksR0FBRyxDQUFDLGVBQWUsQ0FBQyxHQUFHLENBQ2pELElBQUksQ0FBQyxTQUFTLEVBQ2QsSUFBSSxDQUFDLGFBQWEsQ0FDbkIsQ0FBQztnQkFDRixLQUFLLENBQUM7WUFDUixLQUFLLEtBQUs7Z0JBQ1IscUJBQXFCLEdBQUcsSUFBSSxHQUFHLENBQUMsZUFBZSxDQUFDLEdBQUcsQ0FBQyxJQUFJLENBQUMsU0FBUyxDQUFDLENBQUM7Z0JBQ3BFLEtBQUssQ0FBQztTQUNUO1FBQ0QsTUFBTSxDQUFDLHFCQUFxQixDQUFDOztJQUUvQixnQkFBZ0I7SUFDaEI7OztPQUdHOzs7Ozs7SUFDSCxzQ0FBVzs7Ozs7SUFBWCxVQUFZLElBQUk7UUFDZCxNQUFNLENBQUMsR0FBRyxDQUFDLEtBQUssQ0FBQyxJQUFJLENBQUMsT0FBTyxDQUFDLElBQUksQ0FBQyxDQUFDO0tBQ3JDO0lBQ0Q7OztPQUdHOzs7Ozs7SUFDSCxzQ0FBVzs7Ozs7SUFBWCxVQUFZLEtBQTZDO1FBQ3ZELE1BQU0sQ0FBQyxHQUFHLENBQUMsS0FBSyxDQUFDLElBQUksQ0FBQyxTQUFTLENBQUMsS0FBSyxDQUFDLENBQUM7S0FDeEM7SUFFRDs7O09BR0c7Ozs7OztJQUNILHFDQUFVOzs7OztJQUFWLFVBQVcsS0FBSztRQUNkLE1BQU0sQ0FBQyxHQUFHLENBQUMsS0FBSyxDQUFDLEdBQUcsQ0FBQyxTQUFTLENBQUMsS0FBSyxDQUFDLENBQUM7S0FDdkM7SUFFRDs7O09BR0c7Ozs7OztJQUNILHFDQUFVOzs7OztJQUFWLFVBQVcsR0FBRztRQUNaLE1BQU0sQ0FBQyxHQUFHLENBQUMsS0FBSyxDQUFDLEdBQUcsQ0FBQyxPQUFPLENBQUMsR0FBRyxDQUFDLENBQUM7S0FDbkM7SUFDRCxhQUFhOzs7OztJQUViLDBDQUFlOzs7O0lBQWYsVUFBZ0IsR0FBRzs7UUFDakIsSUFBTSxVQUFVLEdBQUcsSUFBSSxVQUFVLENBQUMsRUFBRSxDQUFDLENBQUM7O1FBQ3RDLElBQU0sUUFBUSxHQUFHLElBQUksTUFBTSxDQUFDLGtDQUFrQyxFQUFFLEtBQUssQ0FBQyxDQUFDOztRQUN2RSxJQUFNLHFCQUFxQixHQUFHLElBQUksR0FBRyxDQUFDLGVBQWUsQ0FBQyxHQUFHLENBQUMsR0FBRyxFQUFFLElBQUksVUFBVSxDQUFDLEVBQUUsQ0FBQyxDQUFDLENBQUM7O1FBRW5GLElBQU0sVUFBVSxHQUFHLHFCQUFxQixDQUFDLE9BQU8sQ0FBQyxVQUFVLENBQUMsQ0FBQzs7UUFDN0QsSUFBTSxDQUFDLEdBQUcsSUFBSSxNQUFNLENBQUMsSUFBSSxDQUFDLFVBQVUsQ0FBQyxVQUFVLENBQUMsRUFBRSxLQUFLLENBQUMsQ0FBQzs7UUFDekQsSUFBSSxPQUFPLEdBQUcsSUFBSSxDQUFDLFlBQVksQ0FBQyxDQUFDLENBQUMsQ0FBQzs7UUFFbkMsRUFBRSxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxHQUFHLElBQUksQ0FBQyxDQUFDLENBQUM7WUFDaEIsT0FBTyxHQUFHLElBQUksQ0FBQyxHQUFHLENBQUMsT0FBTyxFQUFFLFFBQVEsQ0FBQyxDQUFDO1NBQ3ZDOztRQUVELElBQUksT0FBTyxHQUFHLElBQUksQ0FBQyxZQUFZLENBQUMsT0FBTyxDQUFDLENBQUM7O1FBRXpDLEVBQUUsQ0FBQyxDQUFDLE9BQU8sQ0FBQyxDQUFDLENBQUMsR0FBRyxJQUFJLENBQUMsQ0FBQyxDQUFDO1lBQ3RCLE9BQU8sR0FBRyxJQUFJLENBQUMsR0FBRyxDQUFDLE9BQU8sRUFBRSxRQUFRLENBQUMsQ0FBQztTQUN2QztRQUVELE1BQU0sQ0FBQyxFQUFFLE9BQU8sRUFBRSxPQUFPLEVBQUUsT0FBTyxFQUFFLE9BQU8sRUFBRSxDQUFDO0tBQy9DOzs7Ozs7SUFFRCxrQ0FBTzs7Ozs7SUFBUCxVQUFRLEdBQUcsRUFBRSxPQUFPO1FBQ2xCLE9BQU8sQ0FBQyxHQUFHLENBQUMsZ0NBQWdDLENBQUMsQ0FBQzs7UUFDOUMsSUFBTSxPQUFPLEdBQUcsSUFBSSxDQUFDLGVBQWUsQ0FBQyxHQUFHLENBQUMsQ0FBQzs7UUFDMUMsSUFBSSxVQUFVLEdBQUcsSUFBSSxDQUFDLElBQUksQ0FBQyxPQUFPLENBQUMsTUFBTSxHQUFHLEVBQUUsQ0FBQyxDQUFDOztRQUNoRCxJQUFJLHFCQUFxQixDQUE0Qjs7UUFBckQsSUFBMkIsU0FBUyxDQUFpQjs7UUFBckQsSUFBc0MsY0FBYyxDQUFDO1FBRXJELEVBQUUsQ0FBQyxDQUFDLFVBQVUsS0FBSyxDQUFDLENBQUMsQ0FBQyxDQUFDO1lBQ3JCLFVBQVUsR0FBRyxDQUFDLENBQUM7WUFDZixxQkFBcUIsR0FBRyxLQUFLLENBQUM7U0FDL0I7UUFBQyxJQUFJLENBQUMsQ0FBQztZQUNOLHFCQUFxQixHQUFHLE9BQU8sQ0FBQyxNQUFNLEdBQUcsRUFBRSxLQUFLLENBQUMsQ0FBQztTQUNuRDtRQUNELGNBQWMsR0FBRyxVQUFVLEdBQUcsQ0FBQyxDQUFDO1FBRWhDLEVBQUUsQ0FBQyxDQUFDLHFCQUFxQixDQUFDLENBQUMsQ0FBQztZQUMxQixTQUFTLEdBQUcsSUFBSSxDQUFDLEdBQUcsQ0FDbEIsSUFBSSxDQUFDLGVBQWUsQ0FBQyxPQUFPLEVBQUUsY0FBYyxDQUFDLEVBQzdDLE9BQU8sQ0FBQyxPQUFPLENBQ2hCLENBQUM7U0FDSDtRQUFDLElBQUksQ0FBQyxDQUFDO1lBQ04sU0FBUyxHQUFHLElBQUksQ0FBQyxHQUFHLENBQ2xCLElBQUksQ0FBQyxxQkFBcUIsQ0FBQyxPQUFPLEVBQUUsY0FBYyxDQUFDLEVBQ25ELE9BQU8sQ0FBQyxPQUFPLENBQ2hCLENBQUM7U0FDSDs7UUFFRCxJQUFJLENBQUMsR0FBRyxJQUFJLE1BQU0sQ0FBQyxrQ0FBa0MsRUFBRSxLQUFLLENBQUMsQ0FBQzs7UUFDOUQsSUFBSSxDQUFDLENBQUM7O1FBRU4sSUFBSSxxQkFBcUIsQ0FBQztRQUMxQixHQUFHLENBQUMsQ0FBQyxJQUFJLEtBQUssR0FBRyxDQUFDLEVBQUUsS0FBSyxHQUFHLGNBQWMsRUFBRSxLQUFLLEVBQUUsRUFBRSxDQUFDO1lBQ3BELHFCQUFxQixHQUFHLElBQUksR0FBRyxDQUFDLGVBQWUsQ0FBQyxHQUFHLENBQUMsR0FBRyxFQUFFLElBQUksVUFBVSxDQUFDLEVBQUUsQ0FBQyxDQUFDLENBQUM7WUFDN0UsQ0FBQyxHQUFHLElBQUksQ0FBQyxHQUFHLENBQUMsQ0FBQyxFQUFFLElBQUksQ0FBQyxlQUFlLENBQUMsT0FBTyxFQUFFLEtBQUssQ0FBQyxDQUFDLENBQUM7O1lBQ3RELElBQU0sVUFBVSxHQUFHLHFCQUFxQixDQUFDLE9BQU8sQ0FBQyxDQUFDLENBQUMsQ0FBQztZQUNwRCxPQUFPLENBQUMsR0FBRyxDQUFDLDRCQUE0QixFQUFFLElBQUksQ0FBQyxVQUFVLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQztZQUM5RCxPQUFPLENBQUMsR0FBRyxDQUFDLDhCQUE4QixFQUFFLElBQUksQ0FBQyxVQUFVLENBQUMsVUFBVSxDQUFDLENBQUMsQ0FBQztZQUN6RSxDQUFDLEdBQUcsSUFBSSxNQUFNLENBQUMsSUFBSSxDQUFDLFVBQVUsQ0FBQyxVQUFVLENBQUMsRUFBRSxLQUFLLENBQUMsQ0FBQztTQUNwRDtRQUNELENBQUMsR0FBRyxJQUFJLENBQUMsR0FBRyxDQUFDLFNBQVMsRUFBRSxDQUFDLENBQUMsQ0FBQztRQUMzQixxQkFBcUIsR0FBRyxJQUFJLEdBQUcsQ0FBQyxlQUFlLENBQUMsR0FBRyxDQUFDLEdBQUcsRUFBRSxJQUFJLFVBQVUsQ0FBQyxFQUFFLENBQUMsQ0FBQyxDQUFDOztRQUM3RSxJQUFNLFVBQVUsR0FBRyxxQkFBcUIsQ0FBQyxPQUFPLENBQUMsQ0FBQyxDQUFDLENBQUM7UUFDcEQsT0FBTyxDQUFDLEdBQUcsQ0FBQywyQkFBMkIsRUFBRSxJQUFJLENBQUMsVUFBVSxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUM7UUFDN0QsT0FBTyxDQUFDLEdBQUcsQ0FBQyw4QkFBOEIsRUFBRSxJQUFJLENBQUMsVUFBVSxDQUFDLFVBQVUsQ0FBQyxDQUFDLENBQUM7UUFDekUsTUFBTSxDQUFDLFVBQVUsQ0FBQztLQUNuQjs7Ozs7O0lBRUQsMENBQWU7Ozs7O0lBQWYsVUFBZ0IsT0FBTyxFQUFFLFVBQVU7O1FBQ2pDLElBQU0sS0FBSyxHQUFHLElBQUksTUFBTSxDQUFDLEVBQUUsQ0FBQyxDQUFDOztRQUM3QixJQUFNLEtBQUssR0FBRyxVQUFVLEdBQUcsRUFBRSxDQUFDOztRQUM5QixJQUFNLEdBQUcsR0FBRyxLQUFLLEdBQUcsRUFBRSxDQUFDOztRQUN2QixJQUFJLE1BQU0sR0FBRyxDQUFDLENBQUM7UUFDZixHQUFHLENBQUMsQ0FBQyxJQUFJLENBQUMsR0FBRyxLQUFLLEVBQUUsQ0FBQyxHQUFHLEdBQUcsRUFBRSxDQUFDLEVBQUUsRUFBRSxDQUFDO1lBQ2pDLEtBQUssQ0FBQyxNQUFNLENBQUMsR0FBRyxPQUFPLENBQUMsQ0FBQyxDQUFDLENBQUM7WUFDM0IsTUFBTSxFQUFFLENBQUM7U0FDVjtRQUNELE1BQU0sQ0FBQyxLQUFLLENBQUM7S0FDZDs7Ozs7O0lBRUQsZ0RBQXFCOzs7OztJQUFyQixVQUFzQixPQUFPLEVBQUUsVUFBVTs7UUFDdkMsSUFBTSxLQUFLLEdBQUcsSUFBSSxNQUFNLENBQUMsRUFBRSxDQUFDLENBQUM7O1FBQzdCLElBQU0sS0FBSyxHQUFHLFVBQVUsR0FBRyxFQUFFLENBQUM7O1FBQzlCLElBQU0sR0FBRyxHQUFHLE9BQU8sQ0FBQyxNQUFNLENBQUM7UUFFM0IsS0FBSyxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUMsQ0FBQzs7UUFDZCxJQUFJLE1BQU0sR0FBRyxDQUFDLENBQUM7UUFDZixHQUFHLENBQUMsQ0FBQyxJQUFJLENBQUMsR0FBRyxLQUFLLEVBQUUsQ0FBQyxHQUFHLEdBQUcsRUFBRSxDQUFDLEVBQUUsRUFBRSxDQUFDO1lBQ2pDLEtBQUssQ0FBQyxNQUFNLENBQUMsR0FBRyxPQUFPLENBQUMsQ0FBQyxDQUFDLENBQUM7WUFDM0IsTUFBTSxFQUFFLENBQUM7U0FDVjtRQUNELEtBQUssQ0FBQyxHQUFHLEdBQUcsS0FBSyxDQUFDLEdBQUcsSUFBSSxDQUFDO1FBRTFCLE1BQU0sQ0FBQyxLQUFLLENBQUM7S0FDZDs7Ozs7SUFFRCx1Q0FBWTs7OztJQUFaLFVBQWEsTUFBTTs7UUFDakIsSUFBTSxPQUFPLEdBQUcsSUFBSSxNQUFNLENBQUMsTUFBTSxDQUFDLE1BQU0sQ0FBQyxDQUFDOztRQUMxQyxJQUFNLElBQUksR0FBRyxNQUFNLENBQUMsTUFBTSxHQUFHLENBQUMsQ0FBQztRQUMvQixHQUFHLENBQUMsQ0FBQyxJQUFJLEtBQUssR0FBRyxDQUFDLEVBQUUsS0FBSyxHQUFHLElBQUksRUFBRSxLQUFLLEVBQUUsRUFBRSxDQUFDOztZQUUxQyxPQUFPLENBQUMsS0FBSyxDQUFDLEdBQUcsTUFBTSxDQUFDLEtBQUssQ0FBQyxJQUFJLENBQUMsQ0FBQzs7WUFFcEMsRUFBRSxDQUFDLENBQUMsTUFBTSxDQUFDLEtBQUssR0FBRyxDQUFDLENBQUMsR0FBRyxJQUFJLENBQUMsQ0FBQyxDQUFDO2dCQUM3QixPQUFPLENBQUMsS0FBSyxDQUFDLElBQUksSUFBSSxDQUFDO2FBQ3hCO1NBQ0Y7O1FBRUQsT0FBTyxDQUFDLElBQUksQ0FBQyxHQUFHLE1BQU0sQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLENBQUM7UUFDbEMsTUFBTSxDQUFDLE9BQU8sQ0FBQztLQUNoQjs7Ozs7O0lBRUQsOEJBQUc7Ozs7O0lBQUgsVUFBSSxPQUFPLEVBQUUsT0FBTzs7UUFDbEIsSUFBTSxNQUFNLEdBQUcsSUFBSSxDQUFDLEdBQUcsQ0FBQyxPQUFPLENBQUMsTUFBTSxFQUFFLE9BQU8sQ0FBQyxNQUFNLENBQUMsQ0FBQzs7UUFDeEQsSUFBTSxNQUFNLEdBQUcsSUFBSSxNQUFNLENBQUMsTUFBTSxDQUFDLENBQUM7UUFDbEMsR0FBRyxDQUFDLENBQUMsSUFBSSxLQUFLLEdBQUcsQ0FBQyxFQUFFLEtBQUssR0FBRyxNQUFNLEVBQUUsS0FBSyxFQUFFLEVBQUUsQ0FBQzs7WUFFNUMsTUFBTSxDQUFDLEtBQUssQ0FBQyxHQUFHLE9BQU8sQ0FBQyxLQUFLLENBQUMsR0FBRyxPQUFPLENBQUMsS0FBSyxDQUFDLENBQUM7U0FDakQ7UUFDRCxNQUFNLENBQUMsTUFBTSxDQUFDO0tBQ2Y7O2dCQXBVRixVQUFVLFNBQUM7b0JBQ1YsVUFBVSxFQUFFLE1BQU07aUJBQ25COzs7OzsyQkFORDs7U0FPYSxnQkFBZ0IiLCJzb3VyY2VzQ29udGVudCI6WyJkZWNsYXJlIGNvbnN0IEJ1ZmZlcjtcbmltcG9ydCAqIGFzIGFlcyBmcm9tICdhZXMtanMnO1xuaW1wb3J0IHsgSW5qZWN0YWJsZSB9IGZyb20gJ0Bhbmd1bGFyL2NvcmUnO1xuXG5ASW5qZWN0YWJsZSh7XG4gIHByb3ZpZGVkSW46ICdyb290J1xufSlcbmV4cG9ydCBjbGFzcyBDeXBoZXJBZXNTZXJ2aWNlIHtcbiAgcHJpdmF0ZSBtYXN0ZXJLZXkgPSBbXTtcbiAgcHJpdmF0ZSBpbml0aWFsVmVjdG9yID0gW107XG4gIHByaXZhdGUgZW5jcnlwdE1ldGhvZCA9ICdDQkMnO1xuICBwcml2YXRlIGlzU3RhdGljSW5pdGlhbFZlY3RvciA9IHRydWU7XG4gIHByaXZhdGUgZW5jdHJ5cE1ldGhvZEluc3RhbmNlO1xuICBwcml2YXRlIGlzQ29uZmlnRXhlY3V0ZWQgPSBmYWxzZTtcbiAgcHJpdmF0ZSBhZGRpdGlvbmFsRW5jcnlwdE1ldGhvZFBhcmFtcztcbiAgY29uc3RydWN0b3IoKSB7fVxuICAvKipcbiAgICogSW5pdGlhbCBjb25maWcgdXNlZCB0byBpbml0YWxpY2UgYWxsIHJlcXVpcmVkIHBhcmFtc1xuICAgKiBAcGFyYW0gbWFzdGVyS2V5IGtleSB1c2VkIHRvIGVuY3J5cHQgYW5kIGRlY3J5cHRcbiAgICogQHBhcmFtIGluaXRpYWxWZWN0b3IgdmVjdG9yIHVzZWQgdG8gZW5jcnlwdCBhYmQgZGVjcnlwdCBleGNlcHQgd2hlbiBFQ0IgZW5jcnlwdCBtZXRob2QgaXMgdXNlZFxuICAgKiBAcGFyYW0gZW5jcnlwdE1ldGhvZCB0eXBlIG9mIGVuY3J5cHQgbWV0aG9kIGlzIHVzZWQsIHRoZSBwb3NzaWJsZSBvcHRpb25zIGFyZTogQ0JDLCBDVFIsIENGQiwgT0ZCLCBFQ0JcbiAgICogQHBhcmFtIGFkZGl0aW9uYWxFbmNyeXB0TWV0aG9kUGFyYW1zIGNvbmZpZ3VyYXRpb24gcGFyYW1zIHVzZWQgYnkgdGhlIHNlbGVjdGVkIGVuY3J5cHQgbWV0aG9kLlxuICAgKiBOb3RlOiBpZiB0aGUgbWV0aG9kIENUUiBvciBDRkIgaXMgdXNlZCB0aGlzIHBhcmFtIGlzIHJlcXVpcmVkIG90aGVyd2lzZSBpcyBhbiBvcHRpbmFsIHBhcmFtLlxuICAgKiBCeSBDVFIgcmVxdWlyZSB0aGUgcGFyYW0gY291bnRlciBhbmQgYnkgQ0ZCIHJlcXVpcmUgdGhlIHBhcmFtIHNlZ21lbnRTaXplXG4gICAqIEBwYXJhbSBpc1N0YXRpY0luaXRpYWxWZWN0b3IgZGVmaW5lcyBpZiB0aGUgaW5pdGlhbCB2ZWN0b3IgaXMgY2hhbmdlZCBvciBub3Qgd2hlbiB0aGUgZGF0YSBhcmUgZW5jcnlwdGVkIG9yIG5vdFxuICAgKi9cbiAgY29uZmlnKFxuICAgIG1hc3RlcktleSxcbiAgICBpbml0aWFsVmVjdG9yID0gWzAsIDAsIDAsIDAsIDAsIDAsIDAsIDAsIDAsIDAsIDAsIDAsIDAsIDAsIDAsIDBdLFxuICAgIGVuY3J5cHRNZXRob2QgPSAnQ0JDJyxcbiAgICBhZGRpdGlvbmFsRW5jcnlwdE1ldGhvZFBhcmFtcyA9IHt9LFxuICAgIGlzU3RhdGljSW5pdGlhbFZlY3RvciA9IHRydWVcbiAgKSB7XG4gICAgdGhpcy5pc0NvbmZpZ0V4ZWN1dGVkID0gdHJ1ZTtcbiAgICB0aGlzLm1hc3RlcktleSA9IG1hc3RlcktleTtcbiAgICB0aGlzLmluaXRpYWxWZWN0b3IgPSBpbml0aWFsVmVjdG9yO1xuICAgIHRoaXMuZW5jcnlwdE1ldGhvZCA9IGVuY3J5cHRNZXRob2Q7XG4gICAgdGhpcy5pc1N0YXRpY0luaXRpYWxWZWN0b3IgPSBpc1N0YXRpY0luaXRpYWxWZWN0b3I7XG4gICAgdGhpcy5hZGRpdGlvbmFsRW5jcnlwdE1ldGhvZFBhcmFtcyA9IGFkZGl0aW9uYWxFbmNyeXB0TWV0aG9kUGFyYW1zO1xuICAgIGlmICghaXNTdGF0aWNJbml0aWFsVmVjdG9yKSB7XG4gICAgICB0aGlzLmVuY3RyeXBNZXRob2RJbnN0YW5jZSA9IHRoaXMuZ2VuZXJhdGVFbmNyeXB0TWV0aG9kSW5zdGFuY2UoKTtcbiAgICB9XG4gIH1cbiAgLyoqXG4gICAqIEVuY3J5cHQgdGhlIGRhdGEgdXNpbmcgdGhlIGVuY3J5cHQgbWV0aG9kIHByZXZpb3VzbHkgY29uZmlndXJlZFxuICAgKiBAcGFyYW0gZGF0YUFycmF5QnVmZmVyIGRhdGEgdG8gZW5jcnlwdFxuICAgKi9cbiAgZW5jcnlwdChkYXRhQXJyYXlCdWZmZXI6IFVpbnQ4QXJyYXkgfCBVaW50MTZBcnJheSB8IFVpbnQzMkFycmF5KSB7XG4gICAgaWYgKCF0aGlzLmlzQ29uZmlnRXhlY3V0ZWQpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcihcbiAgICAgICAgJ011c3QgY29uZmlndXJhdGUgY3lwaGVyLWFlcyBiZWZvcmUgY2FsbCB0aGlzIG1ldGhvZCwgdXNlIHRoZSBtZXRob2QgY29uZmlnKCknXG4gICAgICApO1xuICAgIH1cbiAgICBpZiAodGhpcy5lbmNyeXB0TWV0aG9kID09PSAnQ0JDJyB8fCB0aGlzLmVuY3J5cHRNZXRob2QgPT09ICdFQ0InKSB7XG4gICAgICBkYXRhQXJyYXlCdWZmZXIgPSB0aGlzLmFkZFBhZGRpbmcoZGF0YUFycmF5QnVmZmVyKTtcbiAgICB9XG4gICAgcmV0dXJuIHRoaXMuaXNTdGF0aWNJbml0aWFsVmVjdG9yXG4gICAgICA/IHRoaXMuZ2VuZXJhdGVFbmNyeXB0TWV0aG9kSW5zdGFuY2UoKS5lbmNyeXB0KGRhdGFBcnJheUJ1ZmZlcilcbiAgICAgIDogdGhpcy5lbmN0cnlwTWV0aG9kSW5zdGFuY2UuZW5jcnlwdChkYXRhQXJyYXlCdWZmZXIpO1xuICB9XG4gIC8qKlxuICAgKiBEZWNyeXB0IHRoZSBkYXRhIHVzaW5nIHRoZSBlbmNyeXB0IG1ldGhvZCBwcmV2aW91c2x5IGNvbmZpZ3VyZWRcbiAgICogQHBhcmFtIGRhdGFBcnJheUJ1ZmZlciBkYXRhIHRvIGRlY3J5cHRcbiAgICovXG4gIGRlY3J5cHQoZGF0YUFycmF5QnVmZmVyOiBVaW50OEFycmF5IHwgVWludDE2QXJyYXkgfCBVaW50MzJBcnJheSkge1xuICAgIGlmICghdGhpcy5pc0NvbmZpZ0V4ZWN1dGVkKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoXG4gICAgICAgICdNdXN0IGNvbmZpZ3VyYXRlIGN5cGhlci1hZXMgYmVmb3JlIGNhbGwgdGhpcyBtZXRob2QsIHVzZSB0aGUgbWV0aG9kIGNvbmZpZygpJ1xuICAgICAgKTtcbiAgICB9XG4gICAgcmV0dXJuIHRoaXMuaXNTdGF0aWNJbml0aWFsVmVjdG9yXG4gICAgICA/IHRoaXMuZ2VuZXJhdGVFbmNyeXB0TWV0aG9kSW5zdGFuY2UoKS5kZWNyeXB0KGRhdGFBcnJheUJ1ZmZlcilcbiAgICAgIDogdGhpcy5lbmN0cnlwTWV0aG9kSW5zdGFuY2UuZGVjcnlwdChkYXRhQXJyYXlCdWZmZXIpO1xuICB9XG4gIC8qKlxuICAgKiBDaGFuZ2UgdGhlIGN1cnJlbnQgaW5pdGFsVmVjdG9yXG4gICAqIEBwYXJhbSBpbml0aWFsVmVjdG9yIG5ldyBpbml0YWxWZWN0b3JcbiAgICovXG4gIGNoYW5nZUluaXRpYWxWZWN0b3IoaW5pdGlhbFZlY3Rvcikge1xuICAgIGlmICghdGhpcy5pc1N0YXRpY0luaXRpYWxWZWN0b3IpIHtcbiAgICAgIHRoaXMuZW5jdHJ5cE1ldGhvZEluc3RhbmNlID0gdGhpcy5nZW5lcmF0ZUVuY3J5cHRNZXRob2RJbnN0YW5jZSgpO1xuICAgIH1cbiAgICB0aGlzLmluaXRpYWxWZWN0b3IgPSBpbml0aWFsVmVjdG9yO1xuICB9XG5cbiAgLyoqXG4gICAqIENoYW5nZSB0aGUgY3VycmVudCBlbmN5cHRNZXRob2RcbiAgICogQHBhcmFtIGVuY3J5cHRNZXRob2QgbmV3IGVuY3J5cHRNZXRob2RcbiAgICovXG4gIGNoYW5nZUVuY3J5cHRNZXRob2QoZW5jcnlwdE1ldGhvZCkge1xuICAgIGlmICghdGhpcy5pc1N0YXRpY0luaXRpYWxWZWN0b3IpIHtcbiAgICAgIHRoaXMuZW5jdHJ5cE1ldGhvZEluc3RhbmNlID0gdGhpcy5nZW5lcmF0ZUVuY3J5cHRNZXRob2RJbnN0YW5jZSgpO1xuICAgIH1cbiAgICB0aGlzLmVuY3J5cHRNZXRob2QgPSBlbmNyeXB0TWV0aG9kO1xuICB9XG5cbiAgLyoqXG4gICAqIENoYW5nZSB0aGUgY3VycmVudCBpc1N0YXRpY0luaXRpYWxWZWN0b3JcbiAgICogQHBhcmFtIGlzU3RhdGljSW5pdGlhbFZlY3RvciBuZXcgaXNTdGF0aWNJbml0YWxWZWN0b3JcbiAgICovXG4gIGNoYW5nZVN0YXRpY0luaXRpYWxWZWN0b3IoaXNTdGF0aWNJbml0aWFsVmVjdG9yKSB7XG4gICAgaWYgKCFpc1N0YXRpY0luaXRpYWxWZWN0b3IpIHtcbiAgICAgIHRoaXMuZW5jdHJ5cE1ldGhvZEluc3RhbmNlID0gdGhpcy5nZW5lcmF0ZUVuY3J5cHRNZXRob2RJbnN0YW5jZSgpO1xuICAgIH1cbiAgICB0aGlzLmlzU3RhdGljSW5pdGlhbFZlY3RvciA9IGlzU3RhdGljSW5pdGlhbFZlY3RvcjtcbiAgfVxuICAvKipcbiAgICogQ2hhbmdlIHRoZSBjdXJyZW50IG1hc3RlcktleVxuICAgKiBAcGFyYW0gbWFzdGVyS2V5IG5ldyBtYXN0ZXJLZXlcbiAgICovXG4gIGNoYW5nZU1hc3RlcktleShtYXN0ZXJLZXkpIHtcbiAgICBpZiAoIXRoaXMuaXNTdGF0aWNJbml0aWFsVmVjdG9yKSB7XG4gICAgICB0aGlzLmVuY3RyeXBNZXRob2RJbnN0YW5jZSA9IHRoaXMuZ2VuZXJhdGVFbmNyeXB0TWV0aG9kSW5zdGFuY2UoKTtcbiAgICB9XG4gICAgdGhpcy5tYXN0ZXJLZXkgPSBtYXN0ZXJLZXk7XG4gIH1cblxuICAvKipcbiAgICogQWRkIHBhZGRpbmcgdG8gdGhlIGxpc3RcbiAgICovXG4gIHByaXZhdGUgYWRkUGFkZGluZyhhcnJheUJ1ZmZlcjogVWludDhBcnJheSB8IFVpbnQxNkFycmF5IHwgVWludDMyQXJyYXkpIHtcbiAgICBjb25zdCBwYWRkaW5nTGVuZ3RoID0gTWF0aC5jZWlsKEFycmF5LmZyb20oYXJyYXlCdWZmZXIpLmxlbmd0aCAvIDE2KSAqIDE2O1xuICAgIGNvbnN0IHBhZGRpbmdMaXN0ID0gbmV3IEFycmF5KFxuICAgICAgcGFkZGluZ0xlbmd0aCAtIEFycmF5LmZyb20oYXJyYXlCdWZmZXIpLmxlbmd0aFxuICAgICkuZmlsbCgwKTtcbiAgICByZXR1cm4gbmV3IFVpbnQ4QXJyYXkoQXJyYXkuZnJvbShhcnJheUJ1ZmZlcikuY29uY2F0KHBhZGRpbmdMaXN0KSk7XG4gIH1cbiAgLyoqXG4gICAqIGdlbmVyYXRlIGEgaW5zdGFuY2Ugb2YgdGhlIGVuY3J5cHQgbWV0aG9kIHVzaW5nIHRoZSBjdXJyZW50IG1ldGhvZCBjb25maWd1cmVkXG4gICAqL1xuICBwcml2YXRlIGdlbmVyYXRlRW5jcnlwdE1ldGhvZEluc3RhbmNlKCkge1xuICAgIGxldCBlbmN0cnlwTWV0aG9kSW5zdGFuY2U7XG4gICAgc3dpdGNoICh0aGlzLmVuY3J5cHRNZXRob2QpIHtcbiAgICAgIGNhc2UgJ0NCQyc6XG4gICAgICAgIGVuY3RyeXBNZXRob2RJbnN0YW5jZSA9IG5ldyBhZXMuTW9kZU9mT3BlcmF0aW9uLmNiYyhcbiAgICAgICAgICB0aGlzLm1hc3RlcktleSxcbiAgICAgICAgICB0aGlzLmluaXRpYWxWZWN0b3JcbiAgICAgICAgKTtcbiAgICAgICAgYnJlYWs7XG4gICAgICBjYXNlICdDVFInOlxuICAgICAgICBpZiAoIXRoaXMuYWRkaXRpb25hbEVuY3J5cHRNZXRob2RQYXJhbXMuY291bnRlcikge1xuICAgICAgICAgIHRocm93IG5ldyBFcnJvcihcbiAgICAgICAgICAgICdhZGRpdGlvbmFsRW5jcnlwdE1ldGhvZFBhcmFtcy5jb3VudGVyIGlzIHJlcXVpcmVkIHRvIHVzZSBlbmNyeXB0IG1ldGhvZCBDVFInXG4gICAgICAgICAgKTtcbiAgICAgICAgfVxuICAgICAgICBlbmN0cnlwTWV0aG9kSW5zdGFuY2UgPSBuZXcgYWVzLk1vZGVPZk9wZXJhdGlvbi5jdHIoXG4gICAgICAgICAgdGhpcy5tYXN0ZXJLZXksXG4gICAgICAgICAgdGhpcy5pbml0aWFsVmVjdG9yLFxuICAgICAgICAgIG5ldyBhZXMuQ291bnRlcih0aGlzLmFkZGl0aW9uYWxFbmNyeXB0TWV0aG9kUGFyYW1zLmNvdW50ZXIpXG4gICAgICAgICk7XG4gICAgICAgIGJyZWFrO1xuICAgICAgY2FzZSAnQ0ZCJzpcbiAgICAgICAgaWYgKCF0aGlzLmFkZGl0aW9uYWxFbmNyeXB0TWV0aG9kUGFyYW1zLnNlZ21lbnRTaXplKSB7XG4gICAgICAgICAgdGhyb3cgbmV3IEVycm9yKFxuICAgICAgICAgICAgJ2FkZGl0aW9uYWxFbmNyeXB0TWV0aG9kUGFyYW1zLnNlZ21lbnRTaXplIGlzIHJlcXVpcmVkIHRvIHVzZSBlbmNyeXB0IG1ldGhvZCBDRkInXG4gICAgICAgICAgKTtcbiAgICAgICAgfVxuICAgICAgICBlbmN0cnlwTWV0aG9kSW5zdGFuY2UgPSBuZXcgYWVzLk1vZGVPZk9wZXJhdGlvbi5jZmIoXG4gICAgICAgICAgdGhpcy5tYXN0ZXJLZXksXG4gICAgICAgICAgdGhpcy5pbml0aWFsVmVjdG9yLFxuICAgICAgICAgIHRoaXMuYWRkaXRpb25hbEVuY3J5cHRNZXRob2RQYXJhbXMuc2VnbWVudFNpemVcbiAgICAgICAgKTtcbiAgICAgICAgYnJlYWs7XG4gICAgICBjYXNlICdPRkInOlxuICAgICAgICBlbmN0cnlwTWV0aG9kSW5zdGFuY2UgPSBuZXcgYWVzLk1vZGVPZk9wZXJhdGlvbi5vZmIoXG4gICAgICAgICAgdGhpcy5tYXN0ZXJLZXksXG4gICAgICAgICAgdGhpcy5pbml0aWFsVmVjdG9yXG4gICAgICAgICk7XG4gICAgICAgIGJyZWFrO1xuICAgICAgY2FzZSAnRUNCJzpcbiAgICAgICAgZW5jdHJ5cE1ldGhvZEluc3RhbmNlID0gbmV3IGFlcy5Nb2RlT2ZPcGVyYXRpb24uZWNiKHRoaXMubWFzdGVyS2V5KTtcbiAgICAgICAgYnJlYWs7XG4gICAgfVxuICAgIHJldHVybiBlbmN0cnlwTWV0aG9kSW5zdGFuY2U7XG4gIH1cbiAgLy8gI3JlZ2lvbiBVVElMU1xuICAvKipcbiAgICogQ29udmVydCB0aGUgdGV4dCB0byBieXRlc1xuICAgKiBAcGFyYW0gdGV4dCBUZXh0IHRvIGNvbnZlcnRcbiAgICovXG4gIHRleHRUb0J5dGVzKHRleHQpIHtcbiAgICByZXR1cm4gYWVzLnV0aWxzLnV0ZjgudG9CeXRlcyh0ZXh0KTtcbiAgfVxuICAvKipcbiAgICogQ29udmVydCB0aGUgYnl0ZXMgdG8gdGV4dFxuICAgKiBAcGFyYW0gYnl0ZXMgQnl0ZXMgdG8gY29udmVydFxuICAgKi9cbiAgYnl0ZXNUb1RleHQoYnl0ZXM6IFVpbnQ4QXJyYXkgfCBVaW50MTZBcnJheSB8IFVpbnQzMkFycmF5KSB7XG4gICAgcmV0dXJuIGFlcy51dGlscy51dGY4LmZyb21CeXRlcyhieXRlcyk7XG4gIH1cblxuICAvKipcbiAgICogQ29udmVydCB0aGUgYnl0ZXMgdG8gaGV4XG4gICAqIEBwYXJhbSBieXRlcyBieXRlcyB0byBjb252ZXJ0XG4gICAqL1xuICBieXRlc1RvaGV4KGJ5dGVzKSB7XG4gICAgcmV0dXJuIGFlcy51dGlscy5oZXguZnJvbUJ5dGVzKGJ5dGVzKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBDb252ZXJ0IHRoZSBoZXggdG8gYnl0ZXNcbiAgICogQHBhcmFtIGhleCBIZXggdG8gY29udmVydFxuICAgKi9cbiAgaGV4VG9CeXRlcyhoZXgpIHtcbiAgICByZXR1cm4gYWVzLnV0aWxzLmhleC50b0J5dGVzKGhleCk7XG4gIH1cbiAgLy8gI2VuZHJlZ2lvblxuXG4gIGdlbmVyYXRlU3Via2V5cyhrZXkpIHtcbiAgICBjb25zdCBjb25zdF9aZXJvID0gbmV3IFVpbnQ4QXJyYXkoMTYpO1xuICAgIGNvbnN0IGNvbnN0X1JiID0gbmV3IEJ1ZmZlcignMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwODcnLCAnaGV4Jyk7XG4gICAgY29uc3QgZW5jdHJ5cE1ldGhvZEluc3RhbmNlID0gbmV3IGFlcy5Nb2RlT2ZPcGVyYXRpb24uY2JjKGtleSwgbmV3IFVpbnQ4QXJyYXkoMTYpKTtcblxuICAgIGNvbnN0IGxFbmNyeXB0ZWQgPSBlbmN0cnlwTWV0aG9kSW5zdGFuY2UuZW5jcnlwdChjb25zdF9aZXJvKTtcbiAgICBjb25zdCBsID0gbmV3IEJ1ZmZlcih0aGlzLmJ5dGVzVG9oZXgobEVuY3J5cHRlZCksICdoZXgnKTtcbiAgICBsZXQgc3Via2V5MSA9IHRoaXMuYml0U2hpZnRMZWZ0KGwpO1xuICAgIC8vIHRzbGludDpkaXNhYmxlLW5leHQtbGluZTpuby1iaXR3aXNlXG4gICAgaWYgKGxbMF0gJiAweDgwKSB7XG4gICAgICBzdWJrZXkxID0gdGhpcy54b3Ioc3Via2V5MSwgY29uc3RfUmIpO1xuICAgIH1cblxuICAgIGxldCBzdWJrZXkyID0gdGhpcy5iaXRTaGlmdExlZnQoc3Via2V5MSk7XG4gICAgLy8gdHNsaW50OmRpc2FibGUtbmV4dC1saW5lOm5vLWJpdHdpc2VcbiAgICBpZiAoc3Via2V5MVswXSAmIDB4ODApIHtcbiAgICAgIHN1YmtleTIgPSB0aGlzLnhvcihzdWJrZXkyLCBjb25zdF9SYik7XG4gICAgfVxuXG4gICAgcmV0dXJuIHsgc3Via2V5MTogc3Via2V5MSwgc3Via2V5Mjogc3Via2V5MiB9O1xuICB9XG5cbiAgYWVzQ21hYyhrZXksIG1lc3NhZ2UpIHtcbiAgICBjb25zb2xlLmxvZygnSU5JQ0lBIENJRlJBRE8hISEhISEhISEhISEhISEhJyk7XG4gICAgY29uc3Qgc3Via2V5cyA9IHRoaXMuZ2VuZXJhdGVTdWJrZXlzKGtleSk7XG4gICAgbGV0IGJsb2NrQ291bnQgPSBNYXRoLmNlaWwobWVzc2FnZS5sZW5ndGggLyAxNik7XG4gICAgbGV0IGxhc3RCbG9ja0NvbXBsZXRlRmxhZywgbGFzdEJsb2NrLCBsYXN0QmxvY2tJbmRleDtcblxuICAgIGlmIChibG9ja0NvdW50ID09PSAwKSB7XG4gICAgICBibG9ja0NvdW50ID0gMTtcbiAgICAgIGxhc3RCbG9ja0NvbXBsZXRlRmxhZyA9IGZhbHNlO1xuICAgIH0gZWxzZSB7XG4gICAgICBsYXN0QmxvY2tDb21wbGV0ZUZsYWcgPSBtZXNzYWdlLmxlbmd0aCAlIDE2ID09PSAwO1xuICAgIH1cbiAgICBsYXN0QmxvY2tJbmRleCA9IGJsb2NrQ291bnQgLSAxO1xuXG4gICAgaWYgKGxhc3RCbG9ja0NvbXBsZXRlRmxhZykge1xuICAgICAgbGFzdEJsb2NrID0gdGhpcy54b3IoXG4gICAgICAgIHRoaXMuZ2V0TWVzc2FnZUJsb2NrKG1lc3NhZ2UsIGxhc3RCbG9ja0luZGV4KSxcbiAgICAgICAgc3Via2V5cy5zdWJrZXkxXG4gICAgICApO1xuICAgIH0gZWxzZSB7XG4gICAgICBsYXN0QmxvY2sgPSB0aGlzLnhvcihcbiAgICAgICAgdGhpcy5nZXRQYWRkZWRNZXNzYWdlQmxvY2sobWVzc2FnZSwgbGFzdEJsb2NrSW5kZXgpLFxuICAgICAgICBzdWJrZXlzLnN1YmtleTJcbiAgICAgICk7XG4gICAgfVxuXG4gICAgbGV0IHggPSBuZXcgQnVmZmVyKCcwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMCcsICdoZXgnKTtcbiAgICBsZXQgeTtcblxuICAgIGxldCBlbmN0cnlwTWV0aG9kSW5zdGFuY2U7XG4gICAgZm9yIChsZXQgaW5kZXggPSAwOyBpbmRleCA8IGxhc3RCbG9ja0luZGV4OyBpbmRleCsrKSB7XG4gICAgICBlbmN0cnlwTWV0aG9kSW5zdGFuY2UgPSBuZXcgYWVzLk1vZGVPZk9wZXJhdGlvbi5jYmMoa2V5LCBuZXcgVWludDhBcnJheSgxNikpO1xuICAgICAgeSA9IHRoaXMueG9yKHgsIHRoaXMuZ2V0TWVzc2FnZUJsb2NrKG1lc3NhZ2UsIGluZGV4KSk7XG4gICAgICBjb25zdCB4RW5jcnlwdGVkID0gZW5jdHJ5cE1ldGhvZEluc3RhbmNlLmVuY3J5cHQoeSk7XG4gICAgICBjb25zb2xlLmxvZygnWCBub3JtYWwgPT09PT09PT09PT09PT09PiAnLCB0aGlzLmJ5dGVzVG9oZXgoeSkpO1xuICAgICAgY29uc29sZS5sb2coJ1ggZW5jcnlwdGVkID09PT09PT09PT09PT09PiAnLCB0aGlzLmJ5dGVzVG9oZXgoeEVuY3J5cHRlZCkpO1xuICAgICAgeCA9IG5ldyBCdWZmZXIodGhpcy5ieXRlc1RvaGV4KHhFbmNyeXB0ZWQpLCAnaGV4Jyk7XG4gICAgfVxuICAgIHkgPSB0aGlzLnhvcihsYXN0QmxvY2ssIHgpO1xuICAgIGVuY3RyeXBNZXRob2RJbnN0YW5jZSA9IG5ldyBhZXMuTW9kZU9mT3BlcmF0aW9uLmNiYyhrZXksIG5ldyBVaW50OEFycmF5KDE2KSk7XG4gICAgY29uc3QgeUVuY3J5cHRlZCA9IGVuY3RyeXBNZXRob2RJbnN0YW5jZS5lbmNyeXB0KHkpO1xuICAgIGNvbnNvbGUubG9nKCdZIG5vcm1hbCA9PT09PT09PT09PT09PT4gJywgdGhpcy5ieXRlc1RvaGV4KHkpKTtcbiAgICBjb25zb2xlLmxvZygnWSBlbmNyeXB0ZWQgPT09PT09PT09PT09PT0+ICcsIHRoaXMuYnl0ZXNUb2hleCh5RW5jcnlwdGVkKSk7XG4gICAgcmV0dXJuIHlFbmNyeXB0ZWQ7XG4gIH1cblxuICBnZXRNZXNzYWdlQmxvY2sobWVzc2FnZSwgYmxvY2tJbmRleCkge1xuICAgIGNvbnN0IGJsb2NrID0gbmV3IEJ1ZmZlcigxNik7XG4gICAgY29uc3Qgc3RhcnQgPSBibG9ja0luZGV4ICogMTY7XG4gICAgY29uc3QgZW5kID0gc3RhcnQgKyAxNjtcbiAgICBsZXQgYmxvY2tJID0gMDtcbiAgICBmb3IgKGxldCBpID0gc3RhcnQ7IGkgPCBlbmQ7IGkrKykge1xuICAgICAgYmxvY2tbYmxvY2tJXSA9IG1lc3NhZ2VbaV07XG4gICAgICBibG9ja0krKztcbiAgICB9XG4gICAgcmV0dXJuIGJsb2NrO1xuICB9XG5cbiAgZ2V0UGFkZGVkTWVzc2FnZUJsb2NrKG1lc3NhZ2UsIGJsb2NrSW5kZXgpIHtcbiAgICBjb25zdCBibG9jayA9IG5ldyBCdWZmZXIoMTYpO1xuICAgIGNvbnN0IHN0YXJ0ID0gYmxvY2tJbmRleCAqIDE2O1xuICAgIGNvbnN0IGVuZCA9IG1lc3NhZ2UubGVuZ3RoO1xuXG4gICAgYmxvY2suZmlsbCgwKTtcbiAgICBsZXQgYmxvY2tJID0gMDtcbiAgICBmb3IgKGxldCBpID0gc3RhcnQ7IGkgPCBlbmQ7IGkrKykge1xuICAgICAgYmxvY2tbYmxvY2tJXSA9IG1lc3NhZ2VbaV07XG4gICAgICBibG9ja0krKztcbiAgICB9XG4gICAgYmxvY2tbZW5kIC0gc3RhcnRdID0gMHg4MDtcblxuICAgIHJldHVybiBibG9jaztcbiAgfVxuXG4gIGJpdFNoaWZ0TGVmdChidWZmZXIpIHtcbiAgICBjb25zdCBzaGlmdGVkID0gbmV3IEJ1ZmZlcihidWZmZXIubGVuZ3RoKTtcbiAgICBjb25zdCBsYXN0ID0gYnVmZmVyLmxlbmd0aCAtIDE7XG4gICAgZm9yIChsZXQgaW5kZXggPSAwOyBpbmRleCA8IGxhc3Q7IGluZGV4KyspIHtcbiAgICAgIC8vIHRzbGludDpkaXNhYmxlLW5leHQtbGluZTpuby1iaXR3aXNlXG4gICAgICBzaGlmdGVkW2luZGV4XSA9IGJ1ZmZlcltpbmRleF0gPDwgMTtcbiAgICAgIC8vIHRzbGludDpkaXNhYmxlLW5leHQtbGluZTpuby1iaXR3aXNlXG4gICAgICBpZiAoYnVmZmVyW2luZGV4ICsgMV0gJiAweDgwKSB7XG4gICAgICAgIHNoaWZ0ZWRbaW5kZXhdICs9IDB4MDE7XG4gICAgICB9XG4gICAgfVxuICAgIC8vIHRzbGludDpkaXNhYmxlLW5leHQtbGluZTpuby1iaXR3aXNlXG4gICAgc2hpZnRlZFtsYXN0XSA9IGJ1ZmZlcltsYXN0XSA8PCAxO1xuICAgIHJldHVybiBzaGlmdGVkO1xuICB9XG5cbiAgeG9yKGJ1ZmZlckEsIGJ1ZmZlckIpIHtcbiAgICBjb25zdCBsZW5ndGggPSBNYXRoLm1pbihidWZmZXJBLmxlbmd0aCwgYnVmZmVyQi5sZW5ndGgpO1xuICAgIGNvbnN0IG91dHB1dCA9IG5ldyBCdWZmZXIobGVuZ3RoKTtcbiAgICBmb3IgKGxldCBpbmRleCA9IDA7IGluZGV4IDwgbGVuZ3RoOyBpbmRleCsrKSB7XG4gICAgICAvLyB0c2xpbnQ6ZGlzYWJsZS1uZXh0LWxpbmU6bm8tYml0d2lzZVxuICAgICAgb3V0cHV0W2luZGV4XSA9IGJ1ZmZlckFbaW5kZXhdIF4gYnVmZmVyQltpbmRleF07XG4gICAgfVxuICAgIHJldHVybiBvdXRwdXQ7XG4gIH1cbn1cbiJdfQ==