@c8y/ngx-components
Version:
Angular modules for Cumulocity IoT applications
201 lines • 30.8 kB
JavaScript
import { Component, Optional } from '@angular/core';
import { AlertService, ContextRouteComponent, gettext } from '@c8y/ngx-components';
import { TranslateService } from '@ngx-translate/core';
import { OpcuaService } from './opcuaService';
import * as i0 from "@angular/core";
import * as i1 from "./opcuaService";
import * as i2 from "@c8y/ngx-components";
import * as i3 from "@ngx-translate/core";
import * as i4 from "@angular/common";
import * as i5 from "ngx-bootstrap/popover";
import * as i6 from "./opcua-server-list.component";
import * as i7 from "./opcua-server-config.component";
export class OpcuaServersComponent {
constructor(opcuaService, alertService, translateService, context) {
this.opcuaService = opcuaService;
this.alertService = alertService;
this.translateService = translateService;
this.context = context;
this.serverObjectList = [];
this.initialServerObject = {
id: '',
name: 'New Server',
config: {
securityMode: 'NONE',
keystorePass: null,
keystoreBinaryId: null,
keystoreFilename: '',
certificatePass: null,
serverUrl: '',
userName: '',
userPassword: '',
rescanCron: null,
timeout: null,
autoReconnect: true,
statusCheckInterval: null,
valid: true
},
quickInfo: {
padlock: 'unlock',
padlockMsg: ''
},
active: true
};
this.active = false;
this.moId = '';
this.NEW_SERVER_ID = 'new';
this.initialServerObject.id = this.NEW_SERVER_ID;
}
async ngOnInit() {
this.moId = this.opcuaService.getMoId();
if (this.moId && this.moId.length > 0) {
const res = await this.opcuaService.getServers(this.moId);
if (res && res.status !== 200) {
const data = res.json ? await res.json() : undefined;
this.alertService.addServerFailure({ data, res });
}
else {
this.serverObjectList = (await res.json());
this.serverObjectList.map(server => this.setQuickInfo(server));
this.onPresent(this.serverObjectList[0]);
}
}
}
localServerObjectExist() {
return !!this.serverObjectList.find(server => server.id === this.NEW_SERVER_ID);
}
addServer() {
const server = this.initialServerObject;
this.serverObjectList.push(server);
this.onPresent(server);
}
onSaved(server) {
if (server && server.id) {
server.gatewayId = this.moId;
if (server.id === this.NEW_SERVER_ID) {
this.createServer(server);
}
else {
this.updateServer(server);
}
}
}
reloadTabs() {
if (this.context) {
this.context.refreshTabs();
}
}
onCanceled(server) {
if (server && server.id && server.id === this.NEW_SERVER_ID) {
this.removeServerObjectListById(server.id);
}
else {
// update activity status for UI
this.serverObjectList.forEach(item => {
if (item.id === server.id) {
item.active = false;
}
});
// When server id is not 'new' we just close the details
delete this.server;
}
}
onRemoved(server) {
if (server.id === this.NEW_SERVER_ID) {
this.onCanceled(server);
}
else {
this.removeServer(server);
}
}
async getKeystore(binaryId) {
const { data } = await this.opcuaService.getKeystore(binaryId);
return data;
}
async onPresent(server) {
if (server &&
server.id !== this.NEW_SERVER_ID &&
server.config &&
server.config.keystoreBinaryId) {
try {
const mo = await this.getKeystore(server.config.keystoreBinaryId);
server.config.keystoreFilename = mo.name;
}
catch (ex) {
this.server = Object.assign({}, server);
console.log('Could not get existing keystore:', ex);
}
}
if (this.serverObjectList.length > 0) {
this.serverObjectList.forEach(item => {
item.active = false;
if (item.id === server.id) {
item.active = true;
server.active = item.active;
}
});
this.setQuickInfo(server);
this.server = Object.assign({}, server);
}
}
async createServer(server) {
const response = await this.opcuaService.createServer(server);
const svr = (await response.json());
this.updateServerObjectListById(this.NEW_SERVER_ID, svr);
this.onPresent(svr);
this.reloadTabs();
}
async updateServer(server) {
const updatedServer = (await this.opcuaService.updateServer(server));
if (updatedServer) {
this.updateServerObjectListById(updatedServer.id, updatedServer);
}
}
async removeServer(server) {
try {
await this.opcuaService.removeServer(server);
this.removeServerObjectListById(server.id);
this.reloadTabs();
}
catch (ex) {
console.log('Could not remove OPC UA server:', ex);
}
}
removeServerObjectListById(id) {
this.serverObjectList.forEach((item, index) => {
if (item.id === id) {
this.serverObjectList.splice(index, 1);
delete this.server;
}
});
}
updateServerObjectListById(id, server) {
const idx = this.serverObjectList.findIndex(item => item.id === id);
if (idx > -1) {
this.setQuickInfo(server);
this.serverObjectList[idx] = server;
}
delete this.server;
}
setQuickInfo(server) {
server.quickInfo = {
padlock: 'unlock',
padlockMsg: ''
};
if (server && server.config) {
if (server.config.securityMode) {
server.quickInfo.padlock = server.config.securityMode !== 'NONE' ? 'lock' : 'unlock';
server.quickInfo.padlockMsg = this.translateService.instant(gettext('The security policy is set to {{param}}.'), { param: server.config.securityMode });
}
}
}
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: OpcuaServersComponent, deps: [{ token: i1.OpcuaService }, { token: i2.AlertService }, { token: i3.TranslateService }, { token: i2.ContextRouteComponent, optional: true }], target: i0.ɵɵFactoryTarget.Component }); }
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.13", type: OpcuaServersComponent, selector: "opcua-servers", ngImport: i0, template: "<div class=\"card content-fullpage split-view--5-7\">\n <div class=\"card-header grid__col--fullspan separator\">\n <div class=\"h4 card-title\">OPC UA servers</div>\n <button\n class=\"btn-help\"\n type=\"button\"\n [attr.aria-label]=\"'Help' | translate\"\n popover=\"{{\n 'Below you can configure one or more OPC UA servers. The OPC UA agent will connect to these servers if they are enabled and the connection state is set to connected.'\n | translate\n }}\"\n placement=\"right\"\n triggers=\"focus\"\n ></button>\n </div>\n <div class=\"inner-scroll split-view__list\">\n <div class=\"bg-level-1 flex-grow\">\n <div class=\"c8y-nav-stacked\">\n <opcua-server-list\n [serverList]=\"serverObjectList\"\n (present)=\"onPresent($event)\"\n ></opcua-server-list>\n </div>\n </div>\n <div class=\"card-footer separator sticky-bottom\">\n <button\n class=\"btn btn-default\"\n title=\"{{ 'Add server' | translate }}\"\n type=\"button\"\n [disabled]=\"localServerObjectExist()\"\n (click)=\"addServer()\"\n >\n <i [c8yIcon]=\"'plus-circle'\"></i>\n {{ 'Add server' | translate }}\n </button>\n </div>\n </div>\n\n <opcua-server-config\n class=\"inner-scroll split-view__detail\"\n [ngClass]=\"{ 'split-view__detail--selected': server }\"\n (canceled)=\"onCanceled($event)\"\n (removed)=\"onRemoved($event)\"\n (saved)=\"onSaved($event)\"\n [server]=\"server\"\n ></opcua-server-config>\n</div>\n", dependencies: [{ kind: "directive", type: i2.IconDirective, selector: "[c8yIcon]", inputs: ["c8yIcon"] }, { kind: "directive", type: i4.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i5.PopoverDirective, selector: "[popover]", inputs: ["adaptivePosition", "boundariesElement", "popover", "popoverContext", "popoverTitle", "placement", "outsideClick", "triggers", "container", "containerClass", "isOpen", "delay"], outputs: ["onShown", "onHidden"], exportAs: ["bs-popover"] }, { kind: "component", type: i6.OpcuaServerListComponent, selector: "opcua-server-list", inputs: ["serverList"], outputs: ["present"] }, { kind: "component", type: i7.OpcuaServerConfigComponent, selector: "opcua-server-config", inputs: ["server"], outputs: ["canceled", "removed", "saved"] }, { kind: "pipe", type: i2.C8yTranslatePipe, name: "translate" }] }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: OpcuaServersComponent, decorators: [{
type: Component,
args: [{ selector: 'opcua-servers', template: "<div class=\"card content-fullpage split-view--5-7\">\n <div class=\"card-header grid__col--fullspan separator\">\n <div class=\"h4 card-title\">OPC UA servers</div>\n <button\n class=\"btn-help\"\n type=\"button\"\n [attr.aria-label]=\"'Help' | translate\"\n popover=\"{{\n 'Below you can configure one or more OPC UA servers. The OPC UA agent will connect to these servers if they are enabled and the connection state is set to connected.'\n | translate\n }}\"\n placement=\"right\"\n triggers=\"focus\"\n ></button>\n </div>\n <div class=\"inner-scroll split-view__list\">\n <div class=\"bg-level-1 flex-grow\">\n <div class=\"c8y-nav-stacked\">\n <opcua-server-list\n [serverList]=\"serverObjectList\"\n (present)=\"onPresent($event)\"\n ></opcua-server-list>\n </div>\n </div>\n <div class=\"card-footer separator sticky-bottom\">\n <button\n class=\"btn btn-default\"\n title=\"{{ 'Add server' | translate }}\"\n type=\"button\"\n [disabled]=\"localServerObjectExist()\"\n (click)=\"addServer()\"\n >\n <i [c8yIcon]=\"'plus-circle'\"></i>\n {{ 'Add server' | translate }}\n </button>\n </div>\n </div>\n\n <opcua-server-config\n class=\"inner-scroll split-view__detail\"\n [ngClass]=\"{ 'split-view__detail--selected': server }\"\n (canceled)=\"onCanceled($event)\"\n (removed)=\"onRemoved($event)\"\n (saved)=\"onSaved($event)\"\n [server]=\"server\"\n ></opcua-server-config>\n</div>\n" }]
}], ctorParameters: () => [{ type: i1.OpcuaService }, { type: i2.AlertService }, { type: i3.TranslateService }, { type: i2.ContextRouteComponent, decorators: [{
type: Optional
}] }] });
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoib3BjdWEtc2VydmVycy5jb21wb25lbnQuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi9wcm90b2NvbC1vcGN1YS9vcGN1YS1zZXJ2ZXJzLmNvbXBvbmVudC50cyIsIi4uLy4uLy4uL3Byb3RvY29sLW9wY3VhL29wY3VhLXNlcnZlcnMuY29tcG9uZW50Lmh0bWwiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUFFLFNBQVMsRUFBVSxRQUFRLEVBQUUsTUFBTSxlQUFlLENBQUM7QUFDNUQsT0FBTyxFQUFFLFlBQVksRUFBRSxxQkFBcUIsRUFBRSxPQUFPLEVBQUUsTUFBTSxxQkFBcUIsQ0FBQztBQUNuRixPQUFPLEVBQUUsZ0JBQWdCLEVBQUUsTUFBTSxxQkFBcUIsQ0FBQztBQUV2RCxPQUFPLEVBQUUsWUFBWSxFQUFFLE1BQU0sZ0JBQWdCLENBQUM7Ozs7Ozs7OztBQU05QyxNQUFNLE9BQU8scUJBQXFCO0lBK0JoQyxZQUNVLFlBQTBCLEVBQzFCLFlBQTBCLEVBQzFCLGdCQUFrQyxFQUN0QixPQUE4QjtRQUgxQyxpQkFBWSxHQUFaLFlBQVksQ0FBYztRQUMxQixpQkFBWSxHQUFaLFlBQVksQ0FBYztRQUMxQixxQkFBZ0IsR0FBaEIsZ0JBQWdCLENBQWtCO1FBQ3RCLFlBQU8sR0FBUCxPQUFPLENBQXVCO1FBbENwRCxxQkFBZ0IsR0FBa0IsRUFBRSxDQUFDO1FBQ3JDLHdCQUFtQixHQUFnQjtZQUNqQyxFQUFFLEVBQUUsRUFBRTtZQUNOLElBQUksRUFBRSxZQUFZO1lBQ2xCLE1BQU0sRUFBRTtnQkFDTixZQUFZLEVBQUUsTUFBTTtnQkFDcEIsWUFBWSxFQUFFLElBQUk7Z0JBQ2xCLGdCQUFnQixFQUFFLElBQUk7Z0JBQ3RCLGdCQUFnQixFQUFFLEVBQUU7Z0JBQ3BCLGVBQWUsRUFBRSxJQUFJO2dCQUNyQixTQUFTLEVBQUUsRUFBRTtnQkFDYixRQUFRLEVBQUUsRUFBRTtnQkFDWixZQUFZLEVBQUUsRUFBRTtnQkFDaEIs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RUFBRSxNQUFNLENBQUMsTUFBTSxDQUFDLFlBQVksRUFBRSxDQUN0QyxDQUFDO1lBQ0osQ0FBQztRQUNILENBQUM7SUFDSCxDQUFDOytHQXZNVSxxQkFBcUI7bUdBQXJCLHFCQUFxQixxRENWbEMsNmpEQStDQTs7NEZEckNhLHFCQUFxQjtrQkFKakMsU0FBUzsrQkFDRSxlQUFlOzswQkFzQ3RCLFFBQVEiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBDb21wb25lbnQsIE9uSW5pdCwgT3B0aW9uYWwgfSBmcm9tICdAYW5ndWxhci9jb3JlJztcbmltcG9ydCB7IEFsZXJ0U2VydmljZSwgQ29udGV4dFJvdXRlQ29tcG9uZW50LCBnZXR0ZXh0IH0gZnJvbSAnQGM4eS9uZ3gtY29tcG9uZW50cyc7XG5pbXBvcnQgeyBUcmFuc2xhdGVTZXJ2aWNlIH0gZnJvbSAnQG5neC10cmFuc2xhdGUvY29yZSc7XG5pbXBvcnQgeyBPcGN1YVNlcnZlciB9IGZyb20gJy4vb3BjdWEtc2VydmVyLmludGVyZmFjZSc7XG5pbXBvcnQgeyBPcGN1YVNlcnZpY2UgfSBmcm9tICcuL29wY3VhU2VydmljZSc7XG5cbkBDb21wb25lbnQoe1xuICBzZWxlY3RvcjogJ29wY3VhLXNlcnZlcnMnLFxuICB0ZW1wbGF0ZVVybDogJy4vb3BjdWEtc2VydmVycy5jb21wb25lbnQuaHRtbCdcbn0pXG5leHBvcnQgY2xhc3MgT3BjdWFTZXJ2ZXJzQ29tcG9uZW50IGltcGxlbWVudHMgT25Jbml0IHtcbiAgc2VydmVyT2JqZWN0TGlzdDogT3BjdWFTZXJ2ZXJbXSA9IFtdO1xuICBpbml0aWFsU2VydmVyT2JqZWN0OiBPcGN1YVNlcnZlciA9IHtcbiAgICBpZDogJycsXG4gICAgbmFtZTogJ05ldyBTZXJ2ZXInLFxuICAgIGNvbmZpZzoge1xuICAgICAgc2VjdXJpdHlNb2RlOiAnTk9ORScsXG4gICAgICBrZXlzdG9yZVBhc3M6IG51bGwsXG4gICAgICBrZXlzdG9yZUJpbmFyeUlkOiBudWxsLFxuICAgICAga2V5c3RvcmVGaWxlbmFtZTogJycsXG4gICAgICBjZXJ0aWZpY2F0ZVBhc3M6IG51bGwsXG4gICAgICBzZXJ2ZXJVcmw6ICcnLFxuICAgICAgdXNlck5hbWU6ICcnLFxuICAgICAgdXNlclBhc3N3b3JkOiAnJyxcbiAgICAgIHJlc2NhbkNyb246IG51bGwsXG4gICAgICB0aW1lb3V0OiBudWxsLFxuICAgICAgYXV0b1JlY29ubmVjdDogdHJ1ZSxcbiAgICAgIHN0YXR1c0NoZWNrSW50ZXJ2YWw6IG51bGwsXG4gICAgICB2YWxpZDogdHJ1ZVxuICAgIH0sXG4gICAgcXVpY2tJbmZvOiB7XG4gICAgICBwYWRsb2NrOiAndW5sb2NrJyxcbiAgICAgIHBhZGxvY2tNc2c6ICcnXG4gICAgfSxcbiAgICBhY3RpdmU6IHRydWVcbiAgfTtcbiAgc2VydmVyOiBPcGN1YVNlcnZlcjtcbiAgYWN0aXZlID0gZmFsc2U7XG4gIHByaXZhdGUgbW9JZDogc3RyaW5nO1xuICBwcml2YXRlIE5FV19TRVJWRVJfSUQ6IHN0cmluZztcblxuICBjb25zdHJ1Y3RvcihcbiAgICBwcml2YXRlIG9wY3VhU2VydmljZTogT3BjdWFTZXJ2aWNlLFxuICAgIHByaXZhdGUgYWxlcnRTZXJ2aWNlOiBBbGVydFNlcnZpY2UsXG4gICAgcHJpdmF0ZSB0cmFuc2xhdGVTZXJ2aWNlOiBUcmFuc2xhdGVTZXJ2aWNlLFxuICAgIEBPcHRpb25hbCgpIHByaXZhdGUgY29udGV4dDogQ29udGV4dFJvdXRlQ29tcG9uZW50XG4gICkge1xuICAgIHRoaXMubW9JZCA9ICcnO1xuICAgIHRoaXMuTkVXX1NFUlZFUl9JRCA9ICduZXcnO1xuICAgIHRoaXMuaW5pdGlhbFNlcnZlck9iamVjdC5pZCA9IHRoaXMuTkVXX1NFUlZFUl9JRDtcbiAgfVxuXG4gIGFzeW5jIG5nT25Jbml0KCkge1xuICAgIHRoaXMubW9JZCA9IHRoaXMub3BjdWFTZXJ2aWNlLmdldE1vSWQoKTtcbiAgICBpZiAodGhpcy5tb0lkICYmIHRoaXMubW9JZC5sZW5ndGggPiAwKSB7XG4gICAgICBjb25zdCByZXMgPSBhd2FpdCB0aGlzLm9wY3VhU2VydmljZS5nZXRTZXJ2ZXJzKHRoaXMubW9JZCk7XG4gICAgICBpZiAocmVzICYmIHJlcy5zdGF0dXMgIT09IDIwMCkge1xuICAgICAgICBjb25zdCBkYXRhID0gcmVzLmpzb24gPyBhd2FpdCByZXMuanNvbigpIDogdW5kZWZpbmVkO1xuICAgICAgICB0aGlzLmFsZXJ0U2VydmljZS5hZGRTZXJ2ZXJGYWlsdXJlKHsgZGF0YSwgcmVzIH0pO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgdGhpcy5zZXJ2ZXJPYmplY3RMaXN0ID0gKGF3YWl0IHJlcy5qc29uKCkpIGFzIE9wY3VhU2VydmVyW107XG4gICAgICAgIHRoaXMuc2VydmVyT2JqZWN0TGlzdC5tYXAoc2VydmVyID0+IHRoaXMuc2V0UXVpY2tJbmZvKHNlcnZlcikpO1xuICAgICAgICB0aGlzLm9uUHJlc2VudCh0aGlzLnNlcnZlck9iamVjdExpc3RbMF0pO1xuICAgICAgfVxuICAgIH1cbiAgfVxuXG4gIGxvY2FsU2VydmVyT2JqZWN0RXhpc3QoKSB7XG4gICAgcmV0dXJuICEhdGhpcy5zZXJ2ZXJPYmplY3RMaXN0LmZpbmQoc2VydmVyID0+IHNlcnZlci5pZCA9PT0gdGhpcy5ORVdfU0VSVkVSX0lEKTtcbiAgfVxuXG4gIGFkZFNlcnZlcigpIHtcbiAgICBjb25zdCBzZXJ2ZXI6IE9wY3VhU2VydmVyID0gdGhpcy5pbml0aWFsU2VydmVyT2JqZWN0O1xuICAgIHRoaXMuc2VydmVyT2JqZWN0TGlzdC5wdXNoKHNlcnZlcik7XG4gICAgdGhpcy5vblByZXNlbnQoc2VydmVyKTtcbiAgfVxuXG4gIG9uU2F2ZWQoc2VydmVyOiBPcGN1YVNlcnZlcikge1xuICAgIGlmIChzZXJ2ZXIgJiYgc2VydmVyLmlkKSB7XG4gICAgICBzZXJ2ZXIuZ2F0ZXdheUlkID0gdGhpcy5tb0lkO1xuICAgICAgaWYgKHNlcnZlci5pZCA9PT0gdGhpcy5ORVdfU0VSVkVSX0lEKSB7XG4gICAgICAgIHRoaXMuY3JlYXRlU2VydmVyKHNlcnZlcik7XG4gICAgICB9IGVsc2Uge1xuICAgICAgICB0aGlzLnVwZGF0ZVNlcnZlcihzZXJ2ZXIpO1xuICAgICAgfVxuICAgIH1cbiAgfVxuXG4gIHJlbG9hZFRhYnMoKSB7XG4gICAgaWYgKHRoaXMuY29udGV4dCkge1xuICAgICAgdGhpcy5jb250ZXh0LnJlZnJlc2hUYWJzKCk7XG4gICAgfVxuICB9XG5cbiAgb25DYW5jZWxlZChzZXJ2ZXI6IE9wY3VhU2VydmVyKSB7XG4gICAgaWYgKHNlcnZlciAmJiBzZXJ2ZXIuaWQgJiYgc2VydmVyLmlkID09PSB0aGlzLk5FV19TRVJWRVJfSUQpIHtcbiAgICAgIHRoaXMucmVtb3ZlU2VydmVyT2JqZWN0TGlzdEJ5SWQoc2VydmVyLmlkKTtcbiAgICB9IGVsc2Uge1xuICAgICAgLy8gdXBkYXRlIGFjdGl2aXR5IHN0YXR1cyBmb3IgVUlcbiAgICAgIHRoaXMuc2VydmVyT2JqZWN0TGlzdC5mb3JFYWNoKGl0ZW0gPT4ge1xuICAgICAgICBpZiAoaXRlbS5pZCA9PT0gc2VydmVyLmlkKSB7XG4gICAgICAgICAgaXRlbS5hY3RpdmUgPSBmYWxzZTtcbiAgICAgICAgfVxuICAgICAgfSk7XG4gICAgICAvLyBXaGVuIHNlcnZlciBpZCBpcyBub3QgJ25ldycgd2UganVzdCBjbG9zZSB0aGUgZGV0YWlsc1xuICAgICAgZGVsZXRlIHRoaXMuc2VydmVyO1xuICAgIH1cbiAgfVxuXG4gIG9uUmVtb3ZlZChzZXJ2ZXI6IE9wY3VhU2VydmVyKSB7XG4gICAgaWYgKHNlcnZlci5pZCA9PT0gdGhpcy5ORVdfU0VSVkVSX0lEKSB7XG4gICAgICB0aGlzLm9uQ2FuY2VsZWQoc2VydmVyKTtcbiAgICB9IGVsc2Uge1xuICAgICAgdGhpcy5yZW1vdmVTZXJ2ZXIoc2VydmVyKTtcbiAgICB9XG4gIH1cblxuICBhc3luYyBnZXRLZXlzdG9yZShiaW5hcnlJZDogc3RyaW5nKSB7XG4gICAgY29uc3QgeyBkYXRhIH0gPSBhd2FpdCB0aGlzLm9wY3VhU2VydmljZS5nZXRLZXlzdG9yZShiaW5hcnlJZCk7XG4gICAgcmV0dXJuIGRhdGE7XG4gIH1cblxuICBhc3luYyBvblByZXNlbnQoc2VydmVyOiBPcGN1YVNlcnZlcikge1xuICAgIGlmIChcbiAgICAgIHNlcnZlciAmJlxuICAgICAgc2VydmVyLmlkICE9PSB0aGlzLk5FV19TRVJWRVJfSUQgJiZcbiAgICAgIHNlcnZlci5jb25maWcgJiZcbiAgICAgIHNlcnZlci5jb25maWcua2V5c3RvcmVCaW5hcnlJZFxuICAgICkge1xuICAgICAgdHJ5IHtcbiAgICAgICAgY29uc3QgbW8gPSBhd2FpdCB0aGlzLmdldEtleXN0b3JlKHNlcnZlci5jb25maWcua2V5c3RvcmVCaW5hcnlJZCk7XG4gICAgICAgIHNlcnZlci5jb25maWcua2V5c3RvcmVGaWxlbmFtZSA9IG1vLm5hbWU7XG4gICAgICB9IGNhdGNoIChleCkge1xuICAgICAgICB0aGlzLnNlcnZlciA9IE9iamVjdC5hc3NpZ24oe30sIHNlcnZlcik7XG4gICAgICAgIGNvbnNvbGUubG9nKCdDb3VsZCBub3QgZ2V0IGV4aXN0aW5nIGtleXN0b3JlOicsIGV4KTtcbiAgICAgIH1cbiAgICB9XG4gICAgaWYgKHRoaXMuc2VydmVyT2JqZWN0TGlzdC5sZW5ndGggPiAwKSB7XG4gICAgICB0aGlzLnNlcnZlck9iamVjdExpc3QuZm9yRWFjaChpdGVtID0+IHtcbiAgICAgICAgaXRlbS5hY3RpdmUgPSBmYWxzZTtcblxuICAgICAgICBpZiAoaXRlbS5pZCA9PT0gc2VydmVyLmlkKSB7XG4gICAgICAgICAgaXRlbS5hY3RpdmUgPSB0cnVlO1xuICAgICAgICAgIHNlcnZlci5hY3RpdmUgPSBpdGVtLmFjdGl2ZTtcbiAgICAgICAgfVxuICAgICAgfSk7XG4gICAgICB0aGlzLnNldFF1aWNrSW5mbyhzZXJ2ZXIpO1xuICAgICAgdGhpcy5zZXJ2ZXIgPSBPYmplY3QuYXNzaWduKHt9LCBzZXJ2ZXIpO1xuICAgIH1cbiAgfVxuXG4gIHByaXZhdGUgYXN5bmMgY3JlYXRlU2VydmVyKHNlcnZlcjogT3BjdWFTZXJ2ZXIpIHtcbiAgICBjb25zdCByZXNwb25zZSA9IGF3YWl0IHRoaXMub3BjdWFTZXJ2aWNlLmNyZWF0ZVNlcnZlcihzZXJ2ZXIpO1xuICAgIGNvbnN0IHN2ciA9IChhd2FpdCByZXNwb25zZS5qc29uKCkpIGFzIE9wY3VhU2VydmVyO1xuICAgIHRoaXMudXBkYXRlU2VydmVyT2JqZWN0TGlzdEJ5SWQodGhpcy5ORVdfU0VSVkVSX0lELCBzdnIpO1xuICAgIHRoaXMub25QcmVzZW50KHN2cik7XG4gICAgdGhpcy5yZWxvYWRUYWJzKCk7XG4gIH1cblxuICBwcml2YXRlIGFzeW5jIHVwZGF0ZVNlcnZlcihzZXJ2ZXI6IE9wY3VhU2VydmVyKSB7XG4gICAgY29uc3QgdXBkYXRlZFNlcnZlciA9IChhd2FpdCB0aGlzLm9wY3VhU2VydmljZS51cGRhdGVTZXJ2ZXIoc2VydmVyKSkgYXMgT3BjdWFTZXJ2ZXI7XG4gICAgaWYgKHVwZGF0ZWRTZXJ2ZXIpIHtcbiAgICAgIHRoaXMudXBkYXRlU2VydmVyT2JqZWN0TGlzdEJ5SWQodXBkYXRlZFNlcnZlci5pZCwgdXBkYXRlZFNlcnZlcik7XG4gICAgfVxuICB9XG5cbiAgcHJpdmF0ZSBhc3luYyByZW1vdmVTZXJ2ZXIoc2VydmVyOiBPcGN1YVNlcnZlcikge1xuICAgIHRyeSB7XG4gICAgICBhd2FpdCB0aGlzLm9wY3VhU2VydmljZS5yZW1vdmVTZXJ2ZXIoc2VydmVyKTtcbiAgICAgIHRoaXMucmVtb3ZlU2VydmVyT2JqZWN0TGlzdEJ5SWQoc2VydmVyLmlkKTtcbiAgICAgIHRoaXMucmVsb2FkVGFicygpO1xuICAgIH0gY2F0Y2ggKGV4KSB7XG4gICAgICBjb25zb2xlLmxvZygnQ291bGQgbm90IHJlbW92ZSBPUEMgVUEgc2VydmVyOicsIGV4KTtcbiAgICB9XG4gIH1cblxuICBwcml2YXRlIHJlbW92ZVNlcnZlck9iamVjdExpc3RCeUlkKGlkOiBzdHJpbmcpIHtcbiAgICB0aGlzLnNlcnZlck9iamVjdExpc3QuZm9yRWFjaCgoaXRlbSwgaW5kZXgpID0+IHtcbiAgICAgIGlmIChpdGVtLmlkID09PSBpZCkge1xuICAgICAgICB0aGlzLnNlcnZlck9iamVjdExpc3Quc3BsaWNlKGluZGV4LCAxKTtcbiAgICAgICAgZGVsZXRlIHRoaXMuc2VydmVyO1xuICAgICAgfVxuICAgIH0pO1xuICB9XG5cbiAgcHJpdmF0ZSB1cGRhdGVTZXJ2ZXJPYmplY3RMaXN0QnlJZChpZDogc3RyaW5nLCBzZXJ2ZXI6IE9wY3VhU2VydmVyKSB7XG4gICAgY29uc3QgaWR4ID0gdGhpcy5zZXJ2ZXJPYmplY3RMaXN0LmZpbmRJbmRleChpdGVtID0+IGl0ZW0uaWQgPT09IGlkKTtcbiAgICBpZiAoaWR4ID4gLTEpIHtcbiAgICAgIHRoaXMuc2V0UXVpY2tJbmZvKHNlcnZlcik7XG4gICAgICB0aGlzLnNlcnZlck9iamVjdExpc3RbaWR4XSA9IHNlcnZlcjtcbiAgICB9XG4gICAgZGVsZXRlIHRoaXMuc2VydmVyO1xuICB9XG5cbiAgcHJpdmF0ZSBzZXRRdWlja0luZm8oc2VydmVyOiBPcGN1YVNlcnZlcikge1xuICAgIHNlcnZlci5xdWlja0luZm8gPSB7XG4gICAgICBwYWRsb2NrOiAndW5sb2NrJyxcbiAgICAgIHBhZGxvY2tNc2c6ICcnXG4gICAgfTtcblxuICAgIGlmIChzZXJ2ZXIgJiYgc2VydmVyLmNvbmZpZykge1xuICAgICAgaWYgKHNlcnZlci5jb25maWcuc2VjdXJpdHlNb2RlKSB7XG4gICAgICAgIHNlcnZlci5xdWlja0luZm8ucGFkbG9jayA9IHNlcnZlci5jb25maWcuc2VjdXJpdHlNb2RlICE9PSAnTk9ORScgPyAnbG9jaycgOiAndW5sb2NrJztcbiAgICAgICAgc2VydmVyLnF1aWNrSW5mby5wYWRsb2NrTXNnID0gdGhpcy50cmFuc2xhdGVTZXJ2aWNlLmluc3RhbnQoXG4gICAgICAgICAgZ2V0dGV4dCgnVGhlIHNlY3VyaXR5IHBvbGljeSBpcyBzZXQgdG8ge3twYXJhbX19LicpLFxuICAgICAgICAgIHsgcGFyYW06IHNlcnZlci5jb25maWcuc2VjdXJpdHlNb2RlIH1cbiAgICAgICAgKTtcbiAgICAgIH1cbiAgICB9XG4gIH1cbn1cbiIsIjxkaXYgY2xhc3M9XCJjYXJkIGNvbnRlbnQtZnVsbHBhZ2Ugc3BsaXQtdmlldy0tNS03XCI+XG4gIDxkaXYgY2xhc3M9XCJjYXJkLWhlYWRlciBncmlkX19jb2wtLWZ1bGxzcGFuIHNlcGFyYXRvclwiPlxuICAgIDxkaXYgY2xhc3M9XCJoNCBjYXJkLXRpdGxlXCI+T1BDIFVBIHNlcnZlcnM8L2Rpdj5cbiAgICA8YnV0dG9uXG4gICAgICBjbGFzcz1cImJ0bi1oZWxwXCJcbiAgICAgIHR5cGU9XCJidXR0b25cIlxuICAgICAgW2F0dHIuYXJpYS1sYWJlbF09XCInSGVscCcgfCB0cmFuc2xhdGVcIlxuICAgICAgcG9wb3Zlcj1cInt7XG4gICAgICAgICdCZWxvdyB5b3UgY2FuIGNvbmZpZ3VyZSBvbmUgb3IgbW9yZSBPUEMgVUEgc2VydmVycy4gVGhlIE9QQyBVQSBhZ2VudCB3aWxsIGNvbm5lY3QgdG8gdGhlc2Ugc2VydmVycyBpZiB0aGV5IGFyZSBlbmFibGVkIGFuZCB0aGUgY29ubmVjdGlvbiBzdGF0ZSBpcyBzZXQgdG8gY29ubmVjdGVkLidcbiAgICAgICAgICB8IHRyYW5zbGF0ZVxuICAgICAgfX1cIlxuICAgICAgcGxhY2VtZW50PVwicmlnaHRcIlxuICAgICAgdHJpZ2dlcnM9XCJmb2N1c1wiXG4gICAgPjwvYnV0dG9uPlxuICA8L2Rpdj5cbiAgPGRpdiBjbGFzcz1cImlubmVyLXNjcm9sbCBzcGxpdC12aWV3X19saXN0XCI+XG4gICAgPGRpdiBjbGFzcz1cImJnLWxldmVsLTEgZmxleC1ncm93XCI+XG4gICAgICA8ZGl2IGNsYXNzPVwiYzh5LW5hdi1zdGFja2VkXCI+XG4gICAgICAgIDxvcGN1YS1zZXJ2ZXItbGlzdFxuICAgICAgICAgIFtzZXJ2ZXJMaXN0XT1cInNlcnZlck9iamVjdExpc3RcIlxuICAgICAgICAgIChwcmVzZW50KT1cIm9uUHJlc2VudCgkZXZlbnQpXCJcbiAgICAgICAgPjwvb3BjdWEtc2VydmVyLWxpc3Q+XG4gICAgICA8L2Rpdj5cbiAgICA8L2Rpdj5cbiAgICA8ZGl2IGNsYXNzPVwiY2FyZC1mb290ZXIgc2VwYXJhdG9yIHN0aWNreS1ib3R0b21cIj5cbiAgICAgIDxidXR0b25cbiAgICAgICAgY2xhc3M9XCJidG4gYnRuLWRlZmF1bHRcIlxuICAgICAgICB0aXRsZT1cInt7ICdBZGQgc2VydmVyJyB8IHRyYW5zbGF0ZSB9fVwiXG4gICAgICAgIHR5cGU9XCJidXR0b25cIlxuICAgICAgICBbZGlzYWJsZWRdPVwibG9jYWxTZXJ2ZXJPYmplY3RFeGlzdCgpXCJcbiAgICAgICAgKGNsaWNrKT1cImFkZFNlcnZlcigpXCJcbiAgICAgID5cbiAgICAgICAgPGkgW2M4eUljb25dPVwiJ3BsdXMtY2lyY2xlJ1wiPjwvaT5cbiAgICAgICAge3sgJ0FkZCBzZXJ2ZXInIHwgdHJhbnNsYXRlIH19XG4gICAgICA8L2J1dHRvbj5cbiAgICA8L2Rpdj5cbiAgPC9kaXY+XG5cbiAgPG9wY3VhLXNlcnZlci1jb25maWdcbiAgICBjbGFzcz1cImlubmVyLXNjcm9sbCBzcGxpdC12aWV3X19kZXRhaWxcIlxuICAgIFtuZ0NsYXNzXT1cInsgJ3NwbGl0LXZpZXdfX2RldGFpbC0tc2VsZWN0ZWQnOiBzZXJ2ZXIgfVwiXG4gICAgKGNhbmNlbGVkKT1cIm9uQ2FuY2VsZWQoJGV2ZW50KVwiXG4gICAgKHJlbW92ZWQpPVwib25SZW1vdmVkKCRldmVudClcIlxuICAgIChzYXZlZCk9XCJvblNhdmVkKCRldmVudClcIlxuICAgIFtzZXJ2ZXJdPVwic2VydmVyXCJcbiAgPjwvb3BjdWEtc2VydmVyLWNvbmZpZz5cbjwvZGl2PlxuIl19