@c8y/ngx-components
Version:
Angular modules for Cumulocity IoT applications
197 lines • 44.5 kB
JavaScript
import { Component, ViewChild } from '@angular/core';
import { ActivatedRoute, Router } from '@angular/router';
import { SEVERITY_LABELS } from '@c8y/client';
import { AlarmWithChildrenRealtimeService, AlertService, ContextRouteService, ModalService, ViewContext, gettext } from '@c8y/ngx-components';
import { TranslateService } from '@ngx-translate/core';
import { BehaviorSubject, Subject } from 'rxjs';
import { debounceTime, takeUntil, throttleTime } from 'rxjs/operators';
import { AlarmsIntervalRefreshComponent } from './alarms-interval-refresh.component';
import { AlarmsViewService } from './alarms-view.service';
import { DEFAULT_SEVERITY_VALUES, THROTTLE_REALTIME_REFRESH } from './alarms.model';
import * as i0 from "@angular/core";
import * as i1 from "@angular/router";
import * as i2 from "./alarms-view.service";
import * as i3 from "@c8y/ngx-components";
import * as i4 from "@ngx-translate/core";
import * as i5 from "@angular/common";
import * as i6 from "ngx-bootstrap/tooltip";
import * as i7 from "./alarms-filter.component";
import * as i8 from "./alarms-interval-refresh.component";
import * as i9 from "./alarms-list.component";
import * as i10 from "./alarms-date-filter.component";
import * as i11 from "./alarms-type-filter.component";
export class AlarmsComponent {
constructor(activatedRoute, alarmsViewService, alarmWithChildrenRealtimeService, alertService, contextRouteService, modalService, translateService, router) {
this.activatedRoute = activatedRoute;
this.alarmsViewService = alarmsViewService;
this.alarmWithChildrenRealtimeService = alarmWithChildrenRealtimeService;
this.alertService = alertService;
this.contextRouteService = contextRouteService;
this.modalService = modalService;
this.translateService = translateService;
this.router = router;
this.NEW_REALTIME_ALARM_MESSAGE = this.alarmsViewService.REALTIME_UPDATE_ALARMS_MESSAGE;
this.TITLE = gettext('Alarms');
this.REFRESH_LABEL = gettext('Refresh');
this.alarms$ = new BehaviorSubject(null);
this.isLoading$ = new BehaviorSubject(false);
this.isRealtimeActive = new BehaviorSubject(false);
this.shouldShowIntervalToggle$ = new BehaviorSubject(true);
this.isRealtimeToggleOn = true;
this.typeFilters = [];
this.isDisabled = false;
this.destroy$ = new Subject();
this.selectedSeverities = Object.keys(SEVERITY_LABELS);
this.severityOptions = DEFAULT_SEVERITY_VALUES;
this.showCleared = false;
this.WAIT_TIME_AVOID_MULTIPLE_REQUEST_BY_PARAM_CHANGE = 100;
this.isIntervalRefresh = this.alarmsViewService.isIntervalRefresh();
this.initializeContextSourceId();
}
ngOnInit() {
const isInDetailView = !!this.activatedRoute.children[0]?.snapshot.params.id;
if (isInDetailView) {
this.changeInterval(false);
}
if (!this.isIntervalRefresh) {
this.handleLegacyRealtime();
}
this.alarmsViewService.reloadAlarmsList$
.pipe(debounceTime(this.WAIT_TIME_AVOID_MULTIPLE_REQUEST_BY_PARAM_CHANGE), takeUntil(this.destroy$))
.subscribe(() => {
this.updateAlarms();
});
}
ngOnDestroy() {
this.destroy$.next();
this.destroy$.complete();
}
applyTypeFilters(typeFilters) {
this.typeFilters = typeFilters;
this.alarmsViewService.reloadAlarmsList$.next();
this.isRealtimeActive.next(false);
}
applyFormFilters({ severityOptions, showCleared, selectedDates }) {
this.severityOptions = severityOptions;
this.showCleared = showCleared;
this.selectedDates = selectedDates;
this.selectedSeverities = this.alarmsViewService.updateSelectedSeverities(this.severityOptions);
this.alarmsViewService.reloadAlarmsList$.next();
this.isRealtimeActive.next(false);
}
async applyDateFilter(selectedDates) {
this.alarms$.next(await this.alarmsViewService.retrieveAlarmsByDate(selectedDates));
this.isRealtimeActive.next(false);
}
async clearAll() {
try {
const translatedBody = this.translateService.instant(gettext('Do you really want to clear all alarms of selected severities?'));
await this.modalService.confirm(gettext('Confirm clearing alarms?'), translatedBody, 'danger', {
ok: gettext('Confirm'),
cancel: gettext('Cancel')
});
}
catch {
// modal canceled
return;
}
await this.clearAlarms();
}
refresh() {
this.updateAlarms();
this.isRealtimeActive.next(false);
}
changeInterval(value = true) {
this.shouldShowIntervalToggle$.next(value);
}
toggleRealtimeState() {
this.isRealtimeToggleOn = !this.isRealtimeToggleOn;
}
handleLegacyRealtime() {
this.realtimeIconTitle = this.translateService.instant(gettext('Realtime active'));
this.subscribeToRealtimeUpdates();
}
async clearAlarms() {
try {
const result = await this.alarmsViewService.clearAllActiveAlarms(this.selectedSeverities, this.contextSourceId);
if (result.resolvedImmediately) {
this.alertService.success(this.translateService.instant(gettext('Alarms cleared.')));
this.backToRootRoute();
this.refresh();
}
else {
this.alertService.success(this.translateService.instant(gettext('Alarms are being cleared in background.')));
}
}
catch (error) {
this.alertService.addServerFailure(error);
}
}
backToRootRoute() {
const contextData = this.contextRouteService.getContextData(this.activatedRoute);
this.router.navigate(this.alarmsViewService.getRouterNavigationArray(contextData), {
queryParamsHandling: 'merge'
});
}
async getAlarms() {
try {
this.isLoading$.next(true);
const additionalFilter = {};
if (this.contextSourceId) {
(additionalFilter.source = this.contextSourceId),
(additionalFilter.withSourceAssets = true),
(additionalFilter.withSourceDevices = true);
}
if (this.typeFilters.length > 0) {
additionalFilter.type = this.typeFilters.map(({ filters }) => filters.type).join(',');
}
return await this.alarmsViewService.retrieveFilteredAlarms(this.selectedSeverities, this.showCleared, this.selectedDates, additionalFilter);
}
catch (error) {
if (error?.res?.status === 403) {
this.isDisabled = true;
return;
}
this.alertService.addServerFailure(error);
}
finally {
this.isLoading$.next(false);
}
}
async updateAlarms() {
this.alarms$.next(await this.getAlarms());
}
subscribeToRealtimeUpdates() {
this.alarmWithChildrenRealtimeService
.onAll$(this.contextSourceId)
.pipe(takeUntil(this.destroy$), throttleTime(THROTTLE_REALTIME_REFRESH, undefined, { trailing: true }))
.subscribe(() => {
if (this.isRealtimeToggleOn) {
this.refresh();
}
else {
this.isRealtimeActive.next(true);
}
});
}
initializeContextSourceId() {
const routeContext = this.contextRouteService.getContextData(this.activatedRoute);
if (!routeContext) {
return;
}
const { context, contextData } = routeContext;
if ([ViewContext.Device, ViewContext.Group, ViewContext.Service, ViewContext.Simulators].includes(context)) {
this.contextSourceId = contextData?.id;
}
}
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: AlarmsComponent, deps: [{ token: i1.ActivatedRoute }, { token: i2.AlarmsViewService }, { token: i3.AlarmWithChildrenRealtimeService }, { token: i3.AlertService }, { token: i3.ContextRouteService }, { token: i3.ModalService }, { token: i4.TranslateService }, { token: i1.Router }], target: i0.ɵɵFactoryTarget.Component }); }
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.13", type: AlarmsComponent, selector: "c8y-alarms", providers: [AlarmWithChildrenRealtimeService], viewQueries: [{ propertyName: "alarmIntervalRefreshComponent", first: true, predicate: AlarmsIntervalRefreshComponent, descendants: true }], ngImport: i0, template: "<ng-container *ngIf=\"(activatedRoute.data | async)?.title\">\n <c8y-title>{{ TITLE | translate }}</c8y-title>\n</ng-container>\n\n<c8y-action-bar-item\n [placement]=\"'left'\"\n itemClass=\"navbar-form min-width-fit\"\n>\n <c8y-alarms-filter\n class=\"d-block fit-w\"\n [contextSourceId]=\"contextSourceId\"\n (onFilterApplied)=\"applyFormFilters($event)\"\n ></c8y-alarms-filter>\n</c8y-action-bar-item>\n\n<c8y-action-bar-item\n [placement]=\"'left'\"\n itemClass=\"navbar-form min-width-fit\"\n>\n <c8y-alarms-date-filter (dateFilterChange)=\"applyFormFilters($event)\"></c8y-alarms-date-filter>\n</c8y-action-bar-item>\n\n<c8y-action-bar-item\n [placement]=\"'left'\"\n itemClass=\"navbar-form\"\n>\n <c8y-alarms-type-filter\n class=\"d-block fit-w\"\n [alarms]=\"alarms$ | async\"\n (onFilterChanged)=\"applyTypeFilters($event)\"\n ></c8y-alarms-type-filter>\n</c8y-action-bar-item>\n\n<c8y-action-bar-item\n [placement]=\"'right'\"\n [priority]=\"0\"\n>\n <button\n class=\"btn btn-link\"\n [title]=\"'Clear all alarms' | translate\"\n type=\"button\"\n (click)=\"clearAll()\"\n data-cy=\"c8y-alarms-view--clear-all-button\"\n >\n <i c8yIcon=\"c8y-alert-idle\"></i>\n {{ 'Clear all`alarms`' | translate }}\n </button>\n</c8y-action-bar-item>\n\n<!--Realtime button-->\n<ng-template #realtimeRefresh>\n <div class=\"input-group-btn\">\n <button\n class=\"btn btn-default btn-sm\"\n [attr.aria-label]=\"'Refresh' | translate\"\n [tooltip]=\"\n (isRealtimeActive | async)\n ? (NEW_REALTIME_ALARM_MESSAGE | translate)\n : (REFRESH_LABEL | translate)\n \"\n placement=\"left\"\n container=\"body\"\n type=\"button\"\n [adaptivePosition]=\"false\"\n [delay]=\"500\"\n [disabled]=\"isLoading$ | async\"\n (click)=\"refresh()\"\n >\n <span\n class=\"tag tag--info m-r-8\"\n *ngIf=\"isRealtimeActive | async\"\n >\n {{ 'New alarms' | translate }}\n </span>\n <i\n c8yIcon=\"refresh\"\n [ngClass]=\"{ 'icon-spin': isLoading$ | async }\"\n ></i>\n </button>\n <button\n class=\"c8y-realtime btn btn-default btn-sm\"\n [attr.aria-label]=\"realtimeIconTitle\"\n [tooltip]=\"realtimeIconTitle\"\n placement=\"bottom\"\n type=\"button\"\n data-cy=\"c8y-alarms--realtime-button\"\n [container]=\"'body'\"\n (click)=\"toggleRealtimeState()\"\n >\n <span\n class=\"c8y-pulse m-0\"\n [ngClass]=\"{\n active: isRealtimeToggleOn,\n inactive: !isRealtimeToggleOn\n }\"\n ></span>\n </button>\n </div>\n</ng-template>\n\n<c8y-help\n src=\"/docs/device-management-application/monitoring-and-controlling-devices/#working-with-alarms\"\n></c8y-help>\n\n<div class=\"card content-fullpage split-view--5-7 grid__row--1\">\n <c8y-alarms-list\n class=\"d-contents\"\n [isInitialLoading]=\"isLoading$ | async\"\n [alarms]=\"alarms$ | async\"\n [typeFilters]=\"typeFilters\"\n (onScrollingStateChange)=\"changeInterval(!$event)\"\n (onSelectedAlarm)=\"changeInterval(false)\"\n [splitView]=\"true\"\n [hasPermissions]=\"!isDisabled\"\n >\n <ng-container *ngIf=\"isIntervalRefresh; else realtimeRefresh\">\n <c8y-alarms-interval-refresh\n [alarmsListLoading$]=\"isLoading$\"\n [isIntervalToggleEnabled]=\"shouldShowIntervalToggle$ | async\"\n (onCountdownEnded)=\"refresh()\"\n [isDisabled]=\"isDisabled\"\n ></c8y-alarms-interval-refresh>\n </ng-container>\n </c8y-alarms-list>\n\n <router-outlet class=\"d-contents\"></router-outlet>\n</div>\n", dependencies: [{ kind: "directive", type: i3.IconDirective, selector: "[c8yIcon]", inputs: ["c8yIcon"] }, { kind: "directive", type: i5.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i5.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "component", type: i3.ActionBarItemComponent, selector: "c8y-action-bar-item", inputs: ["placement", "priority", "itemClass", "injector", "groupId", "inGroupPriority"] }, { kind: "component", type: i3.TitleComponent, selector: "c8y-title", inputs: ["pageTitleUpdate"] }, { kind: "component", type: i3.HelpComponent, selector: "c8y-help", inputs: ["src", "isCollapsed", "priority", "icon"] }, { kind: "directive", type: i6.TooltipDirective, selector: "[tooltip], [tooltipHtml]", inputs: ["adaptivePosition", "tooltip", "placement", "triggers", "container", "containerClass", "boundariesElement", "isOpen", "isDisabled", "delay", "tooltipHtml", "tooltipPlacement", "tooltipIsOpen", "tooltipEnable", "tooltipAppendToBody", "tooltipAnimation", "tooltipClass", "tooltipContext", "tooltipPopupDelay", "tooltipFadeDuration", "tooltipTrigger"], outputs: ["tooltipChange", "onShown", "onHidden", "tooltipStateChanged"], exportAs: ["bs-tooltip"] }, { kind: "directive", type: i1.RouterOutlet, selector: "router-outlet", inputs: ["name"], outputs: ["activate", "deactivate", "attach", "detach"], exportAs: ["outlet"] }, { kind: "component", type: i7.AlarmsFilterComponent, selector: "c8y-alarms-filter", inputs: ["contextSourceId"], outputs: ["onFilterApplied"] }, { kind: "component", type: i8.AlarmsIntervalRefreshComponent, selector: "c8y-alarms-interval-refresh", inputs: ["isDisabled", "alarmsListLoading$", "isIntervalToggleEnabled"], outputs: ["onCountdownEnded"] }, { kind: "component", type: i9.AlarmsListComponent, selector: "c8y-alarms-list", inputs: ["alarms", "hasPermissions", "typeFilters", "loadMoreMode", "navigationOptions", "isInitialLoading", "splitView"], outputs: ["onSelectedAlarm", "onScrollingStateChange"] }, { kind: "component", type: i10.AlarmsDateFilterComponent, selector: "c8y-alarms-date-filter", inputs: ["DEFAULT_INTERVAL", "updateQueryParams", "date"], outputs: ["dateFilterChange"] }, { kind: "component", type: i11.AlarmsTypeFilterComponent, selector: "c8y-alarms-type-filter", inputs: ["alarms", "possibleFilters", "activeFilters"], outputs: ["onFilterChanged"] }, { kind: "pipe", type: i5.AsyncPipe, name: "async" }, { kind: "pipe", type: i4.TranslatePipe, name: "translate" }] }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: AlarmsComponent, decorators: [{
type: Component,
args: [{ selector: 'c8y-alarms', providers: [AlarmWithChildrenRealtimeService], template: "<ng-container *ngIf=\"(activatedRoute.data | async)?.title\">\n <c8y-title>{{ TITLE | translate }}</c8y-title>\n</ng-container>\n\n<c8y-action-bar-item\n [placement]=\"'left'\"\n itemClass=\"navbar-form min-width-fit\"\n>\n <c8y-alarms-filter\n class=\"d-block fit-w\"\n [contextSourceId]=\"contextSourceId\"\n (onFilterApplied)=\"applyFormFilters($event)\"\n ></c8y-alarms-filter>\n</c8y-action-bar-item>\n\n<c8y-action-bar-item\n [placement]=\"'left'\"\n itemClass=\"navbar-form min-width-fit\"\n>\n <c8y-alarms-date-filter (dateFilterChange)=\"applyFormFilters($event)\"></c8y-alarms-date-filter>\n</c8y-action-bar-item>\n\n<c8y-action-bar-item\n [placement]=\"'left'\"\n itemClass=\"navbar-form\"\n>\n <c8y-alarms-type-filter\n class=\"d-block fit-w\"\n [alarms]=\"alarms$ | async\"\n (onFilterChanged)=\"applyTypeFilters($event)\"\n ></c8y-alarms-type-filter>\n</c8y-action-bar-item>\n\n<c8y-action-bar-item\n [placement]=\"'right'\"\n [priority]=\"0\"\n>\n <button\n class=\"btn btn-link\"\n [title]=\"'Clear all alarms' | translate\"\n type=\"button\"\n (click)=\"clearAll()\"\n data-cy=\"c8y-alarms-view--clear-all-button\"\n >\n <i c8yIcon=\"c8y-alert-idle\"></i>\n {{ 'Clear all`alarms`' | translate }}\n </button>\n</c8y-action-bar-item>\n\n<!--Realtime button-->\n<ng-template #realtimeRefresh>\n <div class=\"input-group-btn\">\n <button\n class=\"btn btn-default btn-sm\"\n [attr.aria-label]=\"'Refresh' | translate\"\n [tooltip]=\"\n (isRealtimeActive | async)\n ? (NEW_REALTIME_ALARM_MESSAGE | translate)\n : (REFRESH_LABEL | translate)\n \"\n placement=\"left\"\n container=\"body\"\n type=\"button\"\n [adaptivePosition]=\"false\"\n [delay]=\"500\"\n [disabled]=\"isLoading$ | async\"\n (click)=\"refresh()\"\n >\n <span\n class=\"tag tag--info m-r-8\"\n *ngIf=\"isRealtimeActive | async\"\n >\n {{ 'New alarms' | translate }}\n </span>\n <i\n c8yIcon=\"refresh\"\n [ngClass]=\"{ 'icon-spin': isLoading$ | async }\"\n ></i>\n </button>\n <button\n class=\"c8y-realtime btn btn-default btn-sm\"\n [attr.aria-label]=\"realtimeIconTitle\"\n [tooltip]=\"realtimeIconTitle\"\n placement=\"bottom\"\n type=\"button\"\n data-cy=\"c8y-alarms--realtime-button\"\n [container]=\"'body'\"\n (click)=\"toggleRealtimeState()\"\n >\n <span\n class=\"c8y-pulse m-0\"\n [ngClass]=\"{\n active: isRealtimeToggleOn,\n inactive: !isRealtimeToggleOn\n }\"\n ></span>\n </button>\n </div>\n</ng-template>\n\n<c8y-help\n src=\"/docs/device-management-application/monitoring-and-controlling-devices/#working-with-alarms\"\n></c8y-help>\n\n<div class=\"card content-fullpage split-view--5-7 grid__row--1\">\n <c8y-alarms-list\n class=\"d-contents\"\n [isInitialLoading]=\"isLoading$ | async\"\n [alarms]=\"alarms$ | async\"\n [typeFilters]=\"typeFilters\"\n (onScrollingStateChange)=\"changeInterval(!$event)\"\n (onSelectedAlarm)=\"changeInterval(false)\"\n [splitView]=\"true\"\n [hasPermissions]=\"!isDisabled\"\n >\n <ng-container *ngIf=\"isIntervalRefresh; else realtimeRefresh\">\n <c8y-alarms-interval-refresh\n [alarmsListLoading$]=\"isLoading$\"\n [isIntervalToggleEnabled]=\"shouldShowIntervalToggle$ | async\"\n (onCountdownEnded)=\"refresh()\"\n [isDisabled]=\"isDisabled\"\n ></c8y-alarms-interval-refresh>\n </ng-container>\n </c8y-alarms-list>\n\n <router-outlet class=\"d-contents\"></router-outlet>\n</div>\n" }]
}], ctorParameters: () => [{ type: i1.ActivatedRoute }, { type: i2.AlarmsViewService }, { type: i3.AlarmWithChildrenRealtimeService }, { type: i3.AlertService }, { type: i3.ContextRouteService }, { type: i3.ModalService }, { type: i4.TranslateService }, { type: i1.Router }], propDecorators: { alarmIntervalRefreshComponent: [{
type: ViewChild,
args: [AlarmsIntervalRefreshComponent]
}] } });
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYWxhcm1zLmNvbXBvbmVudC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uL2FsYXJtcy9hbGFybXMuY29tcG9uZW50LnRzIiwiLi4vLi4vLi4vYWxhcm1zL2FsYXJtcy5jb21wb25lbnQuaHRtbCJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQUUsU0FBUyxFQUFxQixTQUFTLEVBQUUsTUFBTSxlQUFlLENBQUM7QUFDeEUsT0FBTyxFQUFFLGNBQWMsRUFBRSxNQUFNLEVBQUUsTUFBTSxpQkFBaUIsQ0FBQztBQUN6RCxPQUFPLEVBSUwsZUFBZSxFQUdoQixNQUFNLGFBQWEsQ0FBQztBQUNyQixPQUFPLEVBQ0wsZ0NBQWdDLEVBQ2hDLFlBQVksRUFDWixtQkFBbUIsRUFFbkIsWUFBWSxFQUNaLFdBQVcsRUFDWCxPQUFPLEVBQ1IsTUFBTSxxQkFBcUIsQ0FBQztBQUU3QixPQUFPLEVBQUUsZ0JBQWdCLEVBQUUsTUFBTSxxQkFBcUIsQ0FBQztBQUN2RCxPQUFPLEVBQUUsZUFBZSxFQUFFLE9BQU8sRUFBRSxNQUFNLE1BQU0sQ0FBQztBQUNoRCxPQUFPLEVBQUUsWUFBWSxFQUFFLFNBQVMsRUFBRSxZQUFZLEVBQUUsTUFBTSxnQkFBZ0IsQ0FBQztBQUN2RSxPQUFPLEVBQUUsOEJBQThCLEVBQUUsTUFBTSxxQ0FBcUMsQ0FBQztBQUNyRixPQUFPLEVBQUUsaUJBQWlCLEVBQUUsTUFBTSx1QkFBdUIsQ0FBQztBQUMxRCxPQUFPLEVBRUwsdUJBQXVCLEVBQ3ZCLHlCQUF5QixFQUMxQixNQUFNLGdCQUFnQixDQUFDOzs7Ozs7Ozs7Ozs7O0FBT3hCLE1BQU0sT0FBTyxlQUFlO0lBMEIxQixZQUNTLGNBQThCLEVBQzdCLGlCQUFvQyxFQUNwQyxnQ0FBa0UsRUFDbEUsWUFBMEIsRUFDMUIsbUJBQXdDLEVBQ3hDLFlBQTBCLEVBQzFCLGdCQUFrQyxFQUNsQyxNQUFjO1FBUGYsbUJBQWMsR0FBZCxjQUFjLENBQWdCO1FBQzdCLHNCQUFp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YyxDQUFDLENBQUM7UUFDbEYsSUFBSSxDQUFDLFlBQVksRUFBRSxDQUFDO1lBQ2xCLE9BQU87UUFDVCxDQUFDO1FBQ0QsTUFBTSxFQUFFLE9BQU8sRUFBRSxXQUFXLEVBQUUsR0FBRyxZQUFZLENBQUM7UUFDOUMsSUFDRSxDQUFDLFdBQVcsQ0FBQyxNQUFNLEVBQUUsV0FBVyxDQUFDLEtBQUssRUFBRSxXQUFXLENBQUMsT0FBTyxFQUFFLFdBQVcsQ0FBQyxVQUFVLENBQUMsQ0FBQyxRQUFRLENBQzNGLE9BQU8sQ0FDUixFQUNELENBQUM7WUFDRCxJQUFJLENBQUMsZUFBZSxHQUFHLFdBQVcsRUFBRSxFQUFFLENBQUM7UUFDekMsQ0FBQztJQUNILENBQUM7K0dBM05VLGVBQWU7bUdBQWYsZUFBZSxxQ0FGZixDQUFDLGdDQUFnQyxDQUFDLHlGQU9sQyw4QkFBOEIsZ0RDekMzQyxtbkhBK0hBOzs0RkQzRmEsZUFBZTtrQkFMM0IsU0FBUzsrQkFDRSxZQUFZLGFBRVgsQ0FBQyxnQ0FBZ0MsQ0FBQzs4U0FRN0MsNkJBQTZCO3NCQUQ1QixTQUFTO3VCQUFDLDhCQUE4QiIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IENvbXBvbmVudCwgT25EZXN0cm95LCBPbkluaXQsIFZpZXdDaGlsZCB9IGZyb20gJ0Bhbmd1bGFyL2NvcmUnO1xuaW1wb3J0IHsgQWN0aXZhdGVkUm91dGUsIFJvdXRlciB9IGZyb20gJ0Bhbmd1bGFyL3JvdXRlcic7XG5pbXBvcnQge1xuICBBbGFybVF1ZXJ5RmlsdGVyLFxuICBJQWxhcm0sXG4gIElSZXN1bHRMaXN0LFxuICBTRVZFUklUWV9MQUJFTFMsXG4gIFNldmVyaXR5RmlsdGVyLFxuICBTZXZlcml0eVR5cGVcbn0gZnJvbSAnQGM4eS9jbGllbnQnO1xuaW1wb3J0IHtcbiAgQWxhcm1XaXRoQ2hpbGRyZW5SZWFsdGltZVNlcnZpY2UsXG4gIEFsZXJ0U2VydmljZSxcbiAgQ29udGV4dFJvdXRlU2VydmljZSxcbiAgRGF0ZVRpbWVDb250ZXh0LFxuICBNb2RhbFNlcnZpY2UsXG4gIFZpZXdDb250ZXh0LFxuICBnZXR0ZXh0XG59IGZyb20gJ0BjOHkvbmd4LWNvbXBvbmVudHMnO1xuaW1wb3J0IHsgQWxhcm1EZXRhaWxzIH0gZnJvbSAnQGM4eS9uZ3gtY29tcG9uZW50cy9hbGFybS1ldmVudC1zZWxlY3Rvcic7XG5pbXBvcnQgeyBUcmFuc2xhdGVTZXJ2aWNlIH0gZnJvbSAnQG5neC10cmFuc2xhdGUvY29yZSc7XG5pbXBvcnQgeyBCZWhhdmlvclN1YmplY3QsIFN1YmplY3QgfSBmcm9tICdyeGpzJztcbmltcG9ydCB7IGRlYm91bmNlVGltZSwgdGFrZVVudGlsLCB0aHJvdHRsZVRpbWUgfSBmcm9tICdyeGpzL29wZXJhdG9ycyc7XG5pbXBvcnQgeyBBbGFybXNJbnRlcnZhbFJlZnJlc2hDb21wb25lbnQgfSBmcm9tICcuL2FsYXJtcy1pbnRlcnZhbC1yZWZyZXNoLmNvbXBvbmVudCc7XG5pbXBvcnQgeyBBbGFybXNWaWV3U2VydmljZSB9IGZyb20gJy4vYWxhcm1zLXZpZXcuc2VydmljZSc7XG5pbXBvcnQge1xuICBBbGFybUxpc3RGb3JtRmlsdGVycyxcbiAgREVGQVVMVF9TRVZFUklUWV9WQUxVRVMsXG4gIFRIUk9UVExFX1JFQUxUSU1FX1JFRlJFU0hcbn0gZnJvbSAnLi9hbGFybXMubW9kZWwnO1xuXG5AQ29tcG9uZW50KHtcbiAgc2VsZWN0b3I6ICdjOHktYWxhcm1zJyxcbiAgdGVtcGxhdGVVcmw6ICcuL2FsYXJtcy5jb21wb25lbnQuaHRtbCcsXG4gIHByb3ZpZGVyczogW0FsYXJtV2l0aENoaWxkcmVuUmVhbHRpbWVTZXJ2aWNlXVxufSlcbmV4cG9ydCBjbGFzcyBBbGFybXNDb21wb25lbnQgaW1wbGVtZW50cyBPbkluaXQsIE9uRGVzdHJveSB7XG4gIHJlYWRvbmx5IE5FV19SRUFMVElNRV9BTEFSTV9NRVNTQUdFID0gdGhpcy5hbGFybXNWaWV3U2VydmljZS5SRUFMVElNRV9VUERBVEVfQUxBUk1TX01FU1NBR0U7XG4gIHJlYWRvbmx5IFRJVExFID0gZ2V0dGV4dCgnQWxhcm1zJyk7XG4gIHJlYWRvbmx5IFJFRlJFU0hfTEFCRUwgPSBnZXR0ZXh0KCdSZWZyZXNoJyk7XG5cbiAgQFZpZXdDaGlsZChBbGFybXNJbnRlcnZhbFJlZnJlc2hDb21wb25lbnQpXG4gIGFsYXJtSW50ZXJ2YWxSZWZyZXNoQ29tcG9uZW50OiBBbGFybXNJbnRlcnZhbFJlZnJlc2hDb21wb25lbnQ7XG4gIGFsYXJtcyQ6IEJlaGF2aW9yU3ViamVjdDxJUmVzdWx0TGlzdDxJQWxhcm0+PiA9IG5ldyBCZWhhdmlvclN1YmplY3Q8SVJlc3VsdExpc3Q8SUFsYXJtPj4obnVsbCk7XG4gIGNvbnRleHRTb3VyY2VJZDogbnVtYmVyIHwgc3RyaW5nIHwgbnVsbDtcbiAgLyoqIHJlc3BvbnNpYmxlIGZvciBzaG93aW5nIGVpdGhlciByZWFsdGltZSBidXR0b24gb3IgaW50ZXJ2YWxzLCBiYXNlZCBvbiAncmVmcmVzaFR5cGUnIGtleSBpbiBPcHRpb25zU2VydmljZSAqL1xuICBpc0ludGVydmFsUmVmcmVzaDogYm9vbGVhbjtcbiAgaXNMb2FkaW5nJDogQmVoYXZpb3JTdWJqZWN0PGJvb2xlYW4+ID0gbmV3IEJlaGF2aW9yU3ViamVjdDxib29sZWFuPihmYWxzZSk7XG4gIGlzUmVhbHRpbWVBY3RpdmUgPSBuZXcgQmVoYXZpb3JTdWJqZWN0PGJvb2xlYW4+KGZhbHNlKTtcbiAgcmVhbHRpbWVJY29uVGl0bGU6IHN0cmluZztcbiAgc2hvdWxkU2hvd0ludGVydmFsVG9nZ2xlJCA9IG5ldyBCZWhhdmlvclN1YmplY3Q8Ym9vbGVhbj4odHJ1ZSk7XG4gIGlzUmVhbHRpbWVUb2dnbGVPbiA9IHRydWU7XG4gIHR5cGVGaWx0ZXJzOiBBbGFybURldGFpbHNbXSA9IFtdO1xuICBpc0Rpc2FibGVkID0gZmFsc2U7XG5cbiAgcHJpdmF0ZSBkZXN0cm95JDogU3ViamVjdDx2b2lkPiA9IG5ldyBTdWJqZWN0PHZvaWQ+KCk7XG4gIHByaXZhdGUgc2VsZWN0ZWRTZXZlcml0aWVzID0gT2JqZWN0LmtleXMoU0VWRVJJVFlfTEFCRUxTKSBhcyBTZXZlcml0eVR5cGVbXTtcbiAgcHJpdmF0ZSBzZXZlcml0eU9wdGlvbnM6IFNldmVyaXR5RmlsdGVyID0gREVGQVVMVF9TRVZFUklUWV9WQUxVRVM7XG4gIHByaXZhdGUgc2hvd0NsZWFyZWQgPSBmYWxzZTtcbiAgcHJpdmF0ZSByZWFkb25seSBXQUlUX1RJTUVfQVZPSURfTVVMVElQTEVfUkVRVUVTVF9CWV9QQVJBTV9DSEFOR0UgPSAxMDA7XG4gIHByaXZhdGUgc2VsZWN0ZWREYXRlczogRGF0ZVRpbWVDb250ZXh0O1xuXG4gIGNvbnN0cnVjdG9yKFxuICAgIHB1YmxpYyBhY3RpdmF0ZWRSb3V0ZTogQWN0aXZhdGVkUm91dGUsXG4gICAgcHJpdmF0ZSBhbGFybXNWaWV3U2VydmljZTogQWxhcm1zVmlld1NlcnZpY2UsXG4gICAgcHJpdmF0ZSBhbGFybVdpdGhDaGlsZHJlblJlYWx0aW1lU2VydmljZTogQWxhcm1XaXRoQ2hpbGRyZW5SZWFsdGltZVNlcnZpY2UsXG4gICAgcHJpdmF0ZSBhbGVydFNlcnZpY2U6IEFsZXJ0U2VydmljZSxcbiAgICBwcml2YXRlIGNvbnRleHRSb3V0ZVNlcnZpY2U6IENvbnRleHRSb3V0ZVNlcnZpY2UsXG4gICAgcHJpdmF0ZSBtb2RhbFNlcnZpY2U6IE1vZGFsU2VydmljZSxcbiAgICBwcml2YXRlIHRyYW5zbGF0ZVNlcnZpY2U6IFRyYW5zbGF0ZVNlcnZpY2UsXG4gICAgcHJpdmF0ZSByb3V0ZXI6IFJvdXRlclxuICApIHtcbiAgICB0aGlzLmlzSW50ZXJ2YWxSZWZyZXNoID0gdGhpcy5hbGFybXNWaWV3U2VydmljZS5pc0ludGVydmFsUmVmcmVzaCgpO1xuICAgIHRoaXMuaW5pdGlhbGl6ZUNvbnRleHRTb3VyY2VJZCgpO1xuICB9XG5cbiAgbmdPbkluaXQoKSB7XG4gICAgY29uc3QgaXNJbkRldGFpbFZpZXcgPSAhIXRoaXMuYWN0aXZhdGVkUm91dGUuY2hpbGRyZW5bMF0/LnNuYXBzaG90LnBhcmFtcy5pZDtcbiAgICBpZiAoaXNJbkRldGFpbFZpZXcpIHtcbiAgICAgIHRoaXMuY2hhbmdlSW50ZXJ2YWwoZmFsc2UpO1xuICAgIH1cblxuICAgIGlmICghdGhpcy5pc0ludGVydmFsUmVmcmVzaCkge1xuICAgICAgdGhpcy5oYW5kbGVMZWdhY3lSZWFsdGltZSgpO1xuICAgIH1cblxuICAgIHRoaXMuYWxhcm1zVmlld1NlcnZpY2UucmVsb2FkQWxhcm1zTGlzdCRcbiAgICAgIC5waXBlKFxuICAgICAgICBkZWJvdW5jZVRpbWUodGhpcy5XQUlUX1RJTUVfQVZPSURfTVVMVElQTEVfUkVRVUVTVF9CWV9QQVJBTV9DSEFOR0UpLFxuICAgICAgICB0YWtlVW50aWwodGhpcy5kZXN0cm95JClcbiAgICAgIClcbiAgICAgIC5zdWJzY3JpYmUoKCkgPT4ge1xuICAgICAgICB0aGlzLnVwZGF0ZUFsYXJtcygpO1xuICAgICAgfSk7XG4gIH1cblxuICBuZ09uRGVzdHJveSgpOiB2b2lkIHtcbiAgICB0aGlzLmRlc3Ryb3kkLm5leHQoKTtcbiAgICB0aGlzLmRlc3Ryb3kkLmNvbXBsZXRlKCk7XG4gIH1cblxuICBhcHBseVR5cGVGaWx0ZXJzKHR5cGVGaWx0ZXJzOiBBbGFybURldGFpbHNbXSk6IHZvaWQge1xuICAgIHRoaXMudHlwZUZpbHRlcnMgPSB0eXBlRmlsdGVycztcbiAgICB0aGlzLmFsYXJtc1ZpZXdTZXJ2aWNlLnJlbG9hZEFsYXJtc0xpc3QkLm5leHQoKTtcbiAgICB0aGlzLmlzUmVhbHRpbWVBY3RpdmUubmV4dChmYWxzZSk7XG4gIH1cblxuICBhcHBseUZvcm1GaWx0ZXJzKHsgc2V2ZXJpdHlPcHRpb25zLCBzaG93Q2xlYXJlZCwgc2VsZWN0ZWREYXRlcyB9OiBBbGFybUxpc3RGb3JtRmlsdGVycyk6IHZvaWQge1xuICAgIHRoaXMuc2V2ZXJpdHlPcHRpb25zID0gc2V2ZXJpdHlPcHRpb25zO1xuICAgIHRoaXMuc2hvd0NsZWFyZWQgPSBzaG93Q2xlYXJlZDtcbiAgICB0aGlzLnNlbGVjdGVkRGF0ZXMgPSBzZWxlY3RlZERhdGVzO1xuICAgIHRoaXMuc2VsZWN0ZWRTZXZlcml0aWVzID0gdGhpcy5hbGFybXNWaWV3U2VydmljZS51cGRhdGVTZWxlY3RlZFNldmVyaXRpZXModGhpcy5zZXZlcml0eU9wdGlvbnMpO1xuICAgIHRoaXMuYWxhcm1zVmlld1NlcnZpY2UucmVsb2FkQWxhcm1zTGlzdCQubmV4dCgpO1xuICAgIHRoaXMuaXNSZWFsdGltZUFjdGl2ZS5uZXh0KGZhbHNlKTtcbiAgfVxuXG4gIGFzeW5jIGFwcGx5RGF0ZUZpbHRlcihzZWxlY3RlZERhdGVzOiBbRGF0ZSwgRGF0ZV0pOiBQcm9taXNlPHZvaWQ+IHtcbiAgICB0aGlzLmFsYXJtcyQubmV4dChhd2FpdCB0aGlzLmFsYXJtc1ZpZXdTZXJ2aWNlLnJldHJpZXZlQWxhcm1zQnlEYXRlKHNlbGVjdGVkRGF0ZXMpKTtcbiAgICB0aGlzLmlzUmVhbHRpbWVBY3RpdmUubmV4dChmYWxzZSk7XG4gIH1cblxuICBhc3luYyBjbGVhckFsbCgpOiBQcm9taXNlPHZvaWQ+IHtcbiAgICB0cnkge1xuICAgICAgY29uc3QgdHJhbnNsYXRlZEJvZHkgPSB0aGlzLnRyYW5zbGF0ZVNlcnZpY2UuaW5zdGFudChcbiAgICAgICAgZ2V0dGV4dCgnRG8geW91IHJlYWxseSB3YW50IHRvIGNsZWFyIGFsbCBhbGFybXMgb2Ygc2VsZWN0ZWQgc2V2ZXJpdGllcz8nKVxuICAgICAgKTtcbiAgICAgIGF3YWl0IHRoaXMubW9kYWxTZXJ2aWNlLmNvbmZpcm0oXG4gICAgICAgIGdldHRleHQoJ0NvbmZpcm0gY2xlYXJpbmcgYWxhcm1zPycpLFxuICAgICAgICB0cmFuc2xhdGVkQm9keSxcbiAgICAgICAgJ2RhbmdlcicsXG4gICAgICAgIHtcbiAgICAgICAgICBvazogZ2V0dGV4dCgnQ29uZmlybScpLFxuICAgICAgICAgIGNhbmNlbDogZ2V0dGV4dCgnQ2FuY2VsJylcbiAgICAgICAgfVxuICAgICAgKTtcbiAgICB9IGNhdGNoIHtcbiAgICAgIC8vIG1vZGFsIGNhbmNlbGVkXG4gICAgICByZXR1cm47XG4gICAgfVxuXG4gICAgYXdhaXQgdGhpcy5jbGVhckFsYXJtcygpO1xuICB9XG5cbiAgcmVmcmVzaCgpOiB2b2lkIHtcbiAgICB0aGlzLnVwZGF0ZUFsYXJtcygpO1xuICAgIHRoaXMuaXNSZWFsdGltZUFjdGl2ZS5uZXh0KGZhbHNlKTtcbiAgfVxuXG4gIGNoYW5nZUludGVydmFsKHZhbHVlID0gdHJ1ZSk6IHZvaWQge1xuICAgIHRoaXMuc2hvdWxkU2hvd0ludGVydmFsVG9nZ2xlJC5uZXh0KHZhbHVlKTtcbiAgfVxuXG4gIHRvZ2dsZVJlYWx0aW1lU3RhdGUoKTogdm9pZCB7XG4gICAgdGhpcy5pc1JlYWx0aW1lVG9nZ2xlT24gPSAhdGhpcy5pc1JlYWx0aW1lVG9nZ2xlT247XG4gIH1cblxuICBwcml2YXRlIGhhbmRsZUxlZ2FjeVJlYWx0aW1lKCkge1xuICAgIHRoaXMucmVhbHRpbWVJY29uVGl0bGUgPSB0aGlzLnRyYW5zbGF0ZVNlcnZpY2UuaW5zdGFudChnZXR0ZXh0KCdSZWFsdGltZSBhY3RpdmUnKSk7XG4gICAgdGhpcy5zdWJzY3JpYmVUb1JlYWx0aW1lVXBkYXRlcygpO1xuICB9XG5cbiAgcHJpdmF0ZSBhc3luYyBjbGVhckFsYXJtcygpOiBQcm9taXNlPHZvaWQ+IHtcbiAgICB0cnkge1xuICAgICAgY29uc3QgcmVzdWx0ID0gYXdhaXQgdGhpcy5hbGFybXNWaWV3U2VydmljZS5jbGVhckFsbEFjdGl2ZUFsYXJtcyhcbiAgICAgICAgdGhpcy5zZWxlY3RlZFNldmVyaXRpZXMsXG4gICAgICAgIHRoaXMuY29udGV4dFNvdXJjZUlkXG4gICAgICApO1xuXG4gICAgICBpZiAocmVzdWx0LnJlc29sdmVkSW1tZWRpYXRlbHkpIHtcbiAgICAgICAgdGhpcy5hbGVydFNlcnZpY2Uuc3VjY2Vzcyh0aGlzLnRyYW5zbGF0ZVNlcnZpY2UuaW5zdGFudChnZXR0ZXh0KCdBbGFybXMgY2xlYXJlZC4nKSkpO1xuICAgICAgICB0aGlzLmJhY2tUb1Jvb3RSb3V0ZSgpO1xuICAgICAgICB0aGlzLnJlZnJlc2goKTtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIHRoaXMuYWxlcnRTZXJ2aWNlLnN1Y2Nlc3MoXG4gICAgICAgICAgdGhpcy50cmFuc2xhdGVTZXJ2aWNlLmluc3RhbnQoZ2V0dGV4dCgnQWxhcm1zIGFyZSBiZWluZyBjbGVhcmVkIGluIGJhY2tncm91bmQuJykpXG4gICAgICAgICk7XG4gICAgICB9XG4gICAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICAgIHRoaXMuYWxlcnRTZXJ2aWNlLmFkZFNlcnZlckZhaWx1cmUoZXJyb3IpO1xuICAgIH1cbiAgfVxuXG4gIHByaXZhdGUgYmFja1RvUm9vdFJvdXRlKCk6IHZvaWQge1xuICAgIGNvbnN0IGNvbnRleHREYXRhID0gdGhpcy5jb250ZXh0Um91dGVTZXJ2aWNlLmdldENvbnRleHREYXRhKHRoaXMuYWN0aXZhdGVkUm91dGUpO1xuICAgIHRoaXMucm91dGVyLm5hdmlnYXRlKHRoaXMuYWxhcm1zVmlld1NlcnZpY2UuZ2V0Um91dGVyTmF2aWdhdGlvbkFycmF5KGNvbnRleHREYXRhKSwge1xuICAgICAgcXVlcnlQYXJhbXNIYW5kbGluZzogJ21lcmdlJ1xuICAgIH0pO1xuICB9XG5cbiAgcHJpdmF0ZSBhc3luYyBnZXRBbGFybXMoKTogUHJvbWlzZTxJUmVzdWx0TGlzdDxJQWxhcm0+PiB7XG4gICAgdHJ5IHtcbiAgICAgIHRoaXMuaXNMb2FkaW5nJC5uZXh0KHRydWUpO1xuXG4gICAgICBjb25zdCBhZGRpdGlvbmFsRmlsdGVyOiBQYXJ0aWFsPEFsYXJtUXVlcnlGaWx0ZXI+ID0ge307XG5cbiAgICAgIGlmICh0aGlzLmNvbnRleHRTb3VyY2VJZCkge1xuICAgICAgICAoYWRkaXRpb25hbEZpbHRlci5zb3VyY2UgPSB0aGlzLmNvbnRleHRTb3VyY2VJZCksXG4gICAgICAgICAgKGFkZGl0aW9uYWxGaWx0ZXIud2l0aFNvdXJjZUFzc2V0cyA9IHRydWUpLFxuICAgICAgICAgIChhZGRpdGlvbmFsRmlsdGVyLndpdGhTb3VyY2VEZXZpY2VzID0gdHJ1ZSk7XG4gICAgICB9XG5cbiAgICAgIGlmICh0aGlzLnR5cGVGaWx0ZXJzLmxlbmd0aCA+IDApIHtcbiAgICAgICAgYWRkaXRpb25hbEZpbHRlci50eXBlID0gdGhpcy50eXBlRmlsdGVycy5tYXAoKHsgZmlsdGVycyB9KSA9PiBmaWx0ZXJzLnR5cGUpLmpvaW4oJywnKTtcbiAgICAgIH1cblxuICAgICAgcmV0dXJuIGF3YWl0IHRoaXMuYWxhcm1zVmlld1NlcnZpY2UucmV0cmlldmVGaWx0ZXJlZEFsYXJtcyhcbiAgICAgICAgdGhpcy5zZWxlY3RlZFNldmVyaXRpZXMsXG4gICAgICAgIHRoaXMuc2hvd0NsZWFyZWQsXG4gICAgICAgIHRoaXMuc2VsZWN0ZWREYXRlcyxcbiAgICAgICAgYWRkaXRpb25hbEZpbHRlclxuICAgICAgKTtcbiAgICB9IGNhdGNoIChlcnJvcikge1xuICAgICAgaWYgKGVycm9yPy5yZXM/LnN0YXR1cyA9PT0gNDAzKSB7XG4gICAgICAgIHRoaXMuaXNEaXNhYmxlZCA9IHRydWU7XG4gICAgICAgIHJldHVybjtcbiAgICAgIH1cbiAgICAgIHRoaXMuYWxlcnRTZXJ2aWNlLmFkZFNlcnZlckZhaWx1cmUoZXJyb3IpO1xuICAgIH0gZmluYWxseSB7XG4gICAgICB0aGlzLmlzTG9hZGluZyQubmV4dChmYWxzZSk7XG4gICAgfVxuICB9XG5cbiAgcHJpdmF0ZSBhc3luYyB1cGRhdGVBbGFybXMoKSB7XG4gICAgdGhpcy5hbGFybXMkLm5leHQoYXdhaXQgdGhpcy5nZXRBbGFybXMoKSk7XG4gIH1cblxuICBwcml2YXRlIHN1YnNjcmliZVRvUmVhbHRpbWVVcGRhdGVzKCk6IHZvaWQge1xuICAgIHRoaXMuYWxhcm1XaXRoQ2hpbGRyZW5SZWFsdGltZVNlcnZpY2VcbiAgICAgIC5vbkFsbCQodGhpcy5jb250ZXh0U291cmNlSWQpXG4gICAgICAucGlwZShcbiAgICAgICAgdGFrZVVudGlsKHRoaXMuZGVzdHJveSQpLFxuICAgICAgICB0aHJvdHRsZVRpbWUoVEhST1RUTEVfUkVBTFRJTUVfUkVGUkVTSCwgdW5kZWZpbmVkLCB7IHRyYWlsaW5nOiB0cnVlIH0pXG4gICAgICApXG4gICAgICAuc3Vic2NyaWJlKCgpID0+IHtcbiAgICAgICAgaWYgKHRoaXMuaXNSZWFsdGltZVRvZ2dsZU9uKSB7XG4gICAgICAgICAgdGhpcy5yZWZyZXNoKCk7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgdGhpcy5pc1JlYWx0aW1lQWN0aXZlLm5leHQodHJ1ZSk7XG4gICAgICAgIH1cbiAgICAgIH0pO1xuICB9XG5cbiAgcHJpdmF0ZSBpbml0aWFsaXplQ29udGV4dFNvdXJjZUlkKCk6IHZvaWQge1xuICAgIGNvbnN0IHJvdXRlQ29udGV4dCA9IHRoaXMuY29udGV4dFJvdXRlU2VydmljZS5nZXRDb250ZXh0RGF0YSh0aGlzLmFjdGl2YXRlZFJvdXRlKTtcbiAgICBpZiAoIXJvdXRlQ29udGV4dCkge1xuICAgICAgcmV0dXJuO1xuICAgIH1cbiAgICBjb25zdCB7IGNvbnRleHQsIGNvbnRleHREYXRhIH0gPSByb3V0ZUNvbnRleHQ7XG4gICAgaWYgKFxuICAgICAgW1ZpZXdDb250ZXh0LkRldmljZSwgVmlld0NvbnRleHQuR3JvdXAsIFZpZXdDb250ZXh0LlNlcnZpY2UsIFZpZXdDb250ZXh0LlNpbXVsYXRvcnNdLmluY2x1ZGVzKFxuICAgICAgICBjb250ZXh0XG4gICAgICApXG4gICAgKSB7XG4gICAgICB0aGlzLmNvbnRleHRTb3VyY2VJZCA9IGNvbnRleHREYXRhPy5pZDtcbiAgICB9XG4gIH1cbn1cbiIsIjxuZy1jb250YWluZXIgKm5nSWY9XCIoYWN0aXZhdGVkUm91dGUuZGF0YSB8IGFzeW5jKT8udGl0bGVcIj5cbiAgPGM4eS10aXRsZT57eyBUSVRMRSB8IHRyYW5zbGF0ZSB9fTwvYzh5LXRpdGxlPlxuPC9uZy1jb250YWluZXI+XG5cbjxjOHktYWN0aW9uLWJhci1pdGVtXG4gIFtwbGFjZW1lbnRdPVwiJ2xlZnQnXCJcbiAgaXRlbUNsYXNzPVwibmF2YmFyLWZvcm0gbWluLXdpZHRoLWZpdFwiXG4+XG4gIDxjOHktYWxhcm1zLWZpbHRlclxuICAgIGNsYXNzPVwiZC1ibG9jayBmaXQtd1wiXG4gICAgW2NvbnRleHRTb3VyY2VJZF09XCJjb250ZXh0U291cmNlSWRcIlxuICAgIChvbkZpbHRlckFwcGxpZWQpPVwiYXBwbHlGb3JtRmlsdGVycygkZXZlbnQpXCJcbiAgPjwvYzh5LWFsYXJtcy1maWx0ZXI+XG48L2M4eS1hY3Rpb24tYmFyLWl0ZW0+XG5cbjxjOHktYWN0aW9uLWJhci1pdGVtXG4gIFtwbGFjZW1lbnRdPVwiJ2xlZnQnXCJcbiAgaXRlbUNsYXNzPVwibmF2YmFyLWZvcm0gbWluLXdpZHRoLWZpdFwiXG4+XG4gIDxjOHktYWxhcm1zLWRhdGUtZmlsdGVyIChkYXRlRmlsdGVyQ2hhbmdlKT1cImFwcGx5Rm9ybUZpbHRlcnMoJGV2ZW50KVwiPjwvYzh5LWFsYXJtcy1kYXRlLWZpbHRlcj5cbjwvYzh5LWFjdGlvbi1iYXItaXRlbT5cblxuPGM4eS1hY3Rpb24tYmFyLWl0ZW1cbiAgW3BsYWNlbWVudF09XCInbGVmdCdcIlxuICBpdGVtQ2xhc3M9XCJuYXZiYXItZm9ybVwiXG4+XG4gIDxjOHktYWxhcm1zLXR5cGUtZmlsdGVyXG4gICAgY2xhc3M9XCJkLWJsb2NrIGZpdC13XCJcbiAgICBbYWxhcm1zXT1cImFsYXJtcyQgfCBhc3luY1wiXG4gICAgKG9uRmlsdGVyQ2hhbmdlZCk9XCJhcHBseVR5cGVGaWx0ZXJzKCRldmVudClcIlxuICA+PC9jOHktYWxhcm1zLXR5cGUtZmlsdGVyPlxuPC9jOHktYWN0aW9uLWJhci1pdGVtPlxuXG48Yzh5LWFjdGlvbi1iYXItaXRlbVxuICBbcGxhY2VtZW50XT1cIidyaWdodCdcIlxuICBbcHJpb3JpdHldPVwiMFwiXG4+XG4gIDxidXR0b25cbiAgICBjbGFzcz1cImJ0biBidG4tbGlua1wiXG4gICAgW3RpdGxlXT1cIidDbGVhciBhbGwgYWxhcm1zJyB8IHRyYW5zbGF0ZVwiXG4gICAgdHlwZT1cImJ1dHRvblwiXG4gICAgKGNsaWNrKT1cImNsZWFyQWxsKClcIlxuICAgIGRhdGEtY3k9XCJjOHktYWxhcm1zLXZpZXctLWNsZWFyLWFsbC1idXR0b25cIlxuICA+XG4gICAgPGkgYzh5SWNvbj1cImM4eS1hbGVydC1pZGxlXCI+PC9pPlxuICAgIHt7ICdDbGVhciBhbGxgYWxhcm1zYCcgfCB0cmFuc2xhdGUgfX1cbiAgPC9idXR0b24+XG48L2M4eS1hY3Rpb24tYmFyLWl0ZW0+XG5cbjwhLS1SZWFsdGltZSBidXR0b24tLT5cbjxuZy10ZW1wbGF0ZSAjcmVhbHRpbWVSZWZyZXNoPlxuICA8ZGl2IGNsYXNzPVwiaW5wdXQtZ3JvdXAtYnRuXCI+XG4gICAgPGJ1dHRvblxuICAgICAgY2xhc3M9XCJidG4gYnRuLWRlZmF1bHQgYnRuLXNtXCJcbiAgICAgIFthdHRyLmFyaWEtbGFiZWxdPVwiJ1JlZnJlc2gnIHwgdHJhbnNsYXRlXCJcbiAgICAgIFt0b29sdGlwXT1cIlxuICAgICAgICAoaXNSZWFsdGltZUFjdGl2ZSB8IGFzeW5jKVxuICAgICAgICAgID8gKE5FV19SRUFMVElNRV9BTEFSTV9NRVNTQUdFIHwgdHJhbnNsYXRlKVxuICAgICAgICAgIDogKFJFRlJFU0hfTEFCRUwgfCB0cmFuc2xhdGUpXG4gICAgICBcIlxuICAgICAgcGxhY2VtZW50PVwibGVmdFwiXG4gICAgICBjb250YWluZXI9XCJib2R5XCJcbiAgICAgIHR5cGU9XCJidXR0b25cIlxuICAgICAgW2FkYXB0aXZlUG9zaXRpb25dPVwiZmFsc2VcIlxuICAgICAgW2RlbGF5XT1cIjUwMFwiXG4gICAgICBbZGlzYWJsZWRdPVwiaXNMb2FkaW5nJCB8IGFzeW5jXCJcbiAgICAgIChjbGljayk9XCJyZWZyZXNoKClcIlxuICAgID5cbiAgICAgIDxzcGFuXG4gICAgICAgIGNsYXNzPVwidGFnIHRhZy0taW5mbyBtLXItOFwiXG4gICAgICAgICpuZ0lmPVwiaXNSZWFsdGltZUFjdGl2ZSB8IGFzeW5jXCJcbiAgICAgID5cbiAgICAgICAge3sgJ05ldyBhbGFybXMnIHwgdHJhbnNsYXRlIH19XG4gICAgICA8L3NwYW4+XG4gICAgICA8aVxuICAgICAgICBjOHlJY29uPVwicmVmcmVzaFwiXG4gICAgICAgIFtuZ0NsYXNzXT1cInsgJ2ljb24tc3Bpbic6IGlzTG9hZGluZyQgfCBhc3luYyB9XCJcbiAgICAgID48L2k+XG4gICAgPC9idXR0b24+XG4gICAgPGJ1dHRvblxuICAgICAgY2xhc3M9XCJjOHktcmVhbHRpbWUgYnRuIGJ0bi1kZWZhdWx0IGJ0bi1zbVwiXG4gICAgICBbYXR0ci5hcmlhLWxhYmVsXT1cInJlYWx0aW1lSWNvblRpdGxlXCJcbiAgICAgIFt0b29sdGlwXT1cInJlYWx0aW1lSWNvblRpdGxlXCJcbiAgICAgIHBsYWNlbWVudD1cImJvdHRvbVwiXG4gICAgICB0eXBlPVwiYnV0dG9uXCJcbiAgICAgIGRhdGEtY3k9XCJjOHktYWxhcm1zLS1yZWFsdGltZS1idXR0b25cIlxuICAgICAgW2NvbnRhaW5lcl09XCInYm9keSdcIlxuICAgICAgKGNsaWNrKT1cInRvZ2dsZVJlYWx0aW1lU3RhdGUoKVwiXG4gICAgPlxuICAgICAgPHNwYW5cbiAgICAgICAgY2xhc3M9XCJjOHktcHVsc2UgbS0wXCJcbiAgICAgICAgW25nQ2xhc3NdPVwie1xuICAgICAgICAgIGFjdGl2ZTogaXNSZWFsdGltZVRvZ2dsZU9uLFxuICAgICAgICAgIGluYWN0aXZlOiAhaXNSZWFsdGltZVRvZ2dsZU9uXG4gICAgICAgIH1cIlxuICAgICAgPjwvc3Bhbj5cbiAgICA8L2J1dHRvbj5cbiAgPC9kaXY+XG48L25nLXRlbXBsYXRlPlxuXG48Yzh5LWhlbHBcbiAgc3JjPVwiL2RvY3MvZGV2aWNlLW1hbmFnZW1lbnQtYXBwbGljYXRpb24vbW9uaXRvcmluZy1hbmQtY29udHJvbGxpbmctZGV2aWNlcy8jd29ya2luZy13aXRoLWFsYXJtc1wiXG4+PC9jOHktaGVscD5cblxuPGRpdiBjbGFzcz1cImNhcmQgY29udGVudC1mdWxscGFnZSBzcGxpdC12aWV3LS01LTcgZ3JpZF9fcm93LS0xXCI+XG4gIDxjOHktYWxhcm1zLWxpc3RcbiAgICBjbGFzcz1cImQtY29udGVudHNcIlxuICAgIFtpc0luaXRpYWxMb2FkaW5nXT1cImlzTG9hZGluZyQgfCBhc3luY1wiXG4gICAgW2FsYXJtc109XCJhbGFybXMkIHwgYXN5bmNcIlxuICAgIFt0eXBlRmlsdGVyc109XCJ0eXBlRmlsdGVyc1wiXG4gICAgKG9uU2Nyb2xsaW5nU3RhdGVDaGFuZ2UpPVwiY2hhbmdlSW50ZXJ2YWwoISRldmVudClcIlxuICAgIChvblNlbGVjdGVkQWxhcm0pPVwiY2hhbmdlSW50ZXJ2YWwoZmFsc2UpXCJcbiAgICBbc3BsaXRWaWV3XT1cInRydWVcIlxuICAgIFtoYXNQZXJtaXNzaW9uc109XCIhaXNEaXNhYmxlZFwiXG4gID5cbiAgICA8bmctY29udGFpbmVyICpuZ0lmPVwiaXNJbnRlcnZhbFJlZnJlc2g7IGVsc2UgcmVhbHRpbWVSZWZyZXNoXCI+XG4gICAgICA8Yzh5LWFsYXJtcy1pbnRlcnZhbC1yZWZyZXNoXG4gICAgICAgIFthbGFybXNMaXN0TG9hZGluZyRdPVwiaXNMb2FkaW5nJFwiXG4gICAgICAgIFtpc0ludGVydmFsVG9nZ2xlRW5hYmxlZF09XCJzaG91bGRTaG93SW50ZXJ2YWxUb2dnbGUkIHwgYXN5bmNcIlxuICAgICAgICAob25Db3VudGRvd25FbmRlZCk9XCJyZWZyZXNoKClcIlxuICAgICAgICBbaXNEaXNhYmxlZF09XCJpc0Rpc2FibGVkXCJcbiAgICAgID48L2M4eS1hbGFybXMtaW50ZXJ2YWwtcmVmcmVzaD5cbiAgICA8L25nLWNvbnRhaW5lcj5cbiAgPC9jOHktYWxhcm1zLWxpc3Q+XG5cbiAgPHJvdXRlci1vdXRsZXQgY2xhc3M9XCJkLWNvbnRlbnRzXCI+PC9yb3V0ZXItb3V0bGV0PlxuPC9kaXY+XG4iXX0=