UNPKG

@c8y/ngx-components

Version:

Angular modules for Cumulocity IoT applications

210 lines 52.9 kB
import { Component, EventEmitter, Input, Output, ViewChild } from '@angular/core'; import { FormBuilder } from '@angular/forms'; import { Severity, SEVERITY_LABELS } from '@c8y/client'; import { AlertService } from '@c8y/ngx-components'; import { BsDropdownDirective } from 'ngx-bootstrap/dropdown'; import { BehaviorSubject, Subject, combineLatest, from, forkJoin, EMPTY } from 'rxjs'; import { catchError, filter, finalize, map, startWith, takeUntil } from 'rxjs/operators'; import { AlarmsViewService } from './alarms-view.service'; import { DEFAULT_ALARM_COUNTS, DEFAULT_SEVERITY_VALUES } from './alarms.model'; import { ActivatedRoute, Router } from '@angular/router'; import * as i0 from "@angular/core"; import * as i1 from "@angular/forms"; import * as i2 from "./alarms-view.service"; import * as i3 from "@c8y/ngx-components"; import * as i4 from "@angular/router"; import * as i5 from "@angular/cdk/a11y"; import * as i6 from "ngx-bootstrap/dropdown"; import * as i7 from "@angular/common"; import * as i8 from "@ngx-translate/core"; import * as i9 from "./alarm-severity-to-icon.pipe"; import * as i10 from "./alarm-severities-to-title.pipe"; export class AlarmsFilterComponent { constructor(formBuilder, alarmsViewService, alertService, router, activatedRoute) { this.formBuilder = formBuilder; this.alarmsViewService = alarmsViewService; this.alertService = alertService; this.router = router; this.activatedRoute = activatedRoute; this.severitiesList = Object.keys(SEVERITY_LABELS); /** * EventEmitter to notify when filters have been applied. * Emits a `AlarmListFormFilters` object representing the filter criteria applied by the user. */ this.onFilterApplied = new EventEmitter(); this.formGroup = this.formBuilder.group(DEFAULT_SEVERITY_VALUES); this.chips = []; this.showCleared = false; this.alarmCounts = DEFAULT_ALARM_COUNTS; this.SEVERITY_LABELS = SEVERITY_LABELS; this.isNoneCheckboxSelected$ = new BehaviorSubject(false); this.severitiesTouched$ = new BehaviorSubject(false); this.currentFormGroupValues = this.formGroup.value; this.destroy$ = new Subject(); } ngOnInit() { this.activatedRoute.queryParams.pipe(takeUntil(this.destroy$)).subscribe(params => { this.showCleared = params.showCleared === 'true'; this.formGroup.setValue({ [Severity.CRITICAL]: params[Severity.CRITICAL] === 'true', [Severity.MAJOR]: params[Severity.MAJOR] === 'true', [Severity.MINOR]: params[Severity.MINOR] === 'true', [Severity.WARNING]: params[Severity.WARNING] === 'true' }); if (params.lastUpdatedFrom) { this.selectedDates = [new Date(params.lastUpdatedFrom), new Date(params.createdTo)]; } this.applyFilters(true, false); }); this.trackCheckboxStateWithFormChanges(); this.currentShowClearedValue = this.showCleared; this.updateChipsAndDefaultValues(); } ngAfterViewInit() { this.filtersDropdown.isOpenChange .pipe(takeUntil(this.destroy$), filter(Boolean)) .subscribe(() => this.updateAlarmsCount()); } ngOnDestroy() { this.destroy$.next(); this.destroy$.complete(); } allChanged(selected) { this.formGroup.patchValue({ [Severity.CRITICAL]: selected, [Severity.MAJOR]: selected, [Severity.MINOR]: selected, [Severity.WARNING]: selected }); } applyFilters(emit = true, navigate = true) { this.updateChipsAndDefaultValues(); const combinedFormEvent = { showCleared: this.showCleared, severityOptions: this.formGroup.value, selectedDates: this.selectedDates }; if (emit) { this.onFilterApplied.emit(combinedFormEvent); } this.currentFormGroupValues = this.formGroup.value; this.currentShowClearedValue = this.showCleared; if (navigate) { this.router.navigate([], { queryParams: { showCleared: combinedFormEvent.showCleared, ...combinedFormEvent.severityOptions, lastUpdatedFrom: combinedFormEvent.selectedDates?.[0]?.toISOString(), createdTo: combinedFormEvent.selectedDates?.[1]?.toISOString() }, queryParamsHandling: 'merge' }); } } deselectChip(chip) { this.formGroup.patchValue({ ...this.formGroup.value, [chip]: false }); this.applyFilters(false); this.closeDropdown(); } closeDropdown() { if (this.filtersDropdown.isOpen) { this.filtersDropdown.isOpen = false; } } resetForm() { this.formGroup.reset(this.currentFormGroupValues); this.severitiesTouched$.next(false); this.showCleared = this.currentShowClearedValue; } markSeveritiesAsTouched() { this.severitiesTouched$.next(true); } /** * Asynchronously fetches and updates the count of alarms for each severity level. * * @param showCleared - Whether to include cleared alarms in the count. * Defaults to the current value of `this.currentShowClearedValue`. * @returns A Promise that resolves when all alarm counts have been fetched, * or rejects with an error if the operation fails. * @throws Will throw an error if any of the alarm count fetching promises reject. */ async updateAlarmsCount(showCleared = this.currentShowClearedValue) { this.countLoading = true; const alarmFilter = this.contextSourceId ? { source: this.contextSourceId, withSourceAssets: true, withSourceDevices: true } : null; const observables = this.severitiesList.reduce((acc, severity) => { acc[severity] = from(this.alarmsViewService.getAlarmsCountBySeverity(severity, showCleared, alarmFilter)); return acc; }, { CRITICAL: null, MAJOR: null, MINOR: null, WARNING: null }); forkJoin(observables) .pipe(catchError(err => { this.alarmCounts = {}; this.alertService.addServerFailure(err); return EMPTY; }), finalize(() => (this.countLoading = false))) .subscribe((alarmCounts) => (this.alarmCounts = alarmCounts)); } createFormValueWithChangesStream() { return this.formGroup.valueChanges.pipe(startWith(this.formGroup.value)); } trackCheckboxStateWithFormChanges() { const formValue$ = this.createFormValueWithChangesStream(); this.isEachCheckboxSelected$ = this.createAllSelectedStream(formValue$); this.isIndeterminate$ = this.createIndeterminateStream(formValue$); this.trackAllCheckboxesDisabled(formValue$); this.shouldDisableApplyButton$ = this.createDisableApplyButtonStream(); } createAllSelectedStream(formValue$) { return formValue$.pipe(map(severities => Object.values(severities).every(Boolean))); } createIndeterminateStream(formValue$) { return formValue$.pipe(map(severities => Object.values(severities).some(Boolean) && !Object.values(severities).every(Boolean))); } trackAllCheckboxesDisabled(formValue$) { formValue$.pipe(takeUntil(this.destroy$)).subscribe(severities => { const areAllDisabled = Object.values(severities).every(value => !value); this.isNoneCheckboxSelected$.next(areAllDisabled); }); } createDisableApplyButtonStream() { return combineLatest([this.isNoneCheckboxSelected$, this.severitiesTouched$]).pipe(map(([allCheckboxesAreDisabled, severitiesTouched]) => allCheckboxesAreDisabled || !severitiesTouched)); } updateChipsAndDefaultValues() { const severityFilter = this.formGroup; const seveerityValues = severityFilter.value; this.chips = Object.keys(seveerityValues).filter(key => seveerityValues[key]); const allChipsRemoved = this.chips.length === 0; if (allChipsRemoved) { const defaultValues = DEFAULT_SEVERITY_VALUES; severityFilter.setValue(defaultValues); this.chips = Object.keys(defaultValues); } } static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: AlarmsFilterComponent, deps: [{ token: i1.FormBuilder }, { token: i2.AlarmsViewService }, { token: i3.AlertService }, { token: i4.Router }, { token: i4.ActivatedRoute }], target: i0.ɵɵFactoryTarget.Component }); } static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.13", type: AlarmsFilterComponent, selector: "c8y-alarms-filter", inputs: { contextSourceId: "contextSourceId" }, outputs: { onFilterApplied: "onFilterApplied" }, viewQueries: [{ propertyName: "filtersDropdown", first: true, predicate: ["filtersDropdown"], descendants: true }], ngImport: i0, template: "<form\n class=\"d-flex a-i-center\"\n [formGroup]=\"formGroup\"\n>\n <div\n class=\"dropdown\"\n title=\"{{ 'Filter by severity' | translate }}\"\n dropdown\n #filtersDropdown=\"bs-dropdown\"\n [cdkTrapFocus]=\"filtersDropdown.isOpen\"\n [insideClick]=\"true\"\n >\n <div class=\"input-group fit-w\">\n <div class=\"form-control d-flex a-i-center inner-scroll\" style=\"min-width: 104px; padding-top: 0; padding-bottom: 0;\">\n <ng-container *ngIf=\"chips.length !== severitiesList.length; else allAlarms\">\n <span\n class=\"tag tag--info chip\"\n *ngFor=\"let chip of chips\"\n >\n <button\n class=\"btn btn-xs btn-clean text-10\"\n title=\"{{ 'Remove' | translate }}\"\n type=\"button\"\n (click)=\"deselectChip(chip); $event.stopPropagation()\"\n >\n <i c8yIcon=\"times\"></i>\n </button>\n <i\n class=\"status stroked-icon icon-12\"\n [c8yIcon]=\"chip | AlarmSeverityToIcon\"\n [ngClass]=\"chip | lowercase\"\n ></i>\n {{ SEVERITY_LABELS[chip] | translate }}\n </span>\n </ng-container>\n <ng-template #allAlarms>\n <span class=\"text-truncate\" title=\"{{ 'All severities' | translate }}\">\n {{ 'All severities' | translate }}\n </span>\n </ng-template>\n </div>\n <div class=\"input-group-btn input-group-btn--last\">\n <button\n class=\"btn-default btn btn--caret\"\n title=\"{{ chips | AlarmSeveritiesToTitle }}\"\n data-cy=\"c8y-alarm-filter\"\n dropdownToggle\n (click)=\"resetForm()\"\n >\n <i class=\"caret\"></i>\n </button>\n </div>\n </div>\n <ul\n class=\"dropdown-menu dropdown-menu-action-bar\"\n *dropdownMenu\n >\n <li class=\"p-l-16 p-r-16 p-t-4 p-b-4 d-flex a-i-center sticky-top separator-bottom\">\n <label\n class=\"c8y-checkbox d-flex a-i-center\"\n [title]=\"'All' | translate\"\n >\n <input\n type=\"checkbox\"\n data-cy=\"c8y-alarm-filter--all\"\n [ngModelOptions]=\"{ standalone: true }\"\n (ngModelChange)=\"allChanged($event)\"\n [ngModel]=\"isEachCheckboxSelected$ | async\"\n [indeterminate]=\"isIndeterminate$ | async\"\n (click)=\"markSeveritiesAsTouched()\"\n />\n <span></span>\n <i\n class=\"status stroked-icon m-l-8 icon-20\"\n [c8yIcon]=\"'bell'\"\n ></i>\n <span class=\"m-l-8\">{{ 'All' | translate }}</span>\n </label>\n </li>\n <li\n class=\"p-l-16 p-r-16 p-t-4 p-b-4 d-flex a-i-center\"\n *ngFor=\"let severity of severitiesList\"\n >\n <label\n class=\"c8y-checkbox d-flex a-i-center\"\n [title]=\"SEVERITY_LABELS[severity] | translate\"\n >\n <input\n type=\"checkbox\"\n [attr.data-cy]=\"'c8y-alarm-filter--' + severity\"\n [formControlName]=\"severity\"\n [value]=\"severity\"\n (click)=\"markSeveritiesAsTouched()\"\n />\n <span></span>\n <i\n class=\"status stroked-icon m-l-8 icon-20\"\n [c8yIcon]=\"severity | AlarmSeverityToIcon\"\n [ngClass]=\"severity | lowercase\"\n ></i>\n <span class=\"m-l-8\">{{ SEVERITY_LABELS[severity] | translate }}</span>\n </label>\n <!-- badge -->\n <div\n class=\"badge badge-info m-l-auto\"\n *ngIf=\"alarmCounts[severity] || alarmCounts[severity] === 0\"\n >\n <i\n class=\"icon-spin\"\n [c8yIcon]=\"'circle-o-notch'\"\n *ngIf=\"countLoading\"\n ></i>\n <span\n *ngIf=\"!countLoading\"\n [attr.data-cy]=\"severity + '-badge'\"\n >\n {{ alarmCounts[severity] < 99 ? alarmCounts[severity] : '99+' }}\n </span>\n </div>\n </li>\n <li class=\"p-l-16 p-r-16 p-t-4 p-b-4 d-flex a-i-center separator-top\">\n <label\n class=\"c8y-switch\"\n [attr.aria-label]=\"'Show cleared alarms' | translate\"\n [attr.data-cy]=\"'c8y-alarms-filter--cleared'\"\n >\n <input\n type=\"checkbox\"\n #showClearedCheckbox\n [ngModelOptions]=\"{ standalone: true }\"\n [(ngModel)]=\"showCleared\"\n (click)=\"markSeveritiesAsTouched(); updateAlarmsCount(showClearedCheckbox.checked)\"\n />\n <span></span>\n <span\n class=\"text-truncate\"\n title=\"{{ 'Show cleared alarms' | translate }}\"\n >\n {{ 'Show cleared alarms' | translate }}\n </span>\n </label>\n </li>\n\n <div class=\"p-16 d-flex sticky-bottom separator-top\">\n <button\n [attr.data-cy]=\"'c8y-alarms-filter--apply'\"\n class=\"btn btn-primary btn-sm flex-grow\"\n title=\"{{ 'Apply' | translate }}\"\n type=\"button\"\n (click)=\"applyFilters(false); closeDropdown()\"\n [disabled]=\"shouldDisableApplyButton$ | async\"\n >\n {{ 'Apply' | translate }}\n </button>\n </div>\n </ul>\n </div>\n</form>\n", dependencies: [{ kind: "directive", type: i5.CdkTrapFocus, selector: "[cdkTrapFocus]", inputs: ["cdkTrapFocus", "cdkTrapFocusAutoCapture"], exportAs: ["cdkTrapFocus"] }, { kind: "directive", type: i6.BsDropdownMenuDirective, selector: "[bsDropdownMenu],[dropdownMenu]", exportAs: ["bs-dropdown-menu"] }, { kind: "directive", type: i6.BsDropdownToggleDirective, selector: "[bsDropdownToggle],[dropdownToggle]", exportAs: ["bs-dropdown-toggle"] }, { kind: "directive", type: i6.BsDropdownDirective, selector: "[bsDropdown], [dropdown]", inputs: ["placement", "triggers", "container", "dropup", "autoClose", "isAnimated", "insideClick", "isDisabled", "isOpen"], outputs: ["isOpenChange", "onShown", "onHidden"], exportAs: ["bs-dropdown"] }, { kind: "directive", type: i3.IconDirective, selector: "[c8yIcon]", inputs: ["c8yIcon"] }, { kind: "directive", type: i7.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i7.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i7.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i1.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i1.CheckboxControlValueAccessor, selector: "input[type=checkbox][formControlName],input[type=checkbox][formControl],input[type=checkbox][ngModel]" }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "directive", type: i3.RequiredInputPlaceholderDirective, selector: "input[required], input[formControlName]" }, { kind: "directive", type: i1.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i1.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "pipe", type: i7.AsyncPipe, name: "async" }, { kind: "pipe", type: i7.LowerCasePipe, name: "lowercase" }, { kind: "pipe", type: i8.TranslatePipe, name: "translate" }, { kind: "pipe", type: i9.AlarmSeverityToIconPipe, name: "AlarmSeverityToIcon" }, { kind: "pipe", type: i10.AlarmSeveritiesToTitlePipe, name: "AlarmSeveritiesToTitle" }] }); } } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: AlarmsFilterComponent, decorators: [{ type: Component, args: [{ selector: 'c8y-alarms-filter', template: "<form\n class=\"d-flex a-i-center\"\n [formGroup]=\"formGroup\"\n>\n <div\n class=\"dropdown\"\n title=\"{{ 'Filter by severity' | translate }}\"\n dropdown\n #filtersDropdown=\"bs-dropdown\"\n [cdkTrapFocus]=\"filtersDropdown.isOpen\"\n [insideClick]=\"true\"\n >\n <div class=\"input-group fit-w\">\n <div class=\"form-control d-flex a-i-center inner-scroll\" style=\"min-width: 104px; padding-top: 0; padding-bottom: 0;\">\n <ng-container *ngIf=\"chips.length !== severitiesList.length; else allAlarms\">\n <span\n class=\"tag tag--info chip\"\n *ngFor=\"let chip of chips\"\n >\n <button\n class=\"btn btn-xs btn-clean text-10\"\n title=\"{{ 'Remove' | translate }}\"\n type=\"button\"\n (click)=\"deselectChip(chip); $event.stopPropagation()\"\n >\n <i c8yIcon=\"times\"></i>\n </button>\n <i\n class=\"status stroked-icon icon-12\"\n [c8yIcon]=\"chip | AlarmSeverityToIcon\"\n [ngClass]=\"chip | lowercase\"\n ></i>\n {{ SEVERITY_LABELS[chip] | translate }}\n </span>\n </ng-container>\n <ng-template #allAlarms>\n <span class=\"text-truncate\" title=\"{{ 'All severities' | translate }}\">\n {{ 'All severities' | translate }}\n </span>\n </ng-template>\n </div>\n <div class=\"input-group-btn input-group-btn--last\">\n <button\n class=\"btn-default btn btn--caret\"\n title=\"{{ chips | AlarmSeveritiesToTitle }}\"\n data-cy=\"c8y-alarm-filter\"\n dropdownToggle\n (click)=\"resetForm()\"\n >\n <i class=\"caret\"></i>\n </button>\n </div>\n </div>\n <ul\n class=\"dropdown-menu dropdown-menu-action-bar\"\n *dropdownMenu\n >\n <li class=\"p-l-16 p-r-16 p-t-4 p-b-4 d-flex a-i-center sticky-top separator-bottom\">\n <label\n class=\"c8y-checkbox d-flex a-i-center\"\n [title]=\"'All' | translate\"\n >\n <input\n type=\"checkbox\"\n data-cy=\"c8y-alarm-filter--all\"\n [ngModelOptions]=\"{ standalone: true }\"\n (ngModelChange)=\"allChanged($event)\"\n [ngModel]=\"isEachCheckboxSelected$ | async\"\n [indeterminate]=\"isIndeterminate$ | async\"\n (click)=\"markSeveritiesAsTouched()\"\n />\n <span></span>\n <i\n class=\"status stroked-icon m-l-8 icon-20\"\n [c8yIcon]=\"'bell'\"\n ></i>\n <span class=\"m-l-8\">{{ 'All' | translate }}</span>\n </label>\n </li>\n <li\n class=\"p-l-16 p-r-16 p-t-4 p-b-4 d-flex a-i-center\"\n *ngFor=\"let severity of severitiesList\"\n >\n <label\n class=\"c8y-checkbox d-flex a-i-center\"\n [title]=\"SEVERITY_LABELS[severity] | translate\"\n >\n <input\n type=\"checkbox\"\n [attr.data-cy]=\"'c8y-alarm-filter--' + severity\"\n [formControlName]=\"severity\"\n [value]=\"severity\"\n (click)=\"markSeveritiesAsTouched()\"\n />\n <span></span>\n <i\n class=\"status stroked-icon m-l-8 icon-20\"\n [c8yIcon]=\"severity | AlarmSeverityToIcon\"\n [ngClass]=\"severity | lowercase\"\n ></i>\n <span class=\"m-l-8\">{{ SEVERITY_LABELS[severity] | translate }}</span>\n </label>\n <!-- badge -->\n <div\n class=\"badge badge-info m-l-auto\"\n *ngIf=\"alarmCounts[severity] || alarmCounts[severity] === 0\"\n >\n <i\n class=\"icon-spin\"\n [c8yIcon]=\"'circle-o-notch'\"\n *ngIf=\"countLoading\"\n ></i>\n <span\n *ngIf=\"!countLoading\"\n [attr.data-cy]=\"severity + '-badge'\"\n >\n {{ alarmCounts[severity] < 99 ? alarmCounts[severity] : '99+' }}\n </span>\n </div>\n </li>\n <li class=\"p-l-16 p-r-16 p-t-4 p-b-4 d-flex a-i-center separator-top\">\n <label\n class=\"c8y-switch\"\n [attr.aria-label]=\"'Show cleared alarms' | translate\"\n [attr.data-cy]=\"'c8y-alarms-filter--cleared'\"\n >\n <input\n type=\"checkbox\"\n #showClearedCheckbox\n [ngModelOptions]=\"{ standalone: true }\"\n [(ngModel)]=\"showCleared\"\n (click)=\"markSeveritiesAsTouched(); updateAlarmsCount(showClearedCheckbox.checked)\"\n />\n <span></span>\n <span\n class=\"text-truncate\"\n title=\"{{ 'Show cleared alarms' | translate }}\"\n >\n {{ 'Show cleared alarms' | translate }}\n </span>\n </label>\n </li>\n\n <div class=\"p-16 d-flex sticky-bottom separator-top\">\n <button\n [attr.data-cy]=\"'c8y-alarms-filter--apply'\"\n class=\"btn btn-primary btn-sm flex-grow\"\n title=\"{{ 'Apply' | translate }}\"\n type=\"button\"\n (click)=\"applyFilters(false); closeDropdown()\"\n [disabled]=\"shouldDisableApplyButton$ | async\"\n >\n {{ 'Apply' | translate }}\n </button>\n </div>\n </ul>\n </div>\n</form>\n" }] }], ctorParameters: () => [{ type: i1.FormBuilder }, { type: i2.AlarmsViewService }, { type: i3.AlertService }, { type: i4.Router }, { type: i4.ActivatedRoute }], propDecorators: { contextSourceId: [{ type: Input }], onFilterApplied: [{ type: Output }], filtersDropdown: [{ type: ViewChild, args: ['filtersDropdown'] }] } }); //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYWxhcm1zLWZpbHRlci5jb21wb25lbnQuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi9hbGFybXMvYWxhcm1zLWZpbHRlci5jb21wb25lbnQudHMiLCIuLi8uLi8uLi9hbGFybXMvYWxhcm1zLWZpbHRlci5jb21wb25lbnQuaHRtbCJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBRUwsU0FBUyxFQUNULFlBQVksRUFDWixLQUFLLEVBR0wsTUFBTSxFQUNOLFNBQVMsRUFDVixNQUFNLGVBQWUsQ0FBQztBQUN2QixPQUFPLEVBQUUsV0FBVyxFQUFFLE1BQU0sZ0JBQWdCLENBQUM7QUFDN0MsT0FBTyxFQUVMLFFBQVEsRUFFUixlQUFlLEVBRWhCLE1BQU0sYUFBYSxDQUFDO0FBQ3JCLE9BQU8sRUFBRSxZQUFZLEVBQW1CLE1BQU0scUJBQXFCLENBQUM7QUFDcEUsT0FBTyxFQUFFLG1CQUFtQixFQUFFLE1BQU0sd0JBQXdCLENBQUM7QUFDN0QsT0FBTyxFQUFFLGVBQWUsRUFBYyxPQUFPLEVBQUUsYUFBYSxFQUFFLElBQUksRUFBRSxRQUFRLEVBQUUsS0FBSyxFQUFFLE1BQU0sTUFBTSxDQUFDO0FBQ2xHLE9BQU8sRUFBRSxVQUFVLEVBQUUsTUFBTSxFQUFFLFFBQVEsRUFBRSxHQUFHLEVBQUUsU0FBUyxFQUFFLFNBQVMsRUFBRSxNQUFNLGdCQUFnQixDQUFDO0FBQ3pGLE9BQU8sRUFBRSxpQkFBaUIsRUFBRSxNQUFNLHVCQUF1QixDQUFDO0FBQzFELE9BQU8sRUFFTCxvQkFBb0IsRUFDcEIsdUJBQXVCLEVBRXhCLE1BQU0sZ0JBQWdCLENBQUM7QUFDeEIsT0FBTyxFQUFFLGNBQWMsRUFBRSxNQUFNLEVBQUUsTUFBTSxpQkFBaUIsQ0FBQzs7Ozs7Ozs7Ozs7O0FBT3pELE1BQU0sT0FBTyxxQkFBcUI7SUFnQ2hDLFlBQ1UsV0FBd0IsRUFDeEIsaUJBQW9DLEVBQ3BDLFlBQTBCLEVBQzFCLE1BQWMsRUFDZCxjQUE4QjtRQUo5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UCxlQUFlO3NCQURkLFNBQVM7dUJBQUMsaUJBQWlCIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHtcbiAgQWZ0ZXJWaWV3SW5pdCxcbiAgQ29tcG9uZW50LFxuICBFdmVudEVtaXR0ZXIsXG4gIElucHV0LFxuICBPbkRlc3Ryb3ksXG4gIE9uSW5pdCxcbiAgT3V0cHV0LFxuICBWaWV3Q2hpbGRcbn0gZnJvbSAnQGFuZ3VsYXIvY29yZSc7XG5pbXBvcnQgeyBGb3JtQnVpbGRlciB9IGZyb20gJ0Bhbmd1bGFyL2Zvcm1zJztcbmltcG9ydCB7XG4gIEFsYXJtUXVlcnlGaWx0ZXIsXG4gIFNldmVyaXR5LFxuICBTZXZlcml0eUZpbHRlcixcbiAgU0VWRVJJVFlfTEFCRUxTLFxuICBTZXZlcml0eVR5cGVcbn0gZnJvbSAnQGM4eS9jbGllbnQnO1xuaW1wb3J0IHsgQWxlcnRTZXJ2aWNlLCBEYXRlVGltZUNvbnRleHQgfSBmcm9tICdAYzh5L25neC1jb21wb25lbnRzJztcbmltcG9ydCB7IEJzRHJvcGRvd25EaXJlY3RpdmUgfSBmcm9tICduZ3gtYm9vdHN0cmFwL2Ryb3Bkb3duJztcbmltcG9ydCB7IEJlaGF2aW9yU3ViamVjdCwgT2JzZXJ2YWJsZSwgU3ViamVjdCwgY29tYmluZUxhdGVzdCwgZnJvbSwgZm9ya0pvaW4sIEVNUFRZIH0gZnJvbSAncnhqcyc7XG5pbXBvcnQgeyBjYXRjaEVycm9yLCBmaWx0ZXIsIGZpbmFsaXplLCBtYXAsIHN0YXJ0V2l0aCwgdGFrZVVudGlsIH0gZnJvbSAncnhqcy9vcGVyYXRvcnMnO1xuaW1wb3J0IHsgQWxhcm1zVmlld1NlcnZpY2UgfSBmcm9tICcuL2FsYXJtcy12aWV3LnNlcnZpY2UnO1xuaW1wb3J0IHtcbiAgQWxhcm1Db3VudCxcbiAgREVGQVVMVF9BTEFSTV9DT1VOVFMsXG4gIERFRkFVTFRfU0VWRVJJVFlfVkFMVUVTLFxuICBBbGFybUxpc3RGb3JtRmlsdGVyc1xufSBmcm9tICcuL2FsYXJtcy5tb2RlbCc7XG5pbXBvcnQgeyBBY3RpdmF0ZWRSb3V0ZSwgUm91dGVyIH0gZnJvbSAnQGFuZ3VsYXIvcm91dGVyJztcbmltcG9ydCBfIGZyb20gJ2xvZGFzaCc7XG5cbkBDb21wb25lbnQoe1xuICBzZWxlY3RvcjogJ2M4eS1hbGFybXMtZmlsdGVyJyxcbiAgdGVtcGxhdGVVcmw6ICcuL2FsYXJtcy1maWx0ZXIuY29tcG9uZW50Lmh0bWwnXG59KVxuZXhwb3J0IGNsYXNzIEFsYXJtc0ZpbHRlckNvbXBvbmVudCBpbXBsZW1lbnRzIE9uSW5pdCwgQWZ0ZXJWaWV3SW5pdCwgT25EZXN0cm95IHtcbiAgcmVhZG9ubHkgc2V2ZXJpdGllc0xpc3QgPSBPYmplY3Qua2V5cyhTRVZFUklUWV9MQUJFTFMpIGFzIFNldmVyaXR5VHlwZVtdO1xuXG4gIEBJbnB1dCgpXG4gIGNvbnRleHRTb3VyY2VJZDogbnVtYmVyIHwgc3RyaW5nIHwgbnVsbDtcblxuICAvKipcbiAgICogRXZlbnRFbWl0dGVyIHRvIG5vdGlmeSB3aGVuIGZpbHRlcnMgaGF2ZSBiZWVuIGFwcGxpZWQuXG4gICAqIEVtaXRzIGEgYEFsYXJtTGlzdEZvcm1GaWx0ZXJzYCBvYmplY3QgcmVwcmVzZW50aW5nIHRoZSBmaWx0ZXIgY3JpdGVyaWEgYXBwbGllZCBieSB0aGUgdXNlci5cbiAgICovXG4gIEBPdXRwdXQoKVxuICBvbkZpbHRlckFwcGxpZWQgPSBuZXcgRXZlbnRFbWl0dGVyPEFsYXJtTGlzdEZvcm1GaWx0ZXJzPigpO1xuXG4gIEBWaWV3Q2hpbGQoJ2ZpbHRlcnNEcm9wZG93bicpXG4gIGZpbHRlcnNEcm9wZG93bjogQnNEcm9wZG93bkRpcmVjdGl2ZTtcblxuICBmb3JtR3JvdXAgPSB0aGlzLmZvcm1CdWlsZGVyLmdyb3VwKERFRkFVTFRfU0VWRVJJVFlfVkFMVUVTKTtcbiAgY2hpcHM6IFNldmVyaXR5VHlwZVtdID0gW107XG4gIGlzSW5kZXRlcm1pbmF0ZSQ6IE9ic2VydmFibGU8Ym9vbGVhbj47XG4gIGNvdW50TG9hZGluZzogYm9vbGVhbjtcbiAgc2hvd0NsZWFyZWQgPSBmYWxzZTtcbiAgYWxhcm1Db3VudHM6IEFsYXJtQ291bnQgPSBERUZBVUxUX0FMQVJNX0NPVU5UUztcbiAgc2VsZWN0ZWREYXRlczogRGF0ZVRpbWVDb250ZXh0O1xuICBzaG91bGREaXNhYmxlQXBwbHlCdXR0b24kOiBPYnNlcnZhYmxlPGJvb2xlYW4+O1xuICBpc0VhY2hDaGVja2JveFNlbGVjdGVkJDogT2JzZXJ2YWJsZTxib29sZWFuPjtcbiAgcHJvdGVjdGVkIHJlYWRvbmx5IFNFVkVSSVRZX0xBQkVMUyA9IFNFVkVSSVRZX0xBQkVMUztcbiAgcHJpdmF0ZSBpc05vbmVDaGVja2JveFNlbGVjdGVkJCA9IG5ldyBCZWhhdmlvclN1YmplY3Q8Ym9vbGVhbj4oZmFsc2UpO1xuICBwcml2YXRlIHNldmVyaXRpZXNUb3VjaGVkJCA9IG5ldyBCZWhhdmlvclN1YmplY3Q8Ym9vbGVhbj4oZmFsc2UpO1xuICBwcml2YXRlIGN1cnJlbnRGb3JtR3JvdXBWYWx1ZXMgPSB0aGlzLmZvcm1Hcm91cC52YWx1ZTtcbiAgcHJpdmF0ZSBjdXJyZW50U2hvd0NsZWFyZWRWYWx1ZTogYm9vbGVhbjtcbiAgcHJpdmF0ZSBkZXN0cm95JDogU3ViamVjdDx2b2lkPiA9IG5ldyBTdWJqZWN0PHZvaWQ+KCk7XG5cbiAgY29uc3RydWN0b3IoXG4gICAgcHJpdmF0ZSBmb3JtQnVpbGRlcjogRm9ybUJ1aWxkZXIsXG4gICAgcHJpdmF0ZSBhbGFybXNWaWV3U2VydmljZTogQWxhcm1zVmlld1NlcnZpY2UsXG4gICAgcHJpdmF0ZSBhbGVydFNlcnZpY2U6IEFsZXJ0U2VydmljZSxcbiAgICBwcml2YXRlIHJvdXRlcjogUm91dGVyLFxuICAgIHByaXZhdGUgYWN0aXZhdGVkUm91dGU6IEFjdGl2YXRlZFJvdXRlXG4gICkge31cblxuICBuZ09uSW5pdCgpOiB2b2lkIHtcbiAgICB0aGlzLmFjdGl2YXRlZFJvdXRlLnF1ZXJ5UGFyYW1zLnBpcGUodGFrZVVudGlsKHRoaXMuZGVzdHJveSQpKS5zdWJzY3JpYmUocGFyYW1zID0+IHtcbiAgICAgIHRoaXMuc2hvd0NsZWFyZWQgPSBwYXJhbXMuc2hvd0NsZWFyZWQgPT09ICd0cnVlJztcbiAgICAgIHRoaXMuZm9ybUdyb3VwLnNldFZhbHVlKHtcbiAgICAgICAgW1NldmVyaXR5LkNSSVRJQ0FMXTogcGFyYW1zW1NldmVyaXR5LkNSSVRJQ0FMXSA9PT0gJ3RydWUnLFxuICAgICAgICBbU2V2ZXJpdHkuTUFKT1JdOiBwYXJhbXNbU2V2ZXJpdHkuTUFKT1JdID09PSAndHJ1ZScsXG4gICAgICAgIFtTZXZlcml0eS5NSU5PUl06IHBhcmFtc1tTZXZlcml0eS5NSU5PUl0gPT09ICd0cnVlJyxcbiAgICAgICAgW1NldmVyaXR5LldBUk5JTkddOiBwYXJhbXNbU2V2ZXJpdHkuV0FSTklOR10gPT09ICd0cnVlJ1xuICAgICAgfSk7XG4gICAgICBpZiAocGFyYW1zLmxhc3RVcGRhdGVkRnJvbSkge1xuICAgICAgICB0aGlzLnNlbGVjdGVkRGF0ZXMgPSBbbmV3IERhdGUocGFyYW1zLmxhc3RVcGRhdGVkRnJvbSksIG5ldyBEYXRlKHBhcmFtcy5jcmVhdGVkVG8pXTtcbiAgICAgIH1cbiAgICAgIHRoaXMuYXBwbHlGaWx0ZXJzKHRydWUsIGZhbHNlKTtcbiAgICB9KTtcbiAgICB0aGlzLnRyYWNrQ2hlY2tib3hTdGF0ZVdpdGhGb3JtQ2hhbmdlcygpO1xuICAgIHRoaXMuY3VycmVudFNob3dDbGVhcmVkVmFsdWUgPSB0aGlzLnNob3dDbGVhcmVkO1xuICAgIHRoaXMudXBkYXRlQ2hpcHNBbmREZWZhdWx0VmFsdWVzKCk7XG4gIH1cblxuICBuZ0FmdGVyVmlld0luaXQoKTogdm9pZCB7XG4gICAgdGhpcy5maWx0ZXJzRHJvcGRvd24uaXNPcGVuQ2hhbmdlXG4gICAgICAucGlwZSh0YWtlVW50aWwodGhpcy5kZXN0cm95JCksIGZpbHRlcihCb29sZWFuKSlcbiAgICAgIC5zdWJzY3JpYmUoKCkgPT4gdGhpcy51cGRhdGVBbGFybXNDb3VudCgpKTtcbiAgfVxuXG4gIG5nT25EZXN0cm95KCk6IHZvaWQge1xuICAgIHRoaXMuZGVzdHJveSQubmV4dCgpO1xuICAgIHRoaXMuZGVzdHJveSQuY29tcGxldGUoKTtcbiAgfVxuXG4gIGFsbENoYW5nZWQoc2VsZWN0ZWQ6IGJvb2xlYW4pOiB2b2lkIHtcbiAgICB0aGlzLmZvcm1Hcm91cC5wYXRjaFZhbHVlKHtcbiAgICAgIFtTZXZlcml0eS5DUklUSUNBTF06IHNlbGVjdGVkLFxuICAgICAgW1NldmVyaXR5Lk1BSk9SXTogc2VsZWN0ZWQsXG4gICAgICBbU2V2ZXJpdHkuTUlOT1JdOiBzZWxlY3RlZCxcbiAgICAgIFtTZXZlcml0eS5XQVJOSU5HXTogc2VsZWN0ZWRcbiAgICB9IGFzIFNldmVyaXR5RmlsdGVyKTtcbiAgfVxuXG4gIGFwcGx5RmlsdGVycyhlbWl0ID0gdHJ1ZSwgbmF2aWdhdGUgPSB0cnVlKTogdm9pZCB7XG4gICAgdGhpcy51cGRhdGVDaGlwc0FuZERlZmF1bHRWYWx1ZXMoKTtcbiAgICBjb25zdCBjb21iaW5lZEZvcm1FdmVudDogQWxhcm1MaXN0Rm9ybUZpbHRlcnMgPSB7XG4gICAgICBzaG93Q2xlYXJlZDogdGhpcy5zaG93Q2xlYXJlZCxcbiAgICAgIHNldmVyaXR5T3B0aW9uczogdGhpcy5mb3JtR3JvdXAudmFsdWUsXG4gICAgICBzZWxlY3RlZERhdGVzOiB0aGlzLnNlbGVjdGVkRGF0ZXNcbiAgICB9O1xuICAgIGlmIChlbWl0KSB7XG4gICAgICB0aGlzLm9uRmlsdGVyQXBwbGllZC5lbWl0KGNvbWJpbmVkRm9ybUV2ZW50KTtcbiAgICB9XG4gICAgdGhpcy5jdXJyZW50Rm9ybUdyb3VwVmFsdWVzID0gdGhpcy5mb3JtR3JvdXAudmFsdWU7XG4gICAgdGhpcy5jdXJyZW50U2hvd0NsZWFyZWRWYWx1ZSA9IHRoaXMuc2hvd0NsZWFyZWQ7XG5cbiAgICBpZiAobmF2aWdhdGUpIHtcbiAgICAgIHRoaXMucm91dGVyLm5hdmlnYXRlKFtdLCB7XG4gICAgICAgIHF1ZXJ5UGFyYW1zOiB7XG4gICAgICAgICAgc2hvd0NsZWFyZWQ6IGNvbWJpbmVkRm9ybUV2ZW50LnNob3dDbGVhcmVkLFxuICAgICAgICAgIC4uLmNvbWJpbmVkRm9ybUV2ZW50LnNldmVyaXR5T3B0aW9ucyxcbiAgICAgICAgICBsYXN0VXBkYXRlZEZyb206IGNvbWJpbmVkRm9ybUV2ZW50LnNlbGVjdGVkRGF0ZXM/LlswXT8udG9JU09TdHJpbmcoKSxcbiAgICAgICAgICBjcmVhdGVkVG86IGNvbWJpbmVkRm9ybUV2ZW50LnNlbGVjdGVkRGF0ZXM/LlsxXT8udG9JU09TdHJpbmcoKVxuICAgICAgICB9LFxuICAgICAgICBxdWVyeVBhcmFtc0hhbmRsaW5nOiAnbWVyZ2UnXG4gICAgICB9KTtcbiAgICB9XG4gIH1cblxuICBkZXNlbGVjdENoaXAoY2hpcDogU2V2ZXJpdHlUeXBlKTogdm9pZCB7XG4gICAgdGhpcy5mb3JtR3JvdXAucGF0Y2hWYWx1ZSh7XG4gICAgICAuLi50aGlzLmZvcm1Hcm91cC52YWx1ZSxcbiAgICAgIFtjaGlwXTogZmFsc2VcbiAgICB9KTtcbiAgICB0aGlzLmFwcGx5RmlsdGVycyhmYWxzZSk7XG4gICAgdGhpcy5jbG9zZURyb3Bkb3duKCk7XG4gIH1cblxuICBjbG9zZURyb3Bkb3duKCk6IHZvaWQge1xuICAgIGlmICh0aGlzLmZpbHRlcnNEcm9wZG93bi5pc09wZW4pIHtcbiAgICAgIHRoaXMuZmlsdGVyc0Ryb3Bkb3duLmlzT3BlbiA9IGZhbHNlO1xuICAgIH1cbiAgfVxuXG4gIHJlc2V0Rm9ybSgpOiB2b2lkIHtcbiAgICB0aGlzLmZvcm1Hcm91cC5yZXNldCh0aGlzLmN1cnJlbnRGb3JtR3JvdXBWYWx1ZXMpO1xuICAgIHRoaXMuc2V2ZXJpdGllc1RvdWNoZWQkLm5leHQoZmFsc2UpO1xuICAgIHRoaXMuc2hvd0NsZWFyZWQgPSB0aGlzLmN1cnJlbnRTaG93Q2xlYXJlZFZhbHVlO1xuICB9XG5cbiAgbWFya1NldmVyaXRpZXNBc1RvdWNoZWQoKTogdm9pZCB7XG4gICAgdGhpcy5zZXZlcml0aWVzVG91Y2hlZCQubmV4dCh0cnVlKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBBc3luY2hyb25vdXNseSBmZXRjaGVzIGFuZCB1cGRhdGVzIHRoZSBjb3VudCBvZiBhbGFybXMgZm9yIGVhY2ggc2V2ZXJpdHkgbGV2ZWwuXG4gICAqXG4gICAqIEBwYXJhbSBzaG93Q2xlYXJlZCAtIFdoZXRoZXIgdG8gaW5jbHVkZSBjbGVhcmVkIGFsYXJtcyBpbiB0aGUgY291bnQuXG4gICAqIERlZmF1bHRzIHRvIHRoZSBjdXJyZW50IHZhbHVlIG9mIGB0aGlzLmN1cnJlbnRTaG93Q2xlYXJlZFZhbHVlYC5cbiAgICogQHJldHVybnMgQSBQcm9taXNlIHRoYXQgcmVzb2x2ZXMgd2hlbiBhbGwgYWxhcm0gY291bnRzIGhhdmUgYmVlbiBmZXRjaGVkLFxuICAgKiBvciByZWplY3RzIHdpdGggYW4gZXJyb3IgaWYgdGhlIG9wZXJhdGlvbiBmYWlscy5cbiAgICogQHRocm93cyBXaWxsIHRocm93IGFuIGVycm9yIGlmIGFueSBvZiB0aGUgYWxhcm0gY291bnQgZmV0Y2hpbmcgcHJvbWlzZXMgcmVqZWN0LlxuICAgKi9cbiAgYXN5bmMgdXBkYXRlQWxhcm1zQ291bnQoc2hvd0NsZWFyZWQgPSB0aGlzLmN1cnJlbnRTaG93Q2xlYXJlZFZhbHVlKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgdGhpcy5jb3VudExvYWRpbmcgPSB0cnVlO1xuICAgIGNvbnN0IGFsYXJtRmlsdGVyOiBBbGFybVF1ZXJ5RmlsdGVyIHwgbnVsbCA9IHRoaXMuY29udGV4dFNvdXJjZUlkXG4gICAgICA/IHtcbiAgICAgICAgICBzb3VyY2U6IHRoaXMuY29udGV4dFNvdXJjZUlkLFxuICAgICAgICAgIHdpdGhTb3VyY2VBc3NldHM6IHRydWUsXG4gICAgICAgICAgd2l0aFNvdXJjZURldmljZXM6IHRydWVcbiAgICAgICAgfVxuICAgICAgOiBudWxsO1xuICAgIGNvbnN0IG9ic2VydmFibGVzOiBSZWNvcmQ8U2V2ZXJpdHlUeXBlLCBPYnNlcnZhYmxlPG51bWJlcj4+ID0gdGhpcy5zZXZlcml0aWVzTGlzdC5yZWR1Y2UoXG4gICAgICAoYWNjLCBzZXZlcml0eSkgPT4ge1xuICAgICAgICBhY2Nbc2V2ZXJpdHldID0gZnJvbShcbiAgICAgICAgICB0aGlzLmFsYXJtc1ZpZXdTZXJ2aWNlLmdldEFsYXJtc0NvdW50QnlTZXZlcml0eShzZXZlcml0eSwgc2hvd0NsZWFyZWQsIGFsYXJtRmlsdGVyKVxuICAgICAgICApO1xuICAgICAgICByZXR1cm4gYWNjO1xuICAgICAgfSxcbiAgICAgIHtcbiAgICAgICAgQ1JJVElDQUw6IG51bGwsXG4gICAgICAgIE1BSk9SOiBudWxsLFxuICAgICAgICBNSU5PUjogbnVsbCxcbiAgICAgICAgV0FSTklORzogbnVsbFxuICAgICAgfVxuICAgICk7XG4gICAgZm9ya0pvaW4ob2JzZXJ2YWJsZXMpXG4gICAgICAucGlwZShcbiAgICAgICAgY2F0Y2hFcnJvcihlcnIgPT4ge1xuICAgICAgICAgIHRoaXMuYWxhcm1Db3VudHMgPSB7fSBhcyBBbGFybUNvdW50O1xuICAgICAgICAgIHRoaXMuYWxlcnRTZXJ2aWNlLmFkZFNlcnZlckZhaWx1cmUoZXJyKTtcbiAgICAgICAgICByZXR1cm4gRU1QVFk7XG4gICAgICAgIH0pLFxuICAgICAgICBmaW5hbGl6ZSgoKSA9PiAodGhpcy5jb3VudExvYWRpbmcgPSBmYWxzZSkpXG4gICAgICApXG4gICAgICAuc3Vic2NyaWJlKChhbGFybUNvdW50czogQWxhcm1Db3VudCkgPT4gKHRoaXMuYWxhcm1Db3VudHMgPSBhbGFybUNvdW50cykpO1xuICB9XG5cbiAgcHJpdmF0ZSBjcmVhdGVGb3JtVmFsdWVXaXRoQ2hhbmdlc1N0cmVhbSgpOiBPYnNlcnZhYmxlPFNldmVyaXR5RmlsdGVyPiB7XG4gICAgcmV0dXJuIHRoaXMuZm9ybUdyb3VwLnZhbHVlQ2hhbmdlcy5waXBlKHN0YXJ0V2l0aCh0aGlzLmZvcm1Hcm91cC52YWx1ZSkpO1xuICB9XG5cbiAgcHJpdmF0ZSB0cmFja0NoZWNrYm94U3RhdGVXaXRoRm9ybUNoYW5nZXMoKTogdm9pZCB7XG4gICAgY29uc3QgZm9ybVZhbHVlJCA9IHRoaXMuY3JlYXRlRm9ybVZhbHVlV2l0aENoYW5nZXNTdHJlYW0oKTtcbiAgICB0aGlzLmlzRWFjaENoZWNrYm94U2VsZWN0ZWQkID0gdGhpcy5jcmVhdGVBbGxTZWxlY3RlZFN0cmVhbShmb3JtVmFsdWUkKTtcbiAgICB0aGlzLmlzSW5kZXRlcm1pbmF0ZSQgPSB0aGlzLmNyZWF0ZUluZGV0ZXJtaW5hdGVTdHJlYW0oZm9ybVZhbHVlJCk7XG4gICAgdGhpcy50cmFja0FsbENoZWNrYm94ZXNEaXNhYmxlZChmb3JtVmFsdWUkKTtcbiAgICB0aGlzLnNob3VsZERpc2FibGVBcHBseUJ1dHRvbiQgPSB0aGlzLmNyZWF0ZURpc2FibGVBcHBseUJ1dHRvblN0cmVhbSgpO1xuICB9XG5cbiAgcHJpdmF0ZSBjcmVhdGVBbGxTZWxlY3RlZFN0cmVhbShmb3JtVmFsdWUkOiBPYnNlcnZhYmxlPFNldmVyaXR5RmlsdGVyPik6IE9ic2VydmFibGU8Ym9vbGVhbj4ge1xuICAgIHJldHVybiBmb3JtVmFsdWUkLnBpcGUobWFwKHNldmVyaXRpZXMgPT4gT2JqZWN0LnZhbHVlcyhzZXZlcml0aWVzKS5ldmVyeShCb29sZWFuKSkpO1xuICB9XG5cbiAgcHJpdmF0ZSBjcmVhdGVJbmRldGVybWluYXRlU3RyZWFtKGZvcm1WYWx1ZSQ6IE9ic2VydmFibGU8U2V2ZXJpdHlGaWx0ZXI+KTogT2JzZXJ2YWJsZTxib29sZWFuPiB7XG4gICAgcmV0dXJuIGZvcm1WYWx1ZSQucGlwZShcbiAgICAgIG1hcChcbiAgICAgICAgc2V2ZXJpdGllcyA9PlxuICAgICAgICAgIE9iamVjdC52YWx1ZXMoc2V2ZXJpdGllcykuc29tZShCb29sZWFuKSAmJiAhT2JqZWN0LnZhbHVlcyhzZXZlcml0aWVzKS5ldmVyeShCb29sZWFuKVxuICAgICAgKVxuICAgICk7XG4gIH1cblxuICBwcml2YXRlIHRyYWNrQWxsQ2hlY2tib3hlc0Rpc2FibGVkKGZvcm1WYWx1ZSQ6IE9ic2VydmFibGU8U2V2ZXJpdHlGaWx0ZXI+KTogdm9pZCB7XG4gICAgZm9ybVZhbHVlJC5waXBlKHRha2VVbnRpbCh0aGlzLmRlc3Ryb3kkKSkuc3Vic2NyaWJlKHNldmVyaXRpZXMgPT4ge1xuICAgICAgY29uc3QgYXJlQWxsRGlzYWJsZWQgPSBPYmplY3QudmFsdWVzKHNldmVyaXRpZXMpLmV2ZXJ5KHZhbHVlID0+ICF2YWx1ZSk7XG4gICAgICB0aGlzLmlzTm9uZUNoZWNrYm94U2VsZWN0ZWQkLm5leHQoYXJlQWxsRGlzYWJsZWQpO1xuICAgIH0pO1xuICB9XG5cbiAgcHJpdmF0ZSBjcmVhdGVEaXNhYmxlQXBwbHlCdXR0b25TdHJlYW0oKTogT2JzZXJ2YWJsZTxib29sZWFuPiB7XG4gICAgcmV0dXJuIGNvbWJpbmVMYXRlc3QoW3RoaXMuaXNOb25lQ2hlY2tib3hTZWxlY3RlZCQsIHRoaXMuc2V2ZXJpdGllc1RvdWNoZWQkXSkucGlwZShcbiAgICAgIG1hcChcbiAgICAgICAgKFthbGxDaGVja2JveGVzQXJlRGlzYWJsZWQsIHNldmVyaXRpZXNUb3VjaGVkXSkgPT5cbiAgICAgICAgICBhbGxDaGVja2JveGVzQXJlRGlzYWJsZWQgfHwgIXNldmVyaXRpZXNUb3VjaGVkXG4gICAgICApXG4gICAgKTtcbiAgfVxuXG4gIHByaXZhdGUgdXBkYXRlQ2hpcHNBbmREZWZhdWx0VmFsdWVzKCk6IHZvaWQge1xuICAgIGNvbnN0IHNldmVyaXR5RmlsdGVyID0gdGhpcy5mb3JtR3JvdXA7XG4gICAgY29uc3Qgc2V2ZWVyaXR5VmFsdWVzID0gc2V2ZXJpdHlGaWx0ZXIudmFsdWU7XG5cbiAgICB0aGlzLmNoaXBzID0gT2JqZWN0LmtleXMoc2V2ZWVyaXR5VmFsdWVzKS5maWx0ZXIoa2V5ID0+IHNldmVlcml0eVZhbHVlc1trZXldKSBhcyBTZXZlcml0eVR5cGVbXTtcbiAgICBjb25zdCBhbGxDaGlwc1JlbW92ZWQgPSB0aGlzLmNoaXBzLmxlbmd0aCA9PT0gMDtcbiAgICBpZiAoYWxsQ2hpcHNSZW1vdmVkKSB7XG4gICAgICBjb25zdCBkZWZhdWx0VmFsdWVzID0gREVGQVVMVF9TRVZFUklUWV9WQUxVRVM7XG4gICAgICBzZXZlcml0eUZpbHRlci5zZXRWYWx1ZShkZWZhdWx0VmFsdWVzKTtcbiAgICAgIHRoaXMuY2hpcHMgPSBPYmplY3Qua2V5cyhkZWZhdWx0VmFsdWVzKSBhcyBTZXZlcml0eVR5cGVbXTtcbiAgICB9XG4gIH1cbn1cbiIsIjxmb3JtXG4gIGNsYXNzPVwiZC1mbGV4IGEtaS1jZW50ZXJcIlxuICBbZm9ybUdyb3VwXT1cImZvcm1Hcm91cFwiXG4+XG4gIDxkaXZcbiAgICBjbGFzcz1cImRyb3Bkb3duXCJcbiAgICB0aXRsZT1cInt7ICdGaWx0ZXIgYnkgc2V2ZXJpdHknIHwgdHJhbnNsYXRlIH19XCJcbiAgICBkcm9wZG93blxuICAgICNmaWx0ZXJzRHJvcGRvd249XCJicy1kcm9wZG93blwiXG4gICAgW2Nka1RyYXBGb2N1c109XCJmaWx0ZXJzRHJvcGRvd24uaXNPcGVuXCJcbiAgICBbaW5zaWRlQ2xpY2tdPVwidHJ1ZVwiXG4gID5cbiAgICA8ZGl2IGNsYXNzPVwiaW5wdXQtZ3JvdXAgZml0LXdcIj5cbiAgICAgIDxkaXYgY2xhc3M9XCJmb3JtLWNvbnRyb2wgZC1mbGV4IGEtaS1jZW50ZXIgaW5uZXItc2Nyb2xsXCIgc3R5bGU9XCJtaW4td2lkdGg6IDEwNHB4OyBwYWRkaW5nLXRvcDogMDsgcGFkZGluZy1ib3R0b206IDA7XCI+XG4gICAgICAgIDxuZy1jb250YWluZXIgKm5nSWY9XCJjaGlwcy5sZW5ndGggIT09IHNldmVyaXRpZXNMaXN0Lmxlbmd0aDsgZWxzZSBhbGxBbGFybXNcIj5cbiAgICAgICAgICA8c3BhblxuICAgICAgICAgICAgY2xhc3M9XCJ0YWcgdGFnLS1pbmZvIGNoaXBcIlxuICAgICAgICAgICAgKm5nRm9yPVwibGV0IGNoaXAgb2YgY2hpcHNcIlxuICAgICAgICAgID5cbiAgICAgICAgICAgIDxidXR0b25cbiAgICAgICAgICAgICAgY2xhc3M9XCJidG4gYnRuLXhzIGJ0bi1jbGVhbiB0ZXh0LTEwXCJcbiAgICAgICAgICAgICAgdGl0bGU9XCJ7eyAnUmVtb3ZlJyB8IHRyYW5zbGF0ZSB9fVwiXG4gICAgICAgICAgICAgIHR5cGU9XCJidXR0b25cIlxuICAgICAgICAgICAgICAoY2xpY2spPVwiZGVzZWxlY3RDaGlwKGNoaXApOyAkZXZlbnQuc3RvcFByb3BhZ2F0aW9uKClcIlxuICAgICAgICAgICAgPlxuICAgICAgICAgICAgICA8aSBjOHlJY29uPVwidGltZXNcIj48L2k+XG4gICAgICAgICAgICA8L2J1dHRvbj5cbiAgICAgICAgICAgIDxpXG4gICAgICAgICAgICAgIGNsYXNzPVwic3RhdHVzIHN0cm9rZWQtaWNvbiBpY29uLTEyXCJcbiAgICAgICAgICAgICAgW2M4eUljb25dPVwiY2hpcCB8IEFsYXJtU2V2ZXJpdHlUb0ljb25cIlxuICAgICAgICAgICAgICBbbmdDbGFzc109XCJjaGlwIHwgbG93ZXJjYXNlXCJcbiAgICAgICAgICAgID48L2k+XG4gICAgICAgICAgICB7eyBTRVZFUklUWV9MQUJFTFNbY2hpcF0gfCB0cmFuc2xhdGUgfX1cbiAgICAgICAgICA8L3NwYW4+XG4gICAgICAgIDwvbmctY29udGFpbmVyPlxuICAgICAgICA8bmctdGVtcGxhdGUgI2FsbEFsYXJtcz5cbiAgICAgICAgICA8c3BhbiBjbGFzcz1cInRleHQtdHJ1bmNhdGVcIiB0aXRsZT1cInt7ICdBbGwgc2V2ZXJpdGllcycgfCB0cmFuc2xhdGUgfX1cIj5cbiAgICAgICAgICAgIHt7ICdBbGwgc2V2ZXJpdGllcycgfCB0cmFuc2xhdGUgfX1cbiAgICAgICAgICA8L3NwYW4+XG4gICAgICAgIDwvbmctdGVtcGxhdGU+XG4gICAgICA8L2Rpdj5cbiAgICAgIDxkaXYgY2xhc3M9XCJpbnB1dC1ncm91cC1idG4gaW5wdXQtZ3JvdXAtYnRuLS1sYXN0XCI+XG4gICAgICAgIDxidXR0b25cbiAgICAgICAgICBjbGFzcz1cImJ0bi1kZWZhdWx0IGJ0biBidG4tLWNhcmV0XCJcbiAgICAgICAgICB0aXRsZT1cInt7IGNoaXBzIHwgQWxhcm1TZXZlcml0aWVzVG9UaXRsZSB9fVwiXG4gICAgICAgICAgZGF0YS1jeT1cImM4eS1hbGFybS1maWx0ZXJcIlxuICAgICAgICAgIGRyb3Bkb3duVG9nZ2xlXG4gICAgICAgICAgKGNsaWNrKT1cInJlc2V0Rm9ybSgpXCJcbiAgICAgICAgPlxuICAgICAgICAgIDxpIGNsYXNzPVwiY2FyZXRcIj48L2k+XG4gICAgICAgIDwvYnV0dG9uPlxuICAgICAgPC9kaXY+XG4gICAgPC9kaXY+XG4gICAgPHVsXG4gICAgICBjbGFzcz1cImRyb3Bkb3duLW1lbnUgZHJvcGRvd24tbWVudS1hY3Rpb24tYmFyXCJcbiAgICAgICpkcm9wZG93bk1lbnVcbiAgICA+XG4gICAgICA8bGkgY2xhc3M9XCJwLWwtMTYgcC1yLTE2IHAtdC00IHAtYi00IGQtZmxleCBhLWktY2VudGVyIHN0aWNreS10b3Agc2VwYXJhdG9yLWJvdHRvbVwiPlxuICAgICAgICA8bGFiZWxcbiAgICAgICAgICBjbGFzcz1cImM4eS1jaGVja2JveCBkLWZsZXggYS1pLWNlbnRlclwiXG4gICAgICAgICAgW3RpdGxlXT1cIidBbGwnIHwgdHJhbnNsYXRlXCJcbiAgICAgICAgPlxuICAgICAgICAgIDxpbnB1dFxuICAgICAgICAgICAgdHlwZT1cImNoZWNrYm94XCJcbiAgICAgICAgICAgIGRhdGEtY3k9XCJjOHktYWxhcm0tZmlsdGVyLS1hbGxcIlxuICAgICAgICAgICAgW25nTW9kZWxPcHRpb25zXT1cInsgc3RhbmRhbG9uZTogdHJ1ZSB9XCJcbiAgICAgICAgICAgIChuZ01vZGVsQ2hhbmdlKT1cImFsbENoYW5nZWQoJGV2ZW50KVwiXG4gICAgICAgICAgICBbbmdNb2RlbF09XCJpc0VhY2hDaGVja2JveFNlbGVjdGVkJCB8IGFzeW5jXCJcbiAgICAgICAgICAgIFtpbmRldGVybWluYXRlXT1cImlzSW5kZXRlcm1pbmF0ZSQgfCBhc3luY1wiXG4gICAgICAgICAgICAoY2xpY2spPVwibWFya1NldmVyaXRpZXNBc1RvdWNoZWQoKVwiXG4gICAgICAgICAgLz5cbiAgICAgICAgICA8c3Bhbj48L3NwYW4+XG4gICAgICAgICAgPGlcbiAgICAgICAgICAgIGNsYXNzPVwic3RhdHVzIHN0cm9rZWQtaWNvbiBtLWwtOCBpY29uLTIwXCJcbiAgICAgICAgICAgIFtjOHlJY29uXT1cIidiZWxsJ1wiXG4gICAgICAgICAgPjwvaT5cbiAgICAgICAgICA8c3BhbiBjbGFzcz1cIm0tbC04XCI+e3sgJ0FsbCcgfCB0cmFuc2xhdGUgfX08L3NwYW4+XG4gICAgICAgIDwvbGFiZWw+XG4gICAgICA8L2xpPlxuICAgICAgPGxpXG4gICAgICAgIGNsYXNzPVwicC1sLTE2IHAtci0xNiBwLXQtNCBwLWItNCBkLWZsZXggYS1pLWNlbnRlclwiXG4gICAgICAgICpuZ0Zvcj1cImxldCBzZXZlcml0eSBvZiBzZXZlcml0aWVzTGlzdFwiXG4gICAgICA+XG4gICAgICAgIDxsYWJlbFxuICAgICAgICAgIGNsYXNzPVwiYzh5LWNoZWNrYm94IGQtZmxleCBhLWktY2VudGVyXCJcbiAgICAgICAgICBbdGl0bGVdPVwiU0VWRVJJVFlfTEFCRUxTW3NldmVyaXR5XSB8IHRyYW5zbGF0ZVwiXG4gICAgICAgID5cbiAgICAgICAgICA8aW5wdXRcbiAgICAgICAgICAgIHR5cGU9XCJjaGVja2JveFwiXG4gICAgICAgICAgICBbYXR0ci5kYXRhLWN5XT1cIidjOHktYWxhcm0tZmlsdGVyLS0nICsgc2V2ZXJpdHlcIlxuICAgICAgICAgICAgW2Zvcm1Db250cm9sTmFtZV09XCJzZXZlcml0eVwiXG4gICAgICAgICAgICBbdmFsdWVdPVwic2V2ZXJpdHlcIlxuICAgICAgICAgICAgKGNsaWNrKT1cIm1hcmtTZXZlcml0aWVzQXNUb3VjaGVkKClcIlxuICAgICAgICAgIC8+XG4gICAgICAgICAgPHNwYW4+PC9