@nebulae/angular-ble
Version:
A Web Bluetooth (Bluetooth Low Energy) module for angular (v2+)
1,734 lines • 180 kB
JavaScript
(function (global, factory) {
typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('@angular/core'), require('aes-js'), require('rxjs/operators'), require('rxjs'), require('@angular/common')) :
typeof define === 'function' && define.amd ? define('@nebulae/angular-ble', ['exports', '@angular/core', 'aes-js', 'rxjs/operators', 'rxjs', '@angular/common'], factory) :
(factory((global.nebulae = global.nebulae || {}, global.nebulae['angular-ble'] = {}),global.ng.core,null,global.rxjs.operators,global.rxjs,global.ng.common));
}(this, (function (exports,i0,aes,operators,rxjs,common) { 'use strict';
/**
* @fileoverview added by tsickle
* @suppress {checkTypes,extraRequire,uselessCode} checked by tsc
*/
var BrowserWebBluetooth = (function () {
function BrowserWebBluetooth() {
this._ble = navigator.bluetooth;
if (!this._ble) {
console.log('error cargando bluetooth');
// bluetoothService.setBluetoothAvailable(false);
// throw new Error('Your browser does not support Smart Bluetooth. See http://caniuse.com/#search=Bluetooth for more details.');
}
}
/**
* @param {?} options
* @return {?}
*/
BrowserWebBluetooth.prototype.requestDevice = /**
* @param {?} options
* @return {?}
*/
function (options) {
return this._ble.requestDevice(options);
};
BrowserWebBluetooth.decorators = [
{ type: i0.Injectable },
];
/** @nocollapse */
BrowserWebBluetooth.ctorParameters = function () { return []; };
return BrowserWebBluetooth;
}());
/*! *****************************************************************************
Copyright (c) Microsoft Corporation. All rights reserved.
Licensed under the Apache License, Version 2.0 (the "License"); you may not use
this file except in compliance with the License. You may obtain a copy of the
License at http://www.apache.org/licenses/LICENSE-2.0
THIS CODE IS PROVIDED ON AN *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY IMPLIED
WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE,
MERCHANTABLITY OR NON-INFRINGEMENT.
See the Apache Version 2.0 License for specific language governing permissions
and limitations under the License.
***************************************************************************** */
/* global Reflect, Promise */
var extendStatics = function (d, b) {
extendStatics = Object.setPrototypeOf ||
({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
function (d, b) { for (var p in b)
if (b.hasOwnProperty(p))
d[p] = b[p]; };
return extendStatics(d, b);
};
function __extends(d, b) {
extendStatics(d, b);
function __() { this.constructor = d; }
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
}
function __values(o) {
var m = typeof Symbol === "function" && o[Symbol.iterator], i = 0;
if (m)
return m.call(o);
return {
next: function () {
if (o && i >= o.length)
o = void 0;
return { value: o && o[i++], done: !o };
}
};
}
function __read(o, n) {
var m = typeof Symbol === "function" && o[Symbol.iterator];
if (!m)
return o;
var i = m.call(o), r, ar = [], e;
try {
while ((n === void 0 || n-- > 0) && !(r = i.next()).done)
ar.push(r.value);
}
catch (error) {
e = { error: error };
}
finally {
try {
if (r && !r.done && (m = i["return"]))
m.call(i);
}
finally {
if (e)
throw e.error;
}
}
return ar;
}
/**
* @fileoverview added by tsickle
* @suppress {checkTypes,extraRequire,uselessCode} checked by tsc
*/
/** @type {?} */
var GattServices = {
GENERIC_ACCESS: {
SERVICE: 'generic_access',
DEVICE_NAME: 'device_name',
APPEARANCE: 'appearance',
PRIVACY_FLAG: 'privacy_flag',
RECONNECTION_ADDRESS: 'reconnection_address',
PERIPHERAL_PREFERRED_CONNECTION_PARAMETERS: 'peripheral_preferred_connection_parameters'
},
BATTERY: {
SERVICE: 'battery_service',
BATTERY_LEVEL: 'battery_level'
},
DEVICE_INFORMATION: {
SERVICE: 'device_information',
MANUFACTURER_NAME: 'manufacturer_name_string',
MODEL_NUMBER: 'model_number_string',
SERIAL_NUMBER: 'serial_number_string',
HARDWARE_REVISION: 'hardware_revision_string',
FIRMWARE_REVISION: 'firmware_revision_string',
SOFTWARE_REVISION: 'software_revision_string',
SYSTEM_ID: 'system_id',
PNP_ID: 'pnp_id'
}
};
/** @type {?} */
var GATT_SERVICES = Object.keys(GattServices).map(function (key) { return GattServices[key].SERVICE; });
/**
* @fileoverview added by tsickle
* @suppress {checkTypes,extraRequire,uselessCode} checked by tsc
*/
var CypherAesService = (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: i0.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;
}());
/**
* @fileoverview added by tsickle
* @suppress {checkTypes,extraRequire,uselessCode} checked by tsc
*/
var ConsoleLoggerService = (function () {
function ConsoleLoggerService() {
}
/**
* @param {...?} args
* @return {?}
*/
ConsoleLoggerService.prototype.log = /**
* @param {...?} args
* @return {?}
*/
function () {
var args = [];
for (var _i = 0; _i < arguments.length; _i++) {
args[_i] = arguments[_i];
}
console.log.apply(console, args);
};
/**
* @param {...?} args
* @return {?}
*/
ConsoleLoggerService.prototype.error = /**
* @param {...?} args
* @return {?}
*/
function () {
var args = [];
for (var _i = 0; _i < arguments.length; _i++) {
args[_i] = arguments[_i];
}
console.error.apply(console, args);
};
/**
* @param {...?} args
* @return {?}
*/
ConsoleLoggerService.prototype.warn = /**
* @param {...?} args
* @return {?}
*/
function () {
var args = [];
for (var _i = 0; _i < arguments.length; _i++) {
args[_i] = arguments[_i];
}
console.warn.apply(console, args);
};
ConsoleLoggerService.decorators = [
{ type: i0.Injectable, args: [{
providedIn: 'root'
},] },
];
/** @nocollapse */ ConsoleLoggerService.ngInjectableDef = i0.defineInjectable({ factory: function ConsoleLoggerService_Factory() { return new ConsoleLoggerService(); }, token: ConsoleLoggerService, providedIn: "root" });
return ConsoleLoggerService;
}());
var NoLoggerService = (function () {
function NoLoggerService() {
}
/**
* @param {...?} args
* @return {?}
*/
NoLoggerService.prototype.log = /**
* @param {...?} args
* @return {?}
*/
function () {
var args = [];
for (var _i = 0; _i < arguments.length; _i++) {
args[_i] = arguments[_i];
}
};
/**
* @param {...?} args
* @return {?}
*/
NoLoggerService.prototype.error = /**
* @param {...?} args
* @return {?}
*/
function () {
var args = [];
for (var _i = 0; _i < arguments.length; _i++) {
args[_i] = arguments[_i];
}
};
/**
* @param {...?} args
* @return {?}
*/
NoLoggerService.prototype.warn = /**
* @param {...?} args
* @return {?}
*/
function () {
var args = [];
for (var _i = 0; _i < arguments.length; _i++) {
args[_i] = arguments[_i];
}
};
NoLoggerService.decorators = [
{ type: i0.Injectable, args: [{
providedIn: 'root'
},] },
];
/** @nocollapse */ NoLoggerService.ngInjectableDef = i0.defineInjectable({ factory: function NoLoggerService_Factory() { return new NoLoggerService(); }, token: NoLoggerService, providedIn: "root" });
return NoLoggerService;
}());
/**
* @fileoverview added by tsickle
* @suppress {checkTypes,extraRequire,uselessCode} checked by tsc
*/
var BluetoothService = (function (_super) {
__extends(BluetoothService, _super);
function BluetoothService(_webBle, cypherAesService, _console) {
var _this = _super.call(this) || this;
_this._webBle = _webBle;
_this.cypherAesService = cypherAesService;
_this._console = _console;
_this.serviceCharacteristicVsSubscriptionList = {};
_this.notifierSubject = new rxjs.Subject();
_this.notifierStartedSubject = new rxjs.Subject();
_this.bluetoothAvailable = false;
_this._device$ = new i0.EventEmitter();
if (_webBle._ble) {
_this.bluetoothAvailable = true;
}
return _this;
}
/**
* @return {?}
*/
BluetoothService.prototype.isBluetoothAvailable = /**
* @return {?}
*/
function () {
return this.bluetoothAvailable;
};
/**
* get the current device, if the device return null is because the connection has lost
* @returns the current connceted device
*/
/**
* get the current device, if the device return null is because the connection has lost
* @return {?} the current connceted device
*/
BluetoothService.prototype.getDevice$ = /**
* get the current device, if the device return null is because the connection has lost
* @return {?} the current connceted device
*/
function () {
return this._device$;
};
/**
* @return {?}
*/
BluetoothService.prototype.getNotifierStartedSubject$ = /**
* @return {?}
*/
function () {
return this.notifierStartedSubject;
};
/**
* start a stream by notifiers characteristics
* @param service The service to which the characteristic belongs
* @param characteristic The characteristic whose value you want to listen
* @param options object that contains the
* startByte:number (required), stopByte:number (required),
* lengthPosition: { start: number, end: number, lengthPadding: number } (required)
* @returns A DataView than contains the characteristic value
*/
/**
* start a stream by notifiers characteristics
* @param {?} service The service to which the characteristic belongs
* @param {?} characteristic The characteristic whose value you want to listen
* @param {?} options object that contains the
* startByte:number (required), stopByte:number (required),
* lengthPosition: { start: number, end: number, lengthPadding: number } (required)
* @return {?} A DataView than contains the characteristic value
*/
BluetoothService.prototype.startNotifierListener$ = /**
* start a stream by notifiers characteristics
* @param {?} service The service to which the characteristic belongs
* @param {?} characteristic The characteristic whose value you want to listen
* @param {?} options object that contains the
* startByte:number (required), stopByte:number (required),
* lengthPosition: { start: number, end: number, lengthPadding: number } (required)
* @return {?} A DataView than contains the characteristic value
*/
function (service, characteristic, options) {
var _this = this;
return rxjs.defer(function () {
rxjs.of(service)
.pipe(operators.tap(function () { return _this._console.log('Inicia el notifier con la instancia: ', _this.serviceCharacteristicVsSubscriptionList); }), operators.filter(function (_) {
return Object.keys(_this.serviceCharacteristicVsSubscriptionList).indexOf(service + "-" + characteristic) === -1;
}))
.subscribe(function () {
_this.serviceCharacteristicVsSubscriptionList[service + "-" + characteristic] =
_this.buildNotifierListener$(service, characteristic, options).subscribe(function (message) {
_this.notifierSubject.next(message);
});
}, function (err) {
_this._console.log('[BLE::Info] Error in notifier: ', err);
}, function () { });
return rxjs.of("notifier as subscribed: service= " + service + ", characteristic= " + characteristic);
});
};
/**
* @param {?} service
* @param {?} characteristic
* @return {?}
*/
BluetoothService.prototype.stopNotifierListener$ = /**
* @param {?} service
* @param {?} characteristic
* @return {?}
*/
function (service, characteristic) {
var _this = this;
return rxjs.defer(function () {
// this.serviceCharacteristicVsSubscriptionList[`${service}-${characteristic}`].unsubscribe();
delete _this.serviceCharacteristicVsSubscriptionList[service + "-" + characteristic];
return rxjs.of("the notifier of the characteristic " + characteristic + " as been stopped");
});
};
/**
* @param {?} service
* @param {?} characteristic
* @param {?} options
* @return {?}
*/
BluetoothService.prototype.buildNotifierListener$ = /**
* @param {?} service
* @param {?} characteristic
* @param {?} options
* @return {?}
*/
function (service, characteristic, options) {
var _this = this;
return this.getPrimaryService$(service).pipe(operators.tap(function (serviceInstance) { return _this._console.log("toma exitosamente el servicio ================> " + serviceInstance); }), operators.mergeMap(function (primaryService) {
return _this.getCharacteristic$(primaryService, characteristic)
.pipe(operators.tap(function (char) { return _this._console.log("toma exitosamente la caracteristica ================> " + char); }));
}), operators.mergeMap(function (char) {
return rxjs.defer(function () {
// enable the characteristic notifier
return char.startNotifications();
}).pipe(operators.retryWhen(function (error) {
return error.pipe(operators.tap(function () { return _this._console.log('ERROR EN EL startNotifications ================> '); }), operators.delay(1000), operators.take(5));
}), operators.tap(function () {
_this.notifierStartedSubject.next(true);
_this._console.log("incia las notifiaciones de la caracteristica 2 ================> " + characteristic);
}), operators.mergeMap(function (_) {
// start the lister from the even characteristicvaluechanged to get all changes on the specific
// characteristic
return rxjs.fromEvent(char, 'characteristicvaluechanged').pipe(operators.takeUntil(rxjs.fromEvent(char, 'gattserverdisconnected')), operators.map(function (event) {
// get a event from the characteristic and map that
return {
startByteMatches: false,
stopByteMatches: false,
lengthMatches: false,
messageLength: 0,
timestamp: Date.now(),
data: Array.from(new Uint8Array(((((event.target))
.value)).buffer))
};
}), operators.scan(function (acc, value) {
acc.timestamp = acc.timestamp === 0 ? value.timestamp : acc.timestamp;
// if the current accumulator value is a valid message, then is restarted to get the next
// message
if ((acc.lengthMatches &&
acc.startByteMatches &&
acc.stopByteMatches)
|| acc.timestamp + 1000 < Date.now()) {
acc = {
startByteMatches: false,
stopByteMatches: false,
lengthMatches: false,
messageLength: 0,
timestamp: 0,
data: []
};
}
// validate the start byte
if (!acc.startByteMatches &&
value.data[0] === options.startByte) {
// get the message length using the start and end position
acc.messageLength =
new DataView(new Uint8Array(value.data.slice(options.lengthPosition.start, options.lengthPosition.end)).buffer).getInt16(0, false) +
(options.lengthPosition.lengthPadding
? options.lengthPosition.lengthPadding
: 0);
// valid that the initial byte was found
acc.startByteMatches = true;
}
if (!acc.stopByteMatches &&
value.data[value.data.length - 1] === options.stopByte) {
// valid that the end byte was found
acc.stopByteMatches = true;
}
if (acc.startByteMatches) {
// merge the new data bytes to the old bytes
acc.data = acc.data.concat(value.data);
}
acc.lengthMatches =
acc.startByteMatches &&
acc.stopByteMatches &&
acc.messageLength === acc.data.length;
return acc;
}, {
startByteMatches: false,
stopByteMatches: false,
lengthMatches: false,
messageLength: 0,
timestamp: 0,
data: []
}),
// only publish the complete and valid message
operators.filter(function (data) {
return data.lengthMatches &&
data.startByteMatches &&
data.stopByteMatches;
}),
// remove all custom data and publish the message data
operators.map(function (result) { return result.data; }));
}));
}));
};
/**
* Send a request to the device and wait a unique response
* @param message Message to send
* @param service The service to which the characteristic belongs
* @param characteristic The characteristic whose value you want to send the message
* @param responseType filter to use to identify the response, Sample: [{position: 3, byteToMatch: 0x83},
* {position: 13, byteToMatch: 0x45}]
* @param cypherMasterKey master key to decrypt the message, only use this para if the message to receive is encrypted
*/
/**
* Send a request to the device and wait a unique response
* @param {?} message Message to send
* @param {?} service The service to which the characteristic belongs
* @param {?} characteristic The characteristic whose value you want to send the message
* @param {?} responseType filter to use to identify the response, Sample: [{position: 3, byteToMatch: 0x83},
* {position: 13, byteToMatch: 0x45}]
* @param {?=} cypherMasterKey master key to decrypt the message, only use this para if the message to receive is encrypted
* @return {?}
*/
BluetoothService.prototype.sendAndWaitResponse$ = /**
* Send a request to the device and wait a unique response
* @param {?} message Message to send
* @param {?} service The service to which the characteristic belongs
* @param {?} characteristic The characteristic whose value you want to send the message
* @param {?} responseType filter to use to identify the response, Sample: [{position: 3, byteToMatch: 0x83},
* {position: 13, byteToMatch: 0x45}]
* @param {?=} cypherMasterKey master key to decrypt the message, only use this para if the message to receive is encrypted
* @return {?}
*/
function (message, service, characteristic, responseType, cypherMasterKey) {
this._console.log('[BLE::Info] Send message to device: ', this.cypherAesService.bytesTohex(message));
return rxjs.forkJoin(this.subscribeToNotifierListener(responseType, cypherMasterKey).pipe(operators.take(1)), this.sendToNotifier$(message, service, characteristic)).pipe(operators.map(function (_a) {
var _b = __read(_a, 2), messageResp = _b[0], _ = _b[1];
return messageResp;
}), operators.timeout(3000));
};
/**
* Subscribe to the notifiers filtering by byte checking
* @param filterOptions must specific the position and the byte to match Sample:
* [{position: 3, byteToMatch: 0x83}, {position: 13, byteToMatch: 0x45}]
* @param cypherMasterKey master key to decrypt the message, only use this para if the message to receive is encrypted
*/
/**
* Subscribe to the notifiers filtering by byte checking
* @param {?} filterOptions must specific the position and the byte to match Sample:
* [{position: 3, byteToMatch: 0x83}, {position: 13, byteToMatch: 0x45}]
* @param {?=} cypherMasterKey master key to decrypt the message, only use this para if the message to receive is encrypted
* @return {?}
*/
BluetoothService.prototype.subscribeToNotifierListener = /**
* Subscribe to the notifiers filtering by byte checking
* @param {?} filterOptions must specific the position and the byte to match Sample:
* [{position: 3, byteToMatch: 0x83}, {position: 13, byteToMatch: 0x45}]
* @param {?=} cypherMasterKey master key to decrypt the message, only use this para if the message to receive is encrypted
* @return {?}
*/
function (filterOptions, cypherMasterKey) {
var _this = this;
return this.notifierSubject.pipe(operators.map(function (messageUnformated) {
/** @type {?} */
var messageFormmated = (messageUnformated);
// validate if the message is cyphered
if (cypherMasterKey) {
/** @type {?} */
var datablockLength = new DataView(new Uint8Array(messageFormmated.slice(1, 3)).buffer).getInt16(0, false);
_this.cypherAesService.config(cypherMasterKey);
/** @type {?} */
var datablock = Array.from(_this.cypherAesService.decrypt(((messageUnformated)).slice(3, datablockLength + 3)));
// merge the datablock and the message
messageFormmated = ((messageUnformated))
.slice(0, 3)
.concat(datablock)
.concat(((messageUnformated)).slice(-2));
}
_this._console.log('[BLE::Info] Notification reived from device: ', _this.cypherAesService.bytesTohex(messageFormmated));
return messageFormmated;
}),
// filter the message using the filter options
operators.filter(function (message) {
/** @type {?} */
var availableMessage = false;
try {
for (var filterOptions_1 = __values(filterOptions), filterOptions_1_1 = filterOptions_1.next(); !filterOptions_1_1.done; filterOptions_1_1 = filterOptions_1.next()) {
var option = filterOptions_1_1.value;
if (message[option.position] === option.byteToMatch) {
availableMessage = true;
}
else {
availableMessage = false;
break;
}
}
}
catch (e_1_1) {
e_1 = { error: e_1_1 };
}
finally {
try {
if (filterOptions_1_1 && !filterOptions_1_1.done && (_a = filterOptions_1.return))
_a.call(filterOptions_1);
}
finally {
if (e_1)
throw e_1.error;
}
}
return availableMessage;
var e_1, _a;
}));
};
/**
* Start a request to the browser to list all available bluetooth devices
* @param {?=} options Options to request the devices the structure is:
* acceptAllDevices: true|false
* filters: BluetoothDataFilterInit (see https://webbluetoothcg.github.io/web-bluetooth/#dictdef-bluetoothlescanfilterinit for more info)
* optionalServices: [] (services that are going to be used in
* communication with the device, must use the UIID or GATT identfier to list ther services)
* @return {?}
*/
BluetoothService.prototype.discoverDevice$ = /**
* Start a request to the browser to list all available bluetooth devices
* @param {?=} options Options to request the devices the structure is:
* acceptAllDevices: true|false
* filters: BluetoothDataFilterInit (see https://webbluetoothcg.github.io/web-bluetooth/#dictdef-bluetoothlescanfilterinit for more info)
* optionalServices: [] (services that are going to be used in
* communication with the device, must use the UIID or GATT identfier to list ther services)
* @return {?}
*/
function (options) {
var _this = this;
if (options === void 0) {
options = /** @type {?} */ ({});
}
return rxjs.defer(function () { return _this._webBle.requestDevice(options); }).pipe(operators.mergeMap(function (device) {
_this.device = device;
_this._device$.emit(device);
return _this.configureDeviceDisconnection$(device).pipe(operators.mapTo(device));
}));
};
/**
* @param {?} device
* @return {?}
*/
BluetoothService.prototype.configureDeviceDisconnection$ = /**
* @param {?} device
* @return {?}
*/
function (device) {
var _this = this;
return rxjs.Observable.create(function (observer) {
rxjs.of(device)
.pipe(operators.mergeMap(function (dev) { return rxjs.fromEvent(device, 'gattserverdisconnected'); }), operators.take(1))
.subscribe(function () {
_this._console.log('Se desconecta disp en OnDevice disconnected!!!!!!!');
_this.device = null;
_this._device$.emit(null);
}, function (err) {
_this._console.log('[BLE::Info] Error in notifier: ', err);
observer.error(err);
}, function () {
});
observer.next("DisconnectionEvent as been register");
});
};
/**
* Discover all available devices and connect to a selected device
* @param options Options to request the devices the structure is:
* acceptAllDevices: true|false
* filters: BluetoothDataFilterInit (see https://webbluetoothcg.github.io/web-bluetooth/#dictdef-bluetoothlescanfilterinit for more info)
* optionalServices: [] (services that are going to be used in
* communication with the device, must use the UIID or GATT identfier to list ther services)
* @returns the connected device
*/
/**
* Discover all available devices and connect to a selected device
* @param {?=} options Options to request the devices the structure is:
* acceptAllDevices: true|false
* filters: BluetoothDataFilterInit (see https://webbluetoothcg.github.io/web-bluetooth/#dictdef-bluetoothlescanfilterinit for more info)
* optionalServices: [] (services that are going to be used in
* communication with the device, must use the UIID or GATT identfier to list ther services)
* @return {?} the connected device
*/
BluetoothService.prototype.connectDevice$ = /**
* Discover all available devices and connect to a selected device
* @param {?=} options Options to request the devices the structure is:
* acceptAllDevices: true|false
* filters: BluetoothDataFilterInit (see https://webbluetoothcg.github.io/web-bluetooth/#dictdef-bluetoothlescanfilterinit for more info)
* optionalServices: [] (services that are going to be used in
* communication with the device, must use the UIID or GATT identfier to list ther services)
* @return {?} the connected device
*/
function (options) {
if (!options) {
options = {
acceptAllDevices: true,
optionalServices: []
};
}
else if (!options.optionalServices) {
options.optionalServices = [];
}
options.optionalServices.push(GattServices.GENERIC_ACCESS.SERVICE);
options.optionalServices.push(GattServices.BATTERY.SERVICE);
options.optionalServices.push(GattServices.DEVICE_INFORMATION.SERVICE);
return this.discoverDevice$(options).pipe(operators.mergeMap(function (device) {
return rxjs.defer(function () { return ((device)).gatt.connect(); });
}));
};
/**
* Disconnect the current device
*/
/**
* Disconnect the current device
* @return {?}
*/
BluetoothService.prototype.disconnectDevice = /**
* Disconnect the current device
* @return {?}
*/
function () {
if (this.device) {
this._console.log('se deconecta dispositivo');
this.device.gatt.disconnect();
}
};
/**
* get a data from the device using the characteristic
* @param service UUID or GATT identifier service
* @param characteristic UUID or GATT identifier characteristic
* @return The characteristic data in a DataView object
*/
/**
* get a data from the device using the characteristic
* @param {?} service UUID or GATT identifier service
* @param {?} characteristic UUID or GATT identifier characteristic
* @return {?} The characteristic data in a DataView object
*/
BluetoothService.prototype.readDeviceValue$ = /**
* get a data from the device using the characteristic
* @param {?} service UUID or GATT identifier service
* @param {?} characteristic UUID or GATT identifier characteristic
* @return {?} The characteristic data in a DataView object
*/
function (service, characteristic) {
var _this = this;
if (!this.device) {
throw new Error('Must start a connection to a device before read the device value');
}
return this.getPrimaryService$(service).pipe(operators.mergeMap(function (primaryService) {
return _this.getCharacteristic$(primaryService, characteristic);
}), operators.mergeMap(function (characteristicValue) {
return _this.readValue$(characteristicValue);
}));
};
/**
* write a value in the selected characteristic
* @param characteristic the characterisitc where you want write the value
* @param value value the value to write
*/
/**
* write a value in the selected characteristic
* @param {?} service
* @param {?} characteristic the characterisitc where you want write the value
* @param {?} value value the value to write
* @return {?}
*/
BluetoothService.prototype.writeDeviceValue$ = /**
* write a value in the selected characteristic
* @param {?} service
* @param {?} characteristic the characterisitc where you want write the value
* @param {?} value value the value to write
* @return {?}
*/
function (service, characteristic, value) {
var _this = this;
if (!this.device) {
throw new Error('Must start a connection to a device before read the device value');
}
return this.getPrimaryService$(service).pipe(operators.mergeMap(function (primaryService) {
return _this.getCharacteristic$(primaryService, characteristic);
}), operators.mergeMap(function (characteristicValue) {
return _this.writeValue$(characteristicValue, value);
}));
};
/**
* get a primary service instance using the service UIID or GATT identifier
* @param service service identifier
* @return service instance
*/
/**
* get a primary service instance using the service UIID or GATT identifier
* @param {?} service service identifier
* @return {?} service instance
*/
BluetoothService.prototype.getPrimaryService$ = /**
* get a primary service instance using the service UIID or GATT identifier
* @param {?} service service identifier
* @return {?} service instance
*/
function (service) {
return rxjs.of(this.device).pipe(operators.mergeMap(function (device) {
return device.gatt.getPrimaryService(service);
}));
};
/**
* Get a characterisitic instance using the service instance and a characteristic UUID
* @param primaryService service instance
* @param characteristic characterisitic identifier
* @return characteristic instance
*/
/**
* Get a characterisitic instance using the service instance and a characteristic UUID
* @param {?} primaryService service instance
* @param {?} characteristic characterisitic identifier
* @return {?} characteristic instance
*/
BluetoothService.prototype.getCharacteristic$ = /**
* Get a characterisitic instance using the service instance and a characteristic UUID
* @param {?} primaryService service instance
* @param {?} characteristic characterisitic identifier
* @return {?} characteristic instance
*/
function (primaryService, characteristic) {
return rxjs.defer(function () { return primaryService.getCharacteristic(characteristic); });
};
/**
* read the characteristic value
* @param {?} characteristic characteristic instance
* @return {?} The characteristic data in a DataView object
*/
BluetoothService.prototype.readValue$ = /**
* read the characteristic value
* @param {?} characteristic characteristic instance
* @return {?} The characteristic data in a DataView object
*/
function (characteristic) {
return rxjs.from(characteristic
.readValue()
.then(function (data) { return Promise.resolve(data); }, function (error) { return Promise.reject("" + error.message); }));
};
/**
* write a value in the selected characteristic
* @param {?} characteristic the characterisitc where you want write the value
* @param {?} value the value to write
* @return {?}
*/
BluetoothService.prototype.writeValue$ = /**
* write a value in the selected characteristic
* @param {?} characteristic the characterisitc where you want write the value
* @param {?} value the value to write
* @return {?}
*/
function (characteristic, value) {
return rxjs.defer(function () {
return characteristic
.writeValue(value);
});
};
/**
* change the state of the characteristic to enable it
* @param service parent service of the characteristic
* @param characteristic characteristic to change the state
* @param state new state
*/
/**
* change the state of the characteristic to enable it
* @param {?} service parent service of the characteristic
* @param {?} characteristic characteristic to change the state
* @param {?=} state new state
* @return {?}
*/
BluetoothService.prototype.enableCharacteristic$ = /**
* change the state of the characteristic to enable it
* @param {?} service parent service of the characteristic
* @param {?} characteristic characteristic to change the state
* @param {?=} state new state
* @return {?}
*/
function (service, characteristic, state) {
state = state || new Uint8Array([1]);
return this.setCharacteristicState$(service, characteristic, state);
};
/**
* change the state of the characteristic to disable it
* @param service parent service of the characteristic
* @param characteristic characteristic to change the state
* @param state new state
*/
/**
* change the state of the characteristic to disable it
* @param {?} service parent service of the characteristic
* @param {?} characteristic characteristic to change the state
* @param {?=} state new state
* @return {?}
*/
BluetoothService.prototype.disbaleCharacteristic$ = /**
* change the state of the characteristic to disable it
* @param {?} service parent service of the characteristic
* @param {?} characteristic characteristic to change the state
* @param {?=} state new state
* @return {?}
*/
function (service, characteristic, state) {
state = state || new Uint8Array([0]);
return this.setCharacteristicState$(service, characteristic, state);
};
/**
* set a state to an specific characteristic
* @param service parent service of the characteristic
* @param characteristic characteristic to change the state
* @param state new state
* @return
*/
/**
* set a state to an specific characteristic
* @param {?} service parent service of the characteristic
* @param {?} characteristic characteristic to change the state
* @param {?} state new state
* @return {?}
*/
BluetoothService.prototype.setCharacteristicState$ = /**
* set a state to an specific characteristic
* @param {?} service parent service of the characteristic
* @param {?} characteristic characteristic to change the state
* @param {?} state new state
* @return {?}
*/
function (service, characteristic, state) {
var _this = this;
/** @type {?} */
var primaryService = this.getPrimaryService$(service);
return primaryService.pipe(operators.mergeMap(function (_primaryService) {
return _this.getCharacteristic$(_primaryService, characteristic);
}), operators.map(function (_characteristic) {
return _this.writeValue$(_characteristic, state);
}));
};
/**
* Send a message using a notifier characteristic
* @param message message to send
* @param service service to which the characteristic belongs
* @param characteristic feature in which you want to send the notification
*/
/**
* Send a message using a notifier characteristic
* @param {?} message message to send
* @param {?} service service to which the characteristic belongs
* @param {?} characteristic feature in which you want to send the notification
* @return {?}
*/
BluetoothService.prototype.sendToNotifier$ = /**
* Send a message using a notifier characteristic
* @param {?} message message to send
* @param {?} service service to which the characteristic belongs
* @param {?} characteristic feature in which you want to send the notification
* @return {?}
*/
function (message, service, characteristic) {
var _this = this;
return this.getPrimaryService$(service).pipe(operators.mergeMap(function (primaryService) {
return _this.getCharacteristic$(primaryService, characteristic);
}), operators.mergeMap(function (char) {
if (message.length > 16) {
/** @type {?} */
var obsTest = rxjs.of(undefined);
while (message.length > 16) {
obsTest = obsTest.pipe(operators.concat(_this.writeValue$(char, message.slice(0, 16))));
message = message.slice(16, message.length);
}
if (message.length > 0) {
obsTest = obsTest.pipe(operators.concat(_this.writeValue$(char, message)));
}
return obsTest;
}
else {
return _this.writeValue$(char, message);
}
}));
};
/**
* The Battery Level characteristic is read using the GATT Read Characteristic
* Value sub-procedure and returns the current battery level as a percentage
* from 0% to 100%; 0% represents a battery that is fully discharged, 100%
* represents a battery that is fully charged
*/
/**
* The Battery Level characteristic is read using the GATT Read Characteristic
* Value sub-procedure and returns the current battery level as a percentage
* from 0% to 100%; 0% represents a battery that is fully discharged, 100%
* represents a battery that is fully charged
* @return {?}
*/
BluetoothService.prototype.getBatteryLevel$ = /**
* The Battery Level characteristic is read using the GATT Read Characteristic
* Value sub-procedure and returns the current battery level as a percentage
* from 0% to 100%; 0% represents a battery that is fully discharged, 100%
* represents a battery that is fully charged
* @return {?}
*/
function () {
return this.readDeviceValue$(GattServices.BATTERY.SERVICE, GattServices.BATTERY.BATTERY_LEVEL).pipe(operators.map(function (value) { return value.getUint8(0); }));
};
/**
* This characteristic represents the name of the manufacturer of the device.
*/
/**
* This characteristic represents the name of the manufacturer of the device.
* @return {?}
*/
BluetoothService.prototype.getManufacturerName$ = /**
* This characteristic represents the name of the manufacturer of the device.
* @return {?}
*/
function () {
var _this = this;
return this.readDeviceValue$(GattServices.DEVICE_INFORMATION.SERVICE, GattServices.DEVICE_INFORMATION.MANUFACTURER_NAME).pipe(operators.map(function (dataView) {
return _this.cypherAesService.bytesToText(new Uint8Array(dataView.buffer));
}));
};
/**
* This characteristic represents the model number that is assigned by the device vendor.
*/
/**
* This characteristic represents the model number that is assigned by the device vendor.
* @return {?}
*/
BluetoothService.prototype.getModelNumber$ = /**
* This characteristic represents the model number that is assigned by the device vendor.
* @return {?}
*/
function () {
var _this = this;
return this.readDeviceValue$(GattServices.DEVICE_INFORMATION.SERVICE, GattServices.DEVICE_INFORMATION.MODEL_NUMBER).pipe(operators.map(function (dataView) {
return _this.cypherAesService.bytesToText(new Uint8Array(dataView.buffer));
}));
};
/**
* This characteristic represents the serial number for a particular instance of the device.
*/
/**
* This characteristic represents the serial number for a particular instance of the device.
* @return {?}
*/
BluetoothService.prototype.getSerialNumber$ = /**
* This characteristic represents the serial number for a particular instance of the device.
* @return {?}
*/
function () {
var _this = this;
return this.readDeviceValue$(GattServices.DEVICE_INFORMATION.SERVICE, GattServices.DEVICE_INFORMATION.SERIAL_NUMBER).pipe(operators.map(function (dataView) {
return _this.cypherAesService.bytesToText(new Uint8Array(dataView.buffer));
}));
};
/**
* This characteristic represents the hardware revision for the hardware within the device.
*/
/**
* This characteristic represents the hardware revision for the hardware within the device.
* @return {?}
*/
BluetoothService.prototype.getHardwareRevision$ = /**
* This characteristic represents the hardware revision for the hardware within the device.
* @return {?}
*/
function () {
var _this = this;
return this.readDeviceValue$(GattServices.DEVICE_INFORMATION.SERVICE, GattServices.DEVICE_INFORMATION.HARDWARE_REVISION).pipe(operators.map(function (dataView) {
return _this.cypherAesService.bytesToText(new Uint8Array(dataView.buffer));
}));
};
/**
* This characteristic represents the firmware revision for the firmware within the device.
*/
/**
* This characteristic represents the firmware revision for the firmware within the device.
* @return {?}
*/
BluetoothService.prototype.getFirmwareRevision$ = /**
* This characteristic represents the firmware revision for the firmware within the device.
* @return {?}
*/
function () {
var _this = this;
return this.readDeviceValue$(GattServices.DEVICE_INFORMATION.SERVICE, GattServices.DEVICE_INFORMATION.FIRMWARE_REVISION).pipe(operators.map(function (dataView) {
return _this.cypherAesService.bytesToText(new Uint8Array(dataView.buffer));
}));
};
/**
* This characteristic represents the software revision for the software within the device.
*/
/**
* This characteristic represents the software revision for the software within the device.
* @return {?}
*/
BluetoothService.prototype.getSoftwareRevision$ = /**
* This characteristic represents the software revision for the software within the device.
* @return {?}
*/
function () {
var _this = this;
return this.readDeviceValue$(GattServices.DEVICE_INFORMATION.SERVICE, GattServices.DEVICE_INFORMATION.SOFTWARE_REVISION).pipe(operators.map(function (dataView) {
return _this.cypherAesService.bytesToText(new Uint8Array(dataView.buffer));
}));
};
/**
* This characteristic represents a structure containing an Organizationally Unique Identifier
* (OUI) followed by a manufacturer-defined identifier and is unique for each individual instance of the product.
*/
/**
* This characteristic represents a structure containing an Organizationally Unique Identifier
* (OUI) followed by a manufacturer-defined identifier and is unique for each individual instance of the product.
* @return {?}
*/
BluetoothService.prototype.getSystemId$ = /**
* This characteristic represents a structure containing an Organizationally Unique Identifier
* (OUI) followed by a manufacturer-defined identifier and is unique for each individual instance of the product.
* @return {?}
*/
function () {
return this.readDeviceValue$(GattServices.DEVICE_INFORMATION.SERVICE, GattServices.DEVICE_INFORMATION.SYSTEM_ID);
};
/**
* The PnP_ID characteristic is a set of values used to create a device ID value that is unique for this device.
*/
/**
* The PnP_ID characteristic is a set of values used to create a device ID value that is unique for this device.
* @return {?}
*/
BluetoothService.prototype.getPnpId$ = /**
* The PnP_ID characteristic is a set of values used to create a device ID value that is unique for this device.
* @return {?}
*/
function () {
return this.readDeviceValue$(GattServices.DEVICE_INFORMATION.SERVICE, GattServices.DEVICE_INFORMATION.PNP_ID);
};
BluetoothService.decorators = [
{ type: i0.Injectable, args: [{
providedIn: 'root'
},] },
];
/** @nocollapse */
BluetoothService.ctorParameters = function () {
return [
{ type: BrowserWebBluetooth },
{ type: CypherAesService },
{ type: ConsoleLoggerService }
];
};
/** @nocollapse */ BluetoothService.ngInjectableDef = i0.defineInjectable({ factory: function BluetoothService_Factory() { return new BluetoothService(i0.inject(BrowserWebBluetooth), i0.inject(CypherAesService), i0.inject(ConsoleLoggerService)); }, token: BluetoothService, providedIn: "root" });
return BluetoothService;
}(rxjs.Subject));
/**
* @fileoverview added by tsickle
* @suppress {checkTypes,extraRequire,uselessCode} checked by tsc
*/
/**
* @return {?}
*/
function browserWebBluetooth() {
return new BrowserWebBluetooth();
}
/**
* @param {?} options
* @return {?}
*/
function consoleLoggerServiceConfig(options) {
if (options && options.enableTracing) {
return new ConsoleLoggerService();
}
else {
return new NoLoggerService();
}
}
/**
* @return {?}
*/
function makeMeTokenInjector() {
return new i0.InjectionToken('AWBOptions');
}
var AngularBleModule = (function () {
function AngularBleModule() {
}
/**
* @param {?=} options
* @return {?}
*/
AngularBleModule.forRoot = /**
* @param {?=} options
* @return {?}
*/
function (options) {
if (options === void 0) {
options = {};
}
return {
ngModule: AngularBleModule,
providers: [
BluetoothService,
{
provide: BrowserWebBluetooth,
useFactory: browserWebBluetooth
},
{
provide: makeMeTokenInjector,
useValue: options
},
{
provide: ConsoleLoggerService,
useFactory: consoleLoggerServiceConfig,
deps: [makeMeTokenInjector]
}
]
};
};
AngularBleModule.decorators = [
{ type: i0.NgModule, args: [{
imports: [common.CommonModule]
},] },
];
return AngularBleModule;
}());
/**
* @fileoverview added by tsickle
* @suppress {checkTypes,extraRequire,uselessCode} checked by tsc
*/
/**
* @fileoverview added by tsickle
* @suppress {checkTypes,extraRequire,uselessCode} checked by tsc
*/
exports.BrowserWebBluetooth = BrowserWebBluetooth;
exports.browserWebBluetooth = browserWebBluetooth;
exports.consoleLoggerServiceConfig = consoleLoggerServiceConfig;
exports.makeMeTokenInjector = makeMeTokenInjector;
exports.AngularBleModule = AngularBleModule;
exports.CypherAesService = CypherAesService;
exports.BluetoothService = BluetoothService;
exports.ɵa = ConsoleLoggerService;
Object.defineProperty(exports, '__esModule', { value: true });
})));
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibmVidWxhZS1hbmd1bGFyLWJsZS51bWQuanMubWFwIiwic291cmNlcyI6WyJuZzovL0BuZWJ1bGFlL2FuZ3VsYXItYmxlL2xpYi9wbGF0Zm9ybS9icm93c2VyLnRzIixudWxsLCJuZzovL0BuZWJ1bGFlL2FuZ3VsYXItYmxlL2xpYi9ibHVldG9vdGgvZ2F0dC1zZXJ2aWNlcy50cyIsIm5nOi8vQG5lYnVsYWUvYW5ndWxhci1ibGUvbGliL2N5cGhlci9jeXBoZXItYWVzLnNlcnZpY2UudHMiLCJuZzovL0BuZWJ1bGFlL2FuZ3VsYXItYmxlL2xpYi9sb2dnZXIuc2VydmljZS50cyIsIm5nOi8vQG5lYnVsYWUvYW5ndWxhci1ibGUvbGliL2JsdWV0b290aC9ibHVldG9vdGguc2VydmljZS50cyIsIm5nOi8vQG5lYnVsYWUvYW5ndWxhci1ibGUvbGliL2FuZ3VsYXItYmxlLm1vZHVsZS50cyJdLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBJbmplY3RhYmxlIH0gZnJvbSAnQGFuZ3VsYXIvY29yZSc7XG5pbXBvcnQgeyBCbHVldG9vdGhTZXJ2aWNlIH0gZnJvbSAnLi4vYmx1ZXRvb3RoL2JsdWV0b290aC5zZXJ2aWNlJztcblxuQEluamVjdGFibGUoKVxuZXhwb3J0IGNsYXNzIEJyb3dzZXJXZWJCbHVldG9vdGgge1xuICBwdWJsaWMgX2JsZTtcblxuICBjb25zdHJ1Y3RvcigpIHtcbiAgICB0aGlzLl9ibGUgPSBuYXZpZ2F0b3IuYmx1ZXRvb3RoO1xuICAgIGlmICghdGhpcy5fYmxlKSB7XG4gICAgICBjb25zb2xlLmxvZygnZXJyb3IgY2FyZ2FuZG8gYmx1ZXRvb3RoJyk7XG4gICAgICAvLyBibHVldG9vdGhTZXJ2aWNlLnNldEJsdWV0b290aEF2YWlsYWJsZShmYWxzZSk7XG4gICAgICAvLyB0aHJvdyBuZXcgRXJyb3IoJ1lvdXIgYnJvd3NlciBkb2VzIG5vdCBzdXBwb3J0IFNtYXJ0IEJsdWV0b290aC4gU2VlIGh0dHA6Ly9jYW5pdXNlLmNvbS8jc2VhcmNoPUJsdWV0b290aCBmb3IgbW9yZSBkZXRhaWxzLicpO1xuICAgIH0gZWxzZSB7XG4gICAgICAvLyBibHVldG9vdGhTZXJ2aWNlLnNldEJsdWV0b290aEF2YWlsYWJsZSh0cnVlKTtcbiAgICB9XG4gIH1cblxuICByZXF1ZXN0RGV2aWNlKG9wdGlvbnM6IFJlcXVlc3REZXZpY2VPcHRpb25zKTogUHJvbWlzZTxCbHVldG9vdGhEZXZpY2U+IHtcbiAgICByZXR1cm4gdGhpcy5fYmxlLnJlcXVlc3REZXZpY2Uob3B0aW9ucyk7XG4gIH1cbn1cbiIsIi8qISAqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKlxyXG5Db3B5cmlnaHQgKGMpIE1pY3Jvc29mdCBDb3Jwb3JhdGlvbi4gQWxsIHJpZ2h0cyByZXNlcnZlZC5cclxuTGljZW5zZWQgdW5kZXIgdGhlIEFwYWNoZSBMaWNlbnNlLCBWZXJzaW9uIDIuMCAodGhlIFwiTGljZW5zZVwiKTsgeW91IG1heSBub3QgdXNlXHJcbnRoaXMgZmlsZSBleGNlcHQgaW4gY29tcGxpYW5jZSB3aXRoIHRoZSBMaWNlbnNlLiBZb3UgbWF5IG9idGFpbiBhIGNvcHkgb2YgdGhlXHJcbkxpY2Vuc2UgYXQgaHR0cDovL3d3dy5hcGFjaGUub3JnL2xpY2Vuc2VzL0xJQ0VOU0UtMi4wXHJcblxyXG5USElTIENPREUgSVMgUFJPVklERUQgT04gQU4gKkFTIElTKiBCQVNJUywgV0lUSE9VVCBXQVJSQU5USUVTIE9SIENPTkRJVElPTlMgT0YgQU5ZXHJcbktJTkQsIEVJVEhFUiBFWFBSRVNTIE9SIElNUExJRUQsIElOQ0xVRElORyBXSVRIT1VUIExJTUlUQVRJT04gQU5ZIElNUExJRURcclxuV0FSUkFOVElFUyBPUiBDT05ESVRJT05TIE9GIFRJVExFLCBGSVRORVNTIEZPUiBBIFBBUlRJQ1VMQVIgUFVSUE9TRSxcclxuTUVSQ0hBTlRBQkxJVFkgT1IgTk9OLUlORlJJTkdFTUVOVC5cclxuXHJcblNlZSB0aGUgQXBhY2hlIFZlcnNpb24gMi4wIExpY2Vuc2UgZm9yIHNwZWNpZmljIGxhbmd1YWdlIGdvdmVybmluZyBwZXJtaXNzaW9uc1xyXG5hbmQgbGltaXRhdGlvbnMgdW5kZXIgdGhlIExpY2Vuc2UuXHJcbioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqICovXHJcbi8qIGdsb2JhbCBSZWZsZWN0LCBQcm9taXNlICovXHJcblxyXG52YXIgZXh0ZW5kU3RhdGljcyA9IGZ1bmN0aW9uKGQsIGIpIHtcclxuICAgIGV4dGVuZFN0YXRpY3MgPSBPYmplY3Quc2V0UHJvdG90eXBlT2YgfHxcclxuICAgICAgICAoeyBfX3Byb3RvX186IFtdIH0gaW5zdGFuY2VvZiBBcnJheSAmJiBmdW5jdGlvbiAoZCwgYikgeyBkLl9fcHJvdG9fXyA9IGI7IH0pIHx8XHJcbiAgICAgICAgZnVuY3Rpb24gKGQsIGIpIHsgZm9yICh2YXIgcCBpbiBiKSBpZiAoYi5oYXNPd25Qcm9wZXJ0eShwKSkgZFtwXSA9IGJbcF07IH07XHJcbiAgICByZXR1cm4gZXh0ZW5kU3RhdGljcyhkLCBiKTtcclxufTtcclxuXHJcbmV4cG9ydCBmdW5jdGlvbiBfX2V4dGVuZHMoZCwgYikge1xyXG4gICAgZXh0ZW5kU3RhdGljcyhkLCBiKTtcclxuICAgIGZ1bmN0aW9uIF9fKCkgeyB0aGlzLmNvbnN0cnVjdG9yID0gZDsgfVxyXG4gICAgZC5wcm90b3R5cGUgPSBiID09PSBudWxsID8gT2JqZWN0LmNyZWF0ZShiKSA6IChfXy5wcm90b3R5cGUgPSBiLnByb3RvdHlwZSwgbmV3IF9fKCkpO1xyXG59XHJcblxyXG5leHBvcnQgdmFyIF9fYXNzaWduID0gZnVuY3Rpb24oKSB7XHJcbiAgICBfX2Fzc2lnbiA9IE9iamVjdC5hc3NpZ24gfHwgZnVuY3Rpb24gX19hc3NpZ24odCkge1xyXG4gICAgICAgIGZvciAodmFyIHMsIGkgPSAxLCBuID0gYXJndW1lbnRzLmxlbmd0aDsgaSA8IG47IGkrKykge1xyXG4gICAgICAgICAgICBzID0gYXJndW1lbnRzW2ldO1xyXG4gICAgICAgICAgICBmb3IgKHZhciBwIGluIHMpIGlmIChPYmplY3QucHJvdG90eXBlLmhhc093blByb3BlcnR5LmNhbGwocywgcCkpIHRbcF0gPSBzW3BdO1xyXG4gICAgICAgIH1cclxuICAgICAgICByZXR1cm4gdDtcclxuICAgIH1cclxuICAgIHJldHVybiBfX2Fzc2lnbi5hcHBseSh0aGlzLCBhcmd1bWVudHMpO1xyXG59XHJcblxyXG5leHBvcnQgZnVuY3Rpb24gX19yZXN0KHMsIGUpIHtcclxuICAgIHZhciB0ID0ge307XHJcbiAgICBmb3IgKHZhciBwIGluIHMpIGlmIChPYmplY3QucHJvdG90eXBlLmhhc093blByb3BlcnR5LmNhbGwocywgcCkgJiYgZS5pbmRleE9mKHApIDwgMClcclxuICAgICAgICB0W3BdID0gc1twXTtcclxuICAgIGlmIChzICE9IG51bGwgJiYgdHlwZW9mIE9iamVjdC5nZXRPd25Qcm9wZXJ0eVN5bWJvbHMgPT09IFwiZnVuY3Rpb25cIilcclxuICAgICAgICBmb3IgKHZhciBpID0gMCwgcCA9IE9iamVjdC5nZXRPd25Qcm9wZXJ0eVN5bWJvbHMocyk7IGkgPCBwLmxlbmd0aDsgaSsrKSBpZiAoZS5pbmRleE9mKHBbaV0pIDwgMClcclxuICAgICAgICAgICAgdFtwW2ldXSA9IHNbcFtpXV07XHJcbiAgICByZXR1cm4gdDtcclxufVxyXG5cclxuZXhwb3J0IGZ1bmN0aW9uIF9fZGVjb3JhdGUoZGVjb3JhdG9ycywgdGFyZ2V0LCBrZXksIGRlc2MpIHtcclxuICAgIHZhciBjID0gYXJndW1lbnRzLmxlbmd0aCwgciA9IGMgPCAzID8gdGFyZ2V0IDogZGVzYyA9PT0gbnVsbCA/IGRlc2MgPSBPYmplY3QuZ2V0T3duUHJvcGVydHlEZXNjcmlwdG9yKHRhcmdldCwga2V5KSA6IGRlc2MsIGQ7XHJcbiAgICBpZiAodHlwZW9mIFJlZmxlY3QgPT09IFwib2JqZWN0XCIgJiYgdHlwZW9mIFJlZmxlY3QuZGVjb3JhdGUgPT09IFwiZnVuY3Rpb25cIikgciA9IFJlZmxlY3QuZGVjb3JhdGUoZGVjb3JhdG9ycywgdGFyZ2V0LCBrZXksIGRlc2MpO1xyXG4gICAgZWxzZSBmb3IgKHZhciBpID0gZGVjb3JhdG9ycy5sZW5ndGggLSAxOyBpID49IDA7IGktLSkgaWYgKGQgPSBkZWNvcmF0b3JzW2ldKSByID0gKGMgPCAzID8gZChyKSA6IGMgPiAzID8gZCh0YXJnZXQsIGtleSwgcikgOiBkKHRhcmdldCwga2V5KSkgfHwgcjtcclxuICAgIHJldHVybiBjID4gMyAmJiByICYmIE9iamVjdC5kZWZpbmVQcm9wZXJ0eSh0YXJnZXQsIGtleSwgciksIHI7XHJcbn1cclxuXHJcbmV4cG9ydCBmdW5jdGlvbiBfX3BhcmFtKHBhcmFtSW5kZXgsIGRlY29yYXRvcikge1xyXG4gICAgcmV0dXJuIGZ1bmN0aW9uICh0YXJnZXQsIGtleSkgeyBkZWNvcmF0b3IodGFyZ2V0LCBrZXksIHBhcmFtSW5kZXgpOyB9XHJcbn1cclxuXHJcbmV4cG9ydCBmdW5jdGlvbiBfX21ldGFkYXRhKG1ldGFkYXRhS2V5LCBtZXRhZGF0YVZhbHVlKSB7XHJcbiAgICBpZiAodHlwZW9mIFJlZmxlY3QgPT09IFwib2JqZWN0XCIgJiYgdHlwZW9mIFJlZmxlY3QubWV0YWRhdGEgPT09IFwiZnVuY3Rpb25cIikgcmV0dXJuIFJlZmxlY3QubWV0YWRhdGEobWV0YWRhdGFLZXksIG1ldGFkYXRhVmFsdWUpO1xyXG59XHJcblxyXG5leHBvcnQgZnVuY3Rpb24gX19hd2FpdGVyKHRoaXNBcmcsIF9hcmd1bWVudHMsIFAsIGdlbmVyYXRvcikge1xyXG4gICAgcmV0dXJuIG5ldyAoUCB8fCAoUCA9IFByb21pc2UpKShmdW5jdGlvbiAocmVzb2x2ZSwgcmVqZWN0KSB7XHJcbiAgICAgICAgZnVuY3Rpb24gZnVsZmlsbGVkKHZhbHVlKSB7IHRyeSB7IHN0ZXAoZ2VuZXJhdG9yLm5leHQodmFsdWUpKTsgfSBjYXRjaCAoZSkgeyByZWplY3QoZSk7IH0gfVxyXG4gICAgICAgIGZ1bmN0aW9uIHJlamVjdGVkKHZhbHVlKSB7IHRyeSB7IHN0ZXAoZ2VuZXJhdG9yW1widGhyb3dcIl0odmFsdWUpKTsgfSBjYXRjaCAoZSkgeyByZWplY3QoZSk7IH0gfVxyXG4gICAgICAgIGZ1bmN0aW9uIHN0ZXAocmVzdWx0KSB7IHJlc3VsdC5kb25lID8gcmVzb2x2ZShyZXN1bHQudmFsdWUpIDogbmV3IFAoZnVuY3Rpb24gKHJlc29sdmUpIHsgcmVzb2x2ZShyZXN1bHQudmFsdWUpOyB9KS50aGVuKGZ1bGZpbGxlZCwgcmVqZWN0ZWQpOyB9XHJcbiAgICAgICAgc3RlcCgoZ2VuZXJhdG9yID0gZ2VuZXJhdG9yLmFwcGx5KHRoaXNBcmcsIF9hcmd1bWVudHMgfHwgW10pKS5uZXh0KCkpO1xyXG4gICAgfSk7XHJcbn1cclxuXHJcbmV4cG9ydCBmdW5jdGlvbiBfX2dlbmVyYXRvcih0aGlzQXJnLCBib2R5KSB7XHJcbiAgICB2YXIgXyA9IHsgbGFiZWw6IDAsIHNlbnQ6IGZ1bmN0aW9uKCkgeyBpZiAodFswXSAmIDEpIHRocm93IHRbMV07IHJldHVybiB0WzFdOyB9LCB0cnlzOiBbXSwgb3BzOiBbXSB9LCBmLCB5LCB0LCBnO1xyXG4gICAgcmV0dXJuIGcgPSB7IG5leHQ6IHZlcmIoMCksIFwidGhyb3dcIjogdmVyYigxKSwgXCJyZXR1cm5cIjogdmVyYigyKSB9LCB0eXBlb2YgU3ltYm9sID09PSBcImZ1bmN0aW9uXCIgJiYgKGdbU3ltYm9sLml0ZXJhdG9yXSA9IGZ1bmN0aW9uKCkgeyByZXR1cm4gdGhpczsgfSksIGc7XHJcbiAgICBmdW5jdGlvbiB2ZXJiKG4pIHsgcmV0dXJuIGZ1bmN0aW9uICh2KSB7IHJldHVybiBzdGVwKFtuLCB2XSk7IH07IH1cclxuICAgIGZ1bmN0aW9uIHN0ZXAob3ApIHtcclxuICAgICAgICBpZiAoZikgdGhyb3cgbmV3IFR5cGVFcnJvcihcIkdlbmVyYXRvciBpcyBhbHJlYWR5IGV4ZWN1dGluZy5cIik7XHJcbiAgICAgICAgd2hpbGUgKF8pIHRyeSB7XHJcbiAgICAgICAgICAgIGlmIChmID0gMSwgeSAmJiAodCA9IG9wWzBdICYgMiA/IHlbXCJyZXR1cm5cIl0gOiBvcFswXSA/IHlbXCJ0aHJvd1wiXSB8fCAoKHQgPSB5W1wicmV0dXJuXCJdKSAmJiB0LmNhbGwoeSksIDApIDogeS5uZXh0KSAmJiAhKHQgPSB0LmNhbGwoeSwgb3BbMV0pKS5kb25lKSByZXR1cm4gdDtcclxuICAgICAgICAgICAgaWYgKHkgPSAwLCB0KSBvcCA9IFtvcFswXSAmIDIsIHQudmFsdWVdO1xyXG4gICAgICAgICAgICBzd2l0Y2ggKG9wWzBdKSB7XHJcbiAgICAgICAgICAgICAgICBjYXNlIDA6IGNhc2UgMTogdCA9IG9wOyBicmVhaztcclxuICAgICAgICAgICAgICAgIGNhc2UgNDogXy5sYWJlbCsrOyByZXR1cm4geyB2YWx1ZTogb3BbMV0sIGRvbmU6IGZhbHNlIH07XHJcbiAgICAgICAgICAgICAgICBjYXNlIDU6IF8ubGFiZWwrKzsgeSA9IG9wWzFdOyBvcCA9IFswXTsgY29udGludWU7XHJcbiAgICAgICAgICAgICAgICBjYXNlIDc6IG9wID0gXy5vcHMucG9wKCk7IF8udHJ5cy5wb3AoKTsgY29udGludWU7XHJcbiAgICAgICAgICAgICAgICBkZWZhdWx0OlxyXG4gICAgICAgICAgICAgICAgICAgIGlmICghKHQgPSBfLnRyeXMsIHQgPSB0Lmxlbmd0aCA+IDAgJiYgdFt0Lmxlbmd0aCAtIDFdKSAmJiAob3BbMF0gPT09IDYgfHwgb3BbMF0gPT09IDIpKSB7IF8gPSAwOyBjb250aW51ZTsgfVxyXG4gICAgICAgICAgICAgICAgICAgIGlmIChvcFswXSA9PT0gMyAmJiAoIXQgfHwgKG9wWzFdID4gdFswXSAmJiBvcFsxXSA8IHRbM10pKSkgeyBfLmxhYmVsID0gb3BbMV07IGJyZWFrOyB9XHJcbiAgICAgICAgICAgICAgICAgICAgaWYgKG9wWzBdID09PSA2ICYmIF8ubGFiZWwgPCB0WzFdKSB7IF8ubGFiZWwgPSB0WzFdOyB0ID0gb3A7IGJyZWFrOyB9XHJcbiAgICAgICAgICAgICAgICAgICAgaWYgKHQgJiYgXy5sYWJlbCA8IHRbMl0pIHsgXy5sYWJlbCA9IHRbMl07IF8ub3BzLnB1c2gob3ApOyBicmVhazsgfVxyXG4gICAgICAgICAgICAgICAgICAgIGlmICh0WzJdKSBfLm9wcy5wb3AoKTtcclxuICAgICAgICAgICAgICAgICAgICBfLnRyeXMucG9wKCk7IGNvbnRpbnVlO1xyXG4gICAgICAgICAgICB9XHJcbiAgICAgICAgICAgIG9wID0gYm9keS5jYWxsKHRoaXNBcmcsIF8pO1xyXG4gICAgICAgIH0gY2F0Y2ggKGUpIHsgb3AgPSBbNiwgZV07IHkgPSAwOyB9IGZpbmFsbHkgeyBmID0gdCA9IDA7IH1cclxuICAgICAgICBpZiAob3BbMF0gJiA1KSB0aHJvdyBvcFsxXTsgcmV0dXJuIHsgdmFsdWU6IG9wWzBdID8gb3BbMV0gOiB2b2lkIDAsIGRvbmU6IHRydWUgfTtcclxuICAgIH1cclxufVxyXG5cclxuZXhwb3J0IGZ1bmN0aW9uIF9fZXhwb3J0U3RhcihtLCBleHBvcnRzKSB7XHJcbiAgICBmb3IgKHZhciBwIGluIG0pIGlmICghZXhwb3J0cy5oYXNPd25Qcm9wZXJ0eShwKSkgZXhwb3J0c1twXSA9IG1bcF07XHJcbn1cclxuXHJcbmV4cG9ydCBmdW5jdGlvbiBfX3ZhbHVlcyhvKSB7XHJcbiAgICB2YXIgbSA9IHR5cGVvZiBTeW1ib2wgPT09IFwiZnVuY3Rpb25cIiAmJiBvW1N5bWJvbC5pdGVyYXRvcl0sIGkgPSAwO1xyXG4gICAgaWYgKG0pIHJldHVybiBtLmNhbGwobyk7XHJcbiAgICByZXR1cm4ge1xyXG4gICAgICAgIG5leHQ6IGZ1bmN0aW9uICgpIHtcclxuICAgICAgICAgICAgaWYgKG8gJiYgaSA+PSBvLmxlbmd0aCkgbyA9IHZvaWQgMDtcclxuICAgICAgICAgICAgcmV0dXJuIHsgdmFsdWU6IG8gJiYgb1tpKytdLCBkb25lOiAhbyB9O1xyXG4gICAgICAgIH1cclxuICAgIH07XHJcbn1cclxuXHJcbmV4cG9ydCBmdW5jdGlvbiBfX3JlYWQobywgbikge1xyXG4gICAgdmFyIG0gPSB0eXBlb2YgU3ltYm9sID09PSBcImZ1bmN0aW9uXCIgJiYgb1tTeW1ib2wuaXRlcmF0b3JdO1xyXG4gICAgaWYgKCFtKSByZXR1cm4gbztcclxuICAgIHZhciBpID0gbS5jYWxsKG8pLCByLCBhciA9IFtdLCBlO1xyXG4gICAgdHJ5IHtcclxuICAgICAgICB3aGlsZSAoKG4gPT09IHZvaWQgMCB8fCBuLS0gPiAwKSAmJiAhKHIgPSBpLm5leHQoKSkuZG9uZSkgYXIucHVzaChyLnZhbHVlKTtcclxuICAgIH1cclxuICAgIGNhdGNoIChlcnJvcikgeyBlID0geyBlcnJvcjogZXJyb3IgfTsgfVxyXG4gICAgZmluYWxseSB7XHJcbiAgICAgICAgdHJ5IHtcclxuICAgICAgICAgICAgaWYgKHIgJiYgIXIuZG9uZSAmJiAobSA9IGlbXCJyZXR1cm5cIl0pKSBtLmNhbGwoaSk7XHJcbiAgICAgICAgfVxyXG4gICAgICAgIGZpbmFsbHkgeyBpZiAoZSkgdGhyb3cgZS5lcnJvcjsgfVxyXG4gICAgfVxyXG4gICAgcmV0dXJuIGFyO1xyXG59XHJcblxyXG5leHBvcnQgZnVuY3Rpb24gX19zcHJlYWQoKSB7XHJcbiAgICBmb3IgKHZhciBhciA9IFtdLCBpID0gMDsgaSA8IGFyZ3VtZW50cy5sZW5ndGg7IGkrKylcclxuICAgICAgICBhciA9IGFyLmNvbmNhdChfX3JlYWQoYXJndW1lbnRzW2ldKSk7XHJcbiAgICByZXR1cm4gYXI7XHJcbn1cclxuXHJcbmV4cG9ydCBmdW5jdGlvbiBfX2F3YWl0KHYpIHtcclxuICAgIHJldHVybiB0aGlzIGluc3RhbmNlb2YgX19hd2FpdCA/ICh0aGlzLnYgPSB2LCB0aGlzKSA6IG5ldyBfX2F3YWl0KHYpO1xyXG59XHJcblxyXG5leHBvcnQgZnVuY3Rpb24gX19hc3luY0dlbmVyYXRvcih0aGlzQXJnLCBfYXJndW1lbnRzLCBnZW5lcmF0b3IpIHtcclxuICAgIGlmICghU3ltYm9sLmFzeW5jSXRlcmF0b3IpIHRocm93IG5ldyBUeXBlRXJyb3IoXCJTeW1ib2wuYXN5bmNJdGVyYXRvciBpcyBub3QgZGVmaW5lZC5cIik7XHJcbiAgICB2YXIgZyA9IGdlbmVyYXRvci5hcHBseSh0aGlzQXJnLCBfYXJndW1lbnRzIHx8IFtdKSwgaSwgcSA9IFtdO1xyXG4gICAgcmV0dXJuIGkgPSB7fSwgdmVyYihcIm5leHRcIiksIHZlcmIoXCJ0aHJvd1wiKSwgdmVyYihcInJldHVyblwiKSwgaVtTeW1ib2wuYXN5bmNJdGVyYXRvcl0gPSBmdW5jdGlvbiAoKSB7IHJldHVybiB0aGlzOyB9LCBpO1xyXG4gICAgZnVuY3Rpb24gdmVyYihuKSB7IGlmIChnW25dKSBpW25dID0gZnVuY3Rpb24gKHYpIHsgcmV0dXJuIG5ldyBQcm9taXNlKGZ1bmN0aW9uIChhLCBiKSB7IHEucHVzaChbbiwgdiwgYSwgYl0pID4gMSB8fCByZXN1bWUobiwgdik7IH0pOyB9OyB9XHJcbiAgICBmdW5jdGlvbiByZXN1bWUobiwgdikgeyB0cnkgeyBzdGVwKGdbbl0odikpOyB9IGNhdGNoIChlKSB7IHNldHRsZShxWzBdWzNdLCBlKTsgfSB9XHJcbiAgICBmdW5jdGlvbiBzdGVwKHIpIHsgci52YWx1ZSBpbnN0YW5jZW9mIF9fYXdhaXQgPyBQcm9taXNlLnJlc29sdmUoci52YWx1ZS52KS50aGVuKGZ1bGZpbGwsIHJlamVjdCkgOiBzZXR0bGUocVswXVsyXSwgcik7IH1cclxuICAgIGZ1bmN0aW9uIGZ1bGZpbGwodmFsdWUpIHsgcmVzdW1lKFwibmV4dFwiLCB2YWx1ZSk7IH1cclxuICAgIGZ1bmN0aW9uIHJlamVjdCh2YWx1ZSkgeyByZXN1bWUoXCJ0aHJvd1wiLCB2YWx1ZSk7IH1cclxuICAgIGZ1bmN0aW9uIHNldHRsZShmLCB2KSB7IGlmIChmKHYpLCBxLnNoaWZ0KCksIHEubGVuZ3RoKSByZXN1bWUocVswXVswXSwgcVswXVsxXSk7IH1cclxufVxyXG5cclxuZXhwb3J0IGZ1bmN0aW9uIF9fYXN5bmNEZWxlZ2F0b3Iobykge1xyXG4gICAgdmFyIGksIHA7XHJcbiAgICByZXR1cm4gaSA9IHt9LCB2ZXJiKFwibmV4dFwiKSwgdmVyYihcInRocm93XCIsIGZ1bmN0aW9uIChlKSB7IHRocm93IGU7IH0pLCB2ZXJiKFwicmV0dXJuXCIpLCBpW1N5bWJvbC5pdGVyYXRvcl0gPSBmdW5jdGlvbiAoKSB7IHJldHVybiB0aGlzOyB9LCBpO1xyXG4gICAgZnVuY3Rpb24gdmVyYihuLCBmKSB7IGlbbl0gPSBvW25dID8gZnVuY3Rpb24gKHYpIHsgcmV0dXJuIChwID0gIXApID8geyB2YWx1ZTogX19hd2FpdChvW25dKHYpKSwgZG9uZTogbiA9PT0gXCJyZXR1cm5cIiB9IDogZiA/IGYodikgOiB2OyB9IDogZjsgfVxyXG59XHJcblxyXG5leHBvcnQgZnVuY3Rpb24gX19hc3luY1ZhbHVlcyhvKSB7XHJcbiAgICBpZiAoIVN5bWJvbC5hc3luY0l0ZXJhdG9yKSB0aHJvdyBuZXcgVHlwZUVycm9yKFwiU3ltYm9sLmFzeW5jSXRlcmF0b3IgaXMgbm90IGRlZmluZWQuXCIpO1xyXG4gICAgdmFyIG0gPSBvW1N5bWJvbC5hc3luY0l0ZXJhdG9yXSwgaTtcclxuICAgIHJldHVybiBtID8gbS5jYWxsKG8pIDogKG8gPSB0eXBlb2YgX192YWx1ZXMgPT09IFwiZnVuY3Rpb25cIiA/IF9fdmFsdWVzKG8pIDogb1tTeW1ib2wuaXRlcmF0b3JdKCksIGkgPSB7fSwgdmVyYihcIm5leHRcIiksIHZlcmIoXCJ0aHJvd1wiKSwgdmVyYihcInJldHVyblwiKSwgaVtTeW1ib2wuYXN5bmNJdGVyYXRvcl0gPSBmdW5jdGlvbiAoKSB7IHJldHVybiB0aGlzOyB9LCBpKTtcclxuICAgIGZ1bmN0aW9uIHZlcmIobikgeyBpW25dID0gb1tuXSAmJiBmdW5jdGlvbiAodikgeyByZXR1cm4gbmV3IFByb21pc2UoZnVuY3Rpb24gKHJlc29sdmUsIHJlamVjdCkgeyB2ID0gb1tuXSh2KSwgc2V0dGxlKHJlc29sdmUsIHJlamVjdCwgdi5kb25lLCB2LnZhbHVlKTsgfSk7IH07IH1cclxuICAgIGZ1bmN0aW9uIHNldHRsZShyZXNvbHZlLCByZWplY3QsIGQsIHYpIHsgUHJvbWlzZS5yZXNvbHZlKHYpLnRoZW4oZnVuY3Rpb24odikgeyByZXNvbHZlKHsgdmFsdWU6IHYsIGRvbmU6IGQgfSk7IH0sIHJlamVjdCk7IH1cclxufVxyXG5cclxuZXhwb3J0IGZ1bmN0aW9uIF9fbWFrZVRlbXBsYXRlT2JqZWN0KGNvb2tlZCwgcmF3KSB7XHJcbiAgICBpZiAoT2JqZWN0LmRlZmluZVByb3BlcnR5KSB7IE9iamVjdC5kZWZpbmVQcm9wZXJ0eShjb29rZWQsIFwicmF3XCIsIHsgdmFsdWU6IHJhdyB9KTsgfSBlbHNlIHsgY29va2VkLnJhdyA9IHJhdzsgfVxyXG4gICAgcmV0dXJuIGNvb2tlZDtcclxufTtcclxuXHJcbmV4cG9ydCBmdW5jdGlvbiBfX2ltcG9ydFN0YXIobW9kKSB7XHJcbiAgICBpZiAobW9kICYmIG1vZC5fX2VzTW9kdWxlKSByZXR1cm4gbW9kO1xyXG4gICAgdmFyIHJlc3VsdCA9IHt9O1xyXG4gICAgaWYgKG1vZCAhPSBudWxsKSBmb3IgKHZhciBrIGluIG1vZCkgaWYgKE9iamVjdC5oYXNPd25Qcm9wZXJ0eS5jYWxsKG1vZCwgaykpIHJlc3VsdFtrXSA9IG1vZFtrXTtcclxuICAgIHJlc3VsdC5kZWZhdWx0ID0gbW9kO1xyXG4gICAgcmV0dXJuIHJlc3VsdDtcclxufVxyXG5cclxuZXhwb3J0IGZ1bmN0aW9uIF9faW1wb3J0RGVmYXVsdChtb2QpIHtcclxuICAgIHJldHVybiAobW9kICYmIG1vZC5fX2VzTW9kdWxlKSA/IG1vZCA6IHsgZGVmYXVsdDogbW9kIH07XHJcbn1cclxuIiwiZXhwb3J0IGNvbnN0IEdhdHRTZXJ2aWNlcyA9IHtcbiAgR0VORVJJQ19BQ0NFU1M6IHtcbiAgICBTRVJWSUNFOiAnZ2VuZXJpY19hY2Nlc3MnLFxuICAgIERFVklDRV9OQU1FOiAnZGV2aWNlX25hbWUnLFxuICAgIEFQUEVBUkFOQ0U6ICdhcHBlYXJhbmNlJyxcbiAgICBQUklWQUNZX0ZMQUc6ICdwcml2YWN5X2ZsYWcnLFxuICAgIFJFQ09OTkVDVElPTl9BRERSRVNTOiAncmVjb25uZWN0aW9uX2FkZHJlc3MnLFxuICAgIFBFUklQSEVSQUxfUFJFRkVSUkVEX0NPTk5FQ1RJT05fUEFSQU1FVEVSUzogJ3BlcmlwaGVyYWxfcHJlZmVycmVkX2Nvbm5lY3Rpb25fcGFyYW1ldGVycydcbiAgfSxcbiAgQkFUVEVSWToge1xuICAgIFNFUlZJQ0U6ICdiYXR0ZXJ5X3NlcnZpY2UnLFxuICAgIEJBVFRFUllfTEVWRUw6ICdiYXR0ZXJ5X2xldmVsJ1xuICB9LFxuICBERVZJQ0VfSU5GT1JNQVRJT046IHtcbiAgICBTRVJWSUNFOiAnZGV2aWNlX2luZm9ybWF0aW9uJyxcbiAgICBNQU5VRkFDVFVSRVJfTkFNRTogJ21hbnVmYWN0dXJlcl9uYW1lX3N0cmluZycsXG4gICAgTU9ERUxfTlVNQkVSOiAnbW9kZWxfbnVtYmVyX3N0cmluZycsXG4gICAgU0VSSUFMX05VTUJFUjogJ3NlcmlhbF9udW1iZXJfc3RyaW5nJyxcbiAgICBIQVJEV0FSRV9SRVZJU0lPTjogJ2hhcmR3YXJlX3JldmlzaW9uX3N0cmluZycsXG4gICAgRklSTVdBUkVfUkVWSVNJT046ICdmaXJtd2FyZV9yZXZpc2lvbl9zdHJpbmcnLFxuICAgIFNPRlRXQVJFX1JFVklTSU9OOiAnc29mdHdhcmVfcmV2aXNpb25fc3RyaW5nJyxcbiAgICBTWVNURU1fSUQ6ICdzeXN0ZW1faWQnLFxuICAgIFBOUF9JRDogJ3BucF9pZCdcbiAgfVxufTtcblxuZXhwb3J0IGNvbnN0IEdBVFRfU0VSVklDRVMgPSBPYmplY3Qua2V5cyhHYXR0U2VydmljZXMpLm1hcChcbiAga2V5ID0+IEdhdHRTZXJ2aWNlc1trZXldLlNFUlZJQ0Vcbik7XG4iLCJkZWNsYXJlIGNvbnN0IEJ1ZmZlcjtcbmltcG9ydCAqIGFzIGFlcyBmcm9tICdhZXMtanMnO1xuaW1wb3J0IHsgSW5qZWN0YWJsZSB9IGZyb20gJ0Bhbmd1bGFyL2NvcmUnO1xuXG5ASW5qZWN0YWJsZSh7XG4gIHByb3ZpZGVkSW46ICdyb290J1xufSlcbmV4cG9ydCBjbGFzcyBDeXBoZXJBZXNTZXJ2aWNlIHtcbiAgcHJpdmF0ZSBtYXN0ZXJLZXkgPSBbXTtcbiAgcHJpdmF0ZSBpbml0aWFsVmVjdG9yID0gW107XG4gIHByaXZhdGUgZW5jcnlwdE1ldGhvZCA9ICdDQkMnO1xuICBwcml2YXRlIGlzU3RhdGljSW5pdGlhbFZlY3RvciA9IHRydWU7XG4gIHByaXZhdGUgZW5jdHJ5cE1ldGhvZEluc3RhbmNlO1xuICBwcml2YXRlIGlzQ29uZmlnRXhlY3V0ZWQgPSBmYWxzZTtcbiAgcHJpdmF0ZSBhZGRpdGlvbmFsRW5jcnlwdE1ldGhvZFBhcmFtcztcbiAgY29uc3RydWN0b3IoKSB7fVxuICAvKipcbiAgICogSW5pdGlhbCBjb25maWcgdXNlZCB0byBpbml0YWxpY2UgYWxsIHJlcXVpcmVkIHBhcmFtc1xuICAgKiBAcGFyYW0gbWFzdGVyS2V5IGtleSB1c2VkIHRvIGVuY3J5cHQgYW5kIGRlY3J5cHRcbiAgICogQHBhcmFtIGluaXRpYWxWZWN0b3IgdmVjdG9yIHVzZWQgdG8gZW5jcnlwdCBhYmQgZGVjcnlwdCBleGNlcHQgd2hlbiBFQ0IgZW5jcnlwdCBtZXRob2QgaXMgdXNlZFxuICAgKiBAcGFyYW0gZW5jcnlwdE1ldGhvZCB0eXBlIG9mIGVuY3J5cHQgbWV0aG9kIGlzIHVzZWQsIHRoZSBwb3NzaWJsZSBvcHRpb25zIGFyZTogQ0JDLCBDVFIsIENGQiwgT0ZCLCBFQ0JcbiAgICogQHBhcmFtIGFkZGl0aW9uYWxFbmNyeXB0TWV0aG9kUGFyYW1zIGNvbmZpZ3VyYXRpb24gcGFyYW1zIHVzZWQgYnkgdGhlIHNlbGVjdGVkIGVuY3J5cHQgbWV0aG9kLlxuICAgKiBOb3RlOiBpZiB0aGUgbWV0aG9kIENUUiBvciBDRkIgaXMgdXNlZCB0aGlzIHBhcmFtIGlzIHJlcXVpcmVkIG90aGVyd2lzZSBpcyBhbiBvcHRpbmFsIHBhcmFtLlxuICAgKiBCeSBDVFIgcmVxdWlyZSB0aGUgcGFyYW0gY291bnRlciBhbmQgYnkgQ0ZCIHJlcXVpcmUgdGhlIHBhcmFtIHNlZ21lbnRTaXplXG4gICAqIEBwYXJhbSBpc1N0YXRpY0luaXRpYWxWZWN0b3IgZGVmaW5lcyBpZiB0aGUgaW5pdGlhbCB2ZWN0b3IgaXMgY2hhbmdlZCBvciBub3Qgd2hlbiB0aGUgZGF0YSBhcmUgZW5jcnlwdGVkIG9yIG5vdFxuICAgKi9cbiAgY29uZmlnKFxuICAgIG1hc3RlcktleSxcbiAgICBpbml0aWFsVmVjdG9yID0gWzAsIDAsIDAsIDAsIDAsIDAsIDAsIDAsIDAsIDAsIDAsIDAsIDAsIDAsIDAsIDBdLFxuICAgIGVuY3J5cHRNZXRob2QgPSAnQ0JDJyxcbiAgICBhZGRpdGlvbmFsRW5jcnlwdE1ldGhvZFBhcmFtcyA9IHt9LFxuICAgIGlzU3RhdGljSW5pdGlhbFZlY3RvciA9IHRydWVcbiAgKSB7XG4gICAgdGhpcy5pc0NvbmZpZ0V4ZWN1dGVkID0gdHJ1ZTtcbiAgICB0aGlzLm1hc3RlcktleSA9IG1hc3RlcktleTtcbiAgICB0aGlzLmluaXRpYWxWZWN0b3IgPSBpbml0aWFsVmVjdG9yO1xuICAgIHRoaXMuZW5jcnlwdE1ldGhvZCA9IGVuY3J5cHRNZXRob2Q7XG4gICAgdGhpcy5pc1N0YXRpY0luaXRpYWxWZWN0b3IgPSBpc1N0YXRpY0luaXRpYWxWZWN0b3I7XG4gICAgdGhpcy5hZGRpdGlvbmFsRW5jcnlwdE1ldGhvZFBhcmFtcyA9IGFkZGl0aW9uYWxFbmNyeXB0TWV0aG9kUGFyYW1zO1xuICAgIGlmICghaXNTdGF0aWNJbml0aWFsVmVjdG9yKSB7XG4gICAgICB0aGlzLmVuY3RyeXBNZXRob2RJbnN0YW5jZSA9IHRoaXMuZ2VuZXJhdGVFbmNyeXB0TWV0aG9kSW5zdGFuY2UoKTtcbiAgICB9XG4gIH1cbiAgLyoqXG4gICAqIEVuY3J5cHQgdGhlIGRhdGEgdXNpbmcgdGhlIGVuY3J5cHQgbWV0aG9kIHByZXZpb3VzbHkgY29uZmlndXJlZFxuICAgKiBAcGFyYW0gZGF0YUFycmF5QnVmZmVyIGRhdGEgdG8gZW5jcnlwdFxuICAgKi9cbiAgZW5jcnlwdChkYXRhQXJyYXlCdWZmZXI6IFVpbnQ4QXJyYXkgfCBVaW50MTZBcnJheSB8IFVpbnQzMkFycmF5KSB7XG4gICAgaWYgKCF0aGlzLmlzQ29uZmlnRXhlY3V0ZWQpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcihcbiAgICAgICAgJ011c3QgY29uZmlndXJhdGUgY3lwaGVyLWFlcyBiZWZvcmUgY2FsbCB0aGlzIG1ldGhvZCwgdXNlIHRoZSBtZXRob2QgY29uZmlnKCknXG4gICAgICApO1xuICAgIH1cbiAgICBpZiAodGhpcy5lbmNyeXB0TWV0aG9kID09PSAnQ0JDJyB8fCB0aGlzLmVuY3J5cHRNZXRob2QgPT09ICdFQ0InKSB7XG4gICAgICBkYXRhQXJyYXlCdWZmZXIgPSB0aGlzLmFkZFBhZGRpbmcoZGF0YUFycmF5QnVmZmVyKTtcbiAgICB9XG4gICAgcmV0dXJuIHRoaXMuaXNTdGF0aWNJbml0aWFsVmVjdG9yXG4gICAgICA/IHRoaXMuZ2VuZXJhdGVFbmNyeXB0TWV0aG9kSW5zdGFuY2UoKS5lbmNyeXB0KGRhdGFBcnJheUJ1ZmZlcilcbiAgICAgIDogdGhpcy5lbmN0cnlwTWV0aG9kSW5zdGFuY2UuZW5jcnlwdChkYXRhQXJyYXlCdWZmZXIpO1xuICB9XG4gIC8qKlxuICAgKiBEZWNyeXB0IHRoZSBkYXRhIHVzaW5nIHRoZSBlbmNyeXB0IG1ldGhvZCBwcmV2aW91c2x5IGNvbmZpZ3VyZWRcbiAgICogQHBhcmFtIGRhdGFBcnJheUJ1ZmZlciBkYXRhIHRvIGRlY3J5cHRcbiAgICovXG4gIGRlY3J5cHQoZGF0YUFycmF5QnVmZmVyOiBVaW50OEFycmF5IHwgVWludDE2QXJyYXkgfCBVaW50MzJBcnJheSkge1xuICAgIGlmICghdGhpcy5pc0NvbmZpZ0V4ZWN1dGVkKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoXG4gICAgICAgICdNdXN0IGNvbmZpZ3VyYXRlIGN5cGhlci1hZXMgYmVmb3JlIGNhbGwgdGhpcyBtZXRob2QsIHVzZSB0aGUgbWV0aG9kIGNvbmZpZygpJ1xuICAgICAgKTtcbiAgICB9XG4gICAgcmV0dXJuIHRoaXMuaXNTdGF0aWNJbml0aWFsVmVjdG9yXG4gICAgICA/IHRoaXMuZ2VuZXJhdGVFbmNyeXB0TWV0aG9kSW5zdGFuY2UoKS5kZWNyeXB0KGRhdGFBcnJheUJ1ZmZlcilcbiAgICAgIDogdGhpcy5lbmN0cnlwTWV0aG9kSW5zdGFuY2UuZGVjcnlwdChkYXRhQXJyYXlCdWZmZXIpO1xuICB9XG4gIC8qKlxuICAgKiBDaGFuZ2UgdGhlIGN1cnJlbnQgaW5pdGFsVmVjdG9yXG4gICAqIEBwYXJhbSBpbml0aWFsVmVjdG9yIG5ldyBpbml0YWxWZWN0b3JcbiAgICovXG4gIGNoYW5nZUluaXRpYWxWZWN0b3IoaW5pdGlhbFZlY3Rvcikge1xuICAgIGlmICghdGhpcy5pc1N0YXRpY0luaXRpYWxWZWN0b3IpIHtcbiAgICAgIHRoaXMuZW5jdHJ5cE1ldGhvZEluc3RhbmNlID0gdGhpcy5nZW5lcmF0ZUVuY3J5cHRNZXRob2RJbnN0YW5jZSgpO1xuICAgIH1cbiAgICB0aGlzLmluaXRpYWxWZWN0b3IgPSBpbml0aWFsVmVjdG9yO1xuICB9XG5cbiAgLyoqXG4gICAqIENoYW5nZSB0aGUgY3VycmVudCBlbmN5cHRNZXRob2RcbiAgICogQHBhcmFtIGVuY3J5cHRNZXRob2QgbmV3IGVuY3J5cHRNZXRob2RcbiAgICovXG4gIGNoYW5nZUVuY3J5cHRNZXRob2QoZW5jcnlwdE1ldGhvZCkge1xuICAgIGlmICghdGhpcy5pc1N0YXRpY0luaXRpYWxWZWN0b3IpIHtcbiAgICAgIHRoaXMuZW5jdHJ5cE1ldGhvZEluc3RhbmNlID0gdGhpcy5nZW5lcmF0ZUVuY3J5cHRNZXRob2RJbnN0YW5jZSgpO1xuICAgIH1cbiAgICB0aGlzLmVuY3J5cHRNZXRob2QgPSBlbmNyeXB0TWV0aG9kO1xuICB9XG5cbiAgLyoqXG4gICAqIENoYW5nZSB0aGUgY3VycmVudCBpc1N0YXRpY0luaXRpYWxWZWN0b3JcbiAgICogQHBhcmFtIGlzU3RhdGljSW5pdGlhbFZlY3RvciBuZXcgaXNTdGF0aWNJbml0YWxWZWN0b3JcbiAgICovXG4gIGNoYW5nZVN0YXRpY0luaXRpYWxWZWN0b3IoaXNTdGF0aWNJbml0aWFsVmVjdG9yKSB7XG4gICAgaWYgKCFpc1N0YXRpY0luaXRpYWxWZWN0b3IpIHtcbiAgICAgIHRoaXMuZW5jdHJ5cE1ldGhvZEluc3RhbmNlID0gdGhpcy5nZW5lcmF0ZUVuY3J5cHRNZXRob2RJbnN0YW5jZSgpO1xuICAgIH1cbiAgICB0aGlzLmlzU3RhdGljSW5pdGlhbFZlY3RvciA9IGlzU3RhdGljSW5pdGlhbFZlY3RvcjtcbiAgfVxuICAvKipcbiAgICogQ2hhbmdlIHRoZSBjdXJyZW50IG1hc3RlcktleVxuICAgKiBAcGFyYW0gbWFzdGVyS2V5IG5ldyBtYXN0ZXJLZXlcbiAgICovXG4gIGNoYW5nZU1hc3RlcktleShtYXN0ZXJLZXkpIHtcbiAgICBpZiAoIXRoaXMuaXNTdGF0aWNJbml0aWFsVmVjdG9yKSB7XG4gICAgICB0aGlzLmVuY3RyeXBNZXRob2RJbnN0YW5jZSA9IHRoaXMuZ2VuZXJhdGVFbmNyeXB0TWV0aG9kSW5zdGFuY2UoKTtcbiAgICB9XG4gICAgdGhpcy5tYXN0ZXJLZXkgPSBtYXN0ZXJLZXk7XG4gIH1cblxuICAvKipcbiAgICogQWRkIHBhZGRpbmcgdG8gdGhlIGxpc3RcbiAgICovXG4gIHByaXZhdGUgYWRkUGFkZGluZyhhcnJheUJ1ZmZlcjogVWludDhBcnJheSB8IFVpbnQxNkFycmF5IHwgVWludDMyQXJyYXkpIHtcbiAgICBjb25zdCBwYWRkaW5nTGVuZ3RoID0gTWF0aC5jZWlsKEFycmF5LmZyb20oYXJyYXlCdWZmZXIpLmxlbmd0aCAvIDE2KSAqIDE2O1xuICAgIGNvbnN0IHBhZGRpbmdMaXN0ID0gbmV3IEFycmF5KFxuICAgICAgcGFkZGluZ0xlbmd0aCAtIEFycmF5LmZyb20oYXJyYXlCdWZmZXIpLmxlbmd0aFxuICAgICkuZmlsbCgwKTtcbiAgICByZXR1cm4gbmV3IFVpbnQ4QXJyYXkoQXJyYXkuZnJvbShhcnJheUJ1ZmZlcikuY29uY2F0KHBhZGRpbmdMaXN0KSk7XG4gIH1cbiAgLyoqXG4gICAqIGdlbmVyYXRlIGEgaW5zdGFuY2Ugb2YgdGhlIGVuY3J5cHQgbWV0aG9kIHVzaW5nIHRoZSBjdXJyZW50IG1ldGhvZCBjb25maWd1cmVkXG4gICAqL1xuICBwcml2YXRlIGdlbmVyYXRlRW5jcnlwdE1ldGhvZEluc3RhbmNlKCkge1xuICAgIGxldCBlbmN0cnlwTWV0aG9kSW5zdGFuY2U7XG4gICAgc3dpdGNoICh0aGlzLmVuY3J5cHRNZXRob2QpIHtcbiAgICAgIGNhc2UgJ0NCQyc6XG4gICAgICAgIGVuY3RyeXBNZXRob2RJbnN0YW5jZSA9IG5ldyBhZXMuTW9kZU9mT3BlcmF0aW9uLmNiYyhcbiAgICAgICAgICB0aGlzLm1hc3RlcktleSxcbiAgICAgICAgICB0aGlzLmluaXRpYWxWZWN0b3JcbiAgICAgICAgKTtcbiAgICAgICAgYnJlYWs7XG4gICAgICBjYXNlICdDVFInOlxuICAgICAgICBpZiAoIXRoaXMuYWRkaXRpb25hbEVuY3J5cHRNZXRob2RQYXJhbXMuY291bnRlcikge1xuICAgICAgICAgIHRocm93IG5ldyBFcnJvcihcbiAgICAgICAgICAgICdhZGRpdGlvbmFsRW5jcnlwdE1ldGhvZFBhcmFtcy5jb3VudGVyIGlzIHJlcXVpcmVkIHRvIHVzZSBlbmNyeXB0IG1ldGhvZCBDVFInXG4gICAgICAgICAgKTtcbiAgICAgICAgfVxuICAgICAgICBlbmN0cnlwTWV0aG9kSW5zdGFuY2UgPSBuZXcgYWVzLk1vZGVPZk9wZXJhdGlvbi5jdHIoXG4gICAgICAgICAgdGhpcy5tYXN0ZXJLZXksXG4gICAgICAgICAgdGhpcy5pbml0aWFsVmVjdG9yLFxuICAgICAgICAgIG5ldyBhZXMuQ291bnRlcih0aGlzLmFkZGl0aW9uYWxFbmNyeXB0TWV0aG9kUGFyYW1zLmNvdW50ZXIpXG4gICAgICAgICk7XG4gICAgICAgIGJyZWFrO1xuICAgICAgY2FzZSAnQ0ZCJzpcbiAgICAgICAgaWYgKCF0aGlzLmFkZGl0aW9uYWxFbmNyeXB0TWV0aG9kUGFyYW1zLnNlZ21lbnRTaXplKSB7XG4gICAgICAgICAgdGhyb3cgbmV3IEVycm9yKFxuICAgICAgICAgICAgJ2FkZGl0aW9uYWxFbmNyeXB0TWV0aG9kUGFyYW1zLnNlZ21lbnRTaXplIGlzIHJlcXVpcmVkIHRvIHVzZSBlbmNyeXB0IG1ldGhvZCBDRkInXG4gICAgICAgICAgKTtcbiAgICAgICAgfVxuICAgICAgICBlbmN0cnlwTWV0aG9kSW5zdGFuY2UgPSBuZXcgYWVzLk1vZGVPZk9wZXJhdGlvbi5jZmIoXG4gICAgICAgICAgdGhpcy5tYXN0ZXJLZXksXG4gICAgICAgICAgdGhpcy5pbml0aWFsVmVjdG9yLFxuICAgICAgICAgIHRoaXMuYWRkaXRpb25hbEVuY3J5cHRNZXRob2RQYXJhbXMuc2VnbWVudFNpemVcbiAgICAgICAgKTtcbiAgICAgICAgYnJlYWs7XG4gICAgICBjYXNlICdPRkInOlxuICAgICAgICBlbmN0cnlwTWV0aG9kSW5zdGFuY2UgPSBuZXcgYWVzLk1vZGVPZk9wZXJhdGlvbi5vZmIoXG4gICAgICAgICAgdGhpcy5tYXN0ZXJLZXksXG4gICAgICAgICAgdGhpcy5pbml0aWFsVmVjdG9yXG4gICAgICAgICk7XG4gICAgICAgIGJyZWFrO1xuICAgICAgY2FzZSAnRUNCJzpcbiAgICAgICAgZW5jdHJ5cE1ldGhvZEluc3RhbmNlID0gbmV3IGFlcy5Nb2RlT2ZPcGVyYXRpb24uZWNiKHRoaXMubWFzdGVyS2V5KTtcbiAgICAgICAgYnJlYWs7XG4gICAgfVxuICAgIHJldHVybiBlbmN0cnlwTWV0aG9kSW5zdGFuY2U7XG4gIH1cbiAgLy8gI3JlZ2lvbiBVVElMU1xuICAvKipcbiAgICogQ29udmVydCB0aGUgdGV4dCB0byBieXRlc1xuICAgKiBAcGFyYW0gdGV4dCBUZXh0IHRvIGNvbnZlcnRcbiAgICovXG4gIHRleHRUb0J5dGVzKHRleHQpIHtcbiAgICByZXR1cm4gYWVzLnV0aWxzLnV0ZjgudG9CeXRlcyh0ZXh0KTtcbiAgfVxuICAvKipcbiAgICogQ29udmVydCB0aGUgYnl0ZXMgdG8gdGV4dFxuICAgKiBAcGFyYW0gYnl0ZXMgQnl0ZXMgdG8gY29udmVydFxuICAgKi9cbiAgYnl0ZXNUb1RleHQoYnl0ZXM6IFVpbnQ4QXJyYXkgfCBVaW50MTZBcnJheSB8IFVpbnQzMkFycmF5KSB7XG4gICAgcmV0dXJuIGFlcy51dGlscy51dGY4LmZyb21CeXRlcyhieXRlcyk7XG4gIH1cblxuICAvKipcbiAgICogQ29udmVydCB0aGUgYnl0ZXMgdG8gaGV4XG4gICAqIEBwYXJhbSBieXRlcyBieXRlcyB0byBjb252ZXJ0XG4gICAqL1xuICBieXRlc1RvaGV4KGJ5dGVzKSB7XG4gICAgcmV0dXJuIGFlcy51dGlscy5oZXguZnJvbUJ5dGVzKGJ5dGVzKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBDb252ZXJ0IHRoZSBoZXggdG8gYnl0ZXNcbiAgICogQHBhcmFtIGhleCBIZXggdG8gY29udmVydFxuICAgKi9cbiAgaGV4VG9CeXRlcyhoZXgpIHtcbiAgICByZXR1cm4gYWVzLnV0aWxzLmhleC50b0J5dGVzKGhleCk7XG4gIH1cbiAgLy8gI2VuZHJlZ2lvblxuXG4gIGdlbmVyYXRlU3Via2V5cyhrZXkpIHtcbiAgICBjb25zdCBjb25zdF9aZXJvID0gbmV3IFVpbnQ4QXJyYXkoMTYpO1xuICAgIGNvbnN0IGNvbnN0X1JiID0gbmV3IEJ1ZmZlcignMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwODcnLCAnaGV4Jyk7XG4gICAgY29uc3QgZW5jdHJ5cE1ldGhvZEluc3RhbmNlID0gbmV3IGFlcy5Nb2RlT2ZPcGVyYXRpb24uY2JjKGtleSwgbmV3IFVpbnQ4QXJyYXkoMTYpKTtcblxuICAgIGNvbnN0IGxFbmNyeXB0ZWQgPSBlbmN0cnlwTWV0aG9kSW5zdGFuY2UuZW5jcnlwdChjb25zdF9aZXJvKTtcbiAgICBjb25zdCBsID0gbmV3IEJ1ZmZlcih0aGlzLmJ5dGVzVG9oZXgobEVuY3J5cHRlZCksICdoZXgnKTtcbiAgICBsZXQgc3Via2V5MSA9IHRoaXMuYml0U2hpZnRMZWZ0KGwpO1xuICAgIC8vIHRzbGludDpkaXNhYmxlLW5leHQtbGluZTpuby1iaXR3aXNlXG4gICAgaWYgKGxbMF0gJiAweDgwKSB7XG4gICAgICBzdWJrZXkxID0gdGhpcy54b3Ioc3Via2V5MSwgY29uc3RfUmIpO1xuICAgIH1cblxuICAgIGxldCBzdWJrZXkyID0gdGhpcy5iaXRTaGlmdExlZnQoc3Via2V5MSk7XG4gICAgLy8gdHNsaW50OmRpc2FibGUtbmV4dC1saW5lOm5vLWJpdHdpc2VcbiAgICBpZiAoc3Via2V5MVswXSAmIDB4ODApIHtcbiAgICAgIHN1YmtleTIgPSB0aGlzLnhvcihzdWJrZXkyLCBjb25zdF9SYik7XG4gICAgfVxuXG4gICAgcmV0dXJuIHsgc3Via2V5MTogc3Via2V5MSwgc3Via2V5Mjogc3Via2V5MiB9O1xuICB9XG5cbiAgYWVzQ21hYyhrZXksIG1lc3NhZ2UpIHtcbiAgICBjb25zb2xlLmxvZygnSU5JQ0lBIENJRlJBRE8hISEhISEhISEhISEhISEhJyk7XG4gICAgY29uc3Qgc3Via2V5cyA9IHRoaXMuZ2VuZXJhdGVTdWJrZXlzKGtleSk7XG4gICAgbGV0IGJsb2NrQ291bnQgPSBNYXRoLmNlaWwobWVzc2FnZS5sZW5ndGggLyAxNik7XG4gICAgbGV0IGxhc3RCbG9ja0NvbXBsZXRlRmxhZywgbGFzdEJsb2NrLCBsYXN0QmxvY2tJbmRleDtcblxuICAgIGlmIChibG9ja0NvdW50ID09PSAwKSB7XG4gICAgICBibG9ja0NvdW50ID0gMTtcbiAgICAgIGxhc3RCbG9ja0NvbXBsZXRlRmxhZyA9IGZhbHNlO1xuICAgIH0gZWxzZSB7XG4gICAgICBsYXN0QmxvY2tDb21wbGV0ZUZsYWcgPSBtZXNzYWdlLmxlbmd0aCAlIDE2ID09PSAwO1xuICAgIH1cbiAgICBsYXN0QmxvY2tJbmRleCA9IGJsb2NrQ291bnQgLSAxO1xuXG4gICAgaWYgKGxhc3RCbG9ja0NvbXBsZXRlRmxhZykge1xuICAgICAgbGFzdEJsb2NrID0gdGhpcy54b3IoXG4gICAgICAgIHRoaXMuZ2V0TWVzc2FnZUJsb2NrKG1lc3NhZ2UsIGxhc3RCbG9ja0luZGV4KSxcbiAgICAgICAgc3Via2V5cy5zdWJrZXkxXG4gICAgICApO1xuICAgIH0gZWxzZSB7XG4gICAgICBsYXN0QmxvY2sgPSB0aGlzLnhvcihcbiAgICAgICAgdGhpcy5nZXRQYWRkZWRNZXNzYWdlQmxvY2sobWVzc2FnZSwgbGFzdEJsb2NrSW5kZXgpLFxuICAgICAgICBzdWJrZXlzLnN1YmtleTJcbiAgICAgICk7XG4gICAgfVxuXG4gICAgbGV0IHggPSBuZXcgQnVmZmVyKCcwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMCcsICdoZXgnKTtcbiAgICBsZXQgeTtcblxuICAgIGxldCBlbmN0cnlwTWV0aG9kSW5zdGFuY2U7XG4gICAgZm9yIChsZXQgaW5kZXggPSAwOyBpbmRleCA8IGxhc3RCbG9ja0luZGV4OyBpbmRleCsrKSB7XG4gICAgICBlbmN0cnlwTWV0aG9kSW5zdGFuY2UgPSBuZXcgYWVzLk1vZGVPZk9wZXJhdGlvbi5jYmMoa2V5LCBuZXcgVWludDhBcnJheSgxNikpO1xuICAgICAgeSA9IHRoaXMueG9yKHgsIHRoaXMuZ2V0TWVzc2FnZUJsb2NrKG1lc3NhZ2UsIGluZGV4KSk7XG4gICAgICBjb25zdCB4RW5jcnlwdGVkID0gZW5jdHJ5cE1ldGhvZEluc3RhbmNlLmVuY3J5cHQoeSk7XG4gICAgICBjb25zb2xlLmxvZygnWCBub3JtYWwgPT09PT09PT09PT09PT09PiAnLCB0aGlzLmJ5dGVzVG9oZXgoeSkpO1xuICAgICAgY29uc29sZS5sb2coJ1ggZW5jcnlwdGVkID09PT09PT09PT09PT09PiAnLCB0aGlzLmJ5dGVzVG9oZXgoeEVuY3J5cHRlZCkpO1xuICAgICAgeCA9IG5ldyBCdWZmZXIodGhpcy5ieXRlc1RvaGV4KHhFbmNyeXB0ZWQpLCAnaGV4Jyk7XG4gICAgfVxuICAgIHkgPSB0aGlzLnhvcihsYXN0QmxvY2ssIHgpO1xuICAgIGVuY3RyeXBNZXRob2RJbnN0YW5jZSA9IG5ldyBhZXMuTW9kZU9mT3BlcmF0aW9uLmNiYyhrZXksIG5ldyBVaW50OEFycmF5KDE2KSk7XG4gICAgY29uc3QgeUVuY3J5cHRlZCA9IGVuY3RyeXBNZXRob2RJbnN0YW5jZS5lbmNyeXB0KHkpO1xuICAgIGNvbnNvbGUubG9nKCdZIG5vcm1hbCA9PT09PT09PT09PT09PT4gJywgdGhpcy5ieXRlc1RvaGV4KHkpKTtcbiAgICBjb25zb2xlLmxvZygnWSBlbmNyeXB0ZWQgPT09PT09PT09PT09PT0+ICcsIHRoaXMuYnl0ZXNUb2hleCh5RW5jcnlwdGVkKSk7XG4gICAgcmV0dXJuIHlFbmNyeXB0ZWQ7XG4gIH1cblxuICBnZXRNZXNzYWdlQmxvY2sobWVzc2FnZSwgYmxvY2tJbmRleCkge1xuICAgIGNvbnN0IGJsb2NrID0gbmV3IEJ1ZmZlcigxNik7XG4gICAgY29uc3Qgc3RhcnQgPSBibG9ja0luZGV4ICogMTY7XG4gICAgY29uc3QgZW5kID0gc3RhcnQgKyAxNjtcbiAgICBsZXQgYmxvY2tJID0gMDtcbiAgICBmb3IgKGxldCBpID0gc3RhcnQ7IGkgPCBlbmQ7IGkrKykge1xuICAgICAgYmxvY2tbYmxvY2tJXSA9IG1lc3NhZ2VbaV07XG4gICAgICBibG9ja0krKztcbiAgICB9XG4gICAgcmV0dXJuIGJsb2NrO1xuICB9XG5cbiAgZ2V0UGFkZGVkTWVzc2FnZUJsb2NrKG1lc3NhZ2UsIGJsb2NrSW5kZXgpIHtcbiAgICBjb25zdCBibG9jayA9IG5ldyBCdWZmZXIoMTYpO1xuICAgIGNvbnN0IHN0YXJ0ID0gYmxvY2tJbmRleCAqIDE2O1xuICAgIGNvbnN0IGVuZCA9IG1lc3NhZ2UubGVuZ3RoO1xuXG4gICAgYmxvY2suZmlsbCgwKTtcbiAgICBsZXQgYmxvY2tJID0gMDtcbiAgICBmb3IgKGxldCBpID0gc3RhcnQ7IGkgPCBlbmQ7IGkrKykge1xuICAgICAgYmxvY2tbYmxvY2tJXSA9IG1lc3NhZ2VbaV07XG4gICAgICBibG9ja0krKztcbiAgICB9XG4gICAgYmxvY2tbZW5kIC0gc3RhcnRdID0gMHg4MDtcblxuICAgIHJldHVybiBibG9jaztcbiAgfVxuXG4gIGJpdFNoaWZ0TGVmdChidWZmZXIpIHtcbiAgICBjb25zdCBzaGlmdGVkID0gbmV3IEJ1ZmZlcihidWZmZXIubGVuZ3RoKTtcbiAgICBjb25zdCBsYXN0ID0gYnVmZmVyLmxlbmd0aCAtIDE7XG4gICAgZm9yIChsZXQgaW5kZXggPSAwOyBpbmRleCA8IGxhc3Q7IGluZGV4KyspIHtcbiAgICAgIC8vIHRzbGludDpkaXNhYmxlLW5leHQtbGluZTpuby1iaXR3aXNlXG4gICAgICBzaGlmdGVkW2luZGV4XSA9IGJ1ZmZlcltpbmRleF0gPDwgMTtcbiAgICAgIC8vIHRzbGludDpkaXNhYmxlLW5leHQtbGluZTpuby1iaXR3aXNlXG4gICAgICBpZiAoYnVmZmVyW2luZGV4ICsgMV0gJiAweDgwKSB7XG4gICAgICAgIHNoaWZ0ZWRbaW5kZXhdICs9IDB4MDE7XG4gICAgICB9XG4gICAgfVxuICAgIC8vIHRzbGludDpkaXNhYmxlLW5leHQtbGluZTpuby1iaXR3aXNlXG4gICAgc2hpZnRlZFtsYXN0XSA9IGJ1ZmZlcltsYXN0XSA8PCAxO1xuICAgIHJldHVybiBzaGlmdGVkO1xuICB9XG5cbiAgeG9yKGJ1ZmZlckEsIGJ1ZmZlckIpIHtcbiAgICBjb25zdCBsZW5ndGggPSBNYXRoLm1pbihidWZmZXJBLmxlbmd0aCwgYnVmZmVyQi5sZW5ndGgpO1xuICAgIGNvbnN0IG91dHB1dCA9IG5ldyBCdWZmZXIobGVuZ3RoKTtcbiAgICBmb3IgKGxldCBpbmRleCA9IDA7IGluZGV4IDwgbGVuZ3RoOyBpbmRleCsrKSB7XG4gICAgICAvLyB0c2xpbnQ6ZGlzYWJsZS1uZXh0LWxpbmU6bm8tYml0d2lzZVxuICAgICAgb3V0cHV0W2luZGV4XSA9IGJ1ZmZlckFbaW5kZXhdIF4gYnVmZmVyQltpbmRleF07XG4gICAgfVxuICAgIHJldHVybiBvdXRwdXQ7XG4gIH1cbn1cbiIsImltcG9ydCB7IEluamVjdGFibGUgfSBmcm9tICdAYW5ndWxhci9jb3JlJztcblxuZXhwb3J0IGludGVyZmFjZSBMb2dnZXIge1xuICBsb2coYXJnczogc3RyaW5nW10pOiB2b2lkO1xuICBlcnJvcihhcmdzOiBzdHJpbmdbXSk6IHZvaWQ7XG4gIHdhcm4oYXJnczogc3RyaW5nW10pOiB2b2lkO1xufVxuXG5ASW5qZWN0YWJsZSh7XG4gIHByb3ZpZGVkSW46ICdyb290J1xufSlcbmV4cG9ydCBjbGFzcyBDb25zb2xlTG9nZ2VyU2VydmljZSBpbXBsZW1lbnRzIExvZ2dlciB7XG4gIGxvZyguLi5hcmdzKSB7XG4gICAgY29uc29sZS5sb2cuYXBwbHkoY29uc29sZSwgYXJncyk7XG4gIH1cbiAgZXJyb3IoLi4uYXJncykge1xuICAgIGNvbnNvbGUuZXJyb3IuYXBwbHkoY29uc29sZSwgYXJncyk7XG4gIH1cbiAgd2FybiguLi5hcmdzKSB7XG4gICAgY29uc29sZS53YXJuLmFwcGx5KGNvbnNvbGUsIGFyZ3MpO1xuICB9XG59XG5cbkBJbmplY3RhYmxlKHtcbiAgcHJvdmlkZWRJbjogJ3Jvb3QnXG59KVxuZXhwb3J0IGNsYXNzIE5vTG9nZ2VyU2VydmljZSBpbXBsZW1lbnRzIExvZ2dlciB7XG4gIGxvZyguLi5hcmdzKSB7fVxuICBlcnJvciguLi5hcmdzKSB7fVxuICB3YXJuKC4uLmFyZ3MpIHt9XG59XG4iLCJpbXBvcnQgeyBJbmplY3RhYmxlLCBFdmVudEVtaXR0ZXIgfSBmcm9tICdAYW5ndWxhci9jb3JlJztcbmltcG9ydCB7XG4gIG1hcCxcbiAgbWVyZ2VNYXAsXG4gIGNvbmNhdCxcbiAgbWFwVG8sXG4gIGZpbHRlcixcbiAgdGFrZVVudGlsLFxuICBidWZmZXJUb2dnbGUsXG4gIHNjYW4sXG4gIHRhcCxcbiAgdGFrZSxcbiAgdGltZW91dCxcbiAgcmV0cnlXaGVuLFxuICBkZWxheVxufSBmcm9tICdyeGpzL29wZXJhdG9ycyc7XG5pbXBvcnQge1xuICBPYnNlcnZhYmxlLFxuICBmb3JrSm9pbixcbiAgU3ViamVjdCxcbiAgZGVmZXIsXG4gIGZyb21FdmVudCxcbiAgb2YsXG4gIGZyb20sXG4gIGludGVydmFsXG59IGZyb20gJ3J4anMnO1xuaW1wb3J0IHsgR2F0dFNlcnZpY2VzIH0gZnJvbSAnLi9nYXR0LXNlcnZpY2VzJztcbmltcG9ydCB7IEJyb3dzZXJXZWJCbHVldG9vdGggfSBmcm9tICcuLi9wbGF0Zm9ybS9icm93c2VyJztcbmltcG9ydCB7IEN5cGhlckFlc1NlcnZpY2UgfSBmcm9tICcuLi9jeXBoZXIvY3lwaGVyLWFlcy5zZXJ2aWNlJztcbmltcG9ydCB7IENvbnNvbGVMb2dnZXJTZXJ2aWNlIH0gZnJvbSAnLi4vbG9nZ2VyLnNlcnZpY2UnO1xuXG5ASW5qZWN0YWJsZSh7XG4gIHByb3ZpZGVkSW46ICdyb290J1xufSlcbmV4cG9ydCBjbGFzcyBCbHVldG9vdGhTZXJ2aWNlIGV4dGVuZHMgU3ViamVjdDxCbHVldG9vdGhTZXJ2aWNlPiB7XG4gIHB1YmxpYyBfZGV2aWNlJDogRXZlbnRFbWl0dGVyPEJsdWV0b290aERldmljZT47XG4gIHByaXZhdGUgZGV2aWNlOiBCbHVldG9vdGhEZXZpY2U7XG4gIHByaXZhdGUgc2VydmljZUNoYXJhY3RlcmlzdGljVnNTdWJzY3JpcHRpb25MaXN0ID0ge307XG4gIHByaXZhdGUgbm90aWZpZXJTdWJqZWN0ID0gbmV3IFN1YmplY3QoKTtcbiAgcHJpdmF0ZSBub3RpZmllclN0YXJ0ZWRTdWJqZWN0ID0gbmV3IFN1YmplY3QoKTtcbiAgcHJpdmF0ZSBibHVldG9vdGhBdmFpbGFibGUgPSBmYWxzZTtcbiAgY29uc3RydWN0b3IoXG4gICAgcHVibGljIF93ZWJCbGU6IEJyb3dzZXJXZWJCbHVldG9vdGgsXG4gICAgcHJpdmF0ZSBjeXBoZXJBZXNTZXJ2aWNlOiBDeXBoZXJBZXNTZXJ2aWNlLFxuICAgIHB1YmxpYyBfY29uc29sZTogQ29uc29sZUxvZ2dlclNlcnZpY2VcbiAgKSB7XG4gICAgc3VwZXIoKTtcbiAgICB0aGlzLl9kZXZpY2UkID0gbmV3IEV2ZW50RW1pdHRlcjxCbHVldG9vdGhEZXZpY2U+KCk7XG4gICAgaWYgKF93ZWJCbGUuX2JsZSkge1xuICAgICAgdGhpcy5ibHVldG9vdGhBdmFpbGFibGUgPSB0cnVlO1xuICAgIH1cbiAgfVxuXG4gIGlzQmx1ZXRvb3RoQXZhaWxhYmxlKCkge1xuICAgIHJldHVybiB0aGlzLmJsdWV0b290aEF2YWlsYWJsZTtcbiAgfVxuICAvKipcbiAgICogZ2V0IHRoZSBjdXJyZW50IGRldmljZSwgaWYgdGhlIGRldmljZSByZXR1cm4gbnVsbCBpcyBiZWNhdXNlIHRoZSBjb25uZWN0aW9uIGhhcyBsb3N0XG4gICAqIEByZXR1cm5zIHRoZSBjdXJyZW50IGNvbm5jZXRlZCBkZXZpY2VcbiAgICovXG4gIGdldERldmljZSQoKTogT2JzZXJ2YWJsZTxCbHVldG9vdGhEZXZpY2U+IHtcbiAgICByZXR1cm4gdGhpcy5fZGV2aWNlJDtcbiAgfVxuXG4gIGdldE5vdGlmaWVyU3RhcnRlZFN1YmplY3QkKCkge1xuICAgIHJldHVybiB0aGlzLm5vdGlmaWVyU3RhcnRlZFN1YmplY3Q7XG4gIH1cbiAgLyoqXG4gICAqIHN0YXJ0IGEgc3RyZWFtIGJ5IG5vdGlmaWVycyBjaGFyYWN0ZXJpc3RpY3NcbiAgICogQHBhcmFtIHNlcnZpY2UgVGhlIHNlcnZpY2UgdG8gd2hpY2ggdGhlIGNoYXJhY3RlcmlzdGljIGJlbG9uZ3NcbiAgICogQHBhcmFtIGNoYXJhY3RlcmlzdGljIFRoZSBjaGFyYWN0ZXJpc3RpYyB3aG9zZSB2YWx1ZSB5b3Ugd2FudCB0byBsaXN0ZW5cbiAgICogQHBhcmFtIG9wdGlvbnMgb2JqZWN0IHRoYXQgY29udGFpbnMgdGhlXG4gICAqIHN0YXJ0Qnl0ZTpudW1iZXIgKHJlcXVpcmVkKSwgc3RvcEJ5dGU6bnVtYmVyIChyZXF1aXJlZCksXG4gICAqIGxlbmd0aFBvc2l0aW9uOiB7IHN0YXJ0OiBudW1iZXIsIGVuZDogbnVtYmVyLCBsZW5ndGhQYWRkaW5nOiBudW1iZXIgfSAocmVxdWlyZWQpXG4gICAqIEByZXR1cm5zIEEgRGF0YVZpZXcgdGhhbiBjb250YWlucyB0aGUgY2hhcmFjdGVyaXN0aWMgdmFsdWVcbiAgICovXG4gIHN0YXJ0Tm90aWZpZXJMaXN0ZW5lciQoc2VydmljZSwgY2hhcmFjdGVyaXN0aWMsIG9wdGlvbnMpIHtcbiAgICByZXR1cm4gZGVmZXIoKCkgPT4ge1xuICAgICAgb2Yoc2VydmljZSlcbiAgICAgICAgLnBpcGUoXG4gICAgICAgICAgdGFwKCgpID0+IHRoaXMuX2NvbnNvbGUubG9nKCdJbmljaWEgZWwgbm90aWZpZXIgY29uIGxhIGluc3RhbmNpYTogJywgdGhpcy5zZXJ2aWNlQ2hhcmFjdGVyaXN0aWNWc1N1YnNjcmlwdGlvbkxpc3QpKSxcbiAgICAgICAgICBmaWx0ZXIoXG4gICAgICAgICAgICBfID0+XG4gICAgICAgICAgICAgIE9iamVjdC5rZXlzKHRoaXMuc2VydmljZUNoYXJhY3RlcmlzdGljVnNTdWJzY3JpcHRpb25MaXN0KS5pbmRleE9mKFxuICAgICAgICAgICAgICAgIGAke3NlcnZpY2V9LSR7Y2hhcmFjdGVyaXN0aWN9YFxuICAgICAgICAgICAgICApID09PSAtMVxuICAgICAgICAgIClcbiAgICAgICAgKVxuICAgICAgICAuc3Vic2NyaWJlKFxuICAgICAgICAgICgpID0+IHtcbiAgICAgICAgICAgIHRoaXMuc2VydmljZUNoYXJhY3RlcmlzdGljVnNTdWJzY3JpcHRpb25MaXN0W2Ake3NlcnZpY2V9LSR7Y2hhcmFjdGVyaXN0aWN9YF0gPVxuICAgICAgICAgICAgICB0aGlzLmJ1aWxkTm90aWZpZXJMaXN0ZW5lciQoXG4gICAgICAgICAgICAgICAgc2VydmljZSxcbiAgICAgICAgICAgICAgICBjaGFyYWN0ZXJpc3RpYyxcbiAgICAgICAgICAgICAgICBvcHRpb25zXG4gICAgICAgICAgICAgICkuc3Vic2NyaWJlKG1lc3NhZ2UgPT4ge1xuICAgICAgICAgICAgICAgIHRoaXMubm90aWZpZXJTdWJqZWN0Lm5leHQobWVzc2FnZSk7XG4gICAgICAgICAgICAgIH0pO1xuXG4gICAgICAgICAgfSxcbiAgICAgICAgICBlcnIgPT4ge1xuICAgICAgICAgICAgdGhpcy5fY29uc29sZS5sb2coJ1tCTEU6OkluZm9dIEVycm9yIGluIG5vdGlmaWVyOiAnLCBlcnIpO1xuICAgICAgICAgIH0sXG4gICAgICAgICAgKCkgPT4geyB9XG4gICAgICApO1xuICAgICAgcmV0dXJuIG9mKGBub3RpZmllciBhcyBzdWJzY3JpYmVkOiBzZXJ2aWNlPSAke3NlcnZpY2V9LCBjaGFyYWN0ZXJpc3RpYz0gJHtjaGFyYWN0ZXJpc3RpY31gKTtcbiAgICB9KTtcblxuICB9XG5cbiAgc3RvcE5vdGlmaWVyTGlzdGVuZXIkKHNlcnZpY2UsIGNoYXJhY3RlcmlzdGljKSB7XG4gICAgcmV0dXJuIGRlZmVyKCgpID0+IHtcbiAgICAgIC8vIHRoaXMuc2VydmljZUNoYXJhY3RlcmlzdGljVnNTdWJzY3JpcHRpb25MaXN0W2Ake3NlcnZpY2V9LSR7Y2hhcmFjdGVyaXN0aWN9YF0udW5zdWJzY3JpYmUoKTtcbiAgICAgIGRlbGV0ZSB0aGlzLnNlcnZpY2VDaGFyYWN0ZXJpc3RpY1ZzU3Vic2NyaXB0aW9uTGlzdFtgJHtzZXJ2aWNlfS0ke2NoYXJhY3RlcmlzdGljfWBdO1xuICAgICAgcmV0dXJuIG9mKGB0aGUgbm90aWZpZXIgb2YgdGhlIGNoYXJhY3RlcmlzdGljICR7Y2hhcmFjdGVyaXN0aWN9IGFzIGJlZW4gc3RvcHBlZGApO1xuICAgIH0pO1xuICB9XG5cbiAgcHJpdmF0ZSBidWlsZE5vdGlmaWVyTGlzdGVuZXIkKHNlcnZpY2UsIGNoYXJhY3RlcmlzdGljLCBvcHRpb25zKSB7XG4gICAgcmV0dXJuIHRoaXMuZ2V0UHJpbWFyeVNlcnZpY2UkKHNlcnZpY2UpLnBpcGUoXG4gICAgICB0YXAoc2VydmljZUluc3RhbmNlID0+IHRoaXMuX2NvbnNvbGUubG9nKGB0b21hIGV4aXRvc2FtZW50ZSBlbCBzZXJ2aWNpbyA9PT09PT09PT09PT09PT09PiAke3NlcnZpY2VJbnN0YW5jZX1gKSksXG4gICAgICBtZXJnZU1hcChwcmltYXJ5U2VydmljZSA9PlxuICAgICAgICB0aGlzLmdldENoYXJhY3RlcmlzdGljJChwcmltYXJ5U2VydmljZSwgY2hhcmFjdGVyaXN0aWMpXG4gICAgICAgIC5waXBlKHRhcChjaGFyID0+IHRoaXMuX2NvbnNvbGUubG9nKGB0b21hIGV4aXRvc2FtZW50ZSBsYSBjYXJhY3RlcmlzdGljYSA9PT09PT09PT09PT09PT09PiAke2NoYXJ9YCkpKVxuICAgICAgKSxcbiAgICAgIG1lcmdlTWFwKChjaGFyOiBCbHVldG9vdGhSZW1vdGVHQVRUQ2hhcmFjdGVyaXN0aWMpID0+IHtcbiAgICAgICAgcmV0dXJuIGRlZmVyKCgpID0+IHtcbiAgICAgICAgICAvLyBlbmFibGUgdGhlIGNoYXJhY3RlcmlzdGljIG5vdGlmaWVyXG4gICAgICAgICAgcmV0dXJuIGNoYXIuc3RhcnROb3RpZmljYXRpb25zKCk7XG4gICAgICAgIH0pLnBpcGUoXG4gICAgICAgICAgcmV0cnlXaGVuKGVycm9yID0+XG4gICAgICAgICAgICBlcnJvci5waXBlKFxuICAgICAgICAgICAgICB0YXAoKCkgPT4gdGhpcy5fY29uc29sZS5sb2coJ0VSUk9SIEVOIEVMIHN0YXJ0Tm90aWZpY2F0aW9ucyA9PT09PT09PT09PT09PT09PiAnKSksXG4gICAgICAgICAgICAgIGRlbGF5KDEwMDApLFxuICAgICAgICAgICAgICB0YWtlKDUpXG4gICAgICAgICAgICApXG4gICAgICAgICAgKSxcbiAgICAgICAgICB0YXAoKCkgPT4ge1xuICAgICAgICAgICAgdGhpcy5ub3RpZmllclN0YXJ0ZWRTdWJqZWN0Lm5leHQodHJ1ZSk7XG4gICAgICAgICAgICB0aGlzLl9jb25zb2xlLmxvZyhgaW5jaWEgbGFzIG5vdGlmaWFjaW9uZXMgZGUgbGEgY2FyYWN0ZXJpc3RpY2EgMiA9PT09PT09PT09PT09PT09PiAke2NoYXJhY3RlcmlzdGljfWApO1xuICAgICAgICAgIH0pLFxuICAgICAgICAgIG1lcmdlTWFwKF8gPT4ge1xuICAgICAgICAgICAgLy8gc3RhcnQgdGhlIGxpc3RlciBmcm9tIHRoZSBldmVuIGNoYXJhY3RlcmlzdGljdmFsdWVjaGFuZ2VkIHRvIGdldCBhbGwgY2hhbmdlcyBvbiB0aGUgc3BlY2lmaWNcbiAgICAgICAgICAgIC8vIGNoYXJhY3RlcmlzdGljXG4gICAgICAgICAgICByZXR1cm4gZnJvbUV2ZW50KGNoYXIsICdjaGFyYWN0ZXJpc3RpY3ZhbHVlY2hhbmdlZCcpLnBpcGUoXG4gICAgICAgICAgICAgIHRha2VVbnRpbChmcm9tRXZlbnQoY2hhciwgJ2dhdHRzZXJ2ZXJkaXNjb25uZWN0ZWQnKSksXG4gICAgICAgICAgICAgIG1hcCgoZXZlbnQ6IEV2ZW50KSA9PiB7XG4gICAgICAgICAgICAgICAgLy8gZ2V0IGEgZXZlbnQgZnJvbSB0aGUgY2hhcmFjdGVyaXN0aWMgYW5kIG1hcCB0aGF0XG4gICAgICAgICAgICAgICAgcmV0dXJuIHtcbiAgICAgICAgICAgICAgICAgIHN0YXJ0Qnl0ZU1hdGNoZXM6IGZhbHNlLFxuICAgICAgICAgICAgICAgICAgc3RvcEJ5dGVNYXRjaGVzOiBmYWxzZSxcbiAgICAgICAgICAgICAgICAgIGxlbmd0aE1hdGNoZXM6IGZhbHNlLFxuICAgICAgICAgICAgICAgICAgbWVzc2FnZUxlbmd0aDogMCxcbiAgICAgICAgICAgICAgICAgIHRpbWVzdGFtcDogRGF0ZS5ub3coKSxcbiAgICAgICAgICAgICAgICAgIGRhdGE6IEFycmF5LmZyb20oXG4gICAgICAgICAgICAgICAgICAgIG5ldyBVaW50OEFycmF5KFxuICAgICAgICAgICAgICAgICAgICAgICgoZXZlbnQudGFyZ2V0IGFzIEJsdWV0b290aFJlbW90ZUdBVFRDaGFyYWN0ZXJpc3RpYylcbiAgICAgICAgICAgICAgICAgICAgICAgIC52YWx1ZSBhcyBEYXRhVmlldykuYnVmZmVyXG4gICAgICAgICAgICAgICAgICAgIClcbiAgICAgICAgICAgICAgICAgIClcbiAgICAgICAgICAgICAgICB9O1xuICAgICAgICAgICAgICB9KSxcbiAgICAgICAgICAgICAgc2NhbihcbiAgICAgICAgICAgICAgICAoYWNjLCB2YWx1ZSkgPT4ge1xuICAgICAgICAgICAgICAgICAgYWNjLnRpbWVzdGFtcCA9IGFjYy50aW1lc3RhbXAgPT09IDAgPyB2YWx1ZS50aW1lc3RhbXAgOiBhY2MudGltZXN0YW1wO1xuICAgICAgICAgICAgICAgICAgLy8gaWYgdGhlIGN1cnJlbnQgYWNjdW11bGF0b3IgdmFsdWUgaXMgYSB2YWxpZCBtZXNzYWdlLCB0aGVuIGlzIHJlc3RhcnRlZCB0byBnZXQgdGhlIG5leHRcbiAgICAgICAgICAgICAgICAgIC8vIG1lc3NhZ2VcbiAgICAgICAgICAgICAgICAgIGlmIChcbiAgICAgICAgICAgICAgICAgICAgKGFjYy5sZW5ndGhNYXRjaGVzICYmXG4gICAgICAgICAgICAgICAgICAgICAgYWNjLnN0YXJ0Qnl0ZU1hdGNoZXMgJiZcbiAgICAgICAgICAgICAgICAgICAgICBhY2Muc3RvcEJ5dGVNYXRjaGVzKVxuICAgICAgICAgICAgICAgICAgICB8fCBhY2MudGltZXN0YW1wICsgMTAwMCA8IERhdGUubm93KClcbiAgICAgICAgICAgICAgICAgICkge1xuICAgICAgICAgICAgICAgICAgICBhY2MgPSB7XG4gICAgICAgICAgICAgICAgICAgICAgc3RhcnRCeXRlTWF0Y2hlczogZmFsc2UsXG4gICAgICAgICAgICAgICAgICAgICAgc3RvcEJ5dGVNYXRjaGVzOiBmYWxzZSxcbiAgICAgICAgICAgICAgICAgICAgICBsZW5ndGhNYXRjaGVzOiBmYWxzZSxcbiAgICAgICAgICAgICAgICAgICAgICBtZXNzYWdlTGVuZ3RoOiAwLFxuICAgICAgICAgICAgICAgICAgICAgIHRpbWVzdGFtcDogMCxcbiAgICAgICAgICAgICAgICAgICAgICBkYXRhOiBbXVxuICAgICAgICAgICAgICAgICAgICB9O1xuICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgLy8gdmFsaWRhdGUgdGhlIHN0YXJ0IGJ5dGVcbiAgICAgICAgICAgICAgICAgIGlmIChcbiAgICAgICAgICAgICAgICAgICAgIWFjYy5zdGFydEJ5dGVNYXRjaGVzICYmXG4gICAgICAgICAgICAgICAgICAgIHZhbHVlLmRhdGFbMF0gPT09IG9wdGlvbnMuc3RhcnRCeXRlXG4gICAgICAgICAgICAgICAgICApIHtcbiAgICAgICAgICAgICAgICAgICAgLy8gZ2V0IHRoZSBtZXNzYWdlIGxlbmd0aCB1c2luZyB0aGUgc3RhcnQgYW5kIGVuZCBwb3NpdGlvblxuICAgICAgICAgICAgICAgICAgICBhY2MubWVzc2FnZUxlbmd0aCA9XG4gICAgICAgICAgICAgICAgICAgICAgbmV3IERhdGFWaWV3KFxuICAgICAgICAgICAgICAgICAgICAgICAgbmV3IFVpbnQ4QXJyYXkoXG4gICAgICAgICAgICAgICAgICAgICAgICAgIHZhbHVlLmRhdGEuc2xpY2UoXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgb3B0aW9ucy5sZW5ndGhQb3NpdGlvbi5zdGFydCxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBvcHRpb25zLmxlbmd0aFBvc2l0aW9uLmVuZFxuICAgICAgICAgICAgICAgICAgICAgICAgICApXG4gICAgICAgICAgICAgICAgICAgICAgICApLmJ1ZmZlclxuICAgICAgICAgICAgICAgICAgICAgICkuZ2V0SW50MTYoMCwgZmFsc2UpICtcbiAgICAgICAgICAgICAgICAgICAgICAob3B0aW9ucy5sZW5ndGhQb3NpdGlvbi5sZW5ndGhQYWRkaW5nXG4gICAgICAgICAgICAgICAgICAgICAgICA/IG9wdGlvbnMubGVuZ3RoUG9zaXRpb24ubGVuZ3RoUGFkZGluZ1xuICAgICAgICAgICAgICAgICAgICAgICAgOiAwKTtcbiAgICAgICAgICAgICAgICAgICAgLy8gdmFsaWQgdGhhdCB0aGUgaW5pdGlhbCBieXRlIHdhcyBmb3VuZFxuICAgICAgICAgICAgICAgICAgICBhY2Muc3RhcnRCeXRlTWF0Y2hlcyA9IHRydWU7XG4gICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICBpZiAoXG4gICAgICAgICAgICAgICAgICAgICFhY2Muc3RvcEJ5dGVNYXRjaGVzICYmXG4gICAgICAgICAgICAgICAgICAgIHZhbHVlLmRhdGFbdmFsdWUuZGF0YS5sZW5ndGggLSAxXSA9PT0gb3B0aW9ucy5zdG9wQnl0ZVxuICAgICAgICAgICAgICAgICAgKSB7XG4gICAgICAgICAgICAgICAgICAgIC8vIHZhbGlkIHRoYXQgdGhlIGVuZCBieXRlIHdhcyBmb3VuZFxuICAgICAgICAgICAgICAgICAgICBhY2Muc3RvcEJ5dGVNYXRjaGVzID0gdHJ1ZTtcbiAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgIGlmIChhY2Muc3RhcnRCeXRlTWF0Y2hlcykge1xuICAgICAgICAgICAgICAgICAgICAvLyBtZXJnZSB0aGUgbmV3IGRhdGEgYnl0ZXMgdG8gdGhlIG9sZCBieXRlc1xuICAgICAgICAgICAgICAgICAgICBhY2MuZGF0YSA9IGFjYy5kYXRhLmNvbmNhdCh2YWx1ZS5kYXRhKTtcbiAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgIGFjYy5sZW5ndGhNYXRjaGVzID1cbiAgICAgICAgICAgICAgICAgICAgYWNjLnN0YXJ0Qnl0ZU1hdGNoZXMgJiZcbiAgICAgICAgICAgICAgICAgICAgYWNjLnN0b3BCeXRlTWF0Y2hlcyAmJlxuICAgICAgICAgICAgICAgICAgICBhY2MubWVzc2FnZUxlbmd0aCA9PT0gYWNjLmRhdGEubGVuZ3RoO1xuICAgICAgICAgICAgICAgICAgcmV0dXJuIGFjYztcbiAgICAgICAgICAgICAgICB9LFxuICAgICAgICAgICAgICAgIHtcbiAgICAgICAgICAgICAgICAgIHN0YXJ0Qnl0ZU1hdGNoZXM6IGZhbHNlLFxuICAgICAgICAgICAgICAgICAgc3RvcEJ5dGVNYXRjaGVzOiBmYWxzZSxcbiAgICAgICAgICAgICAgICAgIGxlbmd0aE1hdGNoZXM6IGZhbHNlLFxuICAgICAgICAgICAgICAgICAgbWVzc2FnZUxlbmd0aDogMCxcbiAgICAgICAgICAgICAgICAgIHRpbWVzdGFtcDogMCxcbiAgICAgICAgICAgICAgICAgIGRhdGE6IFtdXG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICApLFxuICAgICAgICAgICAgICAvLyBvbmx5IHB1Ymxpc2ggdGhlIGNvbXBsZXRlIGFuZCB2YWxpZCBtZXNzYWdlXG4gICAgICAgICAgICAgIGZpbHRlcihcbiAgICAgICAgICAgICAgICBkYXRhID0+XG4gICAgICAgICAgICAgICAgICBkYXRhLmxlbmd0aE1hdGNoZXMgJiZcbiAgICAgICAgICAgICAgICAgIGRhdGEuc3RhcnRCeXRlTWF0Y2hlcyAmJlxuICAgICAgICAgICAgICAgICAgZGF0YS5zdG9wQnl0ZU1hdGNoZXNcbiAgICAgICAgICAgICAgKSxcbiAgICAgICAgICAgICAgLy8gcmVtb3ZlIGFsbCBjdXN0b20gZGF0YSBhbmQgcHVibGlzaCB0aGUgbWVzc2FnZSBkYXRhXG4gICAgICAgICAgICAgIG1hcChyZXN1bHQgPT4gcmVzdWx0LmRhdGEpXG4gICAgICAgICAgICApO1xuICAgICAgICAgIH0pXG4gICAgICAgICk7XG4gICAgICB9KVxuICAgICk7XG4gIH1cbiAgLyoqXG4gICAqIFNlbmQgYSByZXF1ZXN0IHRvIHRoZSBkZXZpY2UgYW5kIHdhaXQgYSB1bmlxdWUgcmVzcG9uc2VcbiAgICogQHBhcmFtIG1lc3NhZ2UgTWVzc2FnZSB0byBzZW5kXG4gICAqIEBwYXJhbSBzZXJ2aWNlIFRoZSBzZXJ2aWNlIHRvIHdoaWNoIHRoZSBjaGFyYWN0ZXJpc3RpYyBiZWxvbmdzXG4gICAqIEBwYXJhbSBjaGFyYWN0ZXJpc3RpYyBUaGUgY2hhcmFjdGVyaXN0aWMgd2hvc2UgdmFsdWUgeW91IHdhbnQgdG8gc2VuZCB0aGUgbWVzc2FnZVxuICAgKiBAcGFyYW0gcmVzcG9uc2VUeXBlIGZpbHRlciB0byB1c2UgdG8gaWRlbnRpZnkgdGhlIHJlc3BvbnNlLCBTYW1wbGU6IFt7cG9zaXRpb246IDMsIGJ5dGVUb01hdGNoOiAweDgzfSxcbiAgICogIHtwb3NpdGlvbjogMTMsIGJ5dGVUb01hdGNoOiAweDQ1fV1cbiAgICogQHBhcmFtIGN5cGhlck1hc3RlcktleSBtYXN0ZXIga2V5IHRvIGRlY3J5cHQgdGhlIG1lc3NhZ2UsIG9ubHkgdXNlIHRoaXMgcGFyYSBpZiB0aGUgbWVzc2FnZSB0byByZWNlaXZlIGlzIGVuY3J5cHRlZFxuICAgKi9cbiAgc2VuZEFuZFdhaXRSZXNwb25zZSQoXG4gICAgbWVzc2FnZSxcbiAgICBzZXJ2aWNlLFxuICAgIGNoYXJhY3RlcmlzdGljLFxuICAgIHJlc3BvbnNlVHlwZSxcbiAgICBjeXBoZXJNYXN0ZXJLZXk/XG4gICkge1xuICAgIHRoaXMuX2NvbnNvbGUubG9nKFxuICAgICAgJ1tCTEU6OkluZm9dIFNlbmQgbWVzc2FnZSB0byBkZXZpY2U6ICcsXG4gICAgICB0aGlzLmN5cGhlckFlc1NlcnZpY2UuYnl0ZXNUb2hleChtZXNzYWdlKVxuICAgICk7XG4gICAgcmV0dXJuIGZvcmtKb2luKFxuICAgICAgdGhpcy5zdWJzY3JpYmVUb05vdGlmaWVyTGlzdGVuZXIocmVzcG9uc2VUeXBlLCBjeXBoZXJNYXN0ZXJLZXkpLnBpcGUoXG4gICAgICAgIHRha2UoMSlcbiAgICAgICksXG4gICAgICB0aGlzLnNlbmRUb05vdGlmaWVyJChtZXNzYWdlLCBzZXJ2aWNlLCBjaGFyYWN0ZXJpc3RpYylcbiAgICApLnBpcGUoXG4gICAgICBtYXAoKFttZXNzYWdlUmVzcCwgX10pID0+IG1lc3NhZ2VSZXNwKSxcbiAgICAgIHRpbWVvdXQoMzAwMClcbiAgICApO1xuICB9XG4gIC8qKlxuICAgKiBTdWJzY3JpYmUgdG8gdGhlIG5vdGlmaWVycyBmaWx0ZXJpbmcgYnkgYnl0ZSBjaGVja2luZ1xuICAgKiBAcGFyYW0gZmlsdGVyT3B0aW9ucyBtdXN0IHNwZWNpZmljIHRoZSBwb3NpdGlvbiBhbmQgdGhlIGJ5dGUgdG8gbWF0Y2ggU2FtcGxlOlxuICAgKiBbe3Bvc2l0aW9uOiAzLCBieXRlVG9NYXRjaDogMHg4M30sIHtwb3NpdGlvbjogMTMsIGJ5dGVUb01hdGNoOiAweDQ1fV1cbiAgICogQHBhcmFtIGN5cGhlck1hc3RlcktleSBtYXN0ZXIga2V5IHRvIGRlY3J5cHQgdGhlIG1lc3NhZ2UsIG9ubHkgdXNlIHRoaXMgcGFyYSBpZiB0aGUgbWVzc2FnZSB0byByZWNlaXZlIGlzIGVuY3J5cHRlZFxuICAgKi9cbiAgc3Vic2NyaWJlVG9Ob3RpZmllckxpc3RlbmVyKGZpbHRlck9wdGlvbnMsIGN5cGhlck1hc3RlcktleT8pIHtcbiAgICByZXR1cm4gdGhpcy5ub3RpZmllclN1YmplY3QucGlwZShcbiAgICAgIG1hcChtZXNzYWdlVW5mb3JtYXRlZCA9PiB7XG4gICAgICAgIC8vIHJlY2VpdmUgdGhlIHB1cmUgbWVzc2FnZVxuICAgICAgICBsZXQgbWVzc2FnZUZvcm1tYXRlZCA9IG1lc3NhZ2VVbmZvcm1hdGVkIGFzIGFueTtcbiAgICAgICAgLy8gdmFsaWRhdGUgaWYgdGhlIG1lc3NhZ2UgaXMgY3lwaGVyZWRcbiAgICAgICAgaWYgKGN5cGhlck1hc3RlcktleSkge1xuICAgICAgICAgIC8vIGdldCB0aGUgbWVzc2FnZUxlbmd0aFxuICAgICAgICAgIGNvbnN0IGRhdGFibG9ja0xlbmd0aCA9IG5ldyBEYXRhVmlldyhcbiAgICAgICAgICAgIG5ldyBVaW50OEFycmF5KG1lc3NhZ2VGb3JtbWF0ZWQuc2xpY2UoMSwgMykpLmJ1ZmZlclxuICAgICAgICAgICkuZ2V0SW50MTYoMCwgZmFsc2UpO1xuICAgICAgICAgIHRoaXMuY3lwaGVyQWVzU2VydmljZS5jb25maWcoY3lwaGVyTWFzdGVyS2V5KTtcbiAgICAgICAgICAvLyBnZXQgdGhlIGRhdGFibG9jayBvZiB0aGUgbWVzc2FnZSBhbmQgZGVjcnlwdCB0aGlzIHNlY3Rpb25cbiAgICAgICAgICBjb25zdCBkYXRhYmxvY2sgPSBBcnJheS5mcm9tKFxuICAgICAgICAgICAgdGhpcy5jeXBoZXJBZXNTZXJ2aWNlLmRlY3J5cHQoXG4gICAgICAgICAgICAgIChtZXNzYWdlVW5mb3JtYXRlZCBhcyBhbnkpLnNsaWNlKDMsIGRhdGFibG9ja0xlbmd0aCArIDMpXG4gICAgICAgICAgICApXG4gICAgICAgICAgKTtcbiAgICAgICAgICAvLyBtZXJnZSB0aGUgZGF0YWJsb2NrIGFuZCB0aGUgbWVzc2FnZVxuICAgICAgICAgIG1lc3NhZ2VGb3JtbWF0ZWQgPSAobWVzc2FnZVVuZm9ybWF0ZWQgYXMgYW55KVxuICAgICAgICAgICAgLnNsaWNlKDAsIDMpXG4gICAgICAgICAgICAuY29uY2F0KGRhdGFibG9jaylcbiAgICAgICAgICAgIC5jb25jYXQoKG1lc3NhZ2VVbmZvcm1hdGVkIGFzIGFueSkuc2xpY2UoLTIpKTtcbiAgICAgICAgfVxuICAgICAgICB0aGlzLl9jb25zb2xlLmxvZyhcbiAgICAgICAgICAnW0JMRTo6SW5mb10gTm90aWZpY2F0aW9uIHJlaXZlZCBmcm9tIGRldmljZTogJyxcbiAgICAgICAgICB0aGlzLmN5cGhlckFlc1NlcnZpY2UuYnl0ZXNUb2hleChtZXNzYWdlRm9ybW1hdGVkKVxuICAgICAgICApO1xuICAgICAgICByZXR1cm4gbWVzc2FnZUZvcm1tYXRlZDtcbiAgICAgIH0pLFxuICAgICAgLy8gZmlsdGVyIHRoZSBtZXNzYWdlIHVzaW5nIHRoZSBmaWx0ZXIgb3B0aW9uc1xuICAgICAgZmlsdGVyKG1lc3NhZ2UgPT4ge1xuICAgICAgICBsZXQgYXZhaWxhYmxlTWVzc2FnZSA9IGZhbHNlO1xuICAgICAgICBmb3IgKGNvbnN0IG9wdGlvbiBvZiBmaWx0ZXJPcHRpb25zKSB7XG4gICAgICAgICAgaWYgKG1lc3NhZ2Vbb3B0aW9uLnBvc2l0aW9uXSA9PT0gb3B0aW9uLmJ5dGVUb01hdGNoKSB7XG4gICAgICAgICAgICBhdmFpbGFibGVNZXNzYWdlID0gdHJ1ZTtcbiAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgYXZhaWxhYmxlTWVzc2FnZSA9IGZhbHNlO1xuICAgICAgICAgICAgYnJlYWs7XG4gICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICAgIHJldHVybiBhdmFpbGFibGVNZXNzYWdlO1xuICAgICAgfSlcbiAgICApO1xuICB9XG5cbiAgLyoqXG4gICAqIFN0YXJ0IGEgcmVxdWVzdCB0byB0aGUgYnJvd3NlciB0byBsaXN0IGFsbCBhdmFpbGFibGUgYmx1ZXRvb3RoIGRldmljZXNcbiAgICogQHBhcmFtIG9wdGlvbnMgT3B0aW9ucyB0byByZXF1ZXN0IHRoZSBkZXZpY2VzIHRoZSBzdHJ1Y3R1cmUgaXM6XG4gICAqIGFjY2VwdEFsbERldmljZXM6IHRydWV8ZmFsc2VcbiAgICogZmlsdGVyczogQmx1ZXRvb3RoRGF0YUZpbHRlckluaXQgKHNlZSBodHRwczovL3dlYmJsdWV0b290aGNnLmdpdGh1Yi5pby93ZWItYmx1ZXRvb3RoLyNkaWN0ZGVmLWJsdWV0b290aGxlc2NhbmZpbHRlcmluaXQgZm9yIG1vcmUgaW5mbylcbiAgICogb3B0aW9uYWxTZXJ2aWNlczogW10gKHNlcnZpY2VzIHRoYXQgYXJlIGdvaW5nIHRvIGJlIHVzZWQgaW5cbiAgICogY29tbXVuaWNhdGlvbiB3aXRoIHRoZSBkZXZpY2UsIG11c3QgdXNlIHRoZSBVSUlEIG9yIEdBVFQgaWRlbnRmaWVyIHRvIGxpc3QgdGhlciBzZXJ2aWNlcylcbiAgICovXG4gIHByaXZhdGUgZGlzY292ZXJEZXZpY2UkKFxuICAgIG9wdGlvbnM6IFJlcXVlc3REZXZpY2VPcHRpb25zID0ge30gYXMgUmVxdWVzdERldmljZU9wdGlvbnNcbiAgKSB7XG4gICAgcmV0dXJuIGRlZmVyKCgpID0+IHRoaXMuX3dlYkJsZS5yZXF1ZXN0RGV2aWNlKG9wdGlvbnMpKS5waXBlKFxuICAgICAgbWVyZ2VNYXAoZGV2aWNlID0+IHtcbiAgICAgICAgdGhpcy5kZXZpY2UgPSBkZXZpY2U7XG4gICAgICAgIHRoaXMuX2RldmljZSQuZW1pdChkZXZpY2UpO1xuICAgICAgICByZXR1cm4gdGhpcy5jb25maWd1cmVEZXZpY2VEaXNjb25uZWN0aW9uJChkZXZpY2UpLnBpcGUobWFwVG8oZGV2aWNlKSk7XG4gICAgICB9KVxuICAgICk7XG4gIH1cblxuICBwcml2YXRlIGNvbmZpZ3VyZURldmljZURpc2Nvbm5lY3Rpb24kKGRldmljZSkge1xuICAgIHJldHVybiBPYnNlcnZhYmxlLmNyZWF0ZShvYnNlcnZlciA9PiB7XG4gICAgICBvZihkZXZpY2UpXG4gICAgICAgIC5waXBlKFxuICAgICAgICAgIG1lcmdlTWFwKGRldiA9PiBmcm9tRXZlbnQoZGV2aWNlLCAnZ2F0dHNlcnZlcmRpc2Nvbm5lY3RlZCcpKSxcbiAgICAgICAgICB0YWtlKDEpXG4gICAgICAgIClcbiAgICAgICAgLnN1YnNjcmliZShcbiAgICAgICAgICAoKSA9PiB7XG4gICAgICAgICAgICB0aGlzLl9jb25zb2xlLmxvZyhcbiAgICAgICAgICAgICAgJ1NlIGRlc2NvbmVjdGEgZGlzcCBlbiBPbkRldmljZSBkaXNjb25uZWN0ZWQhISEhISEhJ1xuICAgICAgICAgICAgKTtcbiAgICAgICAgICAgIHRoaXMuZGV2aWNlID0gbnVsbDtcbiAgICAgICAgICAgIHRoaXMuX2RldmljZSQuZW1pdChudWxsKTtcbiAgICAgICAgICB9LFxuICAgICAgICAgIGVyciA9PiB7XG4gICAgICAgICAgICB0aGlzLl9jb25zb2xlLmxvZygnW0JMRTo6SW5mb10gRXJyb3IgaW4gbm90aWZpZXI6ICcsIGVycik7XG4gICAgICAgICAgICBvYnNlcnZlci5lcnJvcihlcnIpO1xuICAgICAgICAgIH0sXG4gICAgICAgICgpID0+IHtcbiAgICAgICAgICB9XG4gICAgICAgICk7XG4gICAgICBvYnNlcnZlci5uZXh0KGBEaXNjb25uZWN0aW9uRXZlbnQgYXMgYmVlbiByZWdpc3RlcmApO1xuICAgIH0pO1xuICB9XG5cbiAgLyoqXG4gICAqIERpc2NvdmVyIGFsbCBhdmFpbGFibGUgZGV2aWNlcyBhbmQgY29ubmVjdCB0byBhIHNlbGVjdGVkIGRldmljZVxuICAgKiBAcGFyYW0gb3B0aW9ucyBPcHRpb25zIHRvIHJlcXVlc3QgdGhlIGRldmljZXMgdGhlIHN0cnVjdHVyZSBpczpcbiAgICogYWNjZXB0QWxsRGV2aWNlczogdHJ1ZXxmYWxzZVxuICAgKiBmaWx0ZXJzOiBCbHVldG9vdGhEYXRhRmlsdGVySW5pdCAoc2VlIGh0dHBzOi8vd2ViYmx1ZXRvb3RoY2cuZ2l0aHViLmlvL3dlYi1ibHVldG9vdGgvI2RpY3RkZWYtYmx1ZXRvb3RobGVzY2FuZmlsdGVyaW5pdCBmb3IgbW9yZSBpbmZvKVxuICAgKiBvcHRpb25hbFNlcnZpY2VzOiBbXSAoc2VydmljZXMgdGhhdCBhcmUgZ29pbmcgdG8gYmUgdXNlZCBpblxuICAgKiBjb21tdW5pY2F0aW9uIHdpdGggdGhlIGRldmljZSwgbXVzdCB1c2UgdGhlIFVJSUQgb3IgR0FUVCBpZGVudGZpZXIgdG8gbGlzdCB0aGVyIHNlcnZpY2VzKVxuICAgKiBAcmV0dXJucyB0aGUgY29ubmVjdGVkIGRldmljZVxuICAgKi9cbiAgY29ubmVjdERldmljZSQob3B0aW9ucz86IFJlcXVlc3REZXZpY2VPcHRpb25zKSB7XG4gICAgaWYgKCFvcHRpb25zKSB7XG4gICAgICBvcHRpb25zID0ge1xuICAgICAgICBhY2NlcHRBbGxEZXZpY2VzOiB0cnVlLFxuICAgICAgICBvcHRpb25hbFNlcnZpY2VzOiBbXVxuICAgICAgfTtcbiAgICB9IGVsc2UgaWYgKCFvcHRpb25zLm9wdGlvbmFsU2VydmljZXMpIHtcbiAgICAgIG9wdGlvbnMub3B0aW9uYWxTZXJ2aWNlcyA9IFtdO1xuICAgIH1cbiAgICBvcHRpb25zLm9wdGlvbmFsU2VydmljZXMucHVzaChHYXR0U2VydmljZXMuR0VORVJJQ19BQ0NFU1MuU0VSVklDRSk7XG4gICAgb3B0aW9ucy5vcHRpb25hbFNlcnZpY2VzLnB1c2goR2F0dFNlcnZpY2VzLkJBVFRFUlkuU0VSVklDRSk7XG4gICAgb3B0aW9ucy5vcHRpb25hbFNlcnZpY2VzLnB1c2goR2F0dFNlcnZpY2VzLkRFVklDRV9JTkZPUk1BVElPTi5TRVJWSUNFKTtcbiAgICByZXR1cm4gdGhpcy5kaXNjb3ZlckRldmljZSQob3B0aW9ucykucGlwZShcbiAgICAgIG1lcmdlTWFwKGRldmljZSA9PiB7XG4gICAgICAgIHJldHVybiBkZWZlcigoKSA9PiAoZGV2aWNlIGFzIGFueSkuZ2F0dC5jb25uZWN0KCkpO1xuICAgICAgfSlcbiAgICApO1xuICB9XG4gIC8qKlxuICAgKiBEaXNjb25uZWN0IHRoZSBjdXJyZW50IGRldmljZVxuICAgKi9cbiAgZGlzY29ubmVjdERldmljZSgpIHtcbiAgICBpZiAodGhpcy5kZXZpY2UpIHtcbiAgICAgIHRoaXMuX2NvbnNvbGUubG9nKCdzZSBkZWNvbmVjdGEgZGlzcG9zaXRpdm8nKTtcbiAgICAgIHRoaXMuZGV2aWNlLmdhdHQuZGlzY29ubmVjdCgpO1xuICAgIH1cbiAgfVxuXG4gIC8qKlxuICAgKiBnZXQgYSBkYXRhIGZyb20gdGhlIGRldmljZSB1c2luZyB0aGUgY2hhcmFjdGVyaXN0aWNcbiAgICogQHBhcmFtIHNlcnZpY2UgVVVJRCBvciBHQVRUIGlkZW50aWZpZXIgc2VydmljZVxuICAgKiBAcGFyYW0gY2hhcmFjdGVyaXN0aWMgVVVJRCBvciBHQVRUIGlkZW50aWZpZXIgY2hhcmFjdGVyaXN0aWNcbiAgICogQHJldHVybiBUaGUgY2hhcmFjdGVyaXN0aWMgZGF0YSBpbiBhIERhdGFWaWV3IG9iamVjdFxuICAgKi9cbiAgcmVhZERldmljZVZhbHVlJChzZXJ2aWNlLCBjaGFyYWN0ZXJpc3RpYykge1xuICAgIGlmICghdGhpcy5kZXZpY2UpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcihcbiAgICAgICAgJ011c3Qgc3RhcnQgYSBjb25uZWN0aW9uIHRvIGEgZGV2aWNlIGJlZm9yZSByZWFkIHRoZSBkZXZpY2UgdmFsdWUnXG4gICAgICApO1xuICAgIH1cbiAgICByZXR1cm4gdGhpcy5nZXRQcmltYXJ5U2VydmljZSQoc2VydmljZSkucGlwZShcbiAgICAgIG1lcmdlTWFwKHByaW1hcnlTZXJ2aWNlID0+XG4gICAgICAgIHRoaXMuZ2V0Q2hhcmFjdGVyaXN0aWMkKHByaW1hcnlTZXJ2aWNlLCBjaGFyYWN0ZXJpc3RpYylcbiAgICAgICksXG4gICAgICBtZXJnZU1hcCgoY2hhcmFjdGVyaXN0aWNWYWx1ZTogQmx1ZXRvb3RoUmVtb3RlR0FUVENoYXJhY3RlcmlzdGljKSA9PlxuICAgICAgICB0aGlzLnJlYWRWYWx1ZSQoY2hhcmFjdGVyaXN0aWNWYWx1ZSlcbiAgICAgIClcbiAgICApO1xuICB9XG5cbiAgLyoqXG4gICAqIHdyaXRlIGEgdmFsdWUgaW4gdGhlIHNlbGVjdGVkIGNoYXJhY3RlcmlzdGljXG4gICAqIEBwYXJhbSBjaGFyYWN0ZXJpc3RpYyB0aGUgY2hhcmFjdGVyaXNpdGMgd2hlcmUgeW91IHdhbnQgd3JpdGUgdGhlIHZhbHVlXG4gICAqIEBwYXJhbSB2YWx1ZSB2YWx1ZSB0aGUgdmFsdWUgdG8gd3JpdGVcbiAgICovXG4gIHdyaXRlRGV2aWNlVmFsdWUkKHNlcnZpY2UsIGNoYXJhY3RlcmlzdGljLCB2YWx1ZSkge1xuICAgIGlmICghdGhpcy5kZXZpY2UpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcihcbiAgICAgICAgJ011c3Qgc3RhcnQgYSBjb25uZWN0aW9uIHRvIGEgZGV2aWNlIGJlZm9yZSByZWFkIHRoZSBkZXZpY2UgdmFsdWUnXG4gICAgICApO1xuICAgIH1cbiAgICByZXR1cm4gdGhpcy5nZXRQcmltYXJ5U2VydmljZSQoc2VydmljZSkucGlwZShcbiAgICAgIG1lcmdlTWFwKHByaW1hcnlTZXJ2aWNlID0+XG4gICAgICAgIHRoaXMuZ2V0Q2hhcmFjdGVyaXN0aWMkKHByaW1hcnlTZXJ2aWNlLCBjaGFyYWN0ZXJpc3RpYylcbiAgICAgICksXG4gICAgICBtZXJnZU1hcCgoY2hhcmFjdGVyaXN0aWNWYWx1ZTogQmx1ZXRvb3RoUmVtb3RlR0FUVENoYXJhY3RlcmlzdGljKSA9PlxuICAgICAgICB0aGlzLndyaXRlVmFsdWUkKGNoYXJhY3RlcmlzdGljVmFsdWUsIHZhbHVlKVxuICAgICAgKVxuICAgICk7XG4gIH1cblxuICAvKipcbiAgICogZ2V0IGEgcHJpbWFyeSBzZXJ2aWNlIGluc3RhbmNlIHVzaW5nIHRoZSBzZXJ2aWNlIFVJSUQgb3IgR0FUVCBpZGVudGlmaWVyXG4gICAqIEBwYXJhbSBzZXJ2aWNlIHNlcnZpY2UgaWRlbnRpZmllclxuICAgKiBAcmV0dXJuIHNlcnZpY2UgaW5zdGFuY2VcbiAgICovXG4gIGdldFByaW1hcnlTZXJ2aWNlJChzZXJ2aWNlOiBCbHVldG9vdGhTZXJ2aWNlVVVJRCkge1xuICAgIHJldHVybiBvZih0aGlzLmRldmljZSkucGlwZShcbiAgICAgIG1lcmdlTWFwKGRldmljZSA9PiB7XG4gICAgICAgIHJldHVybiBkZXZpY2UuZ2F0dC5nZXRQcmltYXJ5U2VydmljZShzZXJ2aWNlKTtcbiAgICAgIH0pXG4gICAgKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBHZXQgYSBjaGFyYWN0ZXJpc2l0aWMgaW5zdGFuY2UgdXNpbmcgdGhlIHNlcnZpY2UgaW5zdGFuY2UgYW5kIGEgY2hhcmFjdGVyaXN0aWMgVVVJRFxuICAgKiBAcGFyYW0gcHJpbWFyeVNlcnZpY2Ugc2VydmljZSBpbnN0YW5jZVxuICAgKiBAcGFyYW0gY2hhcmFjdGVyaXN0aWMgY2hhcmFjdGVyaXNpdGljIGlkZW50aWZpZXJcbiAgICogQHJldHVybiBjaGFyYWN0ZXJpc3RpYyBpbnN0YW5jZVxuICAgKi9cbiAgZ2V0Q2hhcmFjdGVyaXN0aWMkKFxuICAgIHByaW1hcnlTZXJ2aWNlOiBCbHVldG9vdGhSZW1vdGVHQVRUU2VydmljZSxcbiAgICBjaGFyYWN0ZXJpc3RpYzogQmx1ZXRvb3RoQ2hhcmFjdGVyaXN0aWNVVUlEXG4gICk6IE9ic2VydmFibGU8dm9pZCB8IEJsdWV0b290aFJlbW90ZUdBVFRDaGFyYWN0ZXJpc3RpYz4ge1xuICAgIHJldHVybiBkZWZlcigoKSA9PiBwcmltYXJ5U2VydmljZS5nZXRDaGFyYWN0ZXJpc3RpYyhjaGFyYWN0ZXJpc3RpYykpO1xuICB9XG5cbiAgLyoqXG4gICAqIHJlYWQgdGhlIGNoYXJhY3RlcmlzdGljIHZhbHVlXG4gICAqIEBwYXJhbSBjaGFyYWN0ZXJpc3RpYyBjaGFyYWN0ZXJpc3RpYyBpbnN0YW5jZVxuICAgKiBAcmV0dXJuIFRoZSBjaGFyYWN0ZXJpc3RpYyBkYXRhIGluIGEgRGF0YVZpZXcgb2JqZWN0XG4gICAqL1xuICBwcml2YXRlIHJlYWRWYWx1ZSQoXG4gICAgY2hhcmFjdGVyaXN0aWM6IEJsdWV0b290aFJlbW90ZUdBVFRDaGFyYWN0ZXJpc3RpY1xuICApOiBPYnNlcnZhYmxlPERhdGFWaWV3PiB7XG4gICAgcmV0dXJuIGZyb20oXG4gICAgICBjaGFyYWN0ZXJpc3RpY1xuICAgICAgICAucmVhZFZhbHVlKClcbiAgICAgICAgLnRoZW4oXG4gICAgICAgICAgKGRhdGE6IERhdGFWaWV3KSA9PiBQcm9taXNlLnJlc29sdmUoZGF0YSksXG4gICAgICAgICAgKGVycm9yOiBET01FeGNlcHRpb24pID0+IFByb21pc2UucmVqZWN0KGAke2Vycm9yLm1lc3NhZ2V9YClcbiAgICAgICAgKVxuICAgICk7XG4gIH1cblxuICAvKipcbiAgICogd3JpdGUgYSB2YWx1ZSBpbiB0aGUgc2VsZWN0ZWQgY2hhcmFjdGVyaXN0aWNcbiAgICogQHBhcmFtIGNoYXJhY3RlcmlzdGljIHRoZSBjaGFyYWN0ZXJpc2l0YyB3aGVyZSB5b3Ugd2FudCB3cml0ZSB0aGUgdmFsdWVcbiAgICogQHBhcmFtIHZhbHVlIHRoZSB2YWx1ZSB0byB3cml0ZVxuICAgKi9cbiAgcHJpdmF0ZSB3cml0ZVZhbHVlJChcbiAgICBjaGFyYWN0ZXJpc3RpYzogQmx1ZXRvb3RoUmVtb3RlR0FUVENoYXJhY3RlcmlzdGljLFxuICAgIHZhbHVlOiBBcnJheUJ1ZmZlciB8IFVpbnQ4QXJyYXlcbiAgKSB7XG4gICAgcmV0dXJuIGRlZmVyKCgpID0+XG4gICAgICBjaGFyYWN0ZXJpc3RpY1xuICAgICAgICAud3JpdGVWYWx1ZSh2YWx1ZSlcbiAgICApO1xuICB9XG5cbiAgLyoqXG4gICAqIGNoYW5nZSB0aGUgc3RhdGUgb2YgdGhlIGNoYXJhY3RlcmlzdGljIHRvIGVuYWJsZSBpdFxuICAgKiBAcGFyYW0gc2VydmljZSAgcGFyZW50IHNlcnZpY2Ugb2YgdGhlIGNoYXJhY3RlcmlzdGljXG4gICAqIEBwYXJhbSBjaGFyYWN0ZXJpc3RpYyBjaGFyYWN0ZXJpc3RpYyB0byBjaGFuZ2UgdGhlIHN0YXRlXG4gICAqIEBwYXJhbSBzdGF0ZSBuZXcgc3RhdGVcbiAgICovXG4gIGVuYWJsZUNoYXJhY3RlcmlzdGljJChcbiAgICBzZXJ2aWNlOiBCbHVldG9vdGhTZXJ2aWNlVVVJRCxcbiAgICBjaGFyYWN0ZXJpc3RpYzogQmx1ZXRvb3RoQ2hhcmFjdGVyaXN0aWNVVUlELFxuICAgIHN0YXRlPzogYW55XG4gICkge1xuICAgIHN0YXRlID0gc3RhdGUgfHwgbmV3IFVpbnQ4QXJyYXkoWzFdKTtcbiAgICByZXR1cm4gdGhpcy5zZXRDaGFyYWN0ZXJpc3RpY1N0YXRlJChzZXJ2aWNlLCBjaGFyYWN0ZXJpc3RpYywgc3RhdGUpO1xuICB9XG5cbiAgLyoqXG4gICAqIGNoYW5nZSB0aGUgc3RhdGUgb2YgdGhlIGNoYXJhY3RlcmlzdGljIHRvIGRpc2FibGUgaXRcbiAgICogQHBhcmFtIHNlcnZpY2UgIHBhcmVudCBzZXJ2aWNlIG9mIHRoZSBjaGFyYWN0ZXJpc3RpY1xuICAgKiBAcGFyYW0gY2hhcmFjdGVyaXN0aWMgY2hhcmFjdGVyaXN0aWMgdG8gY2hhbmdlIHRoZSBzdGF0ZVxuICAgKiBAcGFyYW0gc3RhdGUgbmV3IHN0YXRlXG4gICAqL1xuICBkaXNiYWxlQ2hhcmFjdGVyaXN0aWMkKFxuICAgIHNlcnZpY2U6IEJsdWV0b290aFNlcnZpY2VVVUlELFxuICAgIGNoYXJhY3RlcmlzdGljOiBCbHVldG9vdGhDaGFyYWN0ZXJpc3RpY1VVSUQsXG4gICAgc3RhdGU/OiBhbnlcbiAgKSB7XG4gICAgc3RhdGUgPSBzdGF0ZSB8fCBuZXcgVWludDhBcnJheShbMF0pO1xuICAgIHJldHVybiB0aGlzLnNldENoYXJhY3RlcmlzdGljU3RhdGUkKHNlcnZpY2UsIGNoYXJhY3RlcmlzdGljLCBzdGF0ZSk7XG4gIH1cblxuICAvKipcbiAgICogc2V0IGEgc3RhdGUgdG8gYW4gc3BlY2lmaWMgY2hhcmFjdGVyaXN0aWNcbiAgICogQHBhcmFtIHNlcnZpY2UgIHBhcmVudCBzZXJ2aWNlIG9mIHRoZSBjaGFyYWN0ZXJpc3RpY1xuICAgKiBAcGFyYW0gY2hhcmFjdGVyaXN0aWMgY2hhcmFjdGVyaXN0aWMgdG8gY2hhbmdlIHRoZSBzdGF0ZVxuICAgKiBAcGFyYW0gc3RhdGUgbmV3IHN0YXRlXG4gICAqIEByZXR1cm5cbiAgICovXG4gIHNldENoYXJhY3RlcmlzdGljU3RhdGUkKFxuICAgIHNlcnZpY2U6IEJsdWV0b290aFNlcnZpY2VVVUlELFxuICAgIGNoYXJhY3RlcmlzdGljOiBCbHVldG9vdGhDaGFyYWN0ZXJpc3RpY1VVSUQsXG4gICAgc3RhdGU6IEFycmF5QnVmZmVyXG4gICkge1xuICAgIGNvbnN0IHByaW1hcnlTZXJ2aWNlID0gdGhpcy5nZXRQcmltYXJ5U2VydmljZSQoc2VydmljZSk7XG4gICAgcmV0dXJuIHByaW1hcnlTZXJ2aWNlLnBpcGUoXG4gICAgICBtZXJnZU1hcChfcHJpbWFyeVNlcnZpY2UgPT5cbiAgICAgICAgdGhpcy5nZXRDaGFyYWN0ZXJpc3RpYyQoX3ByaW1hcnlTZXJ2aWNlLCBjaGFyYWN0ZXJpc3RpYylcbiAgICAgICksXG4gICAgICBtYXAoKF9jaGFyYWN0ZXJpc3RpYzogQmx1ZXRvb3RoUmVtb3RlR0FUVENoYXJhY3RlcmlzdGljKSA9PlxuICAgICAgICB0aGlzLndyaXRlVmFsdWUkKF9jaGFyYWN0ZXJpc3RpYywgc3RhdGUpXG4gICAgICApXG4gICAgKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBTZW5kIGEgbWVzc2FnZSB1c2luZyBhIG5vdGlmaWVyIGNoYXJhY3RlcmlzdGljXG4gICAqIEBwYXJhbSBtZXNzYWdlIG1lc3NhZ2UgdG8gc2VuZFxuICAgKiBAcGFyYW0gc2VydmljZSBzZXJ2aWNlIHRvIHdoaWNoIHRoZSBjaGFyYWN0ZXJpc3RpYyBiZWxvbmdzXG4gICAqIEBwYXJhbSBjaGFyYWN0ZXJpc3RpYyBmZWF0dXJlIGluIHdoaWNoIHlvdSB3YW50IHRvIHNlbmQgdGhlIG5vdGlmaWNhdGlvblxuICAgKi9cbiAgc2VuZFRvTm90aWZpZXIkKG1lc3NhZ2UsIHNlcnZpY2UsIGNoYXJhY3RlcmlzdGljKSB7XG4gICAgcmV0dXJuIHRoaXMuZ2V0UHJpbWFyeVNlcnZpY2UkKHNlcnZpY2UpLnBpcGUoXG4gICAgICBtZXJnZU1hcCgocHJpbWFyeVNlcnZpY2U6IEJsdWV0b290aFJlbW90ZUdBVFRTZXJ2aWNlKSA9PlxuICAgICAgICB0aGlzLmdldENoYXJhY3RlcmlzdGljJChwcmltYXJ5U2VydmljZSwgY2hhcmFjdGVyaXN0aWMpXG4gICAgICApLFxuICAgICAgbWVyZ2VNYXAoKGNoYXI6IEJsdWV0b290aFJlbW90ZUdBVFRDaGFyYWN0ZXJpc3RpYykgPT4ge1xuICAgICAgICBpZiAobWVzc2FnZS5sZW5ndGggPiAxNikge1xuICAgICAgICAgIGxldCBvYnNUZXN0ID0gb2YodW5kZWZpbmVkKTtcbiAgICAgICAgICB3aGlsZSAobWVzc2FnZS5sZW5ndGggPiAxNikge1xuICAgICAgICAgICAgb2JzVGVzdCA9IG9ic1Rlc3QucGlwZShcbiAgICAgICAgICAgICAgY29uY2F0KHRoaXMud3JpdGVWYWx1ZSQoY2hhciwgbWVzc2FnZS5zbGljZSgwLCAxNikpKVxuICAgICAgICAgICAgKTtcbiAgICAgICAgICAgIG1lc3NhZ2UgPSBtZXNzYWdlLnNsaWNlKDE2LCBtZXNzYWdlLmxlbmd0aCk7XG4gICAgICAgICAgfVxuICAgICAgICAgIGlmIChtZXNzYWdlLmxlbmd0aCA+IDApIHtcbiAgICAgICAgICAgIG9ic1Rlc3QgPSBvYnNUZXN0LnBpcGUoY29uY2F0KHRoaXMud3JpdGVWYWx1ZSQoY2hhciwgbWVzc2FnZSkpKTtcbiAgICAgICAgICB9XG4gICAgICAgICAgcmV0dXJuIG9ic1Rlc3Q7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgcmV0dXJuIHRoaXMud3JpdGVWYWx1ZSQoY2hhciwgbWVzc2FnZSk7XG4gICAgICAgIH1cbiAgICAgIH0pXG4gICAgKTtcbiAgfVxuICAvKipcbiAgICogVGhlIEJhdHRlcnkgTGV2ZWwgY2hhcmFjdGVyaXN0aWMgaXMgcmVhZCB1c2luZyB0aGUgR0FUVCBSZWFkIENoYXJhY3RlcmlzdGljXG4gICAqICBWYWx1ZSBzdWItcHJvY2VkdXJlIGFuZCByZXR1cm5zIHRoZSBjdXJyZW50IGJhdHRlcnkgbGV2ZWwgYXMgYSBwZXJjZW50YWdlXG4gICAqICBmcm9tIDAlIHRvIDEwMCU7IDAlIHJlcHJlc2VudHMgYSBiYXR0ZXJ5IHRoYXQgaXMgZnVsbHkgZGlzY2hhcmdlZCwgMTAwJVxuICAgKiByZXByZXNlbnRzIGEgYmF0dGVyeSB0aGF0IGlzIGZ1bGx5IGNoYXJnZWRcbiAgICovXG4gIGdldEJhdHRlcnlMZXZlbCQoKSB7XG4gICAgcmV0dXJuIHRoaXMucmVhZERldmljZVZhbHVlJChcbiAgICAgIEdhdHRTZXJ2aWNlcy5CQVRURVJZLlNFUlZJQ0UsXG4gICAgICBHYXR0U2VydmljZXMuQkFUVEVSWS5CQVRURVJZX0xFVkVMXG4gICAgKS5waXBlKG1hcCh2YWx1ZSA9PiB2YWx1ZS5nZXRVaW50OCgwKSkpO1xuICB9XG4gIC8qKlxuICAgKiBUaGlzIGNoYXJhY3RlcmlzdGljIHJlcHJlc2VudHMgdGhlIG5hbWUgb2YgdGhlIG1hbnVmYWN0dXJlciBvZiB0aGUgZGV2aWNlLlxuICAgKi9cbiAgZ2V0TWFudWZhY3R1cmVyTmFtZSQoKSB7XG4gICAgcmV0dXJuIHRoaXMucmVhZERldmljZVZhbHVlJChcbiAgICAgIEdhdHRTZXJ2aWNlcy5ERVZJQ0VfSU5GT1JNQVRJT04uU0VSVklDRSxcbiAgICAgIEdhdHRTZXJ2aWNlcy5ERVZJQ0VfSU5GT1JNQVRJT04uTUFOVUZBQ1RVUkVSX05BTUVcbiAgICApLnBpcGUoXG4gICAgICBtYXAoZGF0YVZpZXcgPT5cbiAgICAgICAgdGhpcy5jeXBoZXJBZXNTZXJ2aWNlLmJ5dGVzVG9UZXh0KG5ldyBVaW50OEFycmF5KGRhdGFWaWV3LmJ1ZmZlcikpXG4gICAgICApXG4gICAgKTtcbiAgfVxuICAvKipcbiAgICogVGhpcyBjaGFyYWN0ZXJpc3RpYyByZXByZXNlbnRzIHRoZSBtb2RlbCBudW1iZXIgdGhhdCBpcyBhc3NpZ25lZCBieSB0aGUgZGV2aWNlIHZlbmRvci5cbiAgICovXG4gIGdldE1vZGVsTnVtYmVyJCgpIHtcbiAgICByZXR1cm4gdGhpcy5yZWFkRGV2aWNlVmFsdWUkKFxuICAgICAgR2F0dFNlcnZpY2VzLkRFVklDRV9JTkZPUk1BVElPTi5TRVJWSUNFLFxuICAgICAgR2F0dFNlcnZpY2VzLkRFVklDRV9JTkZPUk1BVElPTi5NT0RFTF9OVU1CRVJcbiAgICApLnBpcGUoXG4gICAgICBtYXAoZGF0YVZpZXcgPT5cbiAgICAgICAgdGhpcy5jeXBoZXJBZXNTZXJ2aWNlLmJ5dGVzVG9UZXh0KG5ldyBVaW50OEFycmF5KGRhdGFWaWV3LmJ1ZmZlcikpXG4gICAgICApXG4gICAgKTtcbiAgfVxuICAvKipcbiAgICogVGhpcyBjaGFyYWN0ZXJpc3RpYyByZXByZXNlbnRzIHRoZSBzZXJpYWwgbnVtYmVyIGZvciBhIHBhcnRpY3VsYXIgaW5zdGFuY2Ugb2YgdGhlIGRldmljZS5cbiAgICovXG4gIGdldFNlcmlhbE51bWJlciQoKSB7XG4gICAgcmV0dXJuIHRoaXMucmVhZERldmljZVZhbHVlJChcbiAgICAgIEdhdHRTZXJ2aWNlcy5ERVZJQ0VfSU5GT1JNQVRJT04uU0VSVklDRSxcbiAgICAgIEdhdHRTZXJ2aWNlcy5ERVZJQ0VfSU5GT1JNQVRJT04uU0VSSUFMX05VTUJFUlxuICAgICkucGlwZShcbiAgICAgIG1hcChkYXRhVmlldyA9PlxuICAgICAgICB0aGlzLmN5cGhlckFlc1NlcnZpY2UuYnl0ZXNUb1RleHQobmV3IFVpbnQ4QXJyYXkoZGF0YVZpZXcuYnVmZmVyKSlcbiAgICAgIClcbiAgICApO1xuICB9XG4gIC8qKlxuICAgKiBUaGlzIGNoYXJhY3RlcmlzdGljIHJlcHJlc2VudHMgdGhlIGhhcmR3YXJlIHJldmlzaW9uIGZvciB0aGUgaGFyZHdhcmUgd2l0aGluIHRoZSBkZXZpY2UuXG4gICAqL1xuICBnZXRIYXJkd2FyZVJldmlzaW9uJCgpIHtcbiAgICByZXR1cm4gdGhpcy5yZWFkRGV2aWNlVmFsdWUkKFxuICAgICAgR2F0dFNlcnZpY2VzLkRFVklDRV9JTkZPUk1BVElPTi5TRVJWSUNFLFxuICAgICAgR2F0dFNlcnZpY2VzLkRFVklDRV9JTkZPUk1BVElPTi5IQVJEV0FSRV9SRVZJU0lPTlxuICAgICkucGlwZShcbiAgICAgIG1hcChkYXRhVmlldyA9PlxuICAgICAgICB0aGlzLmN5cGhlckFlc1NlcnZpY2UuYnl0ZXNUb1RleHQobmV3IFVpbnQ4QXJyYXkoZGF0YVZpZXcuYnVmZmVyKSlcbiAgICAgIClcbiAgICApO1xuICB9XG4gIC8qKlxuICAgKiBUaGlzIGNoYXJhY3RlcmlzdGljIHJlcHJlc2VudHMgdGhlIGZpcm13YXJlIHJldmlzaW9uIGZvciB0aGUgZmlybXdhcmUgd2l0aGluIHRoZSBkZXZpY2UuXG4gICAqL1xuICBnZXRGaXJtd2FyZVJldmlzaW9uJCgpIHtcbiAgICByZXR1cm4gdGhpcy5yZWFkRGV2aWNlVmFsdWUkKFxuICAgICAgR2F0dFNlcnZpY2VzLkRFVklDRV9JTkZPUk1BVElPTi5TRVJWSUNFLFxuICAgICAgR2F0dFNlcnZpY2VzLkRFVklDRV9JTkZPUk1BVElPTi5GSVJNV0FSRV9SRVZJU0lPTlxuICAgICkucGlwZShcbiAgICAgIG1hcChkYXRhVmlldyA9PlxuICAgICAgICB0aGlzLmN5cGhlckFlc1NlcnZpY2UuYnl0ZXNUb1RleHQobmV3IFVpbnQ4QXJyYXkoZGF0YVZpZXcuYnVmZmVyKSlcbiAgICAgIClcbiAgICApO1xuICB9XG4gIC8qKlxuICAgKiBUaGlzIGNoYXJhY3RlcmlzdGljIHJlcHJlc2VudHMgdGhlIHNvZnR3YXJlIHJldmlzaW9uIGZvciB0aGUgc29mdHdhcmUgd2l0aGluIHRoZSBkZXZpY2UuXG4gICAqL1xuICBnZXRTb2Z0d2FyZVJldmlzaW9uJCgpIHtcbiAgICByZXR1cm4gdGhpcy5yZWFkRGV2aWNlVmFsdWUkKFxuICAgICAgR2F0dFNlcnZpY2VzLkRFVklDRV9JTkZPUk1BVElPTi5TRVJWSUNFLFxuICAgICAgR2F0dFNlcnZpY2VzLkRFVklDRV9JTkZPUk1BVElPTi5TT0ZUV0FSRV9SRVZJU0lPTlxuICAgICkucGlwZShcbiAgICAgIG1hcChkYXRhVmlldyA9PlxuICAgICAgICB0aGlzLmN5cGhlckFlc1NlcnZpY2UuYnl0ZXNUb1RleHQobmV3IFVpbnQ4QXJyYXkoZGF0YVZpZXcuYnVmZmVyKSlcbiAgICAgIClcbiAgICApO1xuICB9XG4gIC8qKlxuICAgKiBUaGlzIGNoYXJhY3RlcmlzdGljIHJlcHJlc2VudHMgYSBzdHJ1Y3R1cmUgY29udGFpbmluZyBhbiBPcmdhbml6YXRpb25hbGx5IFVuaXF1ZSBJZGVudGlmaWVyXG4gICAqICAoT1VJKSBmb2xsb3dlZCBieSBhIG1hbnVmYWN0dXJlci1kZWZpbmVkIGlkZW50aWZpZXIgYW5kIGlzIHVuaXF1ZSBmb3IgZWFjaCBpbmRpdmlkdWFsIGluc3RhbmNlIG9mIHRoZSBwcm9kdWN0LlxuICAgKi9cbiAgZ2V0U3lzdGVtSWQkKCkge1xuICAgIHJldHVybiB0aGlzLnJlYWREZXZpY2VWYWx1ZSQoXG4gICAgICBHYXR0U2VydmljZXMuREVWSUNFX0lORk9STUFUSU9OLlNFUlZJQ0UsXG4gICAgICBHYXR0U2VydmljZXMuREVWSUNFX0lORk9STUFUSU9OLlNZU1RFTV9JRFxuICAgICk7XG4gIH1cbiAgLyoqXG4gICAqIFRoZSBQblBfSUQgY2hhcmFjdGVyaXN0aWMgaXMgYSBzZXQgb2YgdmFsdWVzIHVzZWQgdG8gY3JlYXRlIGEgZGV2aWNlIElEIHZhbHVlIHRoYXQgaXMgdW5pcXVlIGZvciB0aGlzIGRldmljZS5cbiAgICovXG4gIGdldFBucElkJCgpIHtcbiAgICByZXR1cm4gdGhpcy5yZWFkRGV2aWNlVmFsdWUkKFxuICAgICAgR2F0dFNlcnZpY2VzLkRFVklDRV9JTkZPUk1BVElPTi5TRVJWSUNFLFxuICAgICAgR2F0dFNlcnZpY2VzLkRFVklDRV9JTkZPUk1BVElPTi5QTlBfSURcbiAgICApO1xuICB9XG59XG4iLCJpbXBvcnQgeyBOZ01vZHVsZSwgTW9kdWxlV2l0aFByb3ZpZGVycywgSW5qZWN0aW9uVG9rZW4gIH0gZnJvbSAnQGFuZ3VsYXIvY29yZSc7XG5pbXBvcnQgeyBCcm93c2VyV2ViQmx1ZXRvb3RoIH0gZnJvbSAnLi9wbGF0Zm9ybS9icm93c2VyJztcbmltcG9ydCB7IENvbW1vbk1vZHVsZSB9IGZyb20gJ0Bhbmd1bGFyL2NvbW1vbic7XG5pbXBvcnQgeyBCbHVldG9vdGhTZXJ2aWNlIH0gZnJvbSAnLi9ibHVldG9vdGgvYmx1ZXRvb3RoLnNlcnZpY2UnO1xuaW1wb3J0IHsgQ29uc29sZUxvZ2dlclNlcnZpY2UsIE5vTG9nZ2VyU2VydmljZSB9IGZyb20gJy4vbG9nZ2VyLnNlcnZpY2UnO1xuXG5leHBvcnQgaW50ZXJmYWNlIEFXQk9wdGlvbnMge1xuICBlbmFibGVUcmFjaW5nPzogYm9vbGVhbjtcbn1cblxuZXhwb3J0IGZ1bmN0aW9uIGJyb3dzZXJXZWJCbHVldG9vdGgoKSB7XG4gIHJldHVybiBuZXcgQnJvd3NlcldlYkJsdWV0b290aCgpO1xufVxuXG5leHBvcnQgZnVuY3Rpb24gY29uc29sZUxvZ2dlclNlcnZpY2VDb25maWcob3B0aW9uczogQVdCT3B0aW9ucykge1xuICBpZiAob3B0aW9ucyAmJiBvcHRpb25zLmVuYWJsZVRyYWNpbmcpIHtcbiAgICByZXR1cm4gbmV3IENvbnNvbGVMb2dnZXJTZXJ2aWNlKCk7XG4gIH0gZWxzZSB7XG4gICAgcmV0dXJuIG5ldyBOb0xvZ2dlclNlcnZpY2UoKTtcbiAgfVxufVxuZXhwb3J0IGZ1bmN0aW9uIG1ha2VNZVRva2VuSW5qZWN0b3IoKSB7XG4gIHJldHVybiBuZXcgSW5qZWN0aW9uVG9rZW4oJ0FXQk9wdGlvbnMnKTtcbn1cblxuXG5ATmdNb2R1bGUoe1xuICBpbXBvcnRzOiBbQ29tbW9uTW9kdWxlXVxufSlcbmV4cG9ydCBjbGFzcyBBbmd1bGFyQmxlTW9kdWxlIHtcbiAgc3RhdGljIGZvclJvb3Qob3B0aW9uczogQVdCT3B0aW9ucyA9IHt9KTogTW9kdWxlV2l0aFByb3ZpZGVycyB7XG4gICAgcmV0dXJuIHtcbiAgICAgIG5nTW9kdWxlOiBBbmd1bGFyQmxlTW9kdWxlLFxuICAgICAgcHJvdmlkZXJzOiBbXG4gICAgICAgIEJsdWV0b290aFNlcnZpY2UsXG4gICAgICAgIHtcbiAgICAgICAgICBwcm92aWRlOiBCcm93c2VyV2ViQmx1ZXRvb3RoLFxuICAgICAgICAgIHVzZUZhY3Rvcnk6IGJyb3dzZXJXZWJCbHVldG9vdGhcbiAgICAgICAgfSxcbiAgICAgICAge1xuICAgICAgICAgIHByb3ZpZGU6IG1ha2VNZVRva2VuSW5qZWN0b3IsXG4gICAgICAgICAgdXNlVmFsdWU6IG9wdGlvbnNcbiAgICAgICAgfSxcbiAgICAgICAge1xuICAgICAgICAgIHByb3ZpZGU6IENvbnNvbGVMb2dnZXJTZXJ2aWNlLFxuICAgICAgICAgIHVzZUZhY3Rvcnk6IGNvbnNvbGVMb2dnZXJTZXJ2aWNlQ29uZmlnLFxuICAgICAgICAgIGRlcHM6IFttYWtlTWVUb2tlbkluamVjdG9yXVxuICAgICAgICB9XG4gICAgICBdXG4gICAgfTtcbiAgfVxufVxuIl0sIm5hbWVzIjpbIkluamVjdGFibGUiLCJhZXMuTW9kZU9mT3BlcmF0aW9uIiwiYWVzLkNvdW50ZXIiLCJhZXMudXRpbHMiLCJ0c2xpYl8xLl9fZXh0ZW5kcyIsIlN1YmplY3QiLCJFdmVudEVtaXR0ZXIiLCJkZWZlciIsIm9mIiwidGFwIiwiZmlsdGVyIiwibWVyZ2VNYXAiLCJyZXRyeVdoZW4iLCJkZWxheSIsInRha2UiLCJmcm9tRXZlbnQiLCJ0YWtlVW50aWwiLCJtYXAiLCJzY2FuIiwiZm9ya0pvaW4iLCJ0aW1lb3V0IiwidHNsaWJfMS5fX3ZhbHVlcyIsIm1hcFRvIiwiT2JzZXJ2YWJsZSIsImZyb20iLCJjb25jYXQiLCJJbmplY3Rpb25Ub2tlbiIsIk5nTW9kdWxlIiwiQ29tbW9uTW9kdWxlIl0sIm1hcHBpbmdzIjoiOzs7Ozs7Ozs7O0FBQUE7UUFPRTtZQUNFLElBQUksQ0FBQyxJQUFJLEdBQUcsU0FBUyxDQUFDLFNBQVMsQ0FBQztZQUNoQyxJQUFJLENBQUMsSUFBSSxDQUFD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