UNPKG

@nebulae/angular-ble

Version:

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

375 lines (374 loc) 39.9 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"; 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