@c8y/ngx-components
Version:
Angular modules for Cumulocity IoT applications
158 lines • 29.9 kB
JavaScript
import { Component } from '@angular/core';
import { ActionBarItemComponent, C8yTranslateDirective, C8yTranslatePipe, IconDirective, LoadingComponent, TitleComponent } from '@c8y/ngx-components';
import { gettext } from '@c8y/ngx-components';
import { RemoteAccessService } from '@c8y/ngx-components/remote-access/data';
import { ActivatedRoute } from '@angular/router';
import { NgClass, NgIf } from '@angular/common';
import { saveAs } from 'file-saver';
import { BsModalService } from 'ngx-bootstrap/modal';
import { VncCredentialsPromptComponent } from './vnc-credentials-prompt/vnc-credentials-prompt.component';
import { BehaviorSubject, combineLatest, defer } from 'rxjs';
import { distinctUntilChanged, filter, map } from 'rxjs/operators';
import * as i0 from "@angular/core";
import * as i1 from "@c8y/ngx-components/remote-access/data";
import * as i2 from "@angular/router";
import * as i3 from "ngx-bootstrap/modal";
export class VncViewerComponent {
constructor(remoteAccess, activatedRoute, modalService) {
this.remoteAccess = remoteAccess;
this.activatedRoute = activatedRoute;
this.modalService = modalService;
this.titlePrefix = gettext('VNC viewer');
this.title = '';
this.container = null;
this.powerCapability = false;
this.status = 'connecting';
this.container$ = new BehaviorSubject(null);
const container$ = this.container$.pipe(filter(Boolean));
const configurationId$ = this.activatedRoute.params.pipe(map(params => params.configurationId), filter(Boolean), distinctUntilChanged());
const deviceId$ = this.activatedRoute.parent.params.pipe(map(params => params.id), filter(Boolean), distinctUntilChanged());
this.connectionSubscription = combineLatest([
container$,
deviceId$,
configurationId$,
defer(() => this.getNoVNCClient())
]).subscribe(([container, deviceId, configurationId, noVNC]) => {
this.disconnectFromOldSession();
this.connect(container, deviceId, configurationId, noVNC);
});
}
ngOnDestroy() {
this.connectionSubscription?.unsubscribe();
this.disconnectFromOldSession();
}
ngAfterViewInit() {
this.container$.next(document.getElementById('vnc-screen'));
}
disconnectFromOldSession() {
this.powerCapability = false;
this.title = '';
if (!this.noVNCClient) {
return;
}
this.noVNCClient.disconnect();
delete this.noVNCClient;
}
connect(container, deviceId, configId, noVNC) {
this.container = container;
this.changeStatus('connecting');
const options = {
wsProtocols: ['binary']
};
const uri = this.remoteAccess.getWebSocketUri(deviceId, configId);
this.noVNCClient = new noVNC(container, uri, options);
this.noVNCClient.resizeSession = true;
this.noVNCClient.scaleViewport = true;
this.noVNCClient.showDotCursor = true;
this.noVNCClient.viewOnly = false;
this.noVNCClient.qualityLevel = 6;
// need to set compressionLevel to something different than the default 2 as 2 seems to be causing issues..
this.noVNCClient.compressionLevel = 9;
this.noVNCClient.addEventListener('connect', _e => {
this.changeStatus('connected');
this.noVNCClient.focus();
});
this.noVNCClient.addEventListener('credentialsrequired', e => {
this.requestCredentials(e.detail.types);
});
this.noVNCClient.addEventListener('desktopname', e => {
this.title = e.detail.name;
});
this.noVNCClient.addEventListener('disconnect', () => {
this.changeStatus('disconnected');
});
this.noVNCClient.addEventListener('capabilities', e => {
this.powerCapability = e.detail.capabilities.power;
});
}
downloadScreenshot() {
this.noVNCClient.toBlob(blob => {
const date = new Date().toISOString();
saveAs(blob, `screenshot-${this.title}-${date}.png`);
}, 'image/png', 1);
}
changeStatus(status) {
this.status = status;
}
toggleFullscreen() {
if (document.fullscreenElement) {
document.exitFullscreen();
}
else {
this.container.requestFullscreen();
}
}
sendCtrlAltDel() {
this.noVNCClient.sendCtrlAltDel();
}
sendShutDown() {
this.noVNCClient.machineShutdown();
}
sendReset() {
this.noVNCClient.machineReset();
}
sendReboot() {
this.noVNCClient.machineReboot();
}
async getNoVNCClient() {
const lib = await import('@novnc/novnc/lib/rfb');
if (typeof lib.default === 'function') {
return lib.default;
}
const libDefault = lib.default;
if (typeof libDefault.default === 'function') {
return libDefault.default;
}
throw new Error('NoVNC library not found');
}
async requestCredentials(types) {
const modalRef = this.modalService.show(VncCredentialsPromptComponent, {
ignoreBackdropClick: true,
keyboard: false,
initialState: { types: types }
});
try {
const { username, password } = await modalRef.content.result;
this.noVNCClient.sendCredentials({ username, password, target: undefined });
}
catch (e) {
this.noVNCClient.disconnect();
}
}
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: VncViewerComponent, deps: [{ token: i1.RemoteAccessService }, { token: i2.ActivatedRoute }, { token: i3.BsModalService }], target: i0.ɵɵFactoryTarget.Component }); }
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.13", type: VncViewerComponent, isStandalone: true, selector: "c8y-vnc-viewer", ngImport: i0, template: "<c8y-title>{{ titlePrefix | translate }}: {{ title | translate }}</c8y-title>\n\n<ng-container *ngIf=\"status === 'connected'\">\n <c8y-action-bar-item [placement]=\"'right'\">\n <button\n class=\"btn btn-link\"\n (click)=\"toggleFullscreen()\"\n >\n <i [c8yIcon]=\"'expand'\"></i>\n <span translate>Fullscreen</span>\n </button>\n </c8y-action-bar-item>\n\n <c8y-action-bar-item [placement]=\"'right'\">\n <button\n class=\"btn btn-link\"\n (click)=\"downloadScreenshot()\"\n >\n <i [c8yIcon]=\"'download'\"></i>\n <span translate>Screenshot</span>\n </button>\n </c8y-action-bar-item>\n\n <c8y-action-bar-item [placement]=\"'more'\">\n <button\n class=\"btn btn-link\"\n (click)=\"sendCtrlAltDel()\"\n >\n <i [c8yIcon]=\"'keyboard'\"></i>\n <span translate>Send Ctrl+Alt+Del</span>\n </button>\n </c8y-action-bar-item>\n</ng-container>\n\n<ng-container *ngIf=\"powerCapability && status === 'connected'\">\n <c8y-action-bar-item [placement]=\"'more'\">\n <button\n class=\"btn btn-link\"\n (click)=\"sendShutDown()\"\n >\n <i [c8yIcon]=\"'shutdown'\"></i>\n <span translate>Shutdown</span>\n </button>\n </c8y-action-bar-item>\n\n <c8y-action-bar-item [placement]=\"'more'\">\n <button\n class=\"btn btn-link\"\n (click)=\"sendReboot()\"\n >\n <i [c8yIcon]=\"'reset'\"></i>\n <span translate>Reboot</span>\n </button>\n </c8y-action-bar-item>\n\n <c8y-action-bar-item [placement]=\"'more'\">\n <button\n class=\"btn btn-link\"\n (click)=\"sendReset()\"\n >\n <i [c8yIcon]=\"'reset'\"></i>\n <span translate>Reset</span>\n </button>\n </c8y-action-bar-item>\n</ng-container>\n\n<c8y-loading *ngIf=\"status === 'connecting'\"></c8y-loading>\n\n<div\n class=\"content-fullpage\"\n [ngClass]=\"{ hidden: status !== 'connected' }\"\n>\n <div\n class=\"inner-scroll\"\n id=\"vnc-screen\"\n ></div>\n</div>\n", dependencies: [{ kind: "pipe", type: C8yTranslatePipe, name: "translate" }, { kind: "component", type: TitleComponent, selector: "c8y-title", inputs: ["pageTitleUpdate"] }, { kind: "component", type: ActionBarItemComponent, selector: "c8y-action-bar-item", inputs: ["placement", "priority", "itemClass", "injector", "groupId", "inGroupPriority"] }, { kind: "directive", type: C8yTranslateDirective, selector: "[translate],[ngx-translate]" }, { kind: "directive", type: IconDirective, selector: "[c8yIcon]", inputs: ["c8yIcon"] }, { kind: "directive", type: NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "component", type: LoadingComponent, selector: "c8y-loading", inputs: ["layout", "progress", "message"] }] }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: VncViewerComponent, decorators: [{
type: Component,
args: [{ selector: 'c8y-vnc-viewer', standalone: true, imports: [
C8yTranslatePipe,
TitleComponent,
ActionBarItemComponent,
C8yTranslateDirective,
IconDirective,
NgIf,
NgClass,
LoadingComponent
], template: "<c8y-title>{{ titlePrefix | translate }}: {{ title | translate }}</c8y-title>\n\n<ng-container *ngIf=\"status === 'connected'\">\n <c8y-action-bar-item [placement]=\"'right'\">\n <button\n class=\"btn btn-link\"\n (click)=\"toggleFullscreen()\"\n >\n <i [c8yIcon]=\"'expand'\"></i>\n <span translate>Fullscreen</span>\n </button>\n </c8y-action-bar-item>\n\n <c8y-action-bar-item [placement]=\"'right'\">\n <button\n class=\"btn btn-link\"\n (click)=\"downloadScreenshot()\"\n >\n <i [c8yIcon]=\"'download'\"></i>\n <span translate>Screenshot</span>\n </button>\n </c8y-action-bar-item>\n\n <c8y-action-bar-item [placement]=\"'more'\">\n <button\n class=\"btn btn-link\"\n (click)=\"sendCtrlAltDel()\"\n >\n <i [c8yIcon]=\"'keyboard'\"></i>\n <span translate>Send Ctrl+Alt+Del</span>\n </button>\n </c8y-action-bar-item>\n</ng-container>\n\n<ng-container *ngIf=\"powerCapability && status === 'connected'\">\n <c8y-action-bar-item [placement]=\"'more'\">\n <button\n class=\"btn btn-link\"\n (click)=\"sendShutDown()\"\n >\n <i [c8yIcon]=\"'shutdown'\"></i>\n <span translate>Shutdown</span>\n </button>\n </c8y-action-bar-item>\n\n <c8y-action-bar-item [placement]=\"'more'\">\n <button\n class=\"btn btn-link\"\n (click)=\"sendReboot()\"\n >\n <i [c8yIcon]=\"'reset'\"></i>\n <span translate>Reboot</span>\n </button>\n </c8y-action-bar-item>\n\n <c8y-action-bar-item [placement]=\"'more'\">\n <button\n class=\"btn btn-link\"\n (click)=\"sendReset()\"\n >\n <i [c8yIcon]=\"'reset'\"></i>\n <span translate>Reset</span>\n </button>\n </c8y-action-bar-item>\n</ng-container>\n\n<c8y-loading *ngIf=\"status === 'connecting'\"></c8y-loading>\n\n<div\n class=\"content-fullpage\"\n [ngClass]=\"{ hidden: status !== 'connected' }\"\n>\n <div\n class=\"inner-scroll\"\n id=\"vnc-screen\"\n ></div>\n</div>\n" }]
}], ctorParameters: () => [{ type: i1.RemoteAccessService }, { type: i2.ActivatedRoute }, { type: i3.BsModalService }] });
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidm5jLXZpZXdlci5jb21wb25lbnQuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi9yZW1vdGUtYWNjZXNzL3ZuYy92bmMtdmlld2VyL3ZuYy12aWV3ZXIuY29tcG9uZW50LnRzIiwiLi4vLi4vLi4vLi4vLi4vcmVtb3RlLWFjY2Vzcy92bmMvdm5jLXZpZXdlci92bmMtdmlld2VyLmNvbXBvbmVudC5odG1sIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sRUFBaUIsU0FBUyxFQUFhLE1BQU0sZUFBZSxDQUFDO0FBQ3BFLE9BQU8sRUFDTCxzQkFBc0IsRUFDdEIscUJBQXFCLEVBQ3JCLGdCQUFnQixFQUNoQixhQUFhLEVBQ2IsZ0JBQWdCLEVBQ2hCLGNBQWMsRUFDZixNQUFNLHFCQUFxQixDQUFDO0FBQzdCLE9BQU8sRUFBRSxPQUFPLEVBQUUsTUFBTSxxQkFBcUIsQ0FBQztBQUU5QyxPQUFPLEVBQUUsbUJBQW1CLEVBQUUsTUFBTSx3Q0FBd0MsQ0FBQztBQUM3RSxPQUFPLEVBQUUsY0FBYyxFQUFFLE1BQU0saUJBQWlCLENBQUM7QUFDakQsT0FBTyxFQUFFLE9BQU8sRUFBRSxJQUFJLEVBQUUsTUFBTSxpQkFBaUIsQ0FBQztBQUNoRCxPQUFPLEVBQUUsTUFBTSxFQUFFLE1BQU0sWUFBWSxDQUFDO0FBQ3BDLE9BQU8sRUFBRSxjQUFjLEVBQUUsTUFBTSxxQkFBcUIsQ0FBQztBQUNyRCxPQUFPLEVBQUUsNkJBQTZCLEVBQUUsTUFBTSwyREFBMkQsQ0FBQztBQUMxRyxPQUFPLEVBQUUsZUFBZSxFQUFFLGFBQWEsRUFBRSxLQUFLLEVBQWdCLE1BQU0sTUFBTSxDQUFDO0FBQzNFLE9BQU8sRUFBRSxvQkFBb0IsRUFBRSxNQUFNLEVBQUUsR0FBRyxFQUFFLE1BQU0sZ0JBQWdCLENBQUM7Ozs7O0FBaUJuRSxNQUFNLE9BQU8sa0JBQWtCO0lBWTdCLFlBQ1UsWUFBaUMsRUFDakMsY0FBOEIsRUFDOUIsWUFBNEI7UUFGNUIs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SixPQUFPLG9GQUNQLGdCQUFnQjs7NEZBR1Asa0JBQWtCO2tCQWY5QixTQUFTOytCQUNFLGdCQUFnQixjQUVkLElBQUksV0FDUDt3QkFDUCxnQkFBZ0I7d0JBQ2hCLGNBQWM7d0JBQ2Qsc0JBQXNCO3dCQUN0QixxQkFBcUI7d0JBQ3JCLGFBQWE7d0JBQ2IsSUFBSTt3QkFDSixPQUFPO3dCQUNQLGdCQUFnQjtxQkFDakIiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBBZnRlclZpZXdJbml0LCBDb21wb25lbnQsIE9uRGVzdHJveSB9IGZyb20gJ0Bhbmd1bGFyL2NvcmUnO1xuaW1wb3J0IHtcbiAgQWN0aW9uQmFySXRlbUNvbXBvbmVudCxcbiAgQzh5VHJhbnNsYXRlRGlyZWN0aXZlLFxuICBDOHlUcmFuc2xhdGVQaXBlLFxuICBJY29uRGlyZWN0aXZlLFxuICBMb2FkaW5nQ29tcG9uZW50LFxuICBUaXRsZUNvbXBvbmVudFxufSBmcm9tICdAYzh5L25neC1jb21wb25lbnRzJztcbmltcG9ydCB7IGdldHRleHQgfSBmcm9tICdAYzh5L25neC1jb21wb25lbnRzJztcbmltcG9ydCB0eXBlIHsgTm9WbmNDcmVkZW50aWFscywgTm9WbmNPcHRpb25zLCBkZWZhdWx0IGFzIE5vVm5jQ2xpZW50IH0gZnJvbSAnQG5vdm5jL25vdm5jL2xpYi9yZmInO1xuaW1wb3J0IHsgUmVtb3RlQWNjZXNzU2VydmljZSB9IGZyb20gJ0BjOHkvbmd4LWNvbXBvbmVudHMvcmVtb3RlLWFjY2Vzcy9kYXRhJztcbmltcG9ydCB7IEFjdGl2YXRlZFJvdXRlIH0gZnJvbSAnQGFuZ3VsYXIvcm91dGVyJztcbmltcG9ydCB7IE5nQ2xhc3MsIE5nSWYgfSBmcm9tICdAYW5ndWxhci9jb21tb24nO1xuaW1wb3J0IHsgc2F2ZUFzIH0gZnJvbSAnZmlsZS1zYXZlcic7XG5pbXBvcnQgeyBCc01vZGFsU2VydmljZSB9IGZyb20gJ25neC1ib290c3RyYXAvbW9kYWwnO1xuaW1wb3J0IHsgVm5jQ3JlZGVudGlhbHNQcm9tcHRDb21wb25lbnQgfSBmcm9tICcuL3ZuYy1jcmVkZW50aWFscy1wcm9tcHQvdm5jLWNyZWRlbnRpYWxzLXByb21wdC5jb21wb25lbnQnO1xuaW1wb3J0IHsgQmVoYXZpb3JTdWJqZWN0LCBjb21iaW5lTGF0ZXN0LCBkZWZlciwgU3Vic2NyaXB0aW9uIH0gZnJvbSAncnhqcyc7XG5pbXBvcnQgeyBkaXN0aW5jdFVudGlsQ2hhbmdlZCwgZmlsdGVyLCBtYXAgfSBmcm9tICdyeGpzL29wZXJhdG9ycyc7XG5cbkBDb21wb25lbnQoe1xuICBzZWxlY3RvcjogJ2M4eS12bmMtdmlld2VyJyxcbiAgdGVtcGxhdGVVcmw6ICcuL3ZuYy12aWV3ZXIuY29tcG9uZW50Lmh0bWwnLFxuICBzdGFuZGFsb25lOiB0cnVlLFxuICBpbXBvcnRzOiBbXG4gICAgQzh5VHJhbnNsYXRlUGlwZSxcbiAgICBUaXRsZUNvbXBvbmVudCxcbiAgICBBY3Rpb25CYXJJdGVtQ29tcG9uZW50LFxuICAgIEM4eVRyYW5zbGF0ZURpcmVjdGl2ZSxcbiAgICBJY29uRGlyZWN0aXZlLFxuICAgIE5nSWYsXG4gICAgTmdDbGFzcyxcbiAgICBMb2FkaW5nQ29tcG9uZW50XG4gIF1cbn0pXG5leHBvcnQgY2xhc3MgVm5jVmlld2VyQ29tcG9uZW50IGltcGxlbWVudHMgQWZ0ZXJWaWV3SW5pdCwgT25EZXN0cm95IHtcbiAgdGl0bGVQcmVmaXggPSBnZXR0ZXh0KCdWTkMgdmlld2VyJyk7XG4gIHRpdGxlID0gJyc7XG4gIGNvbnRhaW5lcjogSFRNTEVsZW1lbnQgfCBudWxsID0gbnVsbDtcbiAgbm9WTkNDbGllbnQ6IE5vVm5jQ2xpZW50O1xuICBwb3dlckNhcGFiaWxpdHkgPSBmYWxzZTtcblxuICBzdGF0dXM6ICdjb25uZWN0aW5nJyB8ICdjb25uZWN0ZWQnIHwgJ2Rpc2Nvbm5lY3RlZCcgPSAnY29ubmVjdGluZyc7XG4gIGNvbnRhaW5lciQgPSBuZXcgQmVoYXZpb3JTdWJqZWN0PEhUTUxFbGVtZW50IHwgbnVsbD4obnVsbCk7XG5cbiAgY29ubmVjdGlvblN1YnNjcmlwdGlvbjogU3Vic2NyaXB0aW9uO1xuXG4gIGNvbnN0cnVjdG9yKFxuICAgIHByaXZhdGUgcmVtb3RlQWNjZXNzOiBSZW1vdGVBY2Nlc3NTZXJ2aWNlLFxuICAgIHByaXZhdGUgYWN0aXZhdGVkUm91dGU6IEFjdGl2YXRlZFJvdXRlLFxuICAgIHByaXZhdGUgbW9kYWxTZXJ2aWNlOiBCc01vZGFsU2VydmljZVxuICApIHtcbiAgICBjb25zdCBjb250YWluZXIkID0gdGhpcy5jb250YWluZXIkLnBpcGUoZmlsdGVyKEJvb2xlYW4pKTtcbiAgICBjb25zdCBjb25maWd1cmF0aW9uSWQkID0gdGhpcy5hY3RpdmF0ZWRSb3V0ZS5wYXJhbXMucGlwZShcbiAgICAgIG1hcChwYXJhbXMgPT4gcGFyYW1zLmNvbmZpZ3VyYXRpb25JZCksXG4gICAgICBmaWx0ZXIoQm9vbGVhbiksXG4gICAgICBkaXN0aW5jdFVudGlsQ2hhbmdlZCgpXG4gICAgKTtcbiAgICBjb25zdCBkZXZpY2VJZCQgPSB0aGlzLmFjdGl2YXRlZFJvdXRlLnBhcmVudC5wYXJhbXMucGlwZShcbiAgICAgIG1hcChwYXJhbXMgPT4gcGFyYW1zLmlkKSxcbiAgICAgIGZpbHRlcihCb29sZWFuKSxcbiAgICAgIGRpc3RpbmN0VW50aWxDaGFuZ2VkKClcbiAgICApO1xuXG4gICAgdGhpcy5jb25uZWN0aW9uU3Vic2NyaXB0aW9uID0gY29tYmluZUxhdGVzdChbXG4gICAgICBjb250YWluZXIkLFxuICAgICAgZGV2aWNlSWQkLFxuICAgICAgY29uZmlndXJhdGlvbklkJCxcbiAgICAgIGRlZmVyKCgpID0+IHRoaXMuZ2V0Tm9WTkNDbGllbnQoKSlcbiAgICBdKS5zdWJzY3JpYmUoKFtjb250YWluZXIsIGRldmljZUlkLCBjb25maWd1cmF0aW9uSWQsIG5vVk5DXSkgPT4ge1xuICAgICAgdGhpcy5kaXNjb25uZWN0RnJvbU9sZFNlc3Npb24oKTtcbiAgICAgIHRoaXMuY29ubmVjdChjb250YWluZXIsIGRldmljZUlkLCBjb25maWd1cmF0aW9uSWQsIG5vVk5DKTtcbiAgICB9KTtcbiAgfVxuXG4gIG5nT25EZXN0cm95KCk6IHZvaWQge1xuICAgIHRoaXMuY29ubmVjdGlvblN1YnNjcmlwdGlvbj8udW5zdWJzY3JpYmUoKTtcbiAgICB0aGlzLmRpc2Nvbm5lY3RGcm9tT2xkU2Vzc2lvbigpO1xuICB9XG5cbiAgbmdBZnRlclZpZXdJbml0KCk6IHZvaWQge1xuICAgIHRoaXMuY29udGFpbmVyJC5uZXh0KGRvY3VtZW50LmdldEVsZW1lbnRCeUlkKCd2bmMtc2NyZWVuJykpO1xuICB9XG5cbiAgZGlzY29ubmVjdEZyb21PbGRTZXNzaW9uKCkge1xuICAgIHRoaXMucG93ZXJDYXBhYmlsaXR5ID0gZmFsc2U7XG4gICAgdGhpcy50aXRsZSA9ICcnO1xuICAgIGlmICghdGhpcy5ub1ZOQ0NsaWVudCkge1xuICAgICAgcmV0dXJuO1xuICAgIH1cblxuICAgIHRoaXMubm9WTkNDbGllbnQuZGlzY29ubmVjdCgpO1xuICAgIGRlbGV0ZSB0aGlzLm5vVk5DQ2xpZW50O1xuICB9XG5cbiAgY29ubmVjdChjb250YWluZXI6IEhUTUxFbGVtZW50LCBkZXZpY2VJZDogc3RyaW5nLCBjb25maWdJZDogc3RyaW5nLCBub1ZOQzogdHlwZW9mIE5vVm5jQ2xpZW50KSB7XG4gICAgdGhpcy5jb250YWluZXIgPSBjb250YWluZXI7XG4gICAgdGhpcy5jaGFuZ2VTdGF0dXMoJ2Nvbm5lY3RpbmcnKTtcbiAgICBjb25zdCBvcHRpb25zOiBOb1ZuY09wdGlvbnMgPSB7XG4gICAgICB3c1Byb3RvY29sczogWydiaW5hcnknXVxuICAgIH07XG4gICAgY29uc3QgdXJpID0gdGhpcy5yZW1vdGVBY2Nlc3MuZ2V0V2ViU29ja2V0VXJpKGRldmljZUlkLCBjb25maWdJZCk7XG4gICAgdGhpcy5ub1ZOQ0NsaWVudCA9IG5ldyBub1ZOQyhjb250YWluZXIsIHVyaSwgb3B0aW9ucyk7XG4gICAgdGhpcy5ub1ZOQ0NsaWVudC5yZXNpemVTZXNzaW9uID0gdHJ1ZTtcbiAgICB0aGlzLm5vVk5DQ2xpZW50LnNjYWxlVmlld3BvcnQgPSB0cnVlO1xuICAgIHRoaXMubm9WTkNDbGllbnQuc2hvd0RvdEN1cnNvciA9IHRydWU7XG4gICAgdGhpcy5ub1ZOQ0NsaWVudC52aWV3T25seSA9IGZhbHNlO1xuICAgIHRoaXMubm9WTkNDbGllbnQucXVhbGl0eUxldmVsID0gNjtcbiAgICAvLyBuZWVkIHRvIHNldCBjb21wcmVzc2lvbkxldmVsIHRvIHNvbWV0aGluZyBkaWZmZXJlbnQgdGhhbiB0aGUgZGVmYXVsdCAyIGFzIDIgc2VlbXMgdG8gYmUgY2F1c2luZyBpc3N1ZXMuLlxuICAgIHRoaXMubm9WTkNDbGllbnQuY29tcHJlc3Npb25MZXZlbCA9IDk7XG4gICAgdGhpcy5ub1ZOQ0NsaWVudC5hZGRFdmVudExpc3RlbmVyKCdjb25uZWN0JywgX2UgPT4ge1xuICAgICAgdGhpcy5jaGFuZ2VTdGF0dXMoJ2Nvbm5lY3RlZCcpO1xuICAgICAgdGhpcy5ub1ZOQ0NsaWVudC5mb2N1cygpO1xuICAgIH0pO1xuICAgIHRoaXMubm9WTkNDbGllbnQuYWRkRXZlbnRMaXN0ZW5lcignY3JlZGVudGlhbHNyZXF1aXJlZCcsIGUgPT4ge1xuICAgICAgdGhpcy5yZXF1ZXN0Q3JlZGVudGlhbHMoZS5kZXRhaWwudHlwZXMpO1xuICAgIH0pO1xuICAgIHRoaXMubm9WTkNDbGllbnQuYWRkRXZlbnRMaXN0ZW5lcignZGVza3RvcG5hbWUnLCBlID0+IHtcbiAgICAgIHRoaXMudGl0bGUgPSBlLmRldGFpbC5uYW1lO1xuICAgIH0pO1xuICAgIHRoaXMubm9WTkNDbGllbnQuYWRkRXZlbnRMaXN0ZW5lcignZGlzY29ubmVjdCcsICgpID0+IHtcbiAgICAgIHRoaXMuY2hhbmdlU3RhdHVzKCdkaXNjb25uZWN0ZWQnKTtcbiAgICB9KTtcbiAgICB0aGlzLm5vVk5DQ2xpZW50LmFkZEV2ZW50TGlzdGVuZXIoJ2NhcGFiaWxpdGllcycsIGUgPT4ge1xuICAgICAgdGhpcy5wb3dlckNhcGFiaWxpdHkgPSBlLmRldGFpbC5jYXBhYmlsaXRpZXMucG93ZXI7XG4gICAgfSk7XG4gIH1cblxuICBkb3dubG9hZFNjcmVlbnNob3QoKSB7XG4gICAgdGhpcy5ub1ZOQ0NsaWVudC50b0Jsb2IoXG4gICAgICBibG9iID0+IHtcbiAgICAgICAgY29uc3QgZGF0ZSA9IG5ldyBEYXRlKCkudG9JU09TdHJpbmcoKTtcbiAgICAgICAgc2F2ZUFzKGJsb2IsIGBzY3JlZW5zaG90LSR7dGhpcy50aXRsZX0tJHtkYXRlfS5wbmdgKTtcbiAgICAgIH0sXG4gICAgICAnaW1hZ2UvcG5nJyxcbiAgICAgIDFcbiAgICApO1xuICB9XG5cbiAgY2hhbmdlU3RhdHVzKHN0YXR1czogJ2Nvbm5lY3RpbmcnIHwgJ2Nvbm5lY3RlZCcgfCAnZGlzY29ubmVjdGVkJykge1xuICAgIHRoaXMuc3RhdHVzID0gc3RhdHVzO1xuICB9XG5cbiAgdG9nZ2xlRnVsbHNjcmVlbigpIHtcbiAgICBpZiAoZG9jdW1lbnQuZnVsbHNjcmVlbkVsZW1lbnQpIHtcbiAgICAgIGRvY3VtZW50LmV4aXRGdWxsc2NyZWVuKCk7XG4gICAgfSBlbHNlIHtcbiAgICAgIHRoaXMuY29udGFpbmVyLnJlcXVlc3RGdWxsc2NyZWVuKCk7XG4gICAgfVxuICB9XG5cbiAgc2VuZEN0cmxBbHREZWwoKSB7XG4gICAgdGhpcy5ub1ZOQ0NsaWVudC5zZW5kQ3RybEFsdERlbCgpO1xuICB9XG5cbiAgc2VuZFNodXREb3duKCkge1xuICAgIHRoaXMubm9WTkNDbGllbnQubWFjaGluZVNodXRkb3duKCk7XG4gIH1cblxuICBzZW5kUmVzZXQoKSB7XG4gICAgdGhpcy5ub1ZOQ0NsaWVudC5tYWNoaW5lUmVzZXQoKTtcbiAgfVxuXG4gIHNlbmRSZWJvb3QoKSB7XG4gICAgdGhpcy5ub1ZOQ0NsaWVudC5tYWNoaW5lUmVib290KCk7XG4gIH1cblxuICBhc3luYyBnZXROb1ZOQ0NsaWVudCgpOiBQcm9taXNlPHR5cGVvZiBOb1ZuY0NsaWVudD4ge1xuICAgIGNvbnN0IGxpYiA9IGF3YWl0IGltcG9ydCgnQG5vdm5jL25vdm5jL2xpYi9yZmInKTtcbiAgICBpZiAodHlwZW9mIGxpYi5kZWZhdWx0ID09PSAnZnVuY3Rpb24nKSB7XG4gICAgICByZXR1cm4gbGliLmRlZmF1bHQ7XG4gICAgfVxuICAgIGNvbnN0IGxpYkRlZmF1bHQgPSBsaWIuZGVmYXVsdCBhcyB1bmtub3duIGFzIHsgZGVmYXVsdDogdHlwZW9mIE5vVm5jQ2xpZW50IH07XG4gICAgaWYgKHR5cGVvZiBsaWJEZWZhdWx0LmRlZmF1bHQgPT09ICdmdW5jdGlvbicpIHtcbiAgICAgIHJldHVybiBsaWJEZWZhdWx0LmRlZmF1bHQ7XG4gICAgfVxuXG4gICAgdGhyb3cgbmV3IEVycm9yKCdOb1ZOQyBsaWJyYXJ5IG5vdCBmb3VuZCcpO1xuICB9XG5cbiAgcHJvdGVjdGVkIGFzeW5jIHJlcXVlc3RDcmVkZW50aWFscyh0eXBlczogQXJyYXk8a2V5b2YgTm9WbmNDcmVkZW50aWFscz4pIHtcbiAgICBjb25zdCBtb2RhbFJlZiA9IHRoaXMubW9kYWxTZXJ2aWNlLnNob3coVm5jQ3JlZGVudGlhbHNQcm9tcHRDb21wb25lbnQsIHtcbiAgICAgIGlnbm9yZUJhY2tkcm9wQ2xpY2s6IHRydWUsXG4gICAgICBrZXlib2FyZDogZmFsc2UsXG4gICAgICBpbml0aWFsU3RhdGU6IHsgdHlwZXM6IHR5cGVzIH1cbiAgICB9KTtcblxuICAgIHRyeSB7XG4gICAgICBjb25zdCB7IHVzZXJuYW1lLCBwYXNzd29yZCB9ID0gYXdhaXQgbW9kYWxSZWYuY29udGVudC5yZXN1bHQ7XG4gICAgICB0aGlzLm5vVk5DQ2xpZW50LnNlbmRDcmVkZW50aWFscyh7IHVzZXJuYW1lLCBwYXNzd29yZCwgdGFyZ2V0OiB1bmRlZmluZWQgfSk7XG4gICAgfSBjYXRjaCAoZSkge1xuICAgICAgdGhpcy5ub1ZOQ0NsaWVudC5kaXNjb25uZWN0KCk7XG4gICAgfVxuICB9XG59XG4iLCI8Yzh5LXRpdGxlPnt7IHRpdGxlUHJlZml4IHwgdHJhbnNsYXRlIH19OiB7eyB0aXRsZSB8IHRyYW5zbGF0ZSB9fTwvYzh5LXRpdGxlPlxuXG48bmctY29udGFpbmVyICpuZ0lmPVwic3RhdHVzID09PSAnY29ubmVjdGVkJ1wiPlxuICA8Yzh5LWFjdGlvbi1iYXItaXRlbSBbcGxhY2VtZW50XT1cIidyaWdodCdcIj5cbiAgICA8YnV0dG9uXG4gICAgICBjbGFzcz1cImJ0biBidG4tbGlua1wiXG4gICAgICAoY2xpY2spPVwidG9nZ2xlRnVsbHNjcmVlbigpXCJcbiAgICA+XG4gICAgICA8aSBbYzh5SWNvbl09XCInZXhwYW5kJ1wiPjwvaT5cbiAgICAgIDxzcGFuIHRyYW5zbGF0ZT5GdWxsc2NyZWVuPC9zcGFuPlxuICAgIDwvYnV0dG9uPlxuICA8L2M4eS1hY3Rpb24tYmFyLWl0ZW0+XG5cbiAgPGM4eS1hY3Rpb24tYmFyLWl0ZW0gW3BsYWNlbWVudF09XCIncmlnaHQnXCI+XG4gICAgPGJ1dHRvblxuICAgICAgY2xhc3M9XCJidG4gYnRuLWxpbmtcIlxuICAgICAgKGNsaWNrKT1cImRvd25sb2FkU2NyZWVuc2hvdCgpXCJcbiAgICA+XG4gICAgICA8aSBbYzh5SWNvbl09XCInZG93bmxvYWQnXCI+PC9pPlxuICAgICAgPHNwYW4gdHJhbnNsYXRlPlNjcmVlbnNob3Q8L3NwYW4+XG4gICAgPC9idXR0b24+XG4gIDwvYzh5LWFjdGlvbi1iYXItaXRlbT5cblxuICA8Yzh5LWFjdGlvbi1iYXItaXRlbSBbcGxhY2VtZW50XT1cIidtb3JlJ1wiPlxuICAgIDxidXR0b25cbiAgICAgIGNsYXNzPVwiYnRuIGJ0bi1saW5rXCJcbiAgICAgIChjbGljayk9XCJzZW5kQ3RybEFsdERlbCgpXCJcbiAgICA+XG4gICAgICA8aSBbYzh5SWNvbl09XCIna2V5Ym9hcmQnXCI+PC9pPlxuICAgICAgPHNwYW4gdHJhbnNsYXRlPlNlbmQgQ3RybCtBbHQrRGVsPC9zcGFuPlxuICAgIDwvYnV0dG9uPlxuICA8L2M4eS1hY3Rpb24tYmFyLWl0ZW0+XG48L25nLWNvbnRhaW5lcj5cblxuPG5nLWNvbnRhaW5lciAqbmdJZj1cInBvd2VyQ2FwYWJpbGl0eSAmJiBzdGF0dXMgPT09ICdjb25uZWN0ZWQnXCI+XG4gIDxjOHktYWN0aW9uLWJhci1pdGVtIFtwbGFjZW1lbnRdPVwiJ21vcmUnXCI+XG4gICAgPGJ1dHRvblxuICAgICAgY2xhc3M9XCJidG4gYnRuLWxpbmtcIlxuICAgICAgKGNsaWNrKT1cInNlbmRTaHV0RG93bigpXCJcbiAgICA+XG4gICAgICA8aSBbYzh5SWNvbl09XCInc2h1dGRvd24nXCI+PC9pPlxuICAgICAgPHNwYW4gdHJhbnNsYXRlPlNodXRkb3duPC9zcGFuPlxuICAgIDwvYnV0dG9uPlxuICA8L2M4eS1hY3Rpb24tYmFyLWl0ZW0+XG5cbiAgPGM4eS1hY3Rpb24tYmFyLWl0ZW0gW3BsYWNlbWVudF09XCInbW9yZSdcIj5cbiAgICA8YnV0dG9uXG4gICAgICBjbGFzcz1cImJ0biBidG4tbGlua1wiXG4gICAgICAoY2xpY2spPVwic2VuZFJlYm9vdCgpXCJcbiAgICA+XG4gICAgICA8aSBbYzh5SWNvbl09XCIncmVzZXQnXCI+PC9pPlxuICAgICAgPHNwYW4gdHJhbnNsYXRlPlJlYm9vdDwvc3Bhbj5cbiAgICA8L2J1dHRvbj5cbiAgPC9jOHktYWN0aW9uLWJhci1pdGVtPlxuXG4gIDxjOHktYWN0aW9uLWJhci1pdGVtIFtwbGFjZW1lbnRdPVwiJ21vcmUnXCI+XG4gICAgPGJ1dHRvblxuICAgICAgY2xhc3M9XCJidG4gYnRuLWxpbmtcIlxuICAgICAgKGNsaWNrKT1cInNlbmRSZXNldCgpXCJcbiAgICA+XG4gICAgICA8aSBbYzh5SWNvbl09XCIncmVzZXQnXCI+PC9pPlxuICAgICAgPHNwYW4gdHJhbnNsYXRlPlJlc2V0PC9zcGFuPlxuICAgIDwvYnV0dG9uPlxuICA8L2M4eS1hY3Rpb24tYmFyLWl0ZW0+XG48L25nLWNvbnRhaW5lcj5cblxuPGM4eS1sb2FkaW5nICpuZ0lmPVwic3RhdHVzID09PSAnY29ubmVjdGluZydcIj48L2M4eS1sb2FkaW5nPlxuXG48ZGl2XG4gIGNsYXNzPVwiY29udGVudC1mdWxscGFnZVwiXG4gIFtuZ0NsYXNzXT1cInsgaGlkZGVuOiBzdGF0dXMgIT09ICdjb25uZWN0ZWQnIH1cIlxuPlxuICA8ZGl2XG4gICAgY2xhc3M9XCJpbm5lci1zY3JvbGxcIlxuICAgIGlkPVwidm5jLXNjcmVlblwiXG4gID48L2Rpdj5cbjwvZGl2PlxuIl19