UNPKG

@iotize/ionic

Version:

Iotize specific building blocks on top of @ionic/angular.

281 lines 36.5 kB
import { Injectable } from '@angular/core'; import { Platform } from '@ionic/angular'; import { HostProtocol } from '@iotize/tap'; import { WifiMode } from '@iotize/tap/service/impl/wifi'; import { ReplaySubject } from 'rxjs'; import { CONFIGURATION_MODE_VERSION, FACTORY_RESET_MODE_VERSION, } from '../../config-version'; import { CurrentDeviceService } from '../../current-device.service'; import { debug } from '../../logger'; import { TapInfoRequestService } from '../../tap-info/tap-info-request.service'; import { TapInfo } from '../../tap-info/keys'; import * as i0 from "@angular/core"; import * as i1 from "../../current-device.service"; import * as i2 from "../../tap-info/tap-info-request.service"; import * as i3 from "@ionic/angular"; const MQTT_SECURE_PORTS = ['8883']; const TAG = 'TapConnectionStoreService'; export function filterByConnectionTypes(filteredConnectionTypes) { return (values) => { if (!filteredConnectionTypes) { return values; } return values.filter((value) => filteredConnectionTypes.indexOf(value.connection.type) >= 0); }; } /** * TODO change implementation to not trigger NFC load * Use reactive programming instead */ export class TapConnectionStoreService { constructor(tapService, infoResolver, platform) { this.tapService = tapService; this.infoResolver = infoResolver; this.platform = platform; this.items = []; this.values = new ReplaySubject(1); this.config = { localStorageKey: 'TapConnectionStoreService.items', mqtt: { webSocket: { port: 9001, // TODO configurable }, username: undefined, password: undefined, }, }; this.loadFromStorage(); } set(items) { if (!items) { items = []; } this.items = items; this.values.next(this.items); this.saveToStorage(); } remove(item) { this.items.splice(this.items.indexOf(item), 1); this.set(this.items); } /** * Try to add or refresh current stored connection info * */ async storeCurrentTapConnectionInfo() { const connection = this.tapService.protocolMeta; if (!connection) { debug(`${TAG} No protocol connection info for this Tap. Cannot store connection info.`); return false; } const [serialNumber, version, appName, availableHostProtocols, currentHostProtocol,] = await this.infoResolver.getValues([ TapInfo.serialNumber, TapInfo.configVersion, TapInfo.appName, TapInfo.availableHostProtocols, TapInfo.HostProtocol, ]); if (version === FACTORY_RESET_MODE_VERSION || version === CONFIGURATION_MODE_VERSION) { return false; } const config = { serialNumber, version, appName, }; this.addOrRefresh({ connection, config, }); const additionalProtocols = await this._resolveConnectionProtocols(availableHostProtocols, currentHostProtocol); additionalProtocols.forEach((connection) => { this.addOrRefresh({ connection, config, }); }); return true; } _createMqttProtocolFromTapInfo({ brokerHostname, clientId, password, username, netkey, port, serialNumber, }) { clientId = clientId || `${serialNumber}_${Math.round(Math.random() * 1000000)}`; username = this.config.mqtt.username || username; password = this.config.mqtt.password || password; let brokerPort; if (this.platform.is('mobileweb')) { if (!this.config.mqtt.webSocket?.port) { debug(TAG, 'MQTT over web socket is not available (no port configured. Skipping...)'); return undefined; } brokerPort = this.config.mqtt.webSocket.port.toString(); } else { brokerPort = port; } let url; if (!brokerHostname.match(/^[a-z]+:\/\//i)) { let mqttProtocol = this.platform.is('mobileweb') ? 'ws' : 'mqtt'; if (MQTT_SECURE_PORTS.includes(port)) { mqttProtocol += 's'; } url = `${mqttProtocol}://${brokerHostname}`; } else { url = brokerHostname; if (this.platform.is('mobileweb')) { url = url.replace(/^(mqtt)s?:\/\//iu, 'ws'); } } return { type: 'mqtt', info: { username, password, serialNumber, netkey, clientId, endpoint: `${url}:${brokerPort}`, }, }; } async _resolveConnectionProtocols(availableHostProtocols, currentHostProtocol) { debug(TAG, `availableHostProtocols ${availableHostProtocols .map((protocol) => HostProtocol[protocol]) .join(', ')}...`); const results = []; for (const protocol of availableHostProtocols) { if (protocol === HostProtocol.NFC || protocol === currentHostProtocol) { continue; } try { const connectionInfo = await this._resolveConnectionProtocol(protocol); if (connectionInfo) { results.push(connectionInfo); } } catch (err) { console.warn(`Cannot resolve protocol ${HostProtocol[protocol]}`); // TODO log ? } } return results; } async _resolveConnectionProtocol(protocol) { debug(TAG, `_resolveConnectionProtocol ${HostProtocol[protocol]}...`); switch (protocol) { case HostProtocol.BLE: return { type: 'ble', info: { mac: await this.infoResolver.getValue(TapInfo.bleMacAddress), }, }; case HostProtocol.MQTT: let [brokerHostname, serialNumber, netkey, mqttUsername, mqttPassword, port, clientId,] = await this.infoResolver.getValues([ TapInfo.MqttBrokerHostname, TapInfo.serialNumber, TapInfo.MqttRelayNetKey, TapInfo.MqttUsername, TapInfo.MqttPassword, TapInfo.MqttBrokerPort, TapInfo.MqttClientId, ]); return this._createMqttProtocolFromTapInfo({ brokerHostname, serialNumber, netkey, username: mqttUsername, password: mqttPassword, port, clientId, }); case HostProtocol.WIFI: const [wifiMode, wifiHostname, wifiSSID, wifiKey] = await this.infoResolver.getValues([ TapInfo.WifiMode, TapInfo.WifiHostname, TapInfo.WifiSSID, TapInfo.WifiKey, ]); if (wifiHostname && wifiHostname !== '0.0.0.0') { debug(TAG, `resolveConnectionProtocol wifi mode ${WifiMode[wifiMode]}...`); switch (wifiMode) { case WifiMode.NETWORK: return { type: 'socket', info: { url: `tcp://${wifiHostname}:2000`, }, }; case WifiMode.PEER_TO_PEER: return { type: 'wifi', info: { ssid: wifiSSID, url: `tcp://${wifiHostname}:2000`, password: wifiKey, }, }; default: return undefined; } } default: debug(TAG, `resolveConnectionProtocol nothing to store for protocol ${HostProtocol[protocol]}`); return undefined; } } addOrRefresh(newItem) { debug(`${TAG} Adding/updating new stored device ${JSON.stringify(newItem)}...`); const existingItem = this.items.find((item) => { return (item.config.serialNumber === newItem.config.serialNumber && item.connection.type === newItem.connection.type); }); if (existingItem) { existingItem.config = newItem.config; existingItem.connection = newItem.connection; existingItem.meta.lastConnection = new Date(); } else { this.items.push({ connection: newItem.connection, config: newItem.config, meta: { state: 'online', lastConnection: new Date(), }, }); } debug(`${TAG} Added/updated new stored device ${newItem.config.serialNumber} ${newItem.connection.type}`); this.set(this.items); } clear() { this.set([]); } saveToStorage() { localStorage.setItem(this.config.localStorageKey, JSON.stringify(this.items)); } loadFromStorage() { try { const content = localStorage.getItem(this.config.localStorageKey); if (content) { this.set(JSON.parse(content)); } else { this.set([]); } } catch (err) { console.warn('Cannot load stored connection from local storage', err); this.set([]); } } } /** @nocollapse */ TapConnectionStoreService.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.10", ngImport: i0, type: TapConnectionStoreService, deps: [{ token: i1.CurrentDeviceService }, { token: i2.TapInfoRequestService }, { token: i3.Platform }], target: i0.ɵɵFactoryTarget.Injectable }); /** @nocollapse */ TapConnectionStoreService.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "15.2.10", ngImport: i0, type: TapConnectionStoreService, providedIn: 'root' }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.10", ngImport: i0, type: TapConnectionStoreService, decorators: [{ type: Injectable, args: [{ providedIn: 'root', }] }], ctorParameters: function () { return [{ type: i1.CurrentDeviceService }, { type: i2.TapInfoRequestService }, { type: i3.Platform }]; } }); //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidGFwLWNvbm5lY3Rpb24tc3RvcmUuc2VydmljZS5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uLy4uLy4uLy4uL3Byb2plY3RzL2lvdGl6ZS1pb25pYy9zcmMvbGliL3RhcC1jb25uZWN0L3RhcC1jb25uZWN0aW9uLXN0b3JlL3RhcC1jb25uZWN0aW9uLXN0b3JlLnNlcnZpY2UudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUFFLFVBQVUsRUFBRSxNQUFNLGVBQWUsQ0FBQztBQUMzQyxPQUFPLEVBQUUsUUFBUSxFQUFFLE1BQU0sZ0JBQWdCLENBQUM7QUFDMUMsT0FBTyxFQUFFLFlBQVksRUFBRSxNQUFNLGFBQWEsQ0FBQztBQUMzQyxPQUFPLEVBQUUsUUFBUSxFQUFFLE1BQU0sK0JBQStCLENBQUM7QUFDekQsT0FBTyxFQUFFLGFBQWEsRUFBRSxNQUFNLE1BQU0sQ0FBQztBQUVyQyxPQUFPLEVBQ0wsMEJBQTBCLEVBQzFCLDBCQUEwQixHQUMzQixNQUFNLHNCQUFzQixDQUFDO0FBQzlCLE9BQU8sRUFBRSxvQkFBb0IsRUFBRSxNQUFNLDhCQUE4QixDQUFDO0FBRXBFLE9BQU8sRUFBRSxLQUFLLEVBQUUsTUFBTSxjQUFjLENBQUM7QUFDckMsT0FBTyxFQUFFLHFCQUFxQixFQUFFLE1BQU0seUNBQXlDLENBQUM7QUFDaEYsT0FBTyxFQUFFLE9BQU8sRUFBRSxNQUFNLHFCQUFxQixDQUFDOzs7OztBQUc5QyxNQUFNLGlCQUFpQixHQUFHLENBQUMsTUFBTSxDQUFDLENBQUM7QUFFbkMsTUFBTSxHQUFHLEdBQUcsMkJBQTJCLENBQUM7QUFFeEMsTUFBTSxVQUFVLHVCQUF1QixDQUNyQyx1QkFBNkM7SUFFN0MsT0FBTyxDQUFDLE1BQWdDLEVBQTRCLEVBQUU7UUFDcEUsSUFBSSxDQUFDLHVCQUF1QixFQUFFO1lBQzVCLE9BQU8sTUFBTSxDQUFDO1NBQ2Y7UUFDRCxPQUFPLE1BQU0sQ0FBQyxNQUFNLENBQ2xCLENBQUMsS0FBSyxFQUFFLEVBQUUsQ0FBQyx1QkFBdUIsQ0FBQyxPQUFPLENBQUMsS0FBSyxDQUFDLFVBQVUsQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLENBQ3ZFLENBQUM7SUFDSixDQUFDLENBQUM7QUFDSixDQUFDO0FBaUNEOzs7R0FHRztBQUlILE1BQU0sT0FBTyx5QkFBeUI7SUFnQnBDLFlBQ1UsVUFBZ0MsRUFDaEMsWUFBbUMsRUFDbkMsUUFBa0I7UUFGbEIsZUFBVSxHQUFWLFVBQVUsQ0FBc0I7UUFDaEMsaUJBQVksR0FBWixZQUFZLENBQXVCO1FBQ25DLGFBQVEsR0FBUixRQUFRLENBQVU7UUFsQjVCLFVBQUssR0FBNkIsRUFBRSxDQUFDO1FBRXJDLFdBQU0sR0FBRyxJQUFJLGFBQWEsQ0FBMkIsQ0FBQyxDQUFDLENBQUM7UUFFeEQsV0FBTSxHQUE4QztZQUNsRCxlQUFlLEVBQUUsaUNBQWlDO1lBQ2xELElBQUksRUFBRTtnQkFDSixTQUFTLEVBQUU7b0JBQ1QsSUFBSSxFQUFFLElBQUksRUFBRSxvQkFBb0I7aUJBQ2pDO2dCQUNELFFBQVEsRUFBRSxTQUFTO2dCQUNuQixRQUFRLEVBQUUsU0FBUzthQUNwQjtTQUNGLENBQUM7UUFPQSxJQUFJLENBQUMsZUFBZSxFQUFFLENBQUM7SUFDekIsQ0FBQztJQUVELEdBQUcsQ0FBQyxLQUEyQztRQUM3QyxJQUFJLENBQUMsS0FBSyxFQUFFO1lBQ1YsS0FBSyxHQUFHLEVBQUUsQ0FBQztTQUNaO1FBQ0QsSUFBSSxDQUFDLEtBQUssR0FBRyxLQUFLLENBQUM7UUFDbkIsSUFBSSxDQUFDLE1BQU0sQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLEtBQUssQ0FBQyxDQUFDO1FBQzdCLElBQUksQ0FBQyxhQUFhLEVBQUUsQ0FBQztJQUN2QixDQUFDO0lBRUQsTUFBTSxDQUFDLElBQTRCO1FBQ2pDLElBQUksQ0FBQyxLQUFLLENBQUMsTUFBTSxDQUFDLElBQUksQ0FBQyxLQUFLLENBQUMsT0FBTyxDQUFDLElBQUksQ0FBQyxFQUFFLENBQUMsQ0FBQyxDQUFDO1FBQy9DLElBQUksQ0FBQyxHQUFHLENBQUMsSUFBSSxDQUFDLEtBQUssQ0FBQyxDQUFDO0lBQ3ZCLENBQUM7SUFFRDs7O09BR0c7SUFDSCxLQUFLLENBQUMsNkJBQTZCO1FBQ2pDLE1BQU0sVUFBVSxHQUFHLElBQUksQ0FBQyxVQUFVLENBQUMsWUFBWSxDQUFDO1FBQ2hELElBQUksQ0FBQyxVQUFVLEVBQUU7WUFDZixLQUFLLENBQ0gsR0FBRyxHQUFHLDBFQUEwRSxDQUNqRixDQUFDO1lBQ0YsT0FBTyxLQUFLLENBQUM7U0FDZDtRQUNELE1BQU0sQ0FDSixZQUFZLEVBQ1osT0FBTyxFQUNQLE9BQU8sRUFDUCxzQkFBc0IsRUFDdEIsbUJBQW1CLEVBQ3BCLEdBQUcsTUFBTSxJQUFJLENBQUMsWUFBWSxDQUFDLFNBQVMsQ0FFbkM7WUFDQSxPQUFPLENBQUMsWUFBWTtZQUNwQixPQUFPLENBQUMsYUFBYTtZQUNyQixPQUFPLENBQUMsT0FBTztZQUNmLE9BQU8sQ0FBQyxzQkFBc0I7WUFDOUIsT0FBTyxDQUFDLFlBQVk7U0FDckIsQ0FBQyxDQUFDO1FBRUgsSUFDRSxPQUFPLEtBQUssMEJBQTBCO1lBQ3RDLE9BQU8sS0FBSywwQkFBMEIsRUFDdEM7WUFDQSxPQUFPLEtBQUssQ0FBQztTQUNkO1FBRUQsTUFBTSxNQUFNLEdBQUc7WUFDYixZQUFZO1lBQ1osT0FBTztZQUNQLE9BQU87U0FDUixDQUFDO1FBRUYsSUFBSSxDQUFDLFlBQVksQ0FBQztZQUNoQixVQUFVO1lBQ1YsTUFBTTtTQUNQLENBQUMsQ0FBQztRQUVILE1BQU0sbUJBQW1CLEdBQUcsTUFBTSxJQUFJLENBQUMsMkJBQTJCLENBQ2hFLHNCQUFzQixFQUN0QixtQkFBbUIsQ0FDcEIsQ0FBQztRQUNGLG1CQUFtQixDQUFDLE9BQU8sQ0FBQyxDQUFDLFVBQVUsRUFBRSxFQUFFO1lBQ3pDLElBQUksQ0FBQyxZQUFZLENBQUM7Z0JBQ2hCLFVBQVU7Z0JBQ1YsTUFBTTthQUNQLENBQUMsQ0FBQztRQUNMLENBQUMsQ0FBQyxDQUFDO1FBRUgsT0FBTyxJQUFJLENBQUM7SUFDZCxDQUFDO0lBRU8sOEJBQThCLENBQUMsRUFDckMsY0FBYyxFQUNkLFFBQVEsRUFDUixRQUFRLEVBQ1IsUUFBUSxFQUNSLE1BQU0sRUFDTixJQUFJLEVBQ0osWUFBWSxHQVNiO1FBQ0MsUUFBUTtZQUNOLFFBQVEsSUFBSSxHQUFHLFlBQVksSUFBSSxJQUFJLENBQUMsS0FBSyxDQUFDLElBQUksQ0FBQyxNQUFNLEVBQUUsR0FBRyxPQUFPLENBQUMsRUFBRSxDQUFDO1FBRXZFLFFBQVEsR0FBRyxJQUFJLENBQUMsTUFBTSxDQUFDLElBQUksQ0FBQyxRQUFRLElBQUksUUFBUSxDQUFDO1FBQ2pELFFBQVEsR0FBRyxJQUFJLENBQUMsTUFBTSxDQUFDLElBQUksQ0FBQyxRQUFRLElBQUksUUFBUSxDQUFDO1FBRWpELElBQUksVUFBa0IsQ0FBQztRQUN2QixJQUFJLElBQUksQ0FBQyxRQUFRLENBQUMsRUFBRSxDQUFDLFdBQVcsQ0FBQyxFQUFFO1lBQ2pDLElBQUksQ0FBQyxJQUFJLENBQUMsTUFBTSxDQUFDLElBQUksQ0FBQyxTQUFTLEVBQUUsSUFBSSxFQUFFO2dCQUNyQyxLQUFLLENBQ0gsR0FBRyxFQUNILHlFQUF5RSxDQUMxRSxDQUFDO2dCQUNGLE9BQU8sU0FBUyxDQUFDO2FBQ2xCO1lBQ0QsVUFBVSxHQUFHLElBQUksQ0FBQyxNQUFNLENBQUMsSUFBSSxDQUFDLFNBQVMsQ0FBQyxJQUFJLENBQUMsUUFBUSxFQUFFLENBQUM7U0FDekQ7YUFBTTtZQUNMLFVBQVUsR0FBRyxJQUFJLENBQUM7U0FDbkI7UUFDRCxJQUFJLEdBQVcsQ0FBQztRQUNoQixJQUFJLENBQUMsY0FBYyxDQUFDLEtBQUssQ0FBQyxlQUFlLENBQUMsRUFBRTtZQUMxQyxJQUFJLFlBQVksR0FBRyxJQUFJLENBQUMsUUFBUSxDQUFDLEVBQUUsQ0FBQyxXQUFXLENBQUMsQ0FBQyxDQUFDLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQyxNQUFNLENBQUM7WUFDakUsSUFBSSxpQkFBaUIsQ0FBQyxRQUFRLENBQUMsSUFBSSxDQUFDLEVBQUU7Z0JBQ3BDLFlBQVksSUFBSSxHQUFHLENBQUM7YUFDckI7WUFDRCxHQUFHLEdBQUcsR0FBRyxZQUFZLE1BQU0sY0FBYyxFQUFFLENBQUM7U0FDN0M7YUFBTTtZQUNMLEdBQUcsR0FBRyxjQUFjLENBQUM7WUFDckIsSUFBSSxJQUFJLENBQUMsUUFBUSxDQUFDLEVBQUUsQ0FBQyxXQUFXLENBQUMsRUFBRTtnQkFDakMsR0FBRyxHQUFHLEdBQUcsQ0FBQyxPQUFPLENBQUMsa0JBQWtCLEVBQUUsSUFBSSxDQUFDLENBQUM7YUFDN0M7U0FDRjtRQUNELE9BQU87WUFDTCxJQUFJLEVBQUUsTUFBTTtZQUNaLElBQUksRUFBRTtnQkFDSixRQUFRO2dCQUNSLFFBQVE7Z0JBQ1IsWUFBWTtnQkFDWixNQUFNO2dCQUNOLFFBQVE7Z0JBQ1IsUUFBUSxFQUFFLEdBQUcsR0FBRyxJQUFJLFVBQVUsRUFBRTthQUNqQztTQUNGLENBQUM7SUFDSixDQUFDO0lBRU8sS0FBSyxDQUFDLDJCQUEyQixDQUN2QyxzQkFBc0MsRUFDdEMsbUJBQWlDO1FBRWpDLEtBQUssQ0FDSCxHQUFHLEVBQ0gsMEJBQTBCLHNCQUFzQjthQUM3QyxHQUFHLENBQUMsQ0FBQyxRQUFRLEVBQUUsRUFBRSxDQUFDLFlBQVksQ0FBQyxRQUFRLENBQUMsQ0FBQzthQUN6QyxJQUFJLENBQUMsSUFBSSxDQUFDLEtBQUssQ0FDbkIsQ0FBQztRQUNGLE1BQU0sT0FBTyxHQUFtQixFQUFFLENBQUM7UUFDbkMsS0FBSyxNQUFNLFFBQVEsSUFBSSxzQkFBc0IsRUFBRTtZQUM3QyxJQUFJLFFBQVEsS0FBSyxZQUFZLENBQUMsR0FBRyxJQUFJLFFBQVEsS0FBSyxtQkFBbUIsRUFBRTtnQkFDckUsU0FBUzthQUNWO1lBQ0QsSUFBSTtnQkFDRixNQUFNLGNBQWMsR0FBRyxNQUFNLElBQUksQ0FBQywwQkFBMEIsQ0FBQyxRQUFRLENBQUMsQ0FBQztnQkFDdkUsSUFBSSxjQUFjLEVBQUU7b0JBQ2xCLE9BQU8sQ0FBQyxJQUFJLENBQUMsY0FBYyxDQUFDLENBQUM7aUJBQzlCO2FBQ0Y7WUFBQyxPQUFPLEdBQUcsRUFBRTtnQkFDWixPQUFPLENBQUMsSUFBSSxDQUFDLDJCQUEyQixZQUFZLENBQUMsUUFBUSxDQUFDLEVBQUUsQ0FBQyxDQUFDO2dCQUNsRSxhQUFhO2FBQ2Q7U0FDRjtRQUNELE9BQU8sT0FBTyxDQUFDO0lBQ2pCLENBQUM7SUFFTyxLQUFLLENBQUMsMEJBQTBCLENBQ3RDLFFBQXNCO1FBRXRCLEtBQUssQ0FBQyxHQUFHLEVBQUUsOEJBQThCLFlBQVksQ0FBQyxRQUFRLENBQUMsS0FBSyxDQUFDLENBQUM7UUFDdEUsUUFBUSxRQUFRLEVBQUU7WUFDaEIsS0FBSyxZQUFZLENBQUMsR0FBRztnQkFDbkIsT0FBTztvQkFDTCxJQUFJLEVBQUUsS0FBSztvQkFDWCxJQUFJLEVBQUU7d0JBQ0osR0FBRyxFQUFFLE1BQU0sSUFBSSxDQUFDLFlBQVksQ0FBQyxRQUFRLENBQ25DLE9BQU8sQ0FBQyxhQUFhLENBQ3RCO3FCQUNGO2lCQUNGLENBQUM7WUFDSixLQUFLLFlBQVksQ0FBQyxJQUFJO2dCQUNwQixJQUFJLENBQ0YsY0FBYyxFQUNkLFlBQVksRUFDWixNQUFNLEVBQ04sWUFBWSxFQUNaLFlBQVksRUFDWixJQUFJLEVBQ0osUUFBUSxFQUNULEdBQUcsTUFBTSxJQUFJLENBQUMsWUFBWSxDQUFDLFNBQVMsQ0FFbkM7b0JBQ0EsT0FBTyxDQUFDLGtCQUFrQjtvQkFDMUIsT0FBTyxDQUFDLFlBQVk7b0JBQ3BCLE9BQU8sQ0FBQyxlQUFlO29CQUN2QixPQUFPLENBQUMsWUFBWTtvQkFDcEIsT0FBTyxDQUFDLFlBQVk7b0JBQ3BCLE9BQU8sQ0FBQyxjQUFjO29CQUN0QixPQUFPLENBQUMsWUFBWTtpQkFDckIsQ0FBQyxDQUFDO2dCQUNILE9BQU8sSUFBSSxDQUFDLDhCQUE4QixDQUFDO29CQUN6QyxjQUFjO29CQUNkLFlBQVk7b0JBQ1osTUFBTTtvQkFDTixRQUFRLEVBQUUsWUFBWTtvQkFDdEIsUUFBUSxFQUFFLFlBQVk7b0JBQ3RCLElBQUk7b0JBQ0osUUFBUTtpQkFDVCxDQUFDLENBQUM7WUFDTCxLQUFLLFlBQVksQ0FBQyxJQUFJO2dCQUNwQixNQUFNLENBQUMsUUFBUSxFQUFFLFlBQVksRUFBRSxRQUFRLEVBQUUsT0FBTyxDQUFDLEdBQy9DLE1BQU0sSUFBSSxDQUFDLFlBQVksQ0FBQyxTQUFTLENBQy9CO29CQUNFLE9BQU8sQ0FBQyxRQUFRO29CQUNoQixPQUFPLENBQUMsWUFBWTtvQkFDcEIsT0FBTyxDQUFDLFFBQVE7b0JBQ2hCLE9BQU8sQ0FBQyxPQUFPO2lCQUNoQixDQUNGLENBQUM7Z0JBQ0osSUFBSSxZQUFZLElBQUksWUFBWSxLQUFLLFNBQVMsRUFBRTtvQkFDOUMsS0FBSyxDQUNILEdBQUcsRUFDSCx1Q0FBdUMsUUFBUSxDQUFDLFFBQVEsQ0FBQyxLQUFLLENBQy9ELENBQUM7b0JBQ0YsUUFBUSxRQUFRLEVBQUU7d0JBQ2hCLEtBQUssUUFBUSxDQUFDLE9BQU87NEJBQ25CLE9BQU87Z0NBQ0wsSUFBSSxFQUFFLFFBQVE7Z0NBQ2QsSUFBSSxFQUFFO29DQUNKLEdBQUcsRUFBRSxTQUFTLFlBQVksT0FBTztpQ0FDbEM7NkJBQ0YsQ0FBQzt3QkFDSixLQUFLLFFBQVEsQ0FBQyxZQUFZOzRCQUN4QixPQUFPO2dDQUNMLElBQUksRUFBRSxNQUFNO2dDQUNaLElBQUksRUFBRTtvQ0FDSixJQUFJLEVBQUUsUUFBUTtvQ0FDZCxHQUFHLEVBQUUsU0FBUyxZQUFZLE9BQU87b0NBQ2pDLFFBQVEsRUFBRSxPQUFPO2lDQUNsQjs2QkFDRixDQUFDO3dCQUNKOzRCQUNFLE9BQU8sU0FBUyxDQUFDO3FCQUNwQjtpQkFDRjtZQUNIO2dCQUNFLEtBQUssQ0FDSCxHQUFHLEVBQ0gsMkRBQTJELFlBQVksQ0FBQyxRQUFRLENBQUMsRUFBRSxDQUNwRixDQUFDO2dCQUNGLE9BQU8sU0FBUyxDQUFDO1NBQ3BCO0lBQ0gsQ0FBQztJQUVELFlBQVksQ0FBQyxPQUE4RDtRQUN6RSxLQUFLLENBQ0gsR0FBRyxHQUFHLHNDQUFzQyxJQUFJLENBQUMsU0FBUyxDQUFDLE9BQU8sQ0FBQyxLQUFLLENBQ3pFLENBQUM7UUFDRixNQUFNLFlBQVksR0FBRyxJQUFJLENBQUMsS0FBSyxDQUFDLElBQUksQ0FBQyxDQUFDLElBQUksRUFBRSxFQUFFO1lBQzVDLE9BQU8sQ0FDTCxJQUFJLENBQUMsTUFBTSxDQUFDLFlBQVksS0FBSyxPQUFPLENBQUMsTUFBTSxDQUFDLFlBQVk7Z0JBQ3hELElBQUksQ0FBQyxVQUFVLENBQUMsSUFBSSxLQUFLLE9BQU8sQ0FBQyxVQUFVLENBQUMsSUFBSSxDQUNqRCxDQUFDO1FBQ0osQ0FBQyxDQUFDLENBQUM7UUFDSCxJQUFJLFlBQVksRUFBRTtZQUNoQixZQUFZLENBQUMsTUFBTSxHQUFHLE9BQU8sQ0FBQyxNQUFNLENBQUM7WUFDckMsWUFBWSxDQUFDLFVBQVUsR0FBRyxPQUFPLENBQUMsVUFBVSxDQUFDO1lBQzdDLFlBQVksQ0FBQyxJQUFJLENBQUMsY0FBYyxHQUFHLElBQUksSUFBSSxFQUFFLENBQUM7U0FDL0M7YUFBTTtZQUNMLElBQUksQ0FBQyxLQUFLLENBQUMsSUFBSSxDQUFDO2dCQUNkLFVBQVUsRUFBRSxPQUFPLENBQUMsVUFBVTtnQkFDOUIsTUFBTSxFQUFFLE9BQU8sQ0FBQyxNQUFNO2dCQUN0QixJQUFJLEVBQUU7b0JBQ0osS0FBSyxFQUFFLFFBQVE7b0JBQ2YsY0FBYyxFQUFFLElBQUksSUFBSSxFQUFFO2lCQUMzQjthQUNGLENBQUMsQ0FBQztTQUNKO1FBQ0QsS0FBSyxDQUNILEdBQUcsR0FBRyxvQ0FBb0MsT0FBTyxDQUFDLE1BQU0sQ0FBQyxZQUFZLElBQUksT0FBTyxDQUFDLFVBQVUsQ0FBQyxJQUFJLEVBQUUsQ0FDbkcsQ0FBQztRQUNGLElBQUksQ0FBQyxHQUFHLENBQUMsSUFBSSxDQUFDLEtBQUssQ0FBQyxDQUFDO0lBQ3ZCLENBQUM7SUFFRCxLQUFLO1FBQ0gsSUFBSSxDQUFDLEdBQUcsQ0FBQyxFQUFFLENBQUMsQ0FBQztJQUNmLENBQUM7SUFFRCxhQUFhO1FBQ1gsWUFBWSxDQUFDLE9BQU8sQ0FDbEIsSUFBSSxDQUFDLE1BQU0sQ0FBQyxlQUFlLEVBQzNCLElBQUksQ0FBQyxTQUFTLENBQUMsSUFBSSxDQUFDLEtBQUssQ0FBQyxDQUMzQixDQUFDO0lBQ0osQ0FBQztJQUVELGVBQWU7UUFDYixJQUFJO1lBQ0YsTUFBTSxPQUFPLEdBQUcsWUFBWSxDQUFDLE9BQU8sQ0FBQyxJQUFJLENBQUMsTUFBTSxDQUFDLGVBQWUsQ0FBQyxDQUFDO1lBQ2xFLElBQUksT0FBTyxFQUFFO2dCQUNYLElBQUksQ0FBQyxHQUFHLENBQUMsSUFBSSxDQUFDLEtBQUssQ0FBQyxPQUFPLENBQUMsQ0FBQyxDQUFDO2FBQy9CO2lCQUFNO2dCQUNMLElBQUksQ0FBQyxHQUFHLENBQUMsRUFBRSxDQUFDLENBQUM7YUFDZDtTQUNGO1FBQUMsT0FBTyxHQUFHLEVBQUU7WUFDWixPQUFPLENBQUMsSUFBSSxDQUFDLGtEQUFrRCxFQUFFLEdBQUcsQ0FBQyxDQUFDO1lBQ3RFLElBQUksQ0FBQyxHQUFHLENBQUMsRUFBRSxDQUFDLENBQUM7U0FDZDtJQUNILENBQUM7OzBJQXpVVSx5QkFBeUI7OElBQXpCLHlCQUF5QixjQUZ4QixNQUFNOzRGQUVQLHlCQUF5QjtrQkFIckMsVUFBVTttQkFBQztvQkFDVixVQUFVLEVBQUUsTUFBTTtpQkFDbkIiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBJbmplY3RhYmxlIH0gZnJvbSAnQGFuZ3VsYXIvY29yZSc7XG5pbXBvcnQgeyBQbGF0Zm9ybSB9IGZyb20gJ0Bpb25pYy9hbmd1bGFyJztcbmltcG9ydCB7IEhvc3RQcm90b2NvbCB9IGZyb20gJ0Bpb3RpemUvdGFwJztcbmltcG9ydCB7IFdpZmlNb2RlIH0gZnJvbSAnQGlvdGl6ZS90YXAvc2VydmljZS9pbXBsL3dpZmknO1xuaW1wb3J0IHsgUmVwbGF5U3ViamVjdCB9IGZyb20gJ3J4anMnO1xuXG5pbXBvcnQge1xuICBDT05GSUdVUkFUSU9OX01PREVfVkVSU0lPTixcbiAgRkFDVE9SWV9SRVNFVF9NT0RFX1ZFUlNJT04sXG59IGZyb20gJy4uLy4uL2NvbmZpZy12ZXJzaW9uJztcbmltcG9ydCB7IEN1cnJlbnREZXZpY2VTZXJ2aWNlIH0gZnJvbSAnLi4vLi4vY3VycmVudC1kZXZpY2Uuc2VydmljZSc7XG5pbXBvcnQgeyBQcm90b2NvbE1ldGEgfSBmcm9tICcuLi8uLi9leHRlbnNpb25zL3Byb3RvY29sLWluZm8nO1xuaW1wb3J0IHsgZGVidWcgfSBmcm9tICcuLi8uLi9sb2dnZXInO1xuaW1wb3J0IHsgVGFwSW5mb1JlcXVlc3RTZXJ2aWNlIH0gZnJvbSAnLi4vLi4vdGFwLWluZm8vdGFwLWluZm8tcmVxdWVzdC5zZXJ2aWNlJztcbmltcG9ydCB7IFRhcEluZm8gfSBmcm9tICcuLi8uLi90YXAtaW5mby9rZXlzJztcbmltcG9ydCB7IFRhcENvbm5lY3Rpb25TdG9yZUl0ZW0gfSBmcm9tICcuL2RlZmluaXRpb25zJztcblxuY29uc3QgTVFUVF9TRUNVUkVfUE9SVFMgPSBbJzg4ODMnXTtcblxuY29uc3QgVEFHID0gJ1RhcENvbm5lY3Rpb25TdG9yZVNlcnZpY2UnO1xuXG5leHBvcnQgZnVuY3Rpb24gZmlsdGVyQnlDb25uZWN0aW9uVHlwZXMoXG4gIGZpbHRlcmVkQ29ubmVjdGlvblR5cGVzOiBzdHJpbmdbXSB8IHVuZGVmaW5lZFxuKSB7XG4gIHJldHVybiAodmFsdWVzOiBUYXBDb25uZWN0aW9uU3RvcmVJdGVtW10pOiBUYXBDb25uZWN0aW9uU3RvcmVJdGVtW10gPT4ge1xuICAgIGlmICghZmlsdGVyZWRDb25uZWN0aW9uVHlwZXMpIHtcbiAgICAgIHJldHVybiB2YWx1ZXM7XG4gICAgfVxuICAgIHJldHVybiB2YWx1ZXMuZmlsdGVyKFxuICAgICAgKHZhbHVlKSA9PiBmaWx0ZXJlZENvbm5lY3Rpb25UeXBlcy5pbmRleE9mKHZhbHVlLmNvbm5lY3Rpb24udHlwZSkgPj0gMFxuICAgICk7XG4gIH07XG59XG5leHBvcnQgbmFtZXNwYWNlIFRhcENvbm5lY3Rpb25TdG9yZVNlcnZpY2Uge1xuICBleHBvcnQgaW50ZXJmYWNlIEluc3RhbmNlT3B0aW9ucyB7XG4gICAgLyoqXG4gICAgICogbG9jYWxTdG9yZSBrZXkgcGF0aCB0byBzdG9yZSBjb25uZWN0aW9uc1xuICAgICAqL1xuICAgIGxvY2FsU3RvcmFnZUtleTogc3RyaW5nO1xuICAgIC8qKlxuICAgICAqIE1RVFQgcmVsYXRlZCBvcHRpb25zXG4gICAgICovXG4gICAgbXF0dDoge1xuICAgICAgLyoqXG4gICAgICAgKiBGb3IgYnJvd3NlciBhcHAsIHdlIG11c3QgY29ubmVjdCB0byBNUVRUIGJyb2tlciB0aHJvdWdoIHdlYnNvY2tldFxuICAgICAgICogV2UgY2FuIHNwZWNpZnkgdGhlIHBvcnQgdG8gaW4gdGhpcyBjYXNlLlxuICAgICAgICogRm9yIG1vYmlsZSBhcHAgd2UgdXNlIHRoZSBzYW1lIHBvcnQgY29uZmlndXJlZCBpbiB0aGUgVGFwXG4gICAgICAgKi9cbiAgICAgIHdlYlNvY2tldD86IHtcbiAgICAgICAgcG9ydDogbnVtYmVyO1xuICAgICAgfTtcbiAgICAgIC8qKlxuICAgICAgICogTVFUVCBicm9rZXIgdXNlcm5hbWUgdG8gdXNlclxuICAgICAgICogSWYgbm90IHByb3ZpZGVkIGl0IHdpbGwgdXNlIFRBUCB1c2VybmFtZVxuICAgICAgICovXG4gICAgICB1c2VybmFtZT86IHN0cmluZztcbiAgICAgIC8qKlxuICAgICAgICogTVFUVCBicm9rZXIgcGFzc3dvcmQgdG8gdXNlclxuICAgICAgICogSWYgbm90IHByb3ZpZGVkIGl0IHdpbGwgdHJ5IHRvIHVzZSBUQVAgcGFzc3dvcmQgKGlmIG5vdCBwcm90ZWN0ZWQpXG4gICAgICAgKi9cbiAgICAgIHBhc3N3b3JkPzogc3RyaW5nO1xuICAgIH07XG4gIH1cbn1cblxuLyoqXG4gKiBUT0RPIGNoYW5nZSBpbXBsZW1lbnRhdGlvbiB0byBub3QgdHJpZ2dlciBORkMgbG9hZFxuICogVXNlIHJlYWN0aXZlIHByb2dyYW1taW5nIGluc3RlYWRcbiAqL1xuQEluamVjdGFibGUoe1xuICBwcm92aWRlZEluOiAncm9vdCcsXG59KVxuZXhwb3J0IGNsYXNzIFRhcENvbm5lY3Rpb25TdG9yZVNlcnZpY2Uge1xuICBpdGVtczogVGFwQ29ubmVjdGlvblN0b3JlSXRlbVtdID0gW107XG5cbiAgdmFsdWVzID0gbmV3IFJlcGxheVN1YmplY3Q8VGFwQ29ubmVjdGlvblN0b3JlSXRlbVtdPigxKTtcblxuICBjb25maWc6IFRhcENvbm5lY3Rpb25TdG9yZVNlcnZpY2UuSW5zdGFuY2VPcHRpb25zID0ge1xuICAgIGxvY2FsU3RvcmFnZUtleTogJ1RhcENvbm5lY3Rpb25TdG9yZVNlcnZpY2UuaXRlbXMnLFxuICAgIG1xdHQ6IHtcbiAgICAgIHdlYlNvY2tldDoge1xuICAgICAgICBwb3J0OiA5MDAxLCAvLyBUT0RPIGNvbmZpZ3VyYWJsZVxuICAgICAgfSxcbiAgICAgIHVzZXJuYW1lOiB1bmRlZmluZWQsXG4gICAgICBwYXNzd29yZDogdW5kZWZpbmVkLFxuICAgIH0sXG4gIH07XG5cbiAgY29uc3RydWN0b3IoXG4gICAgcHJpdmF0ZSB0YXBTZXJ2aWNlOiBDdXJyZW50RGV2aWNlU2VydmljZSxcbiAgICBwcml2YXRlIGluZm9SZXNvbHZlcjogVGFwSW5mb1JlcXVlc3RTZXJ2aWNlLFxuICAgIHByaXZhdGUgcGxhdGZvcm06IFBsYXRmb3JtXG4gICkge1xuICAgIHRoaXMubG9hZEZyb21TdG9yYWdlKCk7XG4gIH1cblxuICBzZXQoaXRlbXM6IFRhcENvbm5lY3Rpb25TdG9yZUl0ZW1bXSB8IHVuZGVmaW5lZCkge1xuICAgIGlmICghaXRlbXMpIHtcbiAgICAgIGl0ZW1zID0gW107XG4gICAgfVxuICAgIHRoaXMuaXRlbXMgPSBpdGVtcztcbiAgICB0aGlzLnZhbHVlcy5uZXh0KHRoaXMuaXRlbXMpO1xuICAgIHRoaXMuc2F2ZVRvU3RvcmFnZSgpO1xuICB9XG5cbiAgcmVtb3ZlKGl0ZW06IFRhcENvbm5lY3Rpb25TdG9yZUl0ZW0pIHtcbiAgICB0aGlzLml0ZW1zLnNwbGljZSh0aGlzLml0ZW1zLmluZGV4T2YoaXRlbSksIDEpO1xuICAgIHRoaXMuc2V0KHRoaXMuaXRlbXMpO1xuICB9XG5cbiAgLyoqXG4gICAqIFRyeSB0byBhZGQgb3IgcmVmcmVzaCBjdXJyZW50IHN0b3JlZCBjb25uZWN0aW9uIGluZm9cbiAgICpcbiAgICovXG4gIGFzeW5jIHN0b3JlQ3VycmVudFRhcENvbm5lY3Rpb25JbmZvKCk6IFByb21pc2U8Ym9vbGVhbj4ge1xuICAgIGNvbnN0IGNvbm5lY3Rpb24gPSB0aGlzLnRhcFNlcnZpY2UucHJvdG9jb2xNZXRhO1xuICAgIGlmICghY29ubmVjdGlvbikge1xuICAgICAgZGVidWcoXG4gICAgICAgIGAke1RBR30gTm8gcHJvdG9jb2wgY29ubmVjdGlvbiBpbmZvIGZvciB0aGlzIFRhcC4gQ2Fubm90IHN0b3JlIGNvbm5lY3Rpb24gaW5mby5gXG4gICAgICApO1xuICAgICAgcmV0dXJuIGZhbHNlO1xuICAgIH1cbiAgICBjb25zdCBbXG4gICAgICBzZXJpYWxOdW1iZXIsXG4gICAgICB2ZXJzaW9uLFxuICAgICAgYXBwTmFtZSxcbiAgICAgIGF2YWlsYWJsZUhvc3RQcm90b2NvbHMsXG4gICAgICBjdXJyZW50SG9zdFByb3RvY29sLFxuICAgIF0gPSBhd2FpdCB0aGlzLmluZm9SZXNvbHZlci5nZXRWYWx1ZXM8XG4gICAgICBbc3RyaW5nLCBzdHJpbmcsIHN0cmluZywgSG9zdFByb3RvY29sW10sIEhvc3RQcm90b2NvbF1cbiAgICA+KFtcbiAgICAgIFRhcEluZm8uc2VyaWFsTnVtYmVyLFxuICAgICAgVGFwSW5mby5jb25maWdWZXJzaW9uLFxuICAgICAgVGFwSW5mby5hcHBOYW1lLFxuICAgICAgVGFwSW5mby5hdmFpbGFibGVIb3N0UHJvdG9jb2xzLFxuICAgICAgVGFwSW5mby5Ib3N0UHJvdG9jb2wsXG4gICAgXSk7XG5cbiAgICBpZiAoXG4gICAgICB2ZXJzaW9uID09PSBGQUNUT1JZX1JFU0VUX01PREVfVkVSU0lPTiB8fFxuICAgICAgdmVyc2lvbiA9PT0gQ09ORklHVVJBVElPTl9NT0RFX1ZFUlNJT05cbiAgICApIHtcbiAgICAgIHJldHVybiBmYWxzZTtcbiAgICB9XG5cbiAgICBjb25zdCBjb25maWcgPSB7XG4gICAgICBzZXJpYWxOdW1iZXIsXG4gICAgICB2ZXJzaW9uLFxuICAgICAgYXBwTmFtZSxcbiAgICB9O1xuXG4gICAgdGhpcy5hZGRPclJlZnJlc2goe1xuICAgICAgY29ubmVjdGlvbixcbiAgICAgIGNvbmZpZyxcbiAgICB9KTtcblxuICAgIGNvbnN0IGFkZGl0aW9uYWxQcm90b2NvbHMgPSBhd2FpdCB0aGlzLl9yZXNvbHZlQ29ubmVjdGlvblByb3RvY29scyhcbiAgICAgIGF2YWlsYWJsZUhvc3RQcm90b2NvbHMsXG4gICAgICBjdXJyZW50SG9zdFByb3RvY29sXG4gICAgKTtcbiAgICBhZGRpdGlvbmFsUHJvdG9jb2xzLmZvckVhY2goKGNvbm5lY3Rpb24pID0+IHtcbiAgICAgIHRoaXMuYWRkT3JSZWZyZXNoKHtcbiAgICAgICAgY29ubmVjdGlvbixcbiAgICAgICAgY29uZmlnLFxuICAgICAgfSk7XG4gICAgfSk7XG5cbiAgICByZXR1cm4gdHJ1ZTtcbiAgfVxuXG4gIHByaXZhdGUgX2NyZWF0ZU1xdHRQcm90b2NvbEZyb21UYXBJbmZvKHtcbiAgICBicm9rZXJIb3N0bmFtZSxcbiAgICBjbGllbnRJZCxcbiAgICBwYXNzd29yZCxcbiAgICB1c2VybmFtZSxcbiAgICBuZXRrZXksXG4gICAgcG9ydCxcbiAgICBzZXJpYWxOdW1iZXIsXG4gIH06IHtcbiAgICBicm9rZXJIb3N0bmFtZTogc3RyaW5nO1xuICAgIHNlcmlhbE51bWJlcjogc3RyaW5nO1xuICAgIG5ldGtleTogc3RyaW5nO1xuICAgIHBvcnQ6IHN0cmluZztcbiAgICBjbGllbnRJZD86IHN0cmluZztcbiAgICB1c2VybmFtZT86IHN0cmluZztcbiAgICBwYXNzd29yZD86IHN0cmluZztcbiAgfSk6IFByb3RvY29sTWV0YSB8IFByb21pc2VMaWtlPFByb3RvY29sTWV0YSB8IHVuZGVmaW5lZD4gfCB1bmRlZmluZWQge1xuICAgIGNsaWVudElkID1cbiAgICAgIGNsaWVudElkIHx8IGAke3NlcmlhbE51bWJlcn1fJHtNYXRoLnJvdW5kKE1hdGgucmFuZG9tKCkgKiAxMDAwMDAwKX1gO1xuXG4gICAgdXNlcm5hbWUgPSB0aGlzLmNvbmZpZy5tcXR0LnVzZXJuYW1lIHx8IHVzZXJuYW1lO1xuICAgIHBhc3N3b3JkID0gdGhpcy5jb25maWcubXF0dC5wYXNzd29yZCB8fCBwYXNzd29yZDtcblxuICAgIGxldCBicm9rZXJQb3J0OiBzdHJpbmc7XG4gICAgaWYgKHRoaXMucGxhdGZvcm0uaXMoJ21vYmlsZXdlYicpKSB7XG4gICAgICBpZiAoIXRoaXMuY29uZmlnLm1xdHQud2ViU29ja2V0Py5wb3J0KSB7XG4gICAgICAgIGRlYnVnKFxuICAgICAgICAgIFRBRyxcbiAgICAgICAgICAnTVFUVCBvdmVyIHdlYiBzb2NrZXQgaXMgbm90IGF2YWlsYWJsZSAobm8gcG9ydCBjb25maWd1cmVkLiBTa2lwcGluZy4uLiknXG4gICAgICAgICk7XG4gICAgICAgIHJldHVybiB1bmRlZmluZWQ7XG4gICAgICB9XG4gICAgICBicm9rZXJQb3J0ID0gdGhpcy5jb25maWcubXF0dC53ZWJTb2NrZXQucG9ydC50b1N0cmluZygpO1xuICAgIH0gZWxzZSB7XG4gICAgICBicm9rZXJQb3J0ID0gcG9ydDtcbiAgICB9XG4gICAgbGV0IHVybDogc3RyaW5nO1xuICAgIGlmICghYnJva2VySG9zdG5hbWUubWF0Y2goL15bYS16XSs6XFwvXFwvL2kpKSB7XG4gICAgICBsZXQgbXF0dFByb3RvY29sID0gdGhpcy5wbGF0Zm9ybS5pcygnbW9iaWxld2ViJykgPyAnd3MnIDogJ21xdHQnO1xuICAgICAgaWYgKE1RVFRfU0VDVVJFX1BPUlRTLmluY2x1ZGVzKHBvcnQpKSB7XG4gICAgICAgIG1xdHRQcm90b2NvbCArPSAncyc7XG4gICAgICB9XG4gICAgICB1cmwgPSBgJHttcXR0UHJvdG9jb2x9Oi8vJHticm9rZXJIb3N0bmFtZX1gO1xuICAgIH0gZWxzZSB7XG4gICAgICB1cmwgPSBicm9rZXJIb3N0bmFtZTtcbiAgICAgIGlmICh0aGlzLnBsYXRmb3JtLmlzKCdtb2JpbGV3ZWInKSkge1xuICAgICAgICB1cmwgPSB1cmwucmVwbGFjZSgvXihtcXR0KXM/OlxcL1xcLy9pdSwgJ3dzJyk7XG4gICAgICB9XG4gICAgfVxuICAgIHJldHVybiB7XG4gICAgICB0eXBlOiAnbXF0dCcsXG4gICAgICBpbmZvOiB7XG4gICAgICAgIHVzZXJuYW1lLFxuICAgICAgICBwYXNzd29yZCxcbiAgICAgICAgc2VyaWFsTnVtYmVyLFxuICAgICAgICBuZXRrZXksXG4gICAgICAgIGNsaWVudElkLFxuICAgICAgICBlbmRwb2ludDogYCR7dXJsfToke2Jyb2tlclBvcnR9YCxcbiAgICAgIH0sXG4gICAgfTtcbiAgfVxuXG4gIHByaXZhdGUgYXN5bmMgX3Jlc29sdmVDb25uZWN0aW9uUHJvdG9jb2xzKFxuICAgIGF2YWlsYWJsZUhvc3RQcm90b2NvbHM6IEhvc3RQcm90b2NvbFtdLFxuICAgIGN1cnJlbnRIb3N0UHJvdG9jb2w6IEhvc3RQcm90b2NvbFxuICApIHtcbiAgICBkZWJ1ZyhcbiAgICAgIFRBRyxcbiAgICAgIGBhdmFpbGFibGVIb3N0UHJvdG9jb2xzICR7YXZhaWxhYmxlSG9zdFByb3RvY29sc1xuICAgICAgICAubWFwKChwcm90b2NvbCkgPT4gSG9zdFByb3RvY29sW3Byb3RvY29sXSlcbiAgICAgICAgLmpvaW4oJywgJyl9Li4uYFxuICAgICk7XG4gICAgY29uc3QgcmVzdWx0czogUHJvdG9jb2xNZXRhW10gPSBbXTtcbiAgICBmb3IgKGNvbnN0IHByb3RvY29sIG9mIGF2YWlsYWJsZUhvc3RQcm90b2NvbHMpIHtcbiAgICAgIGlmIChwcm90b2NvbCA9PT0gSG9zdFByb3RvY29sLk5GQyB8fCBwcm90b2NvbCA9PT0gY3VycmVudEhvc3RQcm90b2NvbCkge1xuICAgICAgICBjb250aW51ZTtcbiAgICAgIH1cbiAgICAgIHRyeSB7XG4gICAgICAgIGNvbnN0IGNvbm5lY3Rpb25JbmZvID0gYXdhaXQgdGhpcy5fcmVzb2x2ZUNvbm5lY3Rpb25Qcm90b2NvbChwcm90b2NvbCk7XG4gICAgICAgIGlmIChjb25uZWN0aW9uSW5mbykge1xuICAgICAgICAgIHJlc3VsdHMucHVzaChjb25uZWN0aW9uSW5mbyk7XG4gICAgICAgIH1cbiAgICAgIH0gY2F0Y2ggKGVycikge1xuICAgICAgICBjb25zb2xlLndhcm4oYENhbm5vdCByZXNvbHZlIHByb3RvY29sICR7SG9zdFByb3RvY29sW3Byb3RvY29sXX1gKTtcbiAgICAgICAgLy8gVE9ETyBsb2cgP1xuICAgICAgfVxuICAgIH1cbiAgICByZXR1cm4gcmVzdWx0cztcbiAgfVxuXG4gIHByaXZhdGUgYXN5bmMgX3Jlc29sdmVDb25uZWN0aW9uUHJvdG9jb2woXG4gICAgcHJvdG9jb2w6IEhvc3RQcm90b2NvbFxuICApOiBQcm9taXNlPFByb3RvY29sTWV0YSB8IHVuZGVmaW5lZD4ge1xuICAgIGRlYnVnKFRBRywgYF9yZXNvbHZlQ29ubmVjdGlvblByb3RvY29sICR7SG9zdFByb3RvY29sW3Byb3RvY29sXX0uLi5gKTtcbiAgICBzd2l0Y2ggKHByb3RvY29sKSB7XG4gICAgICBjYXNlIEhvc3RQcm90b2NvbC5CTEU6XG4gICAgICAgIHJldHVybiB7XG4gICAgICAgICAgdHlwZTogJ2JsZScsXG4gICAgICAgICAgaW5mbzoge1xuICAgICAgICAgICAgbWFjOiBhd2FpdCB0aGlzLmluZm9SZXNvbHZlci5nZXRWYWx1ZTxzdHJpbmc+KFxuICAgICAgICAgICAgICBUYXBJbmZvLmJsZU1hY0FkZHJlc3NcbiAgICAgICAgICAgICksXG4gICAgICAgICAgfSxcbiAgICAgICAgfTtcbiAgICAgIGNhc2UgSG9zdFByb3RvY29sLk1RVFQ6XG4gICAgICAgIGxldCBbXG4gICAgICAgICAgYnJva2VySG9zdG5hbWUsXG4gICAgICAgICAgc2VyaWFsTnVtYmVyLFxuICAgICAgICAgIG5ldGtleSxcbiAgICAgICAgICBtcXR0VXNlcm5hbWUsXG4gICAgICAgICAgbXF0dFBhc3N3b3JkLFxuICAgICAgICAgIHBvcnQsXG4gICAgICAgICAgY2xpZW50SWQsXG4gICAgICAgIF0gPSBhd2FpdCB0aGlzLmluZm9SZXNvbHZlci5nZXRWYWx1ZXM8XG4gICAgICAgICAgW3N0cmluZywgc3RyaW5nLCBzdHJpbmcsIHN0cmluZywgc3RyaW5nLCBzdHJpbmcsIHN0cmluZ11cbiAgICAgICAgPihbXG4gICAgICAgICAgVGFwSW5mby5NcXR0QnJva2VySG9zdG5hbWUsXG4gICAgICAgICAgVGFwSW5mby5zZXJpYWxOdW1iZXIsXG4gICAgICAgICAgVGFwSW5mby5NcXR0UmVsYXlOZXRLZXksXG4gICAgICAgICAgVGFwSW5mby5NcXR0VXNlcm5hbWUsXG4gICAgICAgICAgVGFwSW5mby5NcXR0UGFzc3dvcmQsXG4gICAgICAgICAgVGFwSW5mby5NcXR0QnJva2VyUG9ydCxcbiAgICAgICAgICBUYXBJbmZvLk1xdHRDbGllbnRJZCxcbiAgICAgICAgXSk7XG4gICAgICAgIHJldHVybiB0aGlzLl9jcmVhdGVNcXR0UHJvdG9jb2xGcm9tVGFwSW5mbyh7XG4gICAgICAgICAgYnJva2VySG9zdG5hbWUsXG4gICAgICAgICAgc2VyaWFsTnVtYmVyLFxuICAgICAgICAgIG5ldGtleSxcbiAgICAgICAgICB1c2VybmFtZTogbXF0dFVzZXJuYW1lLFxuICAgICAgICAgIHBhc3N3b3JkOiBtcXR0UGFzc3dvcmQsXG4gICAgICAgICAgcG9ydCxcbiAgICAgICAgICBjbGllbnRJZCxcbiAgICAgICAgfSk7XG4gICAgICBjYXNlIEhvc3RQcm90b2NvbC5XSUZJOlxuICAgICAgICBjb25zdCBbd2lmaU1vZGUsIHdpZmlIb3N0bmFtZSwgd2lmaVNTSUQsIHdpZmlLZXldID1cbiAgICAgICAgICBhd2FpdCB0aGlzLmluZm9SZXNvbHZlci5nZXRWYWx1ZXM8W1dpZmlNb2RlLCBzdHJpbmcsIHN0cmluZywgc3RyaW5nXT4oXG4gICAgICAgICAgICBbXG4gICAgICAgICAgICAgIFRhcEluZm8uV2lmaU1vZGUsXG4gICAgICAgICAgICAgIFRhcEluZm8uV2lmaUhvc3RuYW1lLFxuICAgICAgICAgICAgICBUYXBJbmZvLldpZmlTU0lELFxuICAgICAgICAgICAgICBUYXBJbmZvLldpZmlLZXksXG4gICAgICAgICAgICBdXG4gICAgICAgICAgKTtcbiAgICAgICAgaWYgKHdpZmlIb3N0bmFtZSAmJiB3aWZpSG9zdG5hbWUgIT09ICcwLjAuMC4wJykge1xuICAgICAgICAgIGRlYnVnKFxuICAgICAgICAgICAgVEFHLFxuICAgICAgICAgICAgYHJlc29sdmVDb25uZWN0aW9uUHJvdG9jb2wgd2lmaSBtb2RlICR7V2lmaU1vZGVbd2lmaU1vZGVdfS4uLmBcbiAgICAgICAgICApO1xuICAgICAgICAgIHN3aXRjaCAod2lmaU1vZGUpIHtcbiAgICAgICAgICAgIGNhc2UgV2lmaU1vZGUuTkVUV09SSzpcbiAgICAgICAgICAgICAgcmV0dXJuIHtcbiAgICAgICAgICAgICAgICB0eXBlOiAnc29ja2V0JyxcbiAgICAgICAgICAgICAgICBpbmZvOiB7XG4gICAgICAgICAgICAgICAgICB1cmw6IGB0Y3A6Ly8ke3dpZmlIb3N0bmFtZX06MjAwMGAsXG4gICAgICAgICAgICAgICAgfSxcbiAgICAgICAgICAgICAgfTtcbiAgICAgICAgICAgIGNhc2UgV2lmaU1vZGUuUEVFUl9UT19QRUVSOlxuICAgICAgICAgICAgICByZXR1cm4ge1xuICAgICAgICAgICAgICAgIHR5cGU6ICd3aWZpJyxcbiAgICAgICAgICAgICAgICBpbmZvOiB7XG4gICAgICAgICAgICAgICAgICBzc2lkOiB3aWZpU1NJRCxcbiAgICAgICAgICAgICAgICAgIHVybDogYHRjcDovLyR7d2lmaUhvc3RuYW1lfToyMDAwYCxcbiAgICAgICAgICAgICAgICAgIHBhc3N3b3JkOiB3aWZpS2V5LFxuICAgICAgICAgICAgICAgIH0sXG4gICAgICAgICAgICAgIH07XG4gICAgICAgICAgICBkZWZhdWx0OlxuICAgICAgICAgICAgICByZXR1cm4gdW5kZWZpbmVkO1xuICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgZGVmYXVsdDpcbiAgICAgICAgZGVidWcoXG4gICAgICAgICAgVEFHLFxuICAgICAgICAgIGByZXNvbHZlQ29ubmVjdGlvblByb3RvY29sIG5vdGhpbmcgdG8gc3RvcmUgZm9yIHByb3RvY29sICR7SG9zdFByb3RvY29sW3Byb3RvY29sXX1gXG4gICAgICAgICk7XG4gICAgICAgIHJldHVybiB1bmRlZmluZWQ7XG4gICAgfVxuICB9XG5cbiAgYWRkT3JSZWZyZXNoKG5ld0l0ZW06IFBpY2s8VGFwQ29ubmVjdGlvblN0b3JlSXRlbSwgJ2Nvbm5lY3Rpb24nIHwgJ2NvbmZpZyc+KSB7XG4gICAgZGVidWcoXG4gICAgICBgJHtUQUd9IEFkZGluZy91cGRhdGluZyBuZXcgc3RvcmVkIGRldmljZSAke0pTT04uc3RyaW5naWZ5KG5ld0l0ZW0pfS4uLmBcbiAgICApO1xuICAgIGNvbnN0IGV4aXN0aW5nSXRlbSA9IHRoaXMuaXRlbXMuZmluZCgoaXRlbSkgPT4ge1xuICAgICAgcmV0dXJuIChcbiAgICAgICAgaXRlbS5jb25maWcuc2VyaWFsTnVtYmVyID09PSBuZXdJdGVtLmNvbmZpZy5zZXJpYWxOdW1iZXIgJiZcbiAgICAgICAgaXRlbS5jb25uZWN0aW9uLnR5cGUgPT09IG5ld0l0ZW0uY29ubmVjdGlvbi50eXBlXG4gICAgICApO1xuICAgIH0pO1xuICAgIGlmIChleGlzdGluZ0l0ZW0pIHtcbiAgICAgIGV4aXN0aW5nSXRlbS5jb25maWcgPSBuZXdJdGVtLmNvbmZpZztcbiAgICAgIGV4aXN0aW5nSXRlbS5jb25uZWN0aW9uID0gbmV3SXRlbS5jb25uZWN0aW9uO1xuICAgICAgZXhpc3RpbmdJdGVtLm1ldGEubGFzdENvbm5lY3Rpb24gPSBuZXcgRGF0ZSgpO1xuICAgIH0gZWxzZSB7XG4gICAgICB0aGlzLml0ZW1zLnB1c2goe1xuICAgICAgICBjb25uZWN0aW9uOiBuZXdJdGVtLmNvbm5lY3Rpb24sXG4gICAgICAgIGNvbmZpZzogbmV3SXRlbS5jb25maWcsXG4gICAgICAgIG1ldGE6IHtcbiAgICAgICAgICBzdGF0ZTogJ29ubGluZScsXG4gICAgICAgICAgbGFzdENvbm5lY3Rpb246IG5ldyBEYXRlKCksXG4gICAgICAgIH0sXG4gICAgICB9KTtcbiAgICB9XG4gICAgZGVidWcoXG4gICAgICBgJHtUQUd9IEFkZGVkL3VwZGF0ZWQgbmV3IHN0b3JlZCBkZXZpY2UgJHtuZXdJdGVtLmNvbmZpZy5zZXJpYWxOdW1iZXJ9ICR7bmV3SXRlbS5jb25uZWN0aW9uLnR5cGV9YFxuICAgICk7XG4gICAgdGhpcy5zZXQodGhpcy5pdGVtcyk7XG4gIH1cblxuICBjbGVhcigpIHtcbiAgICB0aGlzLnNldChbXSk7XG4gIH1cblxuICBzYXZlVG9TdG9yYWdlKCkge1xuICAgIGxvY2FsU3RvcmFnZS5zZXRJdGVtKFxuICAgICAgdGhpcy5jb25maWcubG9jYWxTdG9yYWdlS2V5LFxuICAgICAgSlNPTi5zdHJpbmdpZnkodGhpcy5pdGVtcylcbiAgICApO1xuICB9XG5cbiAgbG9hZEZyb21TdG9yYWdlKCkge1xuICAgIHRyeSB7XG4gICAgICBjb25zdCBjb250ZW50ID0gbG9jYWxTdG9yYWdlLmdldEl0ZW0odGhpcy5jb25maWcubG9jYWxTdG9yYWdlS2V5KTtcbiAgICAgIGlmIChjb250ZW50KSB7XG4gICAgICAgIHRoaXMuc2V0KEpTT04ucGFyc2UoY29udGVudCkpO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgdGhpcy5zZXQoW10pO1xuICAgICAgfVxuICAgIH0gY2F0Y2ggKGVycikge1xuICAgICAgY29uc29sZS53YXJuKCdDYW5ub3QgbG9hZCBzdG9yZWQgY29ubmVjdGlvbiBmcm9tIGxvY2FsIHN0b3JhZ2UnLCBlcnIpO1xuICAgICAgdGhpcy5zZXQoW10pO1xuICAgIH1cbiAgfVxufVxuIl19