@nebulae/angular-ble
Version:
A Web Bluetooth (Bluetooth Low Energy) module for angular (v2+)
375 lines (374 loc) • 39.9 kB
JavaScript
/**
* @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";
export class CypherAesService {
constructor() {
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
* @return {?}
*/
config(masterKey, initialVector = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], encryptMethod = 'CBC', additionalEncryptMethodParams = {}, 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
* @return {?}
*/
encrypt(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
* @return {?}
*/
decrypt(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
* @return {?}
*/
changeInitialVector(initialVector) {
if (!this.isStaticInitialVector) {
this.enctrypMethodInstance = this.generateEncryptMethodInstance();
}
this.initialVector = initialVector;
}
/**
* Change the current encyptMethod
* @param {?} encryptMethod new encryptMethod
* @return {?}
*/
changeEncryptMethod(encryptMethod) {
if (!this.isStaticInitialVector) {
this.enctrypMethodInstance = this.generateEncryptMethodInstance();
}
this.encryptMethod = encryptMethod;
}
/**
* Change the current isStaticInitialVector
* @param {?} isStaticInitialVector new isStaticInitalVector
* @return {?}
*/
changeStaticInitialVector(isStaticInitialVector) {
if (!isStaticInitialVector) {
this.enctrypMethodInstance = this.generateEncryptMethodInstance();
}
this.isStaticInitialVector = isStaticInitialVector;
}
/**
* Change the current masterKey
* @param {?} masterKey new masterKey
* @return {?}
*/
changeMasterKey(masterKey) {
if (!this.isStaticInitialVector) {
this.enctrypMethodInstance = this.generateEncryptMethodInstance();
}
this.masterKey = masterKey;
}
/**
* Add padding to the list
* @param {?} arrayBuffer
* @return {?}
*/
addPadding(arrayBuffer) {
/** @type {?} */
const paddingLength = Math.ceil(Array.from(arrayBuffer).length / 16) * 16;
/** @type {?} */
const 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 {?}
*/
generateEncryptMethodInstance() {
/** @type {?} */
let 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;
}
/**
* Convert the text to bytes
* @param {?} text Text to convert
* @return {?}
*/
textToBytes(text) {
return aes.utils.utf8.toBytes(text);
}
/**
* Convert the bytes to text
* @param {?} bytes Bytes to convert
* @return {?}
*/
bytesToText(bytes) {
return aes.utils.utf8.fromBytes(bytes);
}
/**
* Convert the bytes to hex
* @param {?} bytes bytes to convert
* @return {?}
*/
bytesTohex(bytes) {
return aes.utils.hex.fromBytes(bytes);
}
/**
* Convert the hex to bytes
* @param {?} hex Hex to convert
* @return {?}
*/
hexToBytes(hex) {
return aes.utils.hex.toBytes(hex);
}
/**
* @param {?} key
* @return {?}
*/
generateSubkeys(key) {
/** @type {?} */
const const_Zero = new Uint8Array(16);
/** @type {?} */
const const_Rb = new Buffer('00000000000000000000000000000087', 'hex');
/** @type {?} */
const enctrypMethodInstance = new aes.ModeOfOperation.cbc(key, new Uint8Array(16));
/** @type {?} */
const lEncrypted = enctrypMethodInstance.encrypt(const_Zero);
/** @type {?} */
const l = new Buffer(this.bytesTohex(lEncrypted), 'hex');
/** @type {?} */
let subkey1 = this.bitShiftLeft(l);
// tslint:disable-next-line:no-bitwise
if (l[0] & 0x80) {
subkey1 = this.xor(subkey1, const_Rb);
}
/** @type {?} */
let 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 {?}
*/
aesCmac(key, message) {
console.log('INICIA CIFRADO!!!!!!!!!!!!!!!!');
/** @type {?} */
const subkeys = this.generateSubkeys(key);
/** @type {?} */
let blockCount = Math.ceil(message.length / 16);
/** @type {?} */
let lastBlockCompleteFlag;
/** @type {?} */
let lastBlock;
/** @type {?} */
let 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 {?} */
let x = new Buffer('00000000000000000000000000000000', 'hex');
/** @type {?} */
let y;
/** @type {?} */
let enctrypMethodInstance;
for (let index = 0; index < lastBlockIndex; index++) {
enctrypMethodInstance = new aes.ModeOfOperation.cbc(key, new Uint8Array(16));
y = this.xor(x, this.getMessageBlock(message, index));
/** @type {?} */
const 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 {?} */
const 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 {?}
*/
getMessageBlock(message, blockIndex) {
/** @type {?} */
const block = new Buffer(16);
/** @type {?} */
const start = blockIndex * 16;
/** @type {?} */
const end = start + 16;
/** @type {?} */
let blockI = 0;
for (let i = start; i < end; i++) {
block[blockI] = message[i];
blockI++;
}
return block;
}
/**
* @param {?} message
* @param {?} blockIndex
* @return {?}
*/
getPaddedMessageBlock(message, blockIndex) {
/** @type {?} */
const block = new Buffer(16);
/** @type {?} */
const start = blockIndex * 16;
/** @type {?} */
const end = message.length;
block.fill(0);
/** @type {?} */
let blockI = 0;
for (let i = start; i < end; i++) {
block[blockI] = message[i];
blockI++;
}
block[end - start] = 0x80;
return block;
}
/**
* @param {?} buffer
* @return {?}
*/
bitShiftLeft(buffer) {
/** @type {?} */
const shifted = new Buffer(buffer.length);
/** @type {?} */
const last = buffer.length - 1;
for (let 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 {?}
*/
xor(bufferA, bufferB) {
/** @type {?} */
const length = Math.min(bufferA.length, bufferB.length);
/** @type {?} */
const output = new Buffer(length);
for (let 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 = () => [];
/** @nocollapse */ CypherAesService.ngInjectableDef = i0.defineInjectable({ factory: function CypherAesService_Factory() { return new CypherAesService(); }, token: CypherAesService, providedIn: "root" });
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,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY3lwaGVyLWFlcy5zZXJ2aWNlLmpzIiwic291cmNlUm9vdCI6Im5nOi8vQG5lYnVsYWUvYW5ndWxhci1ibGUvIiwic291cmNlcyI6WyJsaWIvY3lwaGVyL2N5cGhlci1hZXMuc2VydmljZS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7O0FBQ0EsT0FBTyxLQUFLLEdBQUcsTUFBTSxRQUFRLENBQUM7QUFDOUIsT0FBTyxFQUFFLFVBQVUsRUFBRSxNQUFNLGVBQWUsQ0FBQzs7QUFLM0MsTUFBTTtJQVFKO3lCQVBvQixFQUFFOzZCQUNFLEVBQUU7NkJBQ0YsS0FBSztxQ0FDRyxJQUFJO2dDQUVULEtBQUs7S0FFaEI7Ozs7Ozs7Ozs7OztJQVdoQixNQUFNLENBQ0osU0FBUyxFQUNULGFBQWEsR0FBRyxDQUFDLENBQUMsRUFBRSxDQUFDLEVBQUUsQ0FBQyxFQUFFLENBQUMsRUFBRSxDQUFDLEVBQUUsQ0FBQyxFQUFFLENBQUMsRUFBRSxDQUFDLEVBQUUsQ0FBQyxFQUFFLENBQUMsRUFBRSxDQUFDLEVBQUUsQ0FBQyxFQUFFLENBQUMsRUFBRSxDQUFDLEVBQUUsQ0FBQyxFQUFFLENBQUMsQ0FBQyxFQUNoRSxhQUFhLEdBQUcsS0FBSyxFQUNyQiw2QkFBNkIsR0FBRyxFQUFFLEVBQ2xDLHFCQUFxQixHQUFHLElBQUk7UUFFNUIsSUFBSSxDQUFDLGdCQUFnQixHQUFHLElBQUksQ0FBQztRQUM3QixJQUFJLENBQUMsU0FBUyxHQUFHLFNBQVMsQ0FBQztRQUMzQixJQUFJLENBQUMsYUFBYSxHQUFHLGFBQWEsQ0FBQztRQUNuQyxJQUFJLENBQUMsYUFBYSxHQUFHLGFBQWEsQ0FBQztRQUNuQyxJQUFJLENBQUMscUJBQXFCLEdBQUcscUJBQXFCLENBQUM7UUFDbkQsSUFBSSxDQUFDLDZCQUE2QixHQUFHLDZCQUE2QixDQUFDO1FBQ25FLEVBQUUsQ0FBQyxDQUFDLENBQUMscUJBQXFCLENBQUMsQ0FBQyxDQUFDO1lBQzNCLElBQUksQ0FBQyxxQkFBcUIsR0FBRyxJQUFJ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QUFHLElBQUksRUFBRSxLQUFLLEVBQUUsRUFBRSxDQUFDOztZQUUxQyxPQUFPLENBQUMsS0FBSyxDQUFDLEdBQUcsTUFBTSxDQUFDLEtBQUssQ0FBQyxJQUFJLENBQUMsQ0FBQzs7WUFFcEMsRUFBRSxDQUFDLENBQUMsTUFBTSxDQUFDLEtBQUssR0FBRyxDQUFDLENBQUMsR0FBRyxJQUFJLENBQUMsQ0FBQyxDQUFDO2dCQUM3QixPQUFPLENBQUMsS0FBSyxDQUFDLElBQUksSUFBSSxDQUFDO2FBQ3hCO1NBQ0Y7O1FBRUQsT0FBTyxDQUFDLElBQUksQ0FBQyxHQUFHLE1BQU0sQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLENBQUM7UUFDbEMsTUFBTSxDQUFDLE9BQU8sQ0FBQztLQUNoQjs7Ozs7O0lBRUQsR0FBRyxDQUFDLE9BQU8sRUFBRSxPQUFPOztRQUNsQixNQUFNLE1BQU0sR0FBRyxJQUFJLENBQUMsR0FBRyxDQUFDLE9BQU8sQ0FBQyxNQUFNLEVBQUUsT0FBTyxDQUFDLE1BQU0sQ0FBQyxDQUFDOztRQUN4RCxNQUFNLE1BQU0sR0FBRyxJQUFJLE1BQU0sQ0FBQyxNQUFNLENBQUMsQ0FBQztRQUNsQyxHQUFHLENBQUMsQ0FBQyxJQUFJLEtBQUssR0FBRyxDQUFDLEVBQUUsS0FBSyxHQUFHLE1BQU0sRUFBRSxLQUFLLEVBQUUsRUFBRSxDQUFDOztZQUU1QyxNQUFNLENBQUMsS0FBSyxDQUFDLEdBQUcsT0FBTyxDQUFDLEtBQUssQ0FBQyxHQUFHLE9BQU8sQ0FBQyxLQUFLLENBQUMsQ0FBQztTQUNqRDtRQUNELE1BQU0sQ0FBQyxNQUFNLENBQUM7S0FDZjs7O1lBcFVGLFVBQVUsU0FBQztnQkFDVixVQUFVLEVBQUUsTUFBTTthQUNuQiIsInNvdXJjZXNDb250ZW50IjpbImRlY2xhcmUgY29uc3QgQnVmZmVyO1xuaW1wb3J0ICogYXMgYWVzIGZyb20gJ2Flcy1qcyc7XG5pbXBvcnQgeyBJbmplY3RhYmxlIH0gZnJvbSAnQGFuZ3VsYXIvY29yZSc7XG5cbkBJbmplY3RhYmxlKHtcbiAgcHJvdmlkZWRJbjogJ3Jvb3QnXG59KVxuZXhwb3J0IGNsYXNzIEN5cGhlckFlc1NlcnZpY2Uge1xuICBwcml2YXRlIG1hc3RlcktleSA9IFtdO1xuICBwcml2YXRlIGluaXRpYWxWZWN0b3IgPSBbXTtcbiAgcHJpdmF0ZSBlbmNyeXB0TWV0aG9kID0gJ0NCQyc7XG4gIHByaXZhdGUgaXNTdGF0aWNJbml0aWFsVmVjdG9yID0gdHJ1ZTtcbiAgcHJpdmF0ZSBlbmN0cnlwTWV0aG9kSW5zdGFuY2U7XG4gIHByaXZhdGUgaXNDb25maWdFeGVjdXRlZCA9IGZhbHNlO1xuICBwcml2YXRlIGFkZGl0aW9uYWxFbmNyeXB0TWV0aG9kUGFyYW1zO1xuICBjb25zdHJ1Y3RvcigpIHt9XG4gIC8qKlxuICAgKiBJbml0aWFsIGNvbmZpZyB1c2VkIHRvIGluaXRhbGljZSBhbGwgcmVxdWlyZWQgcGFyYW1zXG4gICAqIEBwYXJhbSBtYXN0ZXJLZXkga2V5IHVzZWQgdG8gZW5jcnlwdCBhbmQgZGVjcnlwdFxuICAgKiBAcGFyYW0gaW5pdGlhbFZlY3RvciB2ZWN0b3IgdXNlZCB0byBlbmNyeXB0IGFiZCBkZWNyeXB0IGV4Y2VwdCB3aGVuIEVDQiBlbmNyeXB0IG1ldGhvZCBpcyB1c2VkXG4gICAqIEBwYXJhbSBlbmNyeXB0TWV0aG9kIHR5cGUgb2YgZW5jcnlwdCBtZXRob2QgaXMgdXNlZCwgdGhlIHBvc3NpYmxlIG9wdGlvbnMgYXJlOiBDQkMsIENUUiwgQ0ZCLCBPRkIsIEVDQlxuICAgKiBAcGFyYW0gYWRkaXRpb25hbEVuY3J5cHRNZXRob2RQYXJhbXMgY29uZmlndXJhdGlvbiBwYXJhbXMgdXNlZCBieSB0aGUgc2VsZWN0ZWQgZW5jcnlwdCBtZXRob2QuXG4gICAqIE5vdGU6IGlmIHRoZSBtZXRob2QgQ1RSIG9yIENGQiBpcyB1c2VkIHRoaXMgcGFyYW0gaXMgcmVxdWlyZWQgb3RoZXJ3aXNlIGlzIGFuIG9wdGluYWwgcGFyYW0uXG4gICAqIEJ5IENUUiByZXF1aXJlIHRoZSBwYXJhbSBjb3VudGVyIGFuZCBieSBDRkIgcmVxdWlyZSB0aGUgcGFyYW0gc2VnbWVudFNpemVcbiAgICogQHBhcmFtIGlzU3RhdGljSW5pdGlhbFZlY3RvciBkZWZpbmVzIGlmIHRoZSBpbml0aWFsIHZlY3RvciBpcyBjaGFuZ2VkIG9yIG5vdCB3aGVuIHRoZSBkYXRhIGFyZSBlbmNyeXB0ZWQgb3Igbm90XG4gICAqL1xuICBjb25maWcoXG4gICAgbWFzdGVyS2V5LFxuICAgIGluaXRpYWxWZWN0b3IgPSBbMCwgMCwgMCwgMCwgMCwgMCwgMCwgMCwgMCwgMCwgMCwgMCwgMCwgMCwgMCwgMF0sXG4gICAgZW5jcnlwdE1ldGhvZCA9ICdDQkMnLFxuICAgIGFkZGl0aW9uYWxFbmNyeXB0TWV0aG9kUGFyYW1zID0ge30sXG4gICAgaXNTdGF0aWNJbml0aWFsVmVjdG9yID0gdHJ1ZVxuICApIHtcbiAgICB0aGlzLmlzQ29uZmlnRXhlY3V0ZWQgPSB0cnVlO1xuICAgIHRoaXMubWFzdGVyS2V5ID0gbWFzdGVyS2V5O1xuICAgIHRoaXMuaW5pdGlhbFZlY3RvciA9IGluaXRpYWxWZWN0b3I7XG4gICAgdGhpcy5lbmNyeXB0TWV0aG9kID0gZW5jcnlwdE1ldGhvZDtcbiAgICB0aGlzLmlzU3RhdGljSW5pdGlhbFZlY3RvciA9IGlzU3RhdGljSW5pdGlhbFZlY3RvcjtcbiAgICB0aGlzLmFkZGl0aW9uYWxFbmNyeXB0TWV0aG9kUGFyYW1zID0gYWRkaXRpb25hbEVuY3J5cHRNZXRob2RQYXJhbXM7XG4gICAgaWYgKCFpc1N0YXRpY0luaXRpYWxWZWN0b3IpIHtcbiAgICAgIHRoaXMuZW5jdHJ5cE1ldGhvZEluc3RhbmNlID0gdGhpcy5nZW5lcmF0ZUVuY3J5cHRNZXRob2RJbnN0YW5jZSgpO1xuICAgIH1cbiAgfVxuICAvKipcbiAgICogRW5jcnlwdCB0aGUgZGF0YSB1c2luZyB0aGUgZW5jcnlwdCBtZXRob2QgcHJldmlvdXNseSBjb25maWd1cmVkXG4gICAqIEBwYXJhbSBkYXRhQXJyYXlCdWZmZXIgZGF0YSB0byBlbmNyeXB0XG4gICAqL1xuICBlbmNyeXB0KGRhdGFBcnJheUJ1ZmZlcjogVWludDhBcnJheSB8IFVpbnQxNkFycmF5IHwgVWludDMyQXJyYXkpIHtcbiAgICBpZiAoIXRoaXMuaXNDb25maWdFeGVjdXRlZCkge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKFxuICAgICAgICAnTXVzdCBjb25maWd1cmF0ZSBjeXBoZXItYWVzIGJlZm9yZSBjYWxsIHRoaXMgbWV0aG9kLCB1c2UgdGhlIG1ldGhvZCBjb25maWcoKSdcbiAgICAgICk7XG4gICAgfVxuICAgIGlmICh0aGlzLmVuY3J5cHRNZXRob2QgPT09ICdDQkMnIHx8IHRoaXMuZW5jcnlwdE1ldGhvZCA9PT0gJ0VDQicpIHtcbiAgICAgIGRhdGFBcnJheUJ1ZmZlciA9IHRoaXMuYWRkUGFkZGluZyhkYXRhQXJyYXlCdWZmZXIpO1xuICAgIH1cbiAgICByZXR1cm4gdGhpcy5pc1N0YXRpY0luaXRpYWxWZWN0b3JcbiAgICAgID8gdGhpcy5nZW5lcmF0ZUVuY3J5cHRNZXRob2RJbnN0YW5jZSgpLmVuY3J5cHQoZGF0YUFycmF5QnVmZmVyKVxuICAgICAgOiB0aGlzLmVuY3RyeXBNZXRob2RJbnN0YW5jZS5lbmNyeXB0KGRhdGFBcnJheUJ1ZmZlcik7XG4gIH1cbiAgLyoqXG4gICAqIERlY3J5cHQgdGhlIGRhdGEgdXNpbmcgdGhlIGVuY3J5cHQgbWV0aG9kIHByZXZpb3VzbHkgY29uZmlndXJlZFxuICAgKiBAcGFyYW0gZGF0YUFycmF5QnVmZmVyIGRhdGEgdG8gZGVjcnlwdFxuICAgKi9cbiAgZGVjcnlwdChkYXRhQXJyYXlCdWZmZXI6IFVpbnQ4QXJyYXkgfCBVaW50MTZBcnJheSB8IFVpbnQzMkFycmF5KSB7XG4gICAgaWYgKCF0aGlzLmlzQ29uZmlnRXhlY3V0ZWQpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcihcbiAgICAgICAgJ011c3QgY29uZmlndXJhdGUgY3lwaGVyLWFlcyBiZWZvcmUgY2FsbCB0aGlzIG1ldGhvZCwgdXNlIHRoZSBtZXRob2QgY29uZmlnKCknXG4gICAgICApO1xuICAgIH1cbiAgICByZXR1cm4gdGhpcy5pc1N0YXRpY0luaXRpYWxWZWN0b3JcbiAgICAgID8gdGhpcy5nZW5lcmF0ZUVuY3J5cHRNZXRob2RJbnN0YW5jZSgpLmRlY3J5cHQoZGF0YUFycmF5QnVmZmVyKVxuICAgICAgOiB0aGlzLmVuY3RyeXBNZXRob2RJbnN0YW5jZS5kZWNyeXB0KGRhdGFBcnJheUJ1ZmZlcik7XG4gIH1cbiAgLyoqXG4gICAqIENoYW5nZSB0aGUgY3VycmVudCBpbml0YWxWZWN0b3JcbiAgICogQHBhcmFtIGluaXRpYWxWZWN0b3IgbmV3IGluaXRhbFZlY3RvclxuICAgKi9cbiAgY2hhbmdlSW5pdGlhbFZlY3Rvcihpbml0aWFsVmVjdG9yKSB7XG4gICAgaWYgKCF0aGlzLmlzU3RhdGljSW5pdGlhbFZlY3Rvcikge1xuICAgICAgdGhpcy5lbmN0cnlwTWV0aG9kSW5zdGFuY2UgPSB0aGlzLmdlbmVyYXRlRW5jcnlwdE1ldGhvZEluc3RhbmNlKCk7XG4gICAgfVxuICAgIHRoaXMuaW5pdGlhbFZlY3RvciA9IGluaXRpYWxWZWN0b3I7XG4gIH1cblxuICAvKipcbiAgICogQ2hhbmdlIHRoZSBjdXJyZW50IGVuY3lwdE1ldGhvZFxuICAgKiBAcGFyYW0gZW5jcnlwdE1ldGhvZCBuZXcgZW5jcnlwdE1ldGhvZFxuICAgKi9cbiAgY2hhbmdlRW5jcnlwdE1ldGhvZChlbmNyeXB0TWV0aG9kKSB7XG4gICAgaWYgKCF0aGlzLmlzU3RhdGljSW5pdGlhbFZlY3Rvcikge1xuICAgICAgdGhpcy5lbmN0cnlwTWV0aG9kSW5zdGFuY2UgPSB0aGlzLmdlbmVyYXRlRW5jcnlwdE1ldGhvZEluc3RhbmNlKCk7XG4gICAgfVxuICAgIHRoaXMuZW5jcnlwdE1ldGhvZCA9IGVuY3J5cHRNZXRob2Q7XG4gIH1cblxuICAvKipcbiAgICogQ2hhbmdlIHRoZSBjdXJyZW50IGlzU3RhdGljSW5pdGlhbFZlY3RvclxuICAgKiBAcGFyYW0gaXNTdGF0aWNJbml0aWFsVmVjdG9yIG5ldyBpc1N0YXRpY0luaXRhbFZlY3RvclxuICAgKi9cbiAgY2hhbmdlU3RhdGljSW5pdGlhbFZlY3Rvcihpc1N0YXRpY0luaXRpYWxWZWN0b3IpIHtcbiAgICBpZiAoIWlzU3RhdGljSW5pdGlhbFZlY3Rvcikge1xuICAgICAgdGhpcy5lbmN0cnlwTWV0aG9kSW5zdGFuY2UgPSB0aGlzLmdlbmVyYXRlRW5jcnlwdE1ldGhvZEluc3RhbmNlKCk7XG4gICAgfVxuICAgIHRoaXMuaXNTdGF0aWNJbml0aWFsVmVjdG9yID0gaXNTdGF0aWNJbml0aWFsVmVjdG9yO1xuICB9XG4gIC8qKlxuICAgKiBDaGFuZ2UgdGhlIGN1cnJlbnQgbWFzdGVyS2V5XG4gICAqIEBwYXJhbSBtYXN0ZXJLZXkgbmV3IG1hc3RlcktleVxuICAgKi9cbiAgY2hhbmdlTWFzdGVyS2V5KG1hc3RlcktleSkge1xuICAgIGlmICghdGhpcy5pc1N0YXRpY0luaXRpYWxWZWN0b3IpIHtcbiAgICAgIHRoaXMuZW5jdHJ5cE1ldGhvZEluc3RhbmNlID0gdGhpcy5nZW5lcmF0ZUVuY3J5cHRNZXRob2RJbnN0YW5jZSgpO1xuICAgIH1cbiAgICB0aGlzLm1hc3RlcktleSA9IG1hc3RlcktleTtcbiAgfVxuXG4gIC8qKlxuICAgKiBBZGQgcGFkZGluZyB0byB0aGUgbGlzdFxuICAgKi9cbiAgcHJpdmF0ZSBhZGRQYWRkaW5nKGFycmF5QnVmZmVyOiBVaW50OEFycmF5IHwgVWludDE2QXJyYXkgfCBVaW50MzJBcnJheSkge1xuICAgIGNvbnN0IHBhZGRpbmdMZW5ndGggPSBNYXRoLmNlaWwoQXJyYXkuZnJvbShhcnJheUJ1ZmZlcikubGVuZ3RoIC8gMTYpICogMTY7XG4gICAgY29uc3QgcGFkZGluZ0xpc3QgPSBuZXcgQXJyYXkoXG4gICAgICBwYWRkaW5nTGVuZ3RoIC0gQXJyYXkuZnJvbShhcnJheUJ1ZmZlcikubGVuZ3RoXG4gICAgKS5maWxsKDApO1xuICAgIHJldHVybiBuZXcgVWludDhBcnJheShBcnJheS5mcm9tKGFycmF5QnVmZmVyKS5jb25jYXQocGFkZGluZ0xpc3QpKTtcbiAgfVxuICAvKipcbiAgICogZ2VuZXJhdGUgYSBpbnN0YW5jZSBvZiB0aGUgZW5jcnlwdCBtZXRob2QgdXNpbmcgdGhlIGN1cnJlbnQgbWV0aG9kIGNvbmZpZ3VyZWRcbiAgICovXG4gIHByaXZhdGUgZ2VuZXJhdGVFbmNyeXB0TWV0aG9kSW5zdGFuY2UoKSB7XG4gICAgbGV0IGVuY3RyeXBNZXRob2RJbnN0YW5jZTtcbiAgICBzd2l0Y2ggKHRoaXMuZW5jcnlwdE1ldGhvZCkge1xuICAgICAgY2FzZSAnQ0JDJzpcbiAgICAgICAgZW5jdHJ5cE1ldGhvZEluc3RhbmNlID0gbmV3IGFlcy5Nb2RlT2ZPcGVyYXRpb24uY2JjKFxuICAgICAgICAgIHRoaXMubWFzdGVyS2V5LFxuICAgICAgICAgIHRoaXMuaW5pdGlhbFZlY3RvclxuICAgICAgICApO1xuICAgICAgICBicmVhaztcbiAgICAgIGNhc2UgJ0NUUic6XG4gICAgICAgIGlmICghdGhpcy5hZGRpdGlvbmFsRW5jcnlwdE1ldGhvZFBhcmFtcy5jb3VudGVyKSB7XG4gICAgICAgICAgdGhyb3cgbmV3IEVycm9yKFxuICAgICAgICAgICAgJ2FkZGl0aW9uYWxFbmNyeXB0TWV0aG9kUGFyYW1zLmNvdW50ZXIgaXMgcmVxdWlyZWQgdG8gdXNlIGVuY3J5cHQgbWV0aG9kIENUUidcbiAgICAgICAgICApO1xuICAgICAgICB9XG4gICAgICAgIGVuY3RyeXBNZXRob2RJbnN0YW5jZSA9IG5ldyBhZXMuTW9kZU9mT3BlcmF0aW9uLmN0cihcbiAgICAgICAgICB0aGlzLm1hc3RlcktleSxcbiAgICAgICAgICB0aGlzLmluaXRpYWxWZWN0b3IsXG4gICAgICAgICAgbmV3IGFlcy5Db3VudGVyKHRoaXMuYWRkaXRpb25hbEVuY3J5cHRNZXRob2RQYXJhbXMuY291bnRlcilcbiAgICAgICAgKTtcbiAgICAgICAgYnJlYWs7XG4gICAgICBjYXNlICdDRkInOlxuICAgICAgICBpZiAoIXRoaXMuYWRkaXRpb25hbEVuY3J5cHRNZXRob2RQYXJhbXMuc2VnbWVudFNpemUpIHtcbiAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoXG4gICAgICAgICAgICAnYWRkaXRpb25hbEVuY3J5cHRNZXRob2RQYXJhbXMuc2VnbWVudFNpemUgaXMgcmVxdWlyZWQgdG8gdXNlIGVuY3J5cHQgbWV0aG9kIENGQidcbiAgICAgICAgICApO1xuICAgICAgICB9XG4gICAgICAgIGVuY3RyeXBNZXRob2RJbnN0YW5jZSA9IG5ldyBhZXMuTW9kZU9mT3BlcmF0aW9uLmNmYihcbiAgICAgICAgICB0aGlzLm1hc3RlcktleSxcbiAgICAgICAgICB0aGlzLmluaXRpYWxWZWN0b3IsXG4gICAgICAgICAgdGhpcy5hZGRpdGlvbmFsRW5jcnlwdE1ldGhvZFBhcmFtcy5zZWdtZW50U2l6ZVxuICAgICAgICApO1xuICAgICAgICBicmVhaztcbiAgICAgIGNhc2UgJ09GQic6XG4gICAgICAgIGVuY3RyeXBNZXRob2RJbnN0YW5jZSA9IG5ldyBhZXMuTW9kZU9mT3BlcmF0aW9uLm9mYihcbiAgICAgICAgICB0aGlzLm1hc3RlcktleSxcbiAgICAgICAgICB0aGlzLmluaXRpYWxWZWN0b3JcbiAgICAgICAgKTtcbiAgICAgICAgYnJlYWs7XG4gICAgICBjYXNlICdFQ0InOlxuICAgICAgICBlbmN0cnlwTWV0aG9kSW5zdGFuY2UgPSBuZXcgYWVzLk1vZGVPZk9wZXJhdGlvbi5lY2IodGhpcy5tYXN0ZXJLZXkpO1xuICAgICAgICBicmVhaztcbiAgICB9XG4gICAgcmV0dXJuIGVuY3RyeXBNZXRob2RJbnN0YW5jZTtcbiAgfVxuICAvLyAjcmVnaW9uIFVUSUxTXG4gIC8qKlxuICAgKiBDb252ZXJ0IHRoZSB0ZXh0IHRvIGJ5dGVzXG4gICAqIEBwYXJhbSB0ZXh0IFRleHQgdG8gY29udmVydFxuICAgKi9cbiAgdGV4dFRvQnl0ZXModGV4dCkge1xuICAgIHJldHVybiBhZXMudXRpbHMudXRmOC50b0J5dGVzKHRleHQpO1xuICB9XG4gIC8qKlxuICAgKiBDb252ZXJ0IHRoZSBieXRlcyB0byB0ZXh0XG4gICAqIEBwYXJhbSBieXRlcyBCeXRlcyB0byBjb252ZXJ0XG4gICAqL1xuICBieXRlc1RvVGV4dChieXRlczogVWludDhBcnJheSB8IFVpbnQxNkFycmF5IHwgVWludDMyQXJyYXkpIHtcbiAgICByZXR1cm4gYWVzLnV0aWxzLnV0ZjguZnJvbUJ5dGVzKGJ5dGVzKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBDb252ZXJ0IHRoZSBieXRlcyB0byBoZXhcbiAgICogQHBhcmFtIGJ5dGVzIGJ5dGVzIHRvIGNvbnZlcnRcbiAgICovXG4gIGJ5dGVzVG9oZXgoYnl0ZXMpIHtcbiAgICByZXR1cm4gYWVzLnV0aWxzLmhleC5mcm9tQnl0ZXMoYnl0ZXMpO1xuICB9XG5cbiAgLyoqXG4gICAqIENvbnZlcnQgdGhlIGhleCB0byBieXRlc1xuICAgKiBAcGFyYW0gaGV4IEhleCB0byBjb252ZXJ0XG4gICAqL1xuICBoZXhUb0J5dGVzKGhleCkge1xuICAgIHJldHVybiBhZXMudXRpbHMuaGV4LnRvQnl0ZXMoaGV4KTtcbiAgfVxuICAvLyAjZW5kcmVnaW9uXG5cbiAgZ2VuZXJhdGVTdWJrZXlzKGtleSkge1xuICAgIGNvbnN0IGNvbnN0X1plcm8gPSBuZXcgVWludDhBcnJheSgxNik7XG4gICAgY29uc3QgY29uc3RfUmIgPSBuZXcgQnVmZmVyKCcwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDA4NycsICdoZXgnKTtcbiAgICBjb25zdCBlbmN0cnlwTWV0aG9kSW5zdGFuY2UgPSBuZXcgYWVzLk1vZGVPZk9wZXJhdGlvbi5jYmMoa2V5LCBuZXcgVWludDhBcnJheSgxNikpO1xuXG4gICAgY29uc3QgbEVuY3J5cHRlZCA9IGVuY3RyeXBNZXRob2RJbnN0YW5jZS5lbmNyeXB0KGNvbnN0X1plcm8pO1xuICAgIGNvbnN0IGwgPSBuZXcgQnVmZmVyKHRoaXMuYnl0ZXNUb2hleChsRW5jcnlwdGVkKSwgJ2hleCcpO1xuICAgIGxldCBzdWJrZXkxID0gdGhpcy5iaXRTaGlmdExlZnQobCk7XG4gICAgLy8gdHNsaW50OmRpc2FibGUtbmV4dC1saW5lOm5vLWJpdHdpc2VcbiAgICBpZiAobFswXSAmIDB4ODApIHtcbiAgICAgIHN1YmtleTEgPSB0aGlzLnhvcihzdWJrZXkxLCBjb25zdF9SYik7XG4gICAgfVxuXG4gICAgbGV0IHN1YmtleTIgPSB0aGlzLmJpdFNoaWZ0TGVmdChzdWJrZXkxKTtcbiAgICAvLyB0c2xpbnQ6ZGlzYWJsZS1uZXh0LWxpbmU6bm8tYml0d2lzZVxuICAgIGlmIChzdWJrZXkxWzBdICYgMHg4MCkge1xuICAgICAgc3Via2V5MiA9IHRoaXMueG9yKHN1YmtleTIsIGNvbnN0X1JiKTtcbiAgICB9XG5cbiAgICByZXR1cm4geyBzdWJrZXkxOiBzdWJrZXkxLCBzdWJrZXkyOiBzdWJrZXkyIH07XG4gIH1cblxuICBhZXNDbWFjKGtleSwgbWVzc2FnZSkge1xuICAgIGNvbnNvbGUubG9nKCdJTklDSUEgQ0lGUkFETyEhISEhISEhISEhISEhISEnKTtcbiAgICBjb25zdCBzdWJrZXlzID0gdGhpcy5nZW5lcmF0ZVN1YmtleXMoa2V5KTtcbiAgICBsZXQgYmxvY2tDb3VudCA9IE1hdGguY2VpbChtZXNzYWdlLmxlbmd0aCAvIDE2KTtcbiAgICBsZXQgbGFzdEJsb2NrQ29tcGxldGVGbGFnLCBsYXN0QmxvY2ssIGxhc3RCbG9ja0luZGV4O1xuXG4gICAgaWYgKGJsb2NrQ291bnQgPT09IDApIHtcbiAgICAgIGJsb2NrQ291bnQgPSAxO1xuICAgICAgbGFzdEJsb2NrQ29tcGxldGVGbGFnID0gZmFsc2U7XG4gICAgfSBlbHNlIHtcbiAgICAgIGxhc3RCbG9ja0NvbXBsZXRlRmxhZyA9IG1lc3NhZ2UubGVuZ3RoICUgMTYgPT09IDA7XG4gICAgfVxuICAgIGxhc3RCbG9ja0luZGV4ID0gYmxvY2tDb3VudCAtIDE7XG5cbiAgICBpZiAobGFzdEJsb2NrQ29tcGxldGVGbGFnKSB7XG4gICAgICBsYXN0QmxvY2sgPSB0aGlzLnhvcihcbiAgICAgICAgdGhpcy5nZXRNZXNzYWdlQmxvY2sobWVzc2FnZSwgbGFzdEJsb2NrSW5kZXgpLFxuICAgICAgICBzdWJrZXlzLnN1YmtleTFcbiAgICAgICk7XG4gICAgfSBlbHNlIHtcbiAgICAgIGxhc3RCbG9jayA9IHRoaXMueG9yKFxuICAgICAgICB0aGlzLmdldFBhZGRlZE1lc3NhZ2VCbG9jayhtZXNzYWdlLCBsYXN0QmxvY2tJbmRleCksXG4gICAgICAgIHN1YmtleXMuc3Via2V5MlxuICAgICAgKTtcbiAgICB9XG5cbiAgICBsZXQgeCA9IG5ldyBCdWZmZXIoJzAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwJywgJ2hleCcpO1xuICAgIGxldCB5O1xuXG4gICAgbGV0IGVuY3RyeXBNZXRob2RJbnN0YW5jZTtcbiAgICBmb3IgKGxldCBpbmRleCA9IDA7IGluZGV4IDwgbGFzdEJsb2NrSW5kZXg7IGluZGV4KyspIHtcbiAgICAgIGVuY3RyeXBNZXRob2RJbnN0YW5jZSA9IG5ldyBhZXMuTW9kZU9mT3BlcmF0aW9uLmNiYyhrZXksIG5ldyBVaW50OEFycmF5KDE2KSk7XG4gICAgICB5ID0gdGhpcy54b3IoeCwgdGhpcy5nZXRNZXNzYWdlQmxvY2sobWVzc2FnZSwgaW5kZXgpKTtcbiAgICAgIGNvbnN0IHhFbmNyeXB0ZWQgPSBlbmN0cnlwTWV0aG9kSW5zdGFuY2UuZW5jcnlwdCh5KTtcbiAgICAgIGNvbnNvbGUubG9nKCdYIG5vcm1hbCA9PT09PT09PT09PT09PT0+ICcsIHRoaXMuYnl0ZXNUb2hleCh5KSk7XG4gICAgICBjb25zb2xlLmxvZygnWCBlbmNyeXB0ZWQgPT09PT09PT09PT09PT0+ICcsIHRoaXMuYnl0ZXNUb2hleCh4RW5jcnlwdGVkKSk7XG4gICAgICB4ID0gbmV3IEJ1ZmZlcih0aGlzLmJ5dGVzVG9oZXgoeEVuY3J5cHRlZCksICdoZXgnKTtcbiAgICB9XG4gICAgeSA9IHRoaXMueG9yKGxhc3RCbG9jaywgeCk7XG4gICAgZW5jdHJ5cE1ldGhvZEluc3RhbmNlID0gbmV3IGFlcy5Nb2RlT2ZPcGVyYXRpb24uY2JjKGtleSwgbmV3IFVpbnQ4QXJyYXkoMTYpKTtcbiAgICBjb25zdCB5RW5jcnlwdGVkID0gZW5jdHJ5cE1ldGhvZEluc3RhbmNlLmVuY3J5cHQoeSk7XG4gICAgY29uc29sZS5sb2coJ1kgbm9ybWFsID09PT09PT09PT09PT09PiAnLCB0aGlzLmJ5dGVzVG9oZXgoeSkpO1xuICAgIGNvbnNvbGUubG9nKCdZIGVuY3J5cHRlZCA9PT09PT09PT09PT09PT4gJywgdGhpcy5ieXRlc1RvaGV4KHlFbmNyeXB0ZWQpKTtcbiAgICByZXR1cm4geUVuY3J5cHRlZDtcbiAgfVxuXG4gIGdldE1lc3NhZ2VCbG9jayhtZXNzYWdlLCBibG9ja0luZGV4KSB7XG4gICAgY29uc3QgYmxvY2sgPSBuZXcgQnVmZmVyKDE2KTtcbiAgICBjb25zdCBzdGFydCA9IGJsb2NrSW5kZXggKiAxNjtcbiAgICBjb25zdCBlbmQgPSBzdGFydCArIDE2O1xuICAgIGxldCBibG9ja0kgPSAwO1xuICAgIGZvciAobGV0IGkgPSBzdGFydDsgaSA8IGVuZDsgaSsrKSB7XG4gICAgICBibG9ja1tibG9ja0ldID0gbWVzc2FnZVtpXTtcbiAgICAgIGJsb2NrSSsrO1xuICAgIH1cbiAgICByZXR1cm4gYmxvY2s7XG4gIH1cblxuICBnZXRQYWRkZWRNZXNzYWdlQmxvY2sobWVzc2FnZSwgYmxvY2tJbmRleCkge1xuICAgIGNvbnN0IGJsb2NrID0gbmV3IEJ1ZmZlcigxNik7XG4gICAgY29uc3Qgc3RhcnQgPSBibG9ja0luZGV4ICogMTY7XG4gICAgY29uc3QgZW5kID0gbWVzc2FnZS5sZW5ndGg7XG5cbiAgICBibG9jay5maWxsKDApO1xuICAgIGxldCBibG9ja0kgPSAwO1xuICAgIGZvciAobGV0IGkgPSBzdGFydDsgaSA8IGVuZDsgaSsrKSB7XG4gICAgICBibG9ja1tibG9ja0ldID0gbWVzc2FnZVtpXTtcbiAgICAgIGJsb2NrSSsrO1xuICAgIH1cbiAgICBibG9ja1tlbmQgLSBzdGFydF0gPSAweDgwO1xuXG4gICAgcmV0dXJuIGJsb2NrO1xuICB9XG5cbiAgYml0U2hpZnRMZWZ0KGJ1ZmZlcikge1xuICAgIGNvbnN0IHNoaWZ0ZWQgPSBuZXcgQnVmZmVyKGJ1ZmZlci5sZW5ndGgpO1xuICAgIGNvbnN0IGxhc3QgPSBidWZmZXIubGVuZ3RoIC0gMTtcbiAgICBmb3IgKGxldCBpbmRleCA9IDA7IGluZGV4IDwgbGFzdDsgaW5kZXgrKykge1xuICAgICAgLy8gdHNsaW50OmRpc2FibGUtbmV4dC1saW5lOm5vLWJpdHdpc2VcbiAgICAgIHNoaWZ0ZWRbaW5kZXhdID0gYnVmZmVyW2luZGV4XSA8PCAxO1xuICAgICAgLy8gdHNsaW50OmRpc2FibGUtbmV4dC1saW5lOm5vLWJpdHdpc2VcbiAgICAgIGlmIChidWZmZXJbaW5kZXggKyAxXSAmIDB4ODApIHtcbiAgICAgICAgc2hpZnRlZFtpbmRleF0gKz0gMHgwMTtcbiAgICAgIH1cbiAgICB9XG4gICAgLy8gdHNsaW50OmRpc2FibGUtbmV4dC1saW5lOm5vLWJpdHdpc2VcbiAgICBzaGlmdGVkW2xhc3RdID0gYnVmZmVyW2xhc3RdIDw8IDE7XG4gICAgcmV0dXJuIHNoaWZ0ZWQ7XG4gIH1cblxuICB4b3IoYnVmZmVyQSwgYnVmZmVyQikge1xuICAgIGNvbnN0IGxlbmd0aCA9IE1hdGgubWluKGJ1ZmZlckEubGVuZ3RoLCBidWZmZXJCLmxlbmd0aCk7XG4gICAgY29uc3Qgb3V0cHV0ID0gbmV3IEJ1ZmZlcihsZW5ndGgpO1xuICAgIGZvciAobGV0IGluZGV4ID0gMDsgaW5kZXggPCBsZW5ndGg7IGluZGV4KyspIHtcbiAgICAgIC8vIHRzbGludDpkaXNhYmxlLW5leHQtbGluZTpuby1iaXR3aXNlXG4gICAgICBvdXRwdXRbaW5kZXhdID0gYnVmZmVyQVtpbmRleF0gXiBidWZmZXJCW2luZGV4XTtcbiAgICB9XG4gICAgcmV0dXJuIG91dHB1dDtcbiAgfVxufVxuIl19