@iotize/ionic
Version:
Iotize specific building blocks on top of @ionic/angular.
281 lines • 36.5 kB
JavaScript
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,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidGFwLWNvbm5lY3Rpb24tc3RvcmUuc2VydmljZS5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uLy4uLy4uLy4uL3Byb2plY3RzL2lvdGl6ZS1pb25pYy9zcmMvbGliL3RhcC1jb25uZWN0L3RhcC1jb25uZWN0aW9uLXN0b3JlL3RhcC1jb25uZWN0aW9uLXN0b3JlLnNlcnZpY2UudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUFFLFVBQVUsRUFBRSxNQUFNLGVBQWUsQ0FBQztBQUMzQyxPQUFPLEVBQUUsUUFBUSxFQUFFLE1BQU0sZ0JBQWdCLENBQUM7QUFDMUMsT0FBTyxFQUFFLFlBQVksRUFBRSxNQUFNLGFBQWEsQ0FBQztBQUMzQyxPQUFPLEVBQUUsUUFBUSxFQUFFLE1BQU0sK0JBQStCLENBQUM7QUFDekQsT0FBTyxFQUFFLGFBQWEsRUFBRSxNQUFNLE1BQU0sQ0FBQztBQUVyQyxPQUFPLEVBQ0wsMEJBQTBCLEVBQzFCLDBCQUEwQixHQUMzQixNQUFNLHNCQUFzQixDQUFDO0FBQzlCLE9BQU8sRUFBRSxvQkFBb0IsRUFBRSxNQUFNLDhCQUE4QixDQUFDO0FBRXBFLE9BQU8sRUFBRSxLQUFLLEVBQUUsTUFBTSxjQUFjLENBQUM7QUFDckMsT0FBTyxFQUFFLHFCQUFxQixFQUFFLE1BQU0seUNBQXlDLENBQUM7QUFDaEYsT0FBTyxFQUFFLE9BQU8sRUFBRSxNQUFNLHFCQUFxQixDQUFDOzs7OztBQUc5QyxNQUFNLGlCQUFpQixHQUFHLENBQUMsTUFBTSxDQUFDLENBQUM7QUFFbkMsTUFBTSxHQUFHLEdBQUcsMkJBQTJCLENBQUM7QUFFeEMsTUFBTSxVQUFVLHVCQUF1QixDQUNyQyx1QkFBNkM7SUFFN0MsT0FBTyxDQUFDLE1BQWdDLEVBQTRCLEVBQUU7UUFDcEUsSUFBSSxDQUFDLHVCQUF1QixFQUFFO1lBQzVCLE9BQU8sTUFBTSxDQUFDO1NBQ2Y7UUFDRCxPQUFPLE1BQU0sQ0FBQyxNQUFNLENBQ2xCLENB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QU0sQ0FBQyxlQUFlLEVBQzNCLElBQUksQ0FBQyxTQUFTLENBQUMsSUFBSSxDQUFDLEtBQUssQ0FBQyxDQUMzQixDQUFDO0lBQ0osQ0FBQztJQUVELGVBQWU7UUFDYixJQUFJO1lBQ0YsTUFBTSxPQUFPLEdBQUcsWUFBWSxDQUFDLE9BQU8sQ0FBQyxJQUFJLENBQUMsTUFBTSxDQUFDLGVBQWUsQ0FBQyxDQUFDO1lBQ2xFLElBQUksT0FBTyxFQUFFO2dCQUNYLElBQUksQ0FBQyxHQUFHLENBQUMsSUFBSSxDQUFDLEtBQUssQ0FBQyxPQUFPLENBQUMsQ0FBQyxDQUFDO2FBQy9CO2lCQUFNO2dCQUNMLElBQUksQ0FBQyxHQUFHLENBQUMsRUFBRSxDQUFDLENBQUM7YUFDZDtTQUNGO1FBQUMsT0FBTyxHQUFHLEVBQUU7WUFDWixPQUFPLENBQUMsSUFBSSxDQUFDLGtEQUFrRCxFQUFFLEdBQUcsQ0FBQyxDQUFDO1lBQ3RFLElBQUksQ0FBQyxHQUFHLENBQUMsRUFBRSxDQUFDLENBQUM7U0FDZDtJQUNILENBQUM7OzBJQXpVVSx5QkFBeUI7OElBQXpCLHlCQUF5QixjQUZ4QixNQUFNOzRGQUVQLHlCQUF5QjtrQkFIckMsVUFBVTttQkFBQztvQkFDVixVQUFVLEVBQUUsTUFBTTtpQkFDbkIiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBJbmplY3RhYmxlIH0gZnJvbSAnQGFuZ3VsYXIvY29yZSc7XG5pbXBvcnQgeyBQbGF0Zm9ybSB9IGZyb20gJ0Bpb25pYy9hbmd1bGFyJztcbmltcG9ydCB7IEhvc3RQcm90b2NvbCB9IGZyb20gJ0Bpb3RpemUvdGFwJztcbmltcG9ydCB7IFdpZmlNb2RlIH0gZnJvbSAnQGlvdGl6ZS90YXAvc2VydmljZS9pbXBsL3dpZmknO1xuaW1wb3J0IHsgUmVwbGF5U3ViamVjdCB9IGZyb20gJ3J4anMnO1xuXG5pbXBvcnQge1xuICBDT05GSUdVUkFUSU9OX01PREVfVkVSU0lPTixcbiAgRkFDVE9SWV9SRVNFVF9NT0RFX1ZFUlNJT04sXG59IGZyb20gJy4uLy4uL2NvbmZpZy12ZXJzaW9uJztcbmltcG9ydCB7IEN1cnJlbnREZXZpY2VTZXJ2aWNlIH0gZnJvbSAnLi4vLi4vY3VycmVudC1kZXZpY2Uuc2VydmljZSc7XG5pbXBvcnQgeyBQcm90b2NvbE1ldGEgfSBmcm9tICcuLi8uLi9leHRlbnNpb25zL3Byb3RvY29sLWluZm8nO1xuaW1wb3J0IHsgZGVidWcgfSBmcm9tICcuLi8uLi9sb2dnZXInO1xuaW1wb3J0IHsgVGFwSW5mb1JlcXVlc3RTZXJ2aWNlIH0gZnJvbSAnLi4vLi4vdGFwLWluZm8vdGFwLWluZm8tcmVxdWVzdC5zZXJ2aWNlJztcbmltcG9ydCB7IFRhcEluZm8gfSBmcm9tICcuLi8uLi90YXAtaW5mby9rZXlzJztcbmltcG9ydCB7IFRhcENvbm5lY3Rpb25TdG9yZUl0ZW0gfSBmcm9tICcuL2RlZmluaXRpb25zJztcblxuY29uc3QgTVFUVF9TRUNVUkVfUE9SVFMgPSBbJzg4ODMnXTtcblxuY29uc3QgVEFHID0gJ1RhcENvbm5lY3Rpb25TdG9yZVNlcnZpY2UnO1xuXG5leHBvcnQgZnVuY3Rpb24gZmlsdGVyQnlDb25uZWN0aW9uVHlwZXMoXG4gIGZpbHRlcmVkQ29ubmVjdGlvblR5cGVzOiBzdHJpbmdbXSB8IHVuZGVmaW5lZFxuKSB7XG4gIHJldHVybiAodmFsdWVzOiBUYXBDb25uZWN0aW9uU3RvcmVJdGVtW10pOiBUYXBDb25uZWN0aW9uU3RvcmVJdGVtW10gPT4ge1xuICAgIGlmICghZmlsdGVyZWRDb25uZWN0aW9uVHlwZXMpIHtcbiAgICAgIHJldHVybiB2YWx1ZXM7XG4gICAgfVxuICAgIHJldHVybiB2YWx1ZXMuZmlsdGVyKFxuICAgICAgKHZhbHVlKSA9PiBmaWx0ZXJlZENvbm5lY3Rpb25UeXBlcy5pbmRleE9mKHZhbHVlLmNvbm5lY3Rpb24udHlwZSkgPj0gMFxuICAgICk7XG4gIH07XG59XG5leHBvcnQgbmFtZXNwYWNlIFRhcENvbm5lY3Rpb25TdG9yZVNlcnZpY2Uge1xuICBleHBvcnQgaW50ZXJmYWNlIEluc3RhbmNlT3B0aW9ucyB7XG4gICAgLyoqXG4gICAgICogbG9jYWxTdG9yZSBrZXkgcGF0aCB0byBzdG9yZSBjb25uZWN0aW9uc1xuICAgICAqL1xuICAgIGxvY2FsU3RvcmFnZUtleTogc3RyaW5nO1xuICAgIC8qKlxuICAgICAqIE1RVFQgcmVsYXRlZCBvcHRpb25zXG4gICAgICovXG4gICAgbXF0dDoge1xuICAgICAgLyoqXG4gICAgICAgKiBGb3IgYnJvd3NlciBhcHAsIHdlIG11c3QgY29ubmVjdCB0byBNUVRUIGJyb2tlciB0aHJvdWdoIHdlYnNvY2tldFxuICAgICAgICogV2UgY2FuIHNwZWNpZnkgdGhlIHBvcnQgdG8gaW4gdGhpcyBjYXNlLlxuICAgICAgICogRm9yIG1vYmlsZSBhcHAgd2UgdXNlIHRoZSBzYW1lIHBvcnQgY29uZmlndXJlZCBpbiB0aGUgVGFwXG4gICAgICAgKi9cbiAgICAgIHdlYlNvY2tldD86IHtcbiAgICAgICAgcG9ydDogbnVtYmVyO1xuICAgICAgfTtcbiAgICAgIC8qKlxuICAgICAgICogTVFUVCBicm9rZXIgdXNlcm5hbWUgdG8gdXNlclxuICAgICAgICogSWYgbm90IHByb3ZpZGVkIGl0IHdpbGwgdXNlIFRBUCB1c2VybmFtZVxuICAgICAgICovXG4gICAgICB1c2VybmFtZT86IHN0cmluZztcbiAgICAgIC8qKlxuICAgICAgICogTVFUVCBicm9rZXIgcGFzc3dvcmQgdG8gdXNlclxuICAgICAgICogSWYgbm90IHByb3ZpZGVkIGl0IHdpbGwgdHJ5IHRvIHVzZSBUQVAgcGFzc3dvcmQgKGlmIG5vdCBwcm90ZWN0ZWQpXG4gICAgICAgKi9cbiAgICAgIHBhc3N3b3JkPzogc3RyaW5nO1xuICAgIH07XG4gIH1cbn1cblxuLyoqXG4gKiBUT0RPIGNoYW5nZSBpbXBsZW1lbnRhdGlvbiB0byBub3QgdHJpZ2dlciBORkMgbG9hZFxuICogVXNlIHJlYWN0aXZlIHByb2dyYW1taW5nIGluc3RlYWRcbiAqL1xuQEluamVjdGFibGUoe1xuICBwcm92aWRlZEluOiAncm9vdCcsXG59KVxuZXhwb3J0IGNsYXNzIFRhcENvbm5lY3Rpb25TdG9yZVNlcnZpY2Uge1xuICBpdGVtczogVGFwQ29ubmVjdGlvblN0b3JlSXRlbVtdID0gW107XG5cbiAgdmFsdWVzID0gbmV3IFJlcGxheVN1YmplY3Q8VGFwQ29ubmVjdGlvblN0b3JlSXRlbVtdPigxKTtcblxuICBjb25maWc6IFRhcENvbm5lY3Rpb25TdG9yZVNlcnZpY2UuSW5zdGFuY2VPcHRpb25zID0ge1xuICAgIGxvY2FsU3RvcmFnZUtleTogJ1RhcENvbm5lY3Rpb25TdG9yZVNlcnZpY2UuaXRlbXMnLFxuICAgIG1xdHQ6IHtcbiAgICAgIHdlYlNvY2tldDoge1xuICAgICAgICBwb3J0OiA5MDAxLCAvLyBUT0RPIGNvbmZpZ3VyYWJsZVxuICAgICAgfSxcbiAgICAgIHVzZXJuYW1lOiB1bmRlZmluZWQsXG4gICAgICBwYXNzd29yZDogdW5kZWZpbmVkLFxuICAgIH0sXG4gIH07XG5cbiAgY29uc3RydWN0b3IoXG4gICAgcHJpdmF0ZSB0YXBTZXJ2aWNlOiBDdXJyZW50RGV2aWNlU2VydmljZSxcbiAgICBwcml2YXRlIGluZm9SZXNvbHZlcjogVGFwSW5mb1JlcXVlc3RTZXJ2aWNlLFxuICAgIHByaXZhdGUgcGxhdGZvcm06IFBsYXRmb3JtXG4gICkge1xuICAgIHRoaXMubG9hZEZyb21TdG9yYWdlKCk7XG4gIH1cblxuICBzZXQoaXRlbXM6IFRhcENvbm5lY3Rpb25TdG9yZUl0ZW1bXSB8IHVuZGVmaW5lZCkge1xuICAgIGlmICghaXRlbXMpIHtcbiAgICAgIGl0ZW1zID0gW107XG4gICAgfVxuICAgIHRoaXMuaXRlbXMgPSBpdGVtcztcbiAgICB0aGlzLnZhbHVlcy5uZXh0KHRoaXMuaXRlbXMpO1xuICAgIHRoaXMuc2F2ZVRvU3RvcmFnZSgpO1xuICB9XG5cbiAgcmVtb3ZlKGl0ZW06IFRhcENvbm5lY3Rpb25TdG9yZUl0ZW0pIHtcbiAgICB0aGlzLml0ZW1zLnNwbGljZSh0aGlzLml0ZW1zLmluZGV4T2YoaXRlbSksIDEpO1xuICAgIHRoaXMuc2V0KHRoaXMuaXRlbXMpO1xuICB9XG5cbiAgLyoqXG4gICAqIFRyeSB0byBhZGQgb3IgcmVmcmVzaCBjdXJyZW50IHN0b3JlZCBjb25uZWN0aW9uIGluZm9cbiAgICpcbiAgICovXG4gIGFzeW5jIHN0b3JlQ3VycmVudFRhcENvbm5lY3Rpb25JbmZvKCk6IFByb21pc2U8Ym9vbGVhbj4ge1xuICAgIGNvbnN0IGNvbm5lY3Rpb24gPSB0aGlzLnRhcFNlcnZpY2UucHJvdG9jb2xNZXRhO1xuICAgIGlmICghY29ubmVjdGlvbikge1xuICAgICAgZGVidWcoXG4gICAgICAgIGAke1RBR30gTm8gcHJvdG9jb2wgY29ubmVjdGlvbiBpbmZvIGZvciB0aGlzIFRhcC4gQ2Fubm90IHN0b3JlIGNvbm5lY3Rpb24gaW5mby5gXG4gICAgICApO1xuICAgICAgcmV0dXJuIGZhbHNlO1xuICAgIH1cbiAgICBjb25zdCBbXG4gICAgICBzZXJpYWxOdW1iZXIsXG4gICAgICB2ZXJzaW9uLFxuICAgICAgYXBwTmFtZSxcbiAgICAgIGF2YWlsYWJsZUhvc3RQcm90b2NvbHMsXG4gICAgICBjdXJyZW50SG9zdFByb3RvY29sLFxuICAgIF0gPSBhd2FpdCB0aGlzLmluZm9SZXNvbHZlci5nZXRWYWx1ZXM8XG4gICAgICBbc3RyaW5nLCBzdHJpbmcsIHN0cmluZywgSG9zdFByb3RvY29sW10sIEhvc3RQcm90b2NvbF1cbiAgICA+KFtcbiAgICAgIFRhcEluZm8uc2VyaWFsTnVtYmVyLFxuICAgICAgVGFwSW5mby5jb25maWdWZXJzaW9uLFxuICAgICAgVGFwSW5mby5hcHBOYW1lLFxuICAgICAgVGFwSW5mby5hdmFpbGFibGVIb3N0UHJvdG9jb2xzLFxuICAgICAgVGFwSW5mby5Ib3N0UHJvdG9jb2wsXG4gICAgXSk7XG5cbiAgICBpZiAoXG4gICAgICB2ZXJzaW9uID09PSBGQUNUT1JZX1JFU0VUX01PREVfVkVSU0lPTiB8fFxuICAgICAgdmVyc2lvbiA9PT0gQ09ORklHVVJBVElPTl9NT0RFX1ZFUlNJT05cbiAgICApIHtcbiAgICAgIHJldHVybiBmYWxzZTtcbiAgICB9XG5cbiAgICBjb25zdCBjb25maWcgPSB7XG4gICAgICBzZXJpYWxOdW1iZXIsXG4gICAgICB2ZXJzaW9uLFxuICAgICAgYXBwTmFtZSxcbiAgICB9O1xuXG4gICAgdGhpcy5hZGRPclJlZnJlc2goe1xuICAgICAgY29ubmVjdGlvbixcbiAgICAgIGNvbmZpZyxcbiAgICB9KTtcblxuICAgIGNvbnN0IGFkZGl0aW9uYWxQcm90b2NvbHMgPSBhd2FpdCB0aGlzLl9yZXNvbHZlQ29ubmVjdGlvblByb3RvY29scyhcbiAgICAgIGF2YWlsYWJsZUhvc3RQcm90b2NvbHMsXG4gICAgICBjdXJyZW50SG9zdFByb3RvY29sXG4gICAgKTtcbiAgICBhZGRpdGlvbmFsUHJvdG9jb2xzLmZvckVhY2goKGNvbm5lY3Rpb24pID0+IHtcbiAgICAgIHRoaXMuYWRkT3JSZWZyZXNoKHtcbiAgICAgICAgY29ubmVjdGlvbixcbiAgICAgICAgY29uZmlnLFxuICAgICAgfSk7XG4gICAgfSk7XG5cbiAgICByZXR1cm4gdHJ1ZTtcbiAgfVxuXG4gIHByaXZhdGUgX2NyZWF0ZU1xdHRQcm90b2NvbEZyb21UYXBJbmZvKHtcbiAgICBicm9rZXJIb3N0bmFtZSxcbiAgICBjbGllbnRJZCxcbiAgICBwYXNzd29yZCxcbiAgICB1c2VybmFtZSxcbiAgICBuZXRrZXksXG4gICAgcG9ydCxcbiAgICBzZXJpYWxOdW1iZXIsXG4gIH06IHtcbiAgICBicm9rZXJIb3N0bmFtZTogc3RyaW5nO1xuICAgIHNlcmlhbE51bWJlcjogc3RyaW5nO1xuICAgIG5ldGtleTogc3RyaW5nO1xuICAgIHBvcnQ6IHN0cmluZztcbiAgICBjbGllbnRJZD86IHN0cmluZztcbiAgICB1c2VybmFtZT86IHN0cmluZztcbiAgICBwYXNzd29yZD86IHN0cmluZztcbiAgfSk6IFByb3RvY29sTWV0YSB8IFByb21pc2VMaWtlPFByb3RvY29sTWV0YSB8IHVuZGVmaW5lZD4gfCB1bmRlZmluZWQge1xuICAgIGNsaWVudElkID1cbiAgICAgIGNsaWVudElkIHx8IGAke3NlcmlhbE51bWJlcn1fJHtNYXRoLnJvdW5kKE1hdGgucmFuZG9tKCkgKiAxMDAwMDAwKX1gO1xuXG4gICAgdXNlcm5hbWUgPSB0aGlzLmNvbmZpZy5tcXR0LnVzZXJuYW1lIHx8IHVzZXJuYW1lO1xuICAgIHBhc3N3b3JkID0gdGhpcy5jb25maWcubXF0dC5wYXNzd29yZCB8fCBwYXNzd29yZDtcblxuICAgIGxldCBicm9rZXJQb3J0OiBzdHJpbmc7XG4gICAgaWYgKHRoaXMucGxhdGZvcm0uaXMoJ21vYmlsZXdlYicpKSB7XG4gICAgICBpZiAoIXRoaXMuY29uZmlnLm1xdHQud2ViU29ja2V0Py5wb3J0KSB7XG4gICAgICAgIGRlYnVnKFxuICAgICAgICAgIFRBRyxcbiAgICAgICAgICAnTVFUVCBvdmVyIHdlYiBzb2NrZXQgaXMgbm90IGF2YWlsYWJsZSAobm8gcG9ydCBjb25maWd1cmVkLiBTa2lwcGluZy4uLiknXG4gICAgICAgICk7XG4gICAgICAgIHJldHVybiB1bmRlZmluZWQ7XG4gICAgICB9XG4gICAgICBicm9rZXJQb3J0ID0gdGhpcy5jb25maWcubXF0dC53ZWJTb2NrZXQucG9ydC50b1N0cmluZygpO1xuICAgIH0gZWxzZSB7XG4gICAgICBicm9rZXJQb3J0ID0gcG9ydDtcbiAgICB9XG4gICAgbGV0IHVybDogc3RyaW5nO1xuICAgIGlmICghYnJva2VySG9zdG5hbWUubWF0Y2goL15bYS16XSs6XFwvXFwvL2kpKSB7XG4gICAgICBsZXQgbXF0dFByb3RvY29sID0gdGhpcy5wbGF0Zm9ybS5pcygnbW9iaWxld2ViJykgPyAnd3MnIDogJ21xdHQnO1xuICAgICAgaWYgKE1RVFRfU0VDVVJFX1BPUlRTLmluY2x1ZGVzKHBvcnQpKSB7XG4gICAgICAgIG1xdHRQcm90b2NvbCArPSAncyc7XG4gICAgICB9XG4gICAgICB1cmwgPSBgJHttcXR0UHJvdG9jb2x9Oi8vJHticm9rZXJIb3N0bmFtZX1gO1xuICAgIH0gZWxzZSB7XG4gICAgICB1cmwgPSBicm9rZXJIb3N0bmFtZTtcbiAgICAgIGlmICh0aGlzLnBsYXRmb3JtLmlzKCdtb2JpbGV3ZWInKSkge1xuICAgICAgICB1cmwgPSB1cmwucmVwbGFjZSgvXihtcXR0KXM/OlxcL1xcLy9pdSwgJ3dzJyk7XG4gICAgICB9XG4gICAgfVxuICAgIHJldHVybiB7XG4gICAgICB0eXBlOiAnbXF0dCcsXG4gICAgICBpbmZvOiB7XG4gICAgICAgIHVzZXJuYW1lLFxuICAgICAgICBwYXNzd29yZCxcbiAgICAgICAgc2VyaWFsTnVtYmVyLFxuICAgICAgICBuZXRrZXksXG4gICAgICAgIGNsaWVudElkLFxuICAgICAgICBlbmRwb2ludDogYCR7dXJsfToke2Jyb2tlclBvcnR9YCxcbiAgICAgIH0sXG4gICAgfTtcbiAgfVxuXG4gIHByaXZhdGUgYXN5bmMgX3Jlc29sdmVDb25uZWN0aW9uUHJvdG9jb2xzKFxuICAgIGF2YWlsYWJsZUhvc3RQcm90b2NvbHM6IEhvc3RQcm90b2NvbFtdLFxuICAgIGN1cnJlbnRIb3N0UHJvdG9jb2w6IEhvc3RQcm90b2NvbFxuICApIHtcbiAgICBkZWJ1ZyhcbiAgICAgIFRBRyxcbiAgICAgIGBhdmFpbGFibGVIb3N0UHJvdG9jb2xzICR7YXZhaWxhYmxlSG9zdFByb3RvY29sc1xuICAgICAgICAubWFwKChwcm90b2NvbCkgPT4gSG9zdFByb3RvY29sW3Byb3RvY29sXSlcbiAgICAgICAgLmpvaW4oJywgJyl9Li4uYFxuICAgICk7XG4gICAgY29uc3QgcmVzdWx0czogUHJvdG9jb2xNZXRhW10gPSBbXTtcbiAgICBmb3IgKGNvbnN0IHByb3RvY29sIG9mIGF2YWlsYWJsZUhvc3RQcm90b2NvbHMpIHtcbiAgICAgIGlmIChwcm90b2NvbCA9PT0gSG9zdFByb3RvY29sLk5GQyB8fCBwcm90b2NvbCA9PT0gY3VycmVudEhvc3RQcm90b2NvbCkge1xuICAgICAgICBjb250aW51ZTtcbiAgICAgIH1cbiAgICAgIHRyeSB7XG4gICAgICAgIGNvbnN0IGNvbm5lY3Rpb25JbmZvID0gYXdhaXQgdGhpcy5fcmVzb2x2ZUNvbm5lY3Rpb25Qcm90b2NvbChwcm90b2NvbCk7XG4gICAgICAgIGlmIChjb25uZWN0aW9uSW5mbykge1xuICAgICAgICAgIHJlc3VsdHMucHVzaChjb25uZWN0aW9uSW5mbyk7XG4gICAgICAgIH1cbiAgICAgIH0gY2F0Y2ggKGVycikge1xuICAgICAgICBjb25zb2xlLndhcm4oYENhbm5vdCByZXNvbHZlIHByb3RvY29sICR7SG9zdFByb3RvY29sW3Byb3RvY29sXX1gKTtcbiAgICAgICAgLy8gVE9ETyBsb2cgP1xuICAgICAgfVxuICAgIH1cbiAgICByZXR1cm4gcmVzdWx0cztcbiAgfVxuXG4gIHByaXZhdGUgYXN5bmMgX3Jlc29sdmVDb25uZWN0aW9uUHJvdG9jb2woXG4gICAgcHJvdG9jb2w6IEhvc3RQcm90b2NvbFxuICApOiBQcm9taXNlPFByb3RvY29sTWV0YSB8IHVuZGVmaW5lZD4ge1xuICAgIGRlYnVnKFRBRywgYF9yZXNvbHZlQ29ubmVjdGlvblByb3RvY29sICR7SG9zdFByb3RvY29sW3Byb3RvY29sXX0uLi5gKTtcbiAgICBzd2l0Y2ggKHByb3RvY29sKSB7XG4gICAgICBjYXNlIEhvc3RQcm90b2NvbC5CTEU6XG4gICAgICAgIHJldHVybiB7XG4gICAgICAgICAgdHlwZTogJ2JsZScsXG4gICAgICAgICAgaW5mbzoge1xuICAgICAgICAgICAgbWFjOiBhd2FpdCB0aGlzLmluZm9SZXNvbHZlci5nZXRWYWx1ZTxzdHJpbmc+KFxuICAgICAgICAgICAgICBUYXBJbmZvLmJsZU1hY0FkZHJlc3NcbiAgICAgICAgICAgICksXG4gICAgICAgICAgfSxcbiAgICAgICAgfTtcbiAgICAgIGNhc2UgSG9zdFByb3RvY29sLk1RVFQ6XG4gICAgICAgIGxldCBbXG4gICAgICAgICAgYnJva2VySG9zdG5hbWUsXG4gICAgICAgICAgc2VyaWFsTnVtYmVyLFxuICAgICAgICAgIG5ldGtleSxcbiAgICAgICAgICBtcXR0VXNlcm5hbWUsXG4gICAgICAgICAgbXF0dFBhc3N3b3JkLFxuICAgICAgICAgIHBvcnQsXG4gICAgICAgICAgY2xpZW50SWQsXG4gICAgICAgIF0gPSBhd2FpdCB0aGlzLmluZm9SZXNvbHZlci5nZXRWYWx1ZXM8XG4gICAgICAgICAgW3N0cmluZywgc3RyaW5nLCBzdHJpbmcsIHN0cmluZywgc3RyaW5nLCBzdHJpbmcsIHN0cmluZ11cbiAgICAgICAgPihbXG4gICAgICAgICAgVGFwSW5mby5NcXR0QnJva2VySG9zdG5hbWUsXG4gICAgICAgICAgVGFwSW5mby5zZXJpYWxOdW1iZXIsXG4gICAgICAgICAgVGFwSW5mby5NcXR0UmVsYXlOZXRLZXksXG4gICAgICAgICAgVGFwSW5mby5NcXR0VXNlcm5hbWUsXG4gICAgICAgICAgVGFwSW5mby5NcXR0UGFzc3dvcmQsXG4gICAgICAgICAgVGFwSW5mby5NcXR0QnJva2VyUG9ydCxcbiAgICAgICAgICBUYXBJbmZvLk1xdHRDbGllbnRJZCxcbiAgICAgICAgXSk7XG4gICAgICAgIHJldHVybiB0aGlzLl9jcmVhdGVNcXR0UHJvdG9jb2xGcm9tVGFwSW5mbyh7XG4gICAgICAgICAgYnJva2VySG9zdG5hbWUsXG4gICAgICAgICAgc2VyaWFsTnVtYmVyLFxuICAgICAgICAgIG5ldGtleSxcbiAgICAgICAgICB1c2VybmFtZTogbXF0dFVzZXJuYW1lLFxuICAgICAgICAgIHBhc3N3b3JkOiBtcXR0UGFzc3dvcmQsXG4gICAgICAgICAgcG9ydCxcbiAgICAgICAgICBjbGllbnRJZCxcbiAgICAgICAgfSk7XG4gICAgICBjYXNlIEhvc3RQcm90b2NvbC5XSUZJOlxuICAgICAgICBjb25zdCBbd2lmaU1vZGUsIHdpZmlIb3N0bmFtZSwgd2lmaVNTSUQsIHdpZmlLZXldID1cbiAgICAgICAgICBhd2FpdCB0aGlzLmluZm9SZXNvbHZlci5nZXRWYWx1ZXM8W1dpZmlNb2RlLCBzdHJpbmcsIHN0cmluZywgc3RyaW5nXT4oXG4gICAgICAgICAgICBbXG4gICAgICAgICAgICAgIFRhcEluZm8uV2lmaU1vZGUsXG4gICAgICAgICAgICAgIFRhcEluZm8uV2lmaUhvc3RuYW1lLFxuICAgICAgICAgICAgICBUYXBJbmZvLldpZmlTU0lELFxuICAgICAgICAgICAgICBUYXBJbmZvLldpZmlLZXksXG4gICAgICAgICAgICBdXG4gICAgICAgICAgKTtcbiAgICAgICAgaWYgKHdpZmlIb3N0bmFtZSAmJiB3aWZpSG9zdG5hbWUgIT09ICcwLjAuMC4wJykge1xuICAgICAgICAgIGRlYnVnKFxuICAgICAgICAgICAgVEFHLFxuICAgICAgICAgICAgYHJlc29sdmVDb25uZWN0aW9uUHJvdG9jb2wgd2lmaSBtb2RlICR7V2lmaU1vZGVbd2lmaU1vZGVdfS4uLmBcbiAgICAgICAgICApO1xuICAgICAgICAgIHN3aXRjaCAod2lmaU1vZGUpIHtcbiAgICAgICAgICAgIGNhc2UgV2lmaU1vZGUuTkVUV09SSzpcbiAgICAgICAgICAgICAgcmV0dXJuIHtcbiAgICAgICAgICAgICAgICB0eXBlOiAnc29ja2V0JyxcbiAgICAgICAgICAgICAgICBpbmZvOiB7XG4gICAgICAgICAgICAgICAgICB1cmw6IGB0Y3A6Ly8ke3dpZmlIb3N0bmFtZX06MjAwMGAsXG4gICAgICAgICAgICAgICAgfSxcbiAgICAgICAgICAgICAgfTtcbiAgICAgICAgICAgIGNhc2UgV2lmaU1vZGUuUEVFUl9UT19QRUVSOlxuICAgICAgICAgICAgICByZXR1cm4ge1xuICAgICAgICAgICAgICAgIHR5cGU6ICd3aWZpJyxcbiAgICAgICAgICAgICAgICBpbmZvOiB7XG4gICAgICAgICAgICAgICAgICBzc2lkOiB3aWZpU1NJRCxcbiAgICAgICAgICAgICAgICAgIHVybDogYHRjcDovLyR7d2lmaUhvc3RuYW1lfToyMDAwYCxcbiAgICAgICAgICAgICAgICAgIHBhc3N3b3JkOiB3aWZpS2V5LFxuICAgICAgICAgICAgICAgIH0sXG4gICAgICAgICAgICAgIH07XG4gICAgICAgICAgICBkZWZhdWx0OlxuICAgICAgICAgICAgICByZXR1cm4gdW5kZWZpbmVkO1xuICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgZGVmYXVsdDpcbiAgICAgICAgZGVidWcoXG4gICAgICAgICAgVEFHLFxuICAgICAgICAgIGByZXNvbHZlQ29ubmVjdGlvblByb3RvY29sIG5vdGhpbmcgdG8gc3RvcmUgZm9yIHByb3RvY29sICR7SG9zdFByb3RvY29sW3Byb3RvY29sXX1gXG4gICAgICAgICk7XG4gICAgICAgIHJldHVybiB1bmRlZmluZWQ7XG4gICAgfVxuICB9XG5cbiAgYWRkT3JSZWZyZXNoKG5ld0l0ZW06IFBpY2s8VGFwQ29ubmVjdGlvblN0b3JlSXRlbSwgJ2Nvbm5lY3Rpb24nIHwgJ2NvbmZpZyc+KSB7XG4gICAgZGVidWcoXG4gICAgICBgJHtUQUd9IEFkZGluZy91cGRhdGluZyBuZXcgc3RvcmVkIGRldmljZSAke0pTT04uc3RyaW5naWZ5KG5ld0l0ZW0pfS4uLmBcbiAgICApO1xuICAgIGNvbnN0IGV4aXN0aW5nSXRlbSA9IHRoaXMuaXRlbXMuZmluZCgoaXRlbSkgPT4ge1xuICAgICAgcmV0dXJuIChcbiAgICAgICAgaXRlbS5jb25maWcuc2VyaWFsTnVtYmVyID09PSBuZXdJdGVtLmNvbmZpZy5zZXJpYWxOdW1iZXIgJiZcbiAgICAgICAgaXRlbS5jb25uZWN0aW9uLnR5cGUgPT09IG5ld0l0ZW0uY29ubmVjdGlvbi50eXBlXG4gICAgICApO1xuICAgIH0pO1xuICAgIGlmIChleGlzdGluZ0l0ZW0pIHtcbiAgICAgIGV4aXN0aW5nSXRlbS5jb25maWcgPSBuZXdJdGVtLmNvbmZpZztcbiAgICAgIGV4aXN0aW5nSXRlbS5jb25uZWN0aW9uID0gbmV3SXRlbS5jb25uZWN0aW9uO1xuICAgICAgZXhpc3RpbmdJdGVtLm1ldGEubGFzdENvbm5lY3Rpb24gPSBuZXcgRGF0ZSgpO1xuICAgIH0gZWxzZSB7XG4gICAgICB0aGlzLml0ZW1zLnB1c2goe1xuICAgICAgICBjb25uZWN0aW9uOiBuZXdJdGVtLmNvbm5lY3Rpb24sXG4gICAgICAgIGNvbmZpZzogbmV3SXRlbS5jb25maWcsXG4gICAgICAgIG1ldGE6IHtcbiAgICAgICAgICBzdGF0ZTogJ29ubGluZScsXG4gICAgICAgICAgbGFzdENvbm5lY3Rpb246IG5ldyBEYXRlKCksXG4gICAgICAgIH0sXG4gICAgICB9KTtcbiAgICB9XG4gICAgZGVidWcoXG4gICAgICBgJHtUQUd9IEFkZGVkL3VwZGF0ZWQgbmV3IHN0b3JlZCBkZXZpY2UgJHtuZXdJdGVtLmNvbmZpZy5zZXJpYWxOdW1iZXJ9ICR7bmV3SXRlbS5jb25uZWN0aW9uLnR5cGV9YFxuICAgICk7XG4gICAgdGhpcy5zZXQodGhpcy5pdGVtcyk7XG4gIH1cblxuICBjbGVhcigpIHtcbiAgICB0aGlzLnNldChbXSk7XG4gIH1cblxuICBzYXZlVG9TdG9yYWdlKCkge1xuICAgIGxvY2FsU3RvcmFnZS5zZXRJdGVtKFxuICAgICAgdGhpcy5jb25maWcubG9jYWxTdG9yYWdlS2V5LFxuICAgICAgSlNPTi5zdHJpbmdpZnkodGhpcy5pdGVtcylcbiAgICApO1xuICB9XG5cbiAgbG9hZEZyb21TdG9yYWdlKCkge1xuICAgIHRyeSB7XG4gICAgICBjb25zdCBjb250ZW50ID0gbG9jYWxTdG9yYWdlLmdldEl0ZW0odGhpcy5jb25maWcubG9jYWxTdG9yYWdlS2V5KTtcbiAgICAgIGlmIChjb250ZW50KSB7XG4gICAgICAgIHRoaXMuc2V0KEpTT04ucGFyc2UoY29udGVudCkpO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgdGhpcy5zZXQoW10pO1xuICAgICAgfVxuICAgIH0gY2F0Y2ggKGVycikge1xuICAgICAgY29uc29sZS53YXJuKCdDYW5ub3QgbG9hZCBzdG9yZWQgY29ubmVjdGlvbiBmcm9tIGxvY2FsIHN0b3JhZ2UnLCBlcnIpO1xuICAgICAgdGhpcy5zZXQoW10pO1xuICAgIH1cbiAgfVxufVxuIl19