UNPKG

@c8y/ngx-components

Version:

Angular modules for Cumulocity IoT applications

191 lines 47.8 kB
import { Component, EventEmitter, forwardRef, Input, Output, ViewChild } from '@angular/core'; import { FormBuilder, NG_VALUE_ACCESSOR } from '@angular/forms'; import { ActivatedRoute, Router } from '@angular/router'; import { Severity } from '@c8y/client'; import { gettext } from '@c8y/ngx-components'; import { Subject, take, takeUntil } from 'rxjs'; import { INTERVAL_TITLES_EXTENDED, INTERVALS_EXTENDED } from './alarms.model'; import { BsDropdownDirective } from 'ngx-bootstrap/dropdown'; import { AlarmsViewService } from './alarms-view.service'; import * as i0 from "@angular/core"; import * as i1 from "@angular/forms"; import * as i2 from "@angular/router"; import * as i3 from "./alarms-view.service"; import * as i4 from "ngx-bootstrap/dropdown"; import * as i5 from "@c8y/ngx-components"; import * as i6 from "@angular/common"; import * as i7 from "ngx-bootstrap/tooltip"; import * as i8 from "@ngx-translate/core"; import * as i9 from "@c8y/ngx-components/interval-picker"; export class AlarmsDateFilterComponent { constructor(formBuilder, router, activatedRoute, alarmsViewService) { this.formBuilder = formBuilder; this.router = router; this.activatedRoute = activatedRoute; this.alarmsViewService = alarmsViewService; this.INTERVALS = INTERVALS_EXTENDED; this.INTERVAL_TITLES = INTERVAL_TITLES_EXTENDED; this.DATE_FORMAT = 'short'; this.DEFAULT_INTERVAL = 'none'; this.updateQueryParams = true; this.noFilterLabel = gettext('No date filter'); this.destroy$ = new Subject(); this.dateFilterChange = new EventEmitter(); // eslint-disable-next-line @typescript-eslint/no-empty-function this.onTouched = () => { }; } ngOnInit() { const context = this.getDefaultContext(); this.form = this.createForm(context); this.date = [ this.form.value.currentDateContextFromDate, this.form.value.currentDateContextToDate ]; this.activatedRoute.queryParams.pipe(take(1), takeUntil(this.destroy$)).subscribe(params => { this.showCleared = params.showCleared === 'true'; this.severityOptions = { [Severity.CRITICAL]: params.critical === 'true', [Severity.MAJOR]: params.major === 'true', [Severity.MINOR]: params.minor === 'true', [Severity.WARNING]: params.warning === 'true' }; if (params.typeFilters) { this.typeFilters = params.typeFilters; } if (!params.interval) { return; } if (params.interval !== 'custom') { this.updateDateTime(params.interval); } else { this.form.patchValue({ currentDateContextInterval: params.interval, temporaryUserSelectedFromDate: params.lastUpdatedFrom, temporaryUserSelectedToDate: params.createdTo }); this.date = [params.lastUpdatedFrom, params.createdTo]; } }); this.subscribeToIntervalChange(); } ngOnDestroy() { this.destroy$.next(); this.destroy$.complete(); } applyDateFilter() { const combinedFormEvent = { showCleared: this.showCleared, severityOptions: this.severityOptions, typeFilters: this.typeFilters, interval: this.form.value.currentDateContextInterval, selectedDates: [ new Date(this.form.value.temporaryUserSelectedFromDate), new Date(this.form.value.temporaryUserSelectedToDate) ] }; // needed for custom interval this.date = [ this.form.value.temporaryUserSelectedFromDate, this.form.value.temporaryUserSelectedToDate ]; this.router.navigate([], { relativeTo: this.activatedRoute, queryParams: { interval: this.form.value.currentDateContextInterval, lastUpdatedFrom: combinedFormEvent.selectedDates[0].toISOString(), createdTo: combinedFormEvent.selectedDates[1].toISOString() }, queryParamsHandling: 'merge' }); this.dateFilterChange.emit(combinedFormEvent); } writeValue(value) { if (value) { this.form.patchValue({ currentDateContextFromDate: typeof value[0] === 'string' ? value[0] : value[0].toISOString(), currentDateContextToDate: typeof value[1] === 'string' ? value[1] : value[1].toISOString() }); } } registerOnChange(fn) { this.onChange = fn; } registerOnTouched(onTouched) { this.onTouched = onTouched; } updateDateTime(interval) { const date = this.alarmsViewService.getDateTimeContextByInterval(interval); if (this.dropdown) { this.dropdown.isOpen = false; } this.date = date.map(d => d.toISOString()); this.form.patchValue({ temporaryUserSelectedFromDate: date[0].toISOString(), temporaryUserSelectedToDate: date[1].toISOString(), currentDateContextInterval: interval }, { emitEvent: false }); this.applyDateFilter(); } getDefaultContext() { return { date: this.alarmsViewService.getDateTimeContextByInterval(this.DEFAULT_INTERVAL), interval: this.DEFAULT_INTERVAL }; } subscribeToIntervalChange() { this.form.controls.currentDateContextInterval.valueChanges .pipe(takeUntil(this.destroy$)) .subscribe(interval => { if (interval === 'custom') { this.form.patchValue({ temporaryUserSelectedFromDate: this.form.controls.temporaryUserSelectedFromDate.value === new Date(0).toISOString() ? this.form.controls.currentDateContextToDate.value : this.form.controls.temporaryUserSelectedFromDate.value, currentDateContextInterval: interval }, { emitEvent: false }); return; } this.updateDateTime(interval); }); } createForm(context) { return this.formBuilder.group({ temporaryUserSelectedFromDate: context.date[0].toISOString(), temporaryUserSelectedToDate: context.date[1].toISOString(), currentDateContextFromDate: context.date[0].toISOString(), currentDateContextToDate: context.date[1].toISOString(), currentDateContextInterval: context.interval || 'custom' }); } static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: AlarmsDateFilterComponent, deps: [{ token: i1.FormBuilder }, { token: i2.Router }, { token: i2.ActivatedRoute }, { token: i3.AlarmsViewService }], target: i0.ɵɵFactoryTarget.Component }); } static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.13", type: AlarmsDateFilterComponent, selector: "c8y-alarms-date-filter", inputs: { DEFAULT_INTERVAL: "DEFAULT_INTERVAL", updateQueryParams: "updateQueryParams", date: "date" }, outputs: { dateFilterChange: "dateFilterChange" }, providers: [ { provide: NG_VALUE_ACCESSOR, useExisting: forwardRef(() => AlarmsDateFilterComponent), multi: true } ], viewQueries: [{ propertyName: "dropdown", first: true, predicate: BsDropdownDirective, descendants: true }], ngImport: i0, template: "<form\n class=\"d-flex gap-16 p-l-xs-16 p-r-xs-16 m-t-xs-8 m-b-xs-8\"\n [formGroup]=\"form\"\n>\n <div\n class=\"dropdown flex-grow\"\n c8yDropdownDirection\n #dropDirection=\"bs-dropdown\"\n dropdown\n [insideClick]=\"true\"\n >\n <button\n class=\"dropdown-toggle form-control l-h-tight d-flex a-i-center\"\n attr.aria-label=\"{{\n (form.value.currentDateContextInterval === 'none'\n ? noFilterLabel\n : (date[0] | c8yDate: DATE_FORMAT) + ' \u2014 ' + (date[1] | c8yDate: DATE_FORMAT)\n ) | translate\n }}\"\n tooltip=\"{{\n (form.value.currentDateContextInterval === 'none'\n ? noFilterLabel\n : (date[0] | c8yDate: DATE_FORMAT) + ' \u2014 ' + (date[1] | c8yDate: DATE_FORMAT)\n ) | translate\n }}\"\n placement=\"top\"\n container=\"body\"\n data-cy=\"alarms-date-filter--date-picker-dropdown-button\"\n [adaptivePosition]=\"false\"\n [delay]=\"500\"\n dropdownToggle\n >\n <i\n class=\"m-r-4\"\n c8yIcon=\"schedule1\"\n ></i>\n <div class=\"d-col text-left fit-w\">\n <span\n class=\"text-12\"\n data-cy=\"widget-time-context--selected-interval\"\n >\n {{ INTERVAL_TITLES[form.controls.currentDateContextInterval.value] | translate }}\n </span>\n <span\n class=\"text-10 text-muted text-truncate\"\n data-cy=\"alarms-date-filter--selected-time-range\"\n *ngIf=\"form.controls.currentDateContextInterval.value !== 'none'\"\n >\n {{ date[0] | c8yDate: DATE_FORMAT }} \u2014 {{ date[1] | c8yDate: DATE_FORMAT }}\n </span>\n </div>\n <span class=\"caret m-r-16 m-l-4\"></span>\n </button>\n\n <ul\n class=\"dropdown-menu dropdown-menu--date-range\"\n *dropdownMenu\n >\n <c8y-interval-picker\n class=\"d-contents\"\n formControlName=\"currentDateContextInterval\"\n [INTERVALS]=\"INTERVALS\"\n ></c8y-interval-picker>\n\n <ng-container *ngIf=\"form.controls.currentDateContextInterval.value === 'custom'\">\n <div class=\"p-l-16 p-r-16\">\n <c8y-form-group\n class=\"m-b-8\"\n [ngClass]=\"form.controls.temporaryUserSelectedFromDate.errors ? 'has-error' : ''\"\n >\n <label\n [title]=\"'From`date`' | translate\"\n for=\"temporaryUserSelectedFromDate\"\n translate\n >\n From`date`\n </label>\n <c8y-date-time-picker\n id=\"temporaryUserSelectedFromDate\"\n [maxDate]=\"form.value.temporaryUserSelectedToDate\"\n [placeholder]=\"'From`date`' | translate\"\n [formControl]=\"form.controls.temporaryUserSelectedFromDate\"\n [ngClass]=\"form.controls.temporaryUserSelectedFromDate.errors ? 'has-error' : ''\"\n ></c8y-date-time-picker>\n <c8y-messages [show]=\"form.controls.temporaryUserSelectedFromDate.errors\">\n <c8y-message\n name=\"dateAfterRangeMax\"\n [text]=\"'This date is after the latest allowed date.' | translate\"\n ></c8y-message>\n <c8y-message\n name=\"invalidDateTime\"\n [text]=\"'This date is invalid.' | translate\"\n ></c8y-message>\n </c8y-messages>\n </c8y-form-group>\n\n <c8y-form-group\n class=\"m-b-8\"\n [ngClass]=\"form.controls.temporaryUserSelectedToDate.errors ? 'has-error' : ''\"\n >\n <label\n [title]=\"'To`date`' | translate\"\n for=\"temporaryUserSelectedToDate\"\n translate\n >\n To`date`\n </label>\n <c8y-date-time-picker\n id=\"temporaryUserSelectedToDate\"\n [minDate]=\"form.value.temporaryUserSelectedFromDate\"\n [placeholder]=\"'To`date`' | translate\"\n [formControl]=\"form.controls.temporaryUserSelectedToDate\"\n [ngClass]=\"form.controls.temporaryUserSelectedToDate.errors ? 'has-error' : ''\"\n ></c8y-date-time-picker>\n <c8y-messages [show]=\"form.controls.temporaryUserSelectedToDate.errors\">\n <c8y-message\n name=\"dateBeforeRangeMin\"\n [text]=\"'This date is before the earliest allowed date.' | translate\"\n ></c8y-message>\n <c8y-message\n name=\"invalidDateTime\"\n [text]=\"'This date is invalid.' | translate\"\n ></c8y-message>\n </c8y-messages>\n </c8y-form-group>\n </div>\n\n <div class=\"p-16 d-flex gap-8 separator-top\">\n <button\n class=\"btn btn-primary btn-sm flex-grow\"\n title=\"{{ 'Apply' | translate }}\"\n type=\"button\"\n (click)=\"applyDateFilter(); dropdown.isOpen = false\"\n [disabled]=\"(form.pristine && form.untouched) || form.invalid\"\n translate\n >\n Apply\n </button>\n </div>\n </ng-container>\n </ul>\n </div>\n</form>\n", dependencies: [{ kind: "directive", type: i4.BsDropdownMenuDirective, selector: "[bsDropdownMenu],[dropdownMenu]", exportAs: ["bs-dropdown-menu"] }, { kind: "directive", type: i4.BsDropdownToggleDirective, selector: "[bsDropdownToggle],[dropdownToggle]", exportAs: ["bs-dropdown-toggle"] }, { kind: "directive", type: i4.BsDropdownDirective, selector: "[bsDropdown], [dropdown]", inputs: ["placement", "triggers", "container", "dropup", "autoClose", "isAnimated", "insideClick", "isDisabled", "isOpen"], outputs: ["isOpenChange", "onShown", "onHidden"], exportAs: ["bs-dropdown"] }, { kind: "directive", type: i5.IconDirective, selector: "[c8yIcon]", inputs: ["c8yIcon"] }, { kind: "directive", type: i5.C8yTranslateDirective, selector: "[translate],[ngx-translate]" }, { kind: "directive", type: i6.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i6.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i5.DropdownDirectionDirective, selector: "[dropdown][c8yBsDropdownDirection],[dropdown][c8yDropdownDirection]" }, { kind: "directive", type: i1.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "component", type: i5.FormGroupComponent, selector: "c8y-form-group", inputs: ["hasError", "hasWarning", "hasSuccess", "novalidation", "status"] }, { kind: "directive", type: i5.MessageDirective, selector: "c8y-message", inputs: ["name", "text"] }, { kind: "component", type: i5.MessagesComponent, selector: "c8y-messages", inputs: ["show", "defaults", "helpMessage"] }, { kind: "directive", type: i1.FormControlDirective, selector: "[formControl]", inputs: ["formControl", "disabled", "ngModel"], outputs: ["ngModelChange"], exportAs: ["ngForm"] }, { 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: "component", type: i5.DateTimePickerComponent, selector: "c8y-date-time-picker", inputs: ["minDate", "maxDate", "placeholder", "dateInputFormat", "adaptivePosition", "size", "dateType", "config"], outputs: ["onDateSelected"] }, { kind: "directive", type: i7.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: i8.TranslateDirective, selector: "[translate],[ngx-translate]", inputs: ["translate", "translateParams"] }, { kind: "component", type: i9.IntervalPickerComponent, selector: "c8y-interval-picker", inputs: ["INTERVALS"] }, { kind: "pipe", type: i5.DatePipe, name: "c8yDate" }, { kind: "pipe", type: i8.TranslatePipe, name: "translate" }] }); } } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: AlarmsDateFilterComponent, decorators: [{ type: Component, args: [{ selector: 'c8y-alarms-date-filter', providers: [ { provide: NG_VALUE_ACCESSOR, useExisting: forwardRef(() => AlarmsDateFilterComponent), multi: true } ], template: "<form\n class=\"d-flex gap-16 p-l-xs-16 p-r-xs-16 m-t-xs-8 m-b-xs-8\"\n [formGroup]=\"form\"\n>\n <div\n class=\"dropdown flex-grow\"\n c8yDropdownDirection\n #dropDirection=\"bs-dropdown\"\n dropdown\n [insideClick]=\"true\"\n >\n <button\n class=\"dropdown-toggle form-control l-h-tight d-flex a-i-center\"\n attr.aria-label=\"{{\n (form.value.currentDateContextInterval === 'none'\n ? noFilterLabel\n : (date[0] | c8yDate: DATE_FORMAT) + ' \u2014 ' + (date[1] | c8yDate: DATE_FORMAT)\n ) | translate\n }}\"\n tooltip=\"{{\n (form.value.currentDateContextInterval === 'none'\n ? noFilterLabel\n : (date[0] | c8yDate: DATE_FORMAT) + ' \u2014 ' + (date[1] | c8yDate: DATE_FORMAT)\n ) | translate\n }}\"\n placement=\"top\"\n container=\"body\"\n data-cy=\"alarms-date-filter--date-picker-dropdown-button\"\n [adaptivePosition]=\"false\"\n [delay]=\"500\"\n dropdownToggle\n >\n <i\n class=\"m-r-4\"\n c8yIcon=\"schedule1\"\n ></i>\n <div class=\"d-col text-left fit-w\">\n <span\n class=\"text-12\"\n data-cy=\"widget-time-context--selected-interval\"\n >\n {{ INTERVAL_TITLES[form.controls.currentDateContextInterval.value] | translate }}\n </span>\n <span\n class=\"text-10 text-muted text-truncate\"\n data-cy=\"alarms-date-filter--selected-time-range\"\n *ngIf=\"form.controls.currentDateContextInterval.value !== 'none'\"\n >\n {{ date[0] | c8yDate: DATE_FORMAT }} \u2014 {{ date[1] | c8yDate: DATE_FORMAT }}\n </span>\n </div>\n <span class=\"caret m-r-16 m-l-4\"></span>\n </button>\n\n <ul\n class=\"dropdown-menu dropdown-menu--date-range\"\n *dropdownMenu\n >\n <c8y-interval-picker\n class=\"d-contents\"\n formControlName=\"currentDateContextInterval\"\n [INTERVALS]=\"INTERVALS\"\n ></c8y-interval-picker>\n\n <ng-container *ngIf=\"form.controls.currentDateContextInterval.value === 'custom'\">\n <div class=\"p-l-16 p-r-16\">\n <c8y-form-group\n class=\"m-b-8\"\n [ngClass]=\"form.controls.temporaryUserSelectedFromDate.errors ? 'has-error' : ''\"\n >\n <label\n [title]=\"'From`date`' | translate\"\n for=\"temporaryUserSelectedFromDate\"\n translate\n >\n From`date`\n </label>\n <c8y-date-time-picker\n id=\"temporaryUserSelectedFromDate\"\n [maxDate]=\"form.value.temporaryUserSelectedToDate\"\n [placeholder]=\"'From`date`' | translate\"\n [formControl]=\"form.controls.temporaryUserSelectedFromDate\"\n [ngClass]=\"form.controls.temporaryUserSelectedFromDate.errors ? 'has-error' : ''\"\n ></c8y-date-time-picker>\n <c8y-messages [show]=\"form.controls.temporaryUserSelectedFromDate.errors\">\n <c8y-message\n name=\"dateAfterRangeMax\"\n [text]=\"'This date is after the latest allowed date.' | translate\"\n ></c8y-message>\n <c8y-message\n name=\"invalidDateTime\"\n [text]=\"'This date is invalid.' | translate\"\n ></c8y-message>\n </c8y-messages>\n </c8y-form-group>\n\n <c8y-form-group\n class=\"m-b-8\"\n [ngClass]=\"form.controls.temporaryUserSelectedToDate.errors ? 'has-error' : ''\"\n >\n <label\n [title]=\"'To`date`' | translate\"\n for=\"temporaryUserSelectedToDate\"\n translate\n >\n To`date`\n </label>\n <c8y-date-time-picker\n id=\"temporaryUserSelectedToDate\"\n [minDate]=\"form.value.temporaryUserSelectedFromDate\"\n [placeholder]=\"'To`date`' | translate\"\n [formControl]=\"form.controls.temporaryUserSelectedToDate\"\n [ngClass]=\"form.controls.temporaryUserSelectedToDate.errors ? 'has-error' : ''\"\n ></c8y-date-time-picker>\n <c8y-messages [show]=\"form.controls.temporaryUserSelectedToDate.errors\">\n <c8y-message\n name=\"dateBeforeRangeMin\"\n [text]=\"'This date is before the earliest allowed date.' | translate\"\n ></c8y-message>\n <c8y-message\n name=\"invalidDateTime\"\n [text]=\"'This date is invalid.' | translate\"\n ></c8y-message>\n </c8y-messages>\n </c8y-form-group>\n </div>\n\n <div class=\"p-16 d-flex gap-8 separator-top\">\n <button\n class=\"btn btn-primary btn-sm flex-grow\"\n title=\"{{ 'Apply' | translate }}\"\n type=\"button\"\n (click)=\"applyDateFilter(); dropdown.isOpen = false\"\n [disabled]=\"(form.pristine && form.untouched) || form.invalid\"\n translate\n >\n Apply\n </button>\n </div>\n </ng-container>\n </ul>\n </div>\n</form>\n" }] }], ctorParameters: () => [{ type: i1.FormBuilder }, { type: i2.Router }, { type: i2.ActivatedRoute }, { type: i3.AlarmsViewService }], propDecorators: { DEFAULT_INTERVAL: [{ type: Input }], updateQueryParams: [{ type: Input }], date: [{ type: Input }], dateFilterChange: [{ type: Output }], dropdown: [{ type: ViewChild, args: [BsDropdownDirective] }] } }); //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYWxhcm1zLWRhdGUtZmlsdGVyLmNvbXBvbmVudC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uL2FsYXJtcy9hbGFybXMtZGF0ZS1maWx0ZXIuY29tcG9uZW50LnRzIiwiLi4vLi4vLi4vYWxhcm1zL2FsYXJtcy1kYXRlLWZpbHRlci5jb21wb25lbnQuaHRtbCJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQ0wsU0FBUyxFQUNULFlBQVksRUFDWixVQUFVLEVBQ1YsS0FBSyxFQUVMLE1BQU0sRUFDTixTQUFTLEVBQ1YsTUFBTSxlQUFlLENBQUM7QUFDdkIsT0FBTyxFQUF3QixXQUFXLEVBQUUsaUJBQWlCLEVBQUUsTUFBTSxnQkFBZ0IsQ0FBQztBQUN0RixPQUFPLEVBQUUsY0FBYyxFQUFFLE1BQU0sRUFBRSxNQUFNLGlCQUFpQixDQUFDO0FBQ3pELE9BQU8sRUFBRSxRQUFRLEVBQWdCLE1BQU0sYUFBYSxDQUFDO0FBQ3JELE9BQU8sRUFBbUIsT0FBTyxFQUFFLE1BQU0scUJBQXFCLENBQUM7QUFDL0QsT0FBTyxFQUFFLE9BQU8sRUFBRSxJQUFJLEVBQUUsU0FBUyxFQUFFLE1BQU0sTUFBTSxDQUFDO0FBQ2hELE9BQU8sRUFFTCx3QkFBd0IsRUFDeEIsa0JBQWtCLEVBRW5CLE1BQU0sZ0JBQWdCLENBQUM7QUFDeEIsT0FBTyxFQUFFLG1CQUFtQixFQUFFLE1BQU0sd0JBQXdCLENBQUM7QUFDN0QsT0FBTyxFQUFFLGlCQUFpQixFQUFFLE1BQU0sdUJBQXVCLENBQUM7Ozs7Ozs7Ozs7O0FBYzFELE1BQU0sT0FBTyx5QkFBeUI7SUF5QnBDLFlBQ1UsV0FBd0IsRUFDeEIsTUFBYyxFQUNkLGNBQThCLEVBQzlCLGlCQUFvQztRQUhwQyxnQkFBVyxHQUFYLFdBQVcsQ0FBYTtRQUN4QixXQUFNLEdBQU4sTUFBTSxDQUFRO1FBQ2QsbUJBQWMsR0FBZCxjQUFjLENBQWdCO1FBQzlCLHNCQUFpQixHQUFqQixpQkFBaUIsQ0FBbUI7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TyxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUMsQ0FBQyxXQUFXLEVBQUU7WUFDNUQsMkJBQTJCLEVBQUUsT0FBTyxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUMsQ0FBQyxXQUFXLEVBQUU7WUFDMUQsMEJBQTBCLEVBQUUsT0FBTyxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUMsQ0FBQyxXQUFXLEVBQUU7WUFDekQsd0JBQXdCLEVBQUUsT0FBTyxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUMsQ0FBQyxXQUFXLEVBQUU7WUFDdkQsMEJBQTBCLEVBQUUsT0FBTyxDQUFDLFFBQVEsSUFBSSxRQUFRO1NBQ3pELENBQUMsQ0FBQztJQUNMLENBQUM7K0dBakxVLHlCQUF5QjttR0FBekIseUJBQXlCLDRNQVJ6QjtZQUNUO2dCQUNFLE9BQU8sRUFBRSxpQkFBaUI7Z0JBQzFCLFdBQVcsRUFBRSxVQUFVLENBQUMsR0FBRyxFQUFFLENBQUMseUJBQXlCLENBQUM7Z0JBQ3hELEtBQUssRUFBRSxJQUFJO2FBQ1o7U0FDRixvRUFxQlUsbUJBQW1CLGdEQ3REaEMsc3NLQStJQTs7NEZENUdhLHlCQUF5QjtrQkFYckMsU0FBUzsrQkFDRSx3QkFBd0IsYUFFdkI7d0JBQ1Q7NEJBQ0UsT0FBTyxFQUFFLGlCQUFpQjs0QkFDMUIsV0FBVyxFQUFFLFVBQVUsQ0FBQyxHQUFHLEVBQUUsMEJBQTBCLENBQUM7NEJBQ3hELEtBQUssRUFBRSxJQUFJO3lCQUNaO3FCQUNGO2tLQU9RLGdCQUFnQjtzQkFBeEIsS0FBSztnQkFDRyxpQkFBaUI7c0JBQXpCLEtBQUs7Z0JBSUcsSUFBSTtzQkFBWixLQUFLO2dCQVFJLGdCQUFnQjtzQkFBekIsTUFBTTtnQkFDeUIsUUFBUTtzQkFBdkMsU0FBUzt1QkFBQyxtQkFBbUIiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQge1xuICBDb21wb25lbnQsXG4gIEV2ZW50RW1pdHRlcixcbiAgZm9yd2FyZFJlZixcbiAgSW5wdXQsXG4gIE9uRGVzdHJveSxcbiAgT3V0cHV0LFxuICBWaWV3Q2hpbGRcbn0gZnJvbSAnQGFuZ3VsYXIvY29yZSc7XG5pbXBvcnQgeyBDb250cm9sVmFsdWVBY2Nlc3NvciwgRm9ybUJ1aWxkZXIsIE5HX1ZBTFVFX0FDQ0VTU09SIH0gZnJvbSAnQGFuZ3VsYXIvZm9ybXMnO1xuaW1wb3J0IHsgQWN0aXZhdGVkUm91dGUsIFJvdXRlciB9IGZyb20gJ0Bhbmd1bGFyL3JvdXRlcic7XG5pbXBvcnQgeyBTZXZlcml0eSwgU2V2ZXJpdHlUeXBlIH0gZnJvbSAnQGM4eS9jbGllbnQnO1xuaW1wb3J0IHsgRGF0ZVRpbWVDb250ZXh0LCBnZXR0ZXh0IH0gZnJvbSAnQGM4eS9uZ3gtY29tcG9uZW50cyc7XG5pbXBvcnQgeyBTdWJqZWN0LCB0YWtlLCB0YWtlVW50aWwgfSBmcm9tICdyeGpzJztcbmltcG9ydCB7XG4gIEFsYXJtTGlzdEZvcm1GaWx0ZXJzLFxuICBJTlRFUlZBTF9USVRMRVNfRVhURU5ERUQsXG4gIElOVEVSVkFMU19FWFRFTkRFRCxcbiAgV2lkZ2V0VGltZUNvbnRleHRTdGF0ZUV4dGVuZGVkXG59IGZyb20gJy4vYWxhcm1zLm1vZGVsJztcbmltcG9ydCB7IEJzRHJvcGRvd25EaXJlY3RpdmUgfSBmcm9tICduZ3gtYm9vdHN0cmFwL2Ryb3Bkb3duJztcbmltcG9ydCB7IEFsYXJtc1ZpZXdTZXJ2aWNlIH0gZnJvbSAnLi9hbGFybXMtdmlldy5zZXJ2aWNlJztcbmltcG9ydCB7IEFsYXJtRmlsdGVySW50ZXJ2YWwgfSBmcm9tICdAYzh5L25neC1jb21wb25lbnRzL2ludGVydmFsLXBpY2tlcic7XG5cbkBDb21wb25lbnQoe1xuICBzZWxlY3RvcjogJ2M4eS1hbGFybXMtZGF0ZS1maWx0ZXInLFxuICB0ZW1wbGF0ZVVybDogJy4vYWxhcm1zLWRhdGUtZmlsdGVyLmNvbXBvbmVudC5odG1sJyxcbiAgcHJvdmlkZXJzOiBbXG4gICAge1xuICAgICAgcHJvdmlkZTogTkdfVkFMVUVfQUNDRVNTT1IsXG4gICAgICB1c2VFeGlzdGluZzogZm9yd2FyZFJlZigoKSA9PiBBbGFybXNEYXRlRmlsdGVyQ29tcG9uZW50KSxcbiAgICAgIG11bHRpOiB0cnVlXG4gICAgfVxuICBdXG59KVxuZXhwb3J0IGNsYXNzIEFsYXJtc0RhdGVGaWx0ZXJDb21wb25lbnQgaW1wbGVtZW50cyBPbkRlc3Ryb3ksIENvbnRyb2xWYWx1ZUFjY2Vzc29yIHtcbiAgcmVhZG9ubHkgSU5URVJWQUxTID0gSU5URVJWQUxTX0VYVEVOREVEO1xuICByZWFkb25seSBJTlRFUlZBTF9USVRMRVMgPSBJTlRFUlZBTF9USVRMRVNfRVhURU5ERUQ7XG4gIHJlYWRvbmx5IERBVEVfRk9STUFUID0gJ3Nob3J0JztcblxuICBASW5wdXQoKSBERUZBVUxUX0lOVEVSVkFMOiBBbGFybUZpbHRlckludGVydmFsWydpZCddID0gJ25vbmUnO1xuICBASW5wdXQoKSB1cGRhdGVRdWVyeVBhcmFtcyA9IHRydWU7XG4gIC8qKlxuICAgKiBEYXRlIHJhbmdlIHRvIGJlIGRpc3BsYXllZCBpbiB0aGUgZGF0ZSBwaWNrZXIuXG4gICAqL1xuICBASW5wdXQoKSBkYXRlOiBbc3RyaW5nLCBzdHJpbmddO1xuICBub0ZpbHRlckxhYmVsID0gZ2V0dGV4dCgnTm8gZGF0ZSBmaWx0ZXInKTtcblxuICBwcml2YXRlIHNob3dDbGVhcmVkOiBib29sZWFuO1xuICBwcml2YXRlIHNldmVyaXR5T3B0aW9uczogeyBba2V5IGluIFNldmVyaXR5VHlwZV06IGJvb2xlYW4gfTtcbiAgcHJpdmF0ZSB0eXBlRmlsdGVyczogc3RyaW5nO1xuICBwcml2YXRlIGRlc3Ryb3kkOiBTdWJqZWN0PHZvaWQ+ID0gbmV3IFN1YmplY3Q8dm9pZD4oKTtcblxuICBAT3V0cHV0KCkgZGF0ZUZpbHRlckNoYW5nZSA9IG5ldyBFdmVudEVtaXR0ZXI8QWxhcm1MaXN0Rm9ybUZpbHRlcnM+KCk7XG4gIEBWaWV3Q2hpbGQoQnNEcm9wZG93bkRpcmVjdGl2ZSkgZHJvcGRvd246IEJzRHJvcGRvd25EaXJlY3RpdmU7XG5cbiAgZm9ybTogUmV0dXJuVHlwZTxBbGFybXNEYXRlRmlsdGVyQ29tcG9uZW50WydjcmVhdGVGb3JtJ10+O1xuICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgQHR5cGVzY3JpcHQtZXNsaW50L25vLWVtcHR5LWZ1bmN0aW9uXG4gIG9uQ2hhbmdlOiAodmFsdWU6IGFueSkgPT4gdm9pZDtcblxuICBjb25zdHJ1Y3RvcihcbiAgICBwcml2YXRlIGZvcm1CdWlsZGVyOiBGb3JtQnVpbGRlcixcbiAgICBwcml2YXRlIHJvdXRlcjogUm91dGVyLFxuICAgIHByaXZhdGUgYWN0aXZhdGVkUm91dGU6IEFjdGl2YXRlZFJvdXRlLFxuICAgIHByaXZhdGUgYWxhcm1zVmlld1NlcnZpY2U6IEFsYXJtc1ZpZXdTZXJ2aWNlXG4gICkge31cblxuICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgQHR5cGVzY3JpcHQtZXNsaW50L25vLWVtcHR5LWZ1bmN0aW9uXG4gIG9uVG91Y2hlZCA9ICgpID0+IHt9O1xuXG4gIG5nT25Jbml0KCkge1xuICAgIGNvbnN0IGNvbnRleHQgPSB0aGlzLmdldERlZmF1bHRDb250ZXh0KCk7XG4gICAgdGhpcy5mb3JtID0gdGhpcy5jcmVhdGVGb3JtKGNvbnRleHQpO1xuICAgIHRoaXMuZGF0ZSA9IFtcbiAgICAgIHRoaXMuZm9ybS52YWx1ZS5jdXJyZW50RGF0ZUNvbnRleHRGcm9tRGF0ZSxcbiAgICAgIHRoaXMuZm9ybS52YWx1ZS5jdXJyZW50RGF0ZUNvbnRleHRUb0RhdGVcbiAgICBdO1xuICAgIHRoaXMuYWN0aXZhdGVkUm91dGUucXVlcnlQYXJhbXMucGlwZSh0YWtlKDEpLCB0YWtlVW50aWwodGhpcy5kZXN0cm95JCkpLnN1YnNjcmliZShwYXJhbXMgPT4ge1xuICAgICAgdGhpcy5zaG93Q2xlYXJlZCA9IHBhcmFtcy5zaG93Q2xlYXJlZCA9PT0gJ3RydWUnO1xuICAgICAgdGhpcy5zZXZlcml0eU9wdGlvbnMgPSB7XG4gICAgICAgIFtTZXZlcml0eS5DUklUSUNBTF06IHBhcmFtcy5jcml0aWNhbCA9PT0gJ3RydWUnLFxuICAgICAgICBbU2V2ZXJpdHkuTUFKT1JdOiBwYXJhbXMubWFqb3IgPT09ICd0cnVlJyxcbiAgICAgICAgW1NldmVyaXR5Lk1JTk9SXTogcGFyYW1zLm1pbm9yID09PSAndHJ1ZScsXG4gICAgICAgIFtTZXZlcml0eS5XQVJOSU5HXTogcGFyYW1zLndhcm5pbmcgPT09ICd0cnVlJ1xuICAgICAgfTtcbiAgICAgIGlmIChwYXJhbXMudHlwZUZpbHRlcnMpIHtcbiAgICAgICAgdGhpcy50eXBlRmlsdGVycyA9IHBhcmFtcy50eXBlRmlsdGVycztcbiAgICAgIH1cbiAgICAgIGlmICghcGFyYW1zLmludGVydmFsKSB7XG4gICAgICAgIHJldHVybjtcbiAgICAgIH1cbiAgICAgIGlmIChwYXJhbXMuaW50ZXJ2YWwgIT09ICdjdXN0b20nKSB7XG4gICAgICAgIHRoaXMudXBkYXRlRGF0ZVRpbWUocGFyYW1zLmludGVydmFsKTtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIHRoaXMuZm9ybS5wYXRjaFZhbHVlKHtcbiAgICAgICAgICBjdXJyZW50RGF0ZUNvbnRleHRJbnRlcnZhbDogcGFyYW1zLmludGVydmFsLFxuICAgICAgICAgIHRlbXBvcmFyeVVzZXJTZWxlY3RlZEZyb21EYXRlOiBwYXJhbXMubGFzdFVwZGF0ZWRGcm9tLFxuICAgICAgICAgIHRlbXBvcmFyeVVzZXJTZWxlY3RlZFRvRGF0ZTogcGFyYW1zLmNyZWF0ZWRUb1xuICAgICAgICB9KTtcbiAgICAgICAgdGhpcy5kYXRlID0gW3BhcmFtcy5sYXN0VXBkYXRlZEZyb20sIHBhcmFtcy5jcmVhdGVkVG9dO1xuICAgICAgfVxuICAgIH0pO1xuXG4gICAgdGhpcy5zdWJzY3JpYmVUb0ludGVydmFsQ2hhbmdlKCk7XG4gIH1cblxuICBuZ09uRGVzdHJveSgpOiB2b2lkIHtcbiAgICB0aGlzLmRlc3Ryb3kkLm5leHQoKTtcbiAgICB0aGlzLmRlc3Ryb3kkLmNvbXBsZXRlKCk7XG4gIH1cblxuICBhcHBseURhdGVGaWx0ZXIoKTogdm9pZCB7XG4gICAgY29uc3QgY29tYmluZWRGb3JtRXZlbnQgPSB7XG4gICAgICBzaG93Q2xlYXJlZDogdGhpcy5zaG93Q2xlYXJlZCxcbiAgICAgIHNldmVyaXR5T3B0aW9uczogdGhpcy5zZXZlcml0eU9wdGlvbnMsXG4gICAgICB0eXBlRmlsdGVyczogdGhpcy50eXBlRmlsdGVycyxcbiAgICAgIGludGVydmFsOiB0aGlzLmZvcm0udmFsdWUuY3VycmVudERhdGVDb250ZXh0SW50ZXJ2YWwsXG4gICAgICBzZWxlY3RlZERhdGVzOiBbXG4gICAgICAgIG5ldyBEYXRlKHRoaXMuZm9ybS52YWx1ZS50ZW1wb3JhcnlVc2VyU2VsZWN0ZWRGcm9tRGF0ZSksXG4gICAgICAgIG5ldyBEYXRlKHRoaXMuZm9ybS52YWx1ZS50ZW1wb3JhcnlVc2VyU2VsZWN0ZWRUb0RhdGUpXG4gICAgICBdIGFzIERhdGVUaW1lQ29udGV4dFxuICAgIH07XG5cbiAgICAvLyBuZWVkZWQgZm9yIGN1c3RvbSBpbnRlcnZhbFxuICAgIHRoaXMuZGF0ZSA9IFtcbiAgICAgIHRoaXMuZm9ybS52YWx1ZS50ZW1wb3JhcnlVc2VyU2VsZWN0ZWRGcm9tRGF0ZSxcbiAgICAgIHRoaXMuZm9ybS52YWx1ZS50ZW1wb3JhcnlVc2VyU2VsZWN0ZWRUb0RhdGVcbiAgICBdO1xuXG4gICAgdGhpcy5yb3V0ZXIubmF2aWdhdGUoW10sIHtcbiAgICAgIHJlbGF0aXZlVG86IHRoaXMuYWN0aXZhdGVkUm91dGUsXG4gICAgICBxdWVyeVBhcmFtczoge1xuICAgICAgICBpbnRlcnZhbDogdGhpcy5mb3JtLnZhbHVlLmN1cnJlbnREYXRlQ29udGV4dEludGVydmFsLFxuICAgICAgICBsYXN0VXBkYXRlZEZyb206IGNvbWJpbmVkRm9ybUV2ZW50LnNlbGVjdGVkRGF0ZXNbMF0udG9JU09TdHJpbmcoKSxcbiAgICAgICAgY3JlYXRlZFRvOiBjb21iaW5lZEZvcm1FdmVudC5zZWxlY3RlZERhdGVzWzFdLnRvSVNPU3RyaW5nKClcbiAgICAgIH0sXG4gICAgICBxdWVyeVBhcmFtc0hhbmRsaW5nOiAnbWVyZ2UnXG4gICAgfSk7XG4gICAgdGhpcy5kYXRlRmlsdGVyQ2hhbmdlLmVtaXQoY29tYmluZWRGb3JtRXZlbnQpO1xuICB9XG5cbiAgd3JpdGVWYWx1ZSh2YWx1ZTogYW55KTogdm9pZCB7XG4gICAgaWYgKHZhbHVlKSB7XG4gICAgICB0aGlzLmZvcm0ucGF0Y2hWYWx1ZSh7XG4gICAgICAgIGN1cnJlbnREYXRlQ29udGV4dEZyb21EYXRlOlxuICAgICAgICAgIHR5cGVvZiB2YWx1ZVswXSA9PT0gJ3N0cmluZycgPyB2YWx1ZVswXSA6IHZhbHVlWzBdLnRvSVNPU3RyaW5nKCksXG4gICAgICAgIGN1cnJlbnREYXRlQ29udGV4dFRvRGF0ZTogdHlwZW9mIHZhbHVlWzFdID09PSAnc3RyaW5nJyA/IHZhbHVlWzFdIDogdmFsdWVbMV0udG9JU09TdHJpbmcoKVxuICAgICAgfSk7XG4gICAgfVxuICB9XG5cbiAgcmVnaXN0ZXJPbkNoYW5nZShmbjogYW55KTogdm9pZCB7XG4gICAgdGhpcy5vbkNoYW5nZSA9IGZuO1xuICB9XG5cbiAgcmVnaXN0ZXJPblRvdWNoZWQob25Ub3VjaGVkOiBhbnkpIHtcbiAgICB0aGlzLm9uVG91Y2hlZCA9IG9uVG91Y2hlZDtcbiAgfVxuXG4gIHByaXZhdGUgdXBkYXRlRGF0ZVRpbWUoaW50ZXJ2YWw6IEFsYXJtRmlsdGVySW50ZXJ2YWxbJ2lkJ10pOiB2b2lkIHtcbiAgICBjb25zdCBkYXRlID0gdGhpcy5hbGFybXNWaWV3U2VydmljZS5nZXREYXRlVGltZUNvbnRleHRCeUludGVydmFsKGludGVydmFsKTtcbiAgICBpZiAodGhpcy5kcm9wZG93bikge1xuICAgICAgdGhpcy5kcm9wZG93bi5pc09wZW4gPSBmYWxzZTtcbiAgICB9XG4gICAgdGhpcy5kYXRlID0gZGF0ZS5tYXAoZCA9PiBkLnRvSVNPU3RyaW5nKCkpIGFzIFtzdHJpbmcsIHN0cmluZ107XG4gICAgdGhpcy5mb3JtLnBhdGNoVmFsdWUoXG4gICAgICB7XG4gICAgICAgIHRlbXBvcmFyeVVzZXJTZWxlY3RlZEZyb21EYXRlOiBkYXRlWzBdLnRvSVNPU3RyaW5nKCksXG4gICAgICAgIHRlbXBvcmFyeVVzZXJTZWxlY3RlZFRvRGF0ZTogZGF0ZVsxXS50b0lTT1N0cmluZygpLFxuICAgICAgICBjdXJyZW50RGF0ZUNvbnRleHRJbnRlcnZhbDogaW50ZXJ2YWxcbiAgICAgIH0sXG4gICAgICB7IGVtaXRFdmVudDogZmFsc2UgfVxuICAgICk7XG4gICAgdGhpcy5hcHBseURhdGVGaWx0ZXIoKTtcbiAgfVxuXG4gIHByaXZhdGUgZ2V0RGVmYXVsdENvbnRleHQoKSB7XG4gICAgcmV0dXJuIHtcbiAgICAgIGRhdGU6IHRoaXMuYWxhcm1zVmlld1NlcnZpY2UuZ2V0RGF0ZVRpbWVDb250ZXh0QnlJbnRlcnZhbCh0aGlzLkRFRkFVTFRfSU5URVJWQUwpLFxuICAgICAgaW50ZXJ2YWw6IHRoaXMuREVGQVVMVF9JTlRFUlZBTFxuICAgIH07XG4gIH1cblxuICBwcml2YXRlIHN1YnNjcmliZVRvSW50ZXJ2YWxDaGFuZ2UoKTogdm9pZCB7XG4gICAgdGhpcy5mb3JtLmNvbnRyb2xzLmN1cnJlbnREYXRlQ29udGV4dEludGVydmFsLnZhbHVlQ2hhbmdlc1xuICAgICAgLnBpcGUodGFrZVVudGlsKHRoaXMuZGVzdHJveSQpKVxuICAgICAgLnN1YnNjcmliZShpbnRlcnZhbCA9PiB7XG4gICAgICAgIGlmIChpbnRlcnZhbCA9PT0gJ2N1c3RvbScpIHtcbiAgICAgICAgICB0aGlzLmZvcm0ucGF0Y2hWYWx1ZShcbiAgICAgICAgICAgIHtcbiAgICAgICAgICAgICAgdGVtcG9yYXJ5VXNlclNlbGVjdGVkRnJvbURhdGU6XG4gICAgICAgICAgICAgICAgdGhpcy5mb3JtLmNvbnRyb2xzLnRlbXBvcmFyeVVzZXJTZWxlY3RlZEZyb21EYXRlLnZhbHVlID09PSBuZXcgRGF0ZSgwKS50b0lTT1N0cmluZygpXG4gICAgICAgICAgICAgICAgICA/IHRoaXMuZm9ybS5jb250cm9scy5jdXJyZW50RGF0ZUNvbnRleHRUb0RhdGUudmFsdWVcbiAgICAgICAgICAgICAgICAgIDogdGhpcy5mb3JtLmNvbnRyb2xzLnRlbXBvcmFyeVVzZXJTZWxlY3RlZEZyb21EYXRlLnZhbHVlLFxuICAgICAgICAgICAgICBjdXJyZW50RGF0ZUNvbnRleHRJbnRlcnZhbDogaW50ZXJ2YWxcbiAgICAgICAgICAgIH0sXG4gICAgICAgICAgICB7IGVtaXRFdmVudDogZmFsc2UgfVxuICAgICAgICAgICk7XG4gICAgICAgICAgcmV0dXJuO1xuICAgICAgICB9XG4gICAgICAgIHRoaXMudXBkYXRlRGF0ZVRpbWUoaW50ZXJ2YWwpO1xuICAgICAgfSk7XG4gIH1cblxuICBwcml2YXRlIGNyZWF0ZUZvcm0oY29udGV4dDogV2lkZ2V0VGltZUNvbnRleHRTdGF0ZUV4dGVuZGVkKSB7XG4gICAgcmV0dXJuIHRoaXMuZm9ybUJ1aWxkZXIuZ3JvdXAoe1xuICAgICAgdGVtcG9yYXJ5VXNlclNlbGVjdGVkRnJvbURhdGU6IGNvbnRleHQuZGF0ZVswXS50b0lTT1N0cmluZygpLFxuICAgICAgdGVtcG9yYXJ5VXNlclNlbGVjdGVkVG9EYXRlOiBjb250ZXh0LmRhdGVbMV0udG9JU09TdHJpbmcoKSxcbiAgICAgIGN1cnJlbnREYXRlQ29udGV4dEZyb21EYXRlOiBjb250ZXh0LmRhdGVbMF0udG9JU09TdHJpbmcoKSxcbiAgICAgIGN1cnJlbnREYXRlQ29udGV4dFRvRGF0ZTogY29udGV4dC5kYXRlWzFdLnRvSVNPU3RyaW5nKCksXG4gICAgICBjdXJyZW50RGF0ZUNvbnRleHRJbnRlcnZhbDogY29udGV4dC5pbnRlcnZhbCB8fCAnY3VzdG9tJ1xuICAgIH0pO1xuICB9XG59XG4iLCI8Zm9ybVxuICBjbGFzcz1cImQtZmxleCBnYXAtMTYgcC1sLXhzLTE2IHAtci14cy0xNiBtLXQteHMtOCBtLWIteHMtOFwiXG4gIFtmb3JtR3JvdXBdPVwiZm9ybVwiXG4+XG4gIDxkaXZcbiAgICBjbGFzcz1cImRyb3Bkb3duIGZsZXgtZ3Jvd1wiXG4gICAgYzh5RHJvcGRvd25EaXJlY3Rpb25cbiAgICAjZHJvcERpcmVjdGlvbj1cImJzLWRyb3Bkb3duXCJcbiAgICBkcm9wZG93blxuICAgIFtpbnNpZGVDbGlja109XCJ0cnVlXCJcbiAgPlxuICAgIDxidXR0b25cbiAgICAgIGNsYXNzPVwiZHJvcGRvd24tdG9nZ2xlIGZvcm0tY29udHJvbCBsLWgtdGlnaHQgZC1mbGV4IGEtaS1jZW50ZXJcIlxuICAgICAgYXR0ci5hcmlhLWxhYmVsPVwie3tcbiAgICAgICAgKGZvcm0udmFsdWUuY3VycmVudERhdGVDb250ZXh0SW50ZXJ2YWwgPT09ICdub25lJ1xuICAgICAgICAgID8gbm9GaWx0ZXJMYWJlbFxuICAgICAgICAgIDogKGRhdGVbMF0gfCBjOHlEYXRlOiBEQVRFX0ZPUk1BVCkgKyAnIOKAlCAnICsgKGRhdGVbMV0gfCBjOHlEYXRlOiBEQVRFX0ZPUk1BVClcbiAgICAgICAgKSB8IHRyYW5zbGF0ZVxuICAgICAgfX1cIlxuICAgICAgdG9vbHRpcD1cInt7XG4gICAgICAgIChmb3JtLnZhbHVlLmN1cnJlbnREYXRlQ29udGV4dEludGVydmFsID09PSAnbm9uZSdcbiAgICAgICAgICA/IG5vRmlsdGVyTGFiZWxcbiAgICAgICAgICA6IChkYXRlWzBdIHwgYzh5RGF0ZTogREFURV9GT1JNQVQpICsgJyDigJQgJyArIChkYXRlWzFdIHwgYzh5RGF0ZTogREFURV9GT1JNQVQpXG4gICAgICAgICkgfCB0cmFuc2xhdGVcbiAgICAgIH19XCJcbiAgICAgIHBsYWNlbWVudD1cInRvcFwiXG4gICAgICBjb250YWluZXI9XCJib2R5XCJcbiAgICAgIGRhdGEtY3k9XCJhbGFybXMtZGF0ZS1maWx0ZXItLWRhdGUtcGlja2VyLWRyb3Bkb3duLWJ1dHRvblwiXG4gICAgICBbYWRhcHRpdmVQb3NpdGlvbl09XCJmYWxzZVwiXG4gICAgICBbZGVsYXldPVwiNTAwXCJcbiAgICAgIGRyb3Bkb3duVG9nZ2xlXG4gICAgPlxuICAgICAgPGlcbiAgICAgICAgY2xhc3M9XCJtLXItNFwiXG4gICAgICAgIGM4eUljb249XCJzY2hlZHVsZTFcIlxuICAgICAgPjwvaT5cbiAgICAgIDxkaXYgY2xhc3M9XCJkLWNvbCB0ZXh0LWxlZnQgZml0LXdcIj5cbiAgICAgICAgPHNwYW5cbiAgICAgICAgICBjbGFzcz1cInRleHQtMTJcIlxuICAgICAgICAgIGRhdGEtY3k9XCJ3aWRnZXQtdGltZS1jb250ZXh0LS1zZWxlY3RlZC1pbnRlcnZhbFwiXG4gICAgICAgID5cbiAgICAgICAgICB7eyBJTlRFUlZBTF9USVRMRVNbZm9ybS5jb250cm9scy5jdXJyZW50RGF0ZUNvbnRleHRJbnRlcnZhbC52YWx1ZV0gfCB0cmFuc2xhdGUgfX1cbiAgICAgICAgPC9zcGFuPlxuICAgICAgICA8c3BhblxuICAgICAgICAgIGNsYXNzPVwidGV4dC0xMCB0ZXh0LW11dGVkIHRleHQtdHJ1bmNhdGVcIlxuICAgICAgICAgIGRhdGEtY3k9XCJhbGFybXMtZGF0ZS1maWx0ZXItLXNlbGVjdGVkLXRpbWUtcmFuZ2VcIlxuICAgICAgICAgICpuZ0lmPVwiZm9ybS5jb250cm9scy5jdXJyZW50RGF0ZUNvbnRleHRJbnRlcnZhbC52YWx1ZSAhPT0gJ25vbmUnXCJcbiAgICAgICAgPlxuICAgICAgICAgIHt7IGRhdGVbMF0gfCBjOHlEYXRlOiBEQVRFX0ZPUk1BVCB9fSDigJQge3sgZGF0ZVsxXSB8IGM4eURhdGU6IERBVEVfRk9STUFUIH19XG4gICAgICAgIDwvc3Bhbj5cbiAgICAgIDwvZGl2PlxuICAgICAgPHNwYW4gY2xhc3M9XCJjYXJldCBtLXItMTYgbS1sLTRcIj48L3NwYW4+XG4gICAgPC9idXR0b24+XG5cbiAgICA8dWxcbiAgICAgIGNsYXNzPVwiZHJvcGRvd24tbWVudSBkcm9wZG93bi1tZW51LS1kYXRlLXJhbmdlXCJcbiAgICAgICpkcm9wZG93bk1lbnVcbiAgICA+XG4gICAgICA8Yzh5LWludGVydmFsLXBpY2tlclxuICAgICAgICBjbGFzcz1cImQtY29udGVudHNcIlxuICAgICAgICBmb3JtQ29udHJvbE5hbWU9XCJjdXJyZW50RGF0ZUNvbnRleHRJbnRlcnZhbFwiXG4gICAgICAgIFtJTlRFUlZBTFNdPVwiSU5URVJWQUxTXCJcbiAgICAgID48L2M4eS1pbnRlcnZhbC1waWNrZXI+XG5cbiAgICAgIDxuZy1jb250YWluZXIgKm5nSWY9XCJmb3JtLmNvbnRyb2xzLmN1cnJlbnREYXRlQ29udGV4dEludGVydmFsLnZhbHVlID09PSAnY3VzdG9tJ1wiPlxuICAgICAgICA8ZGl2IGNsYXNzPVwicC1sLTE2IHAtci0xNlwiPlxuICAgICAgICAgIDxjOHktZm9ybS1ncm91cFxuICAgICAgICAgICAgY2xhc3M9XCJtLWItOFwiXG4gICAgICAgICAgICBbbmdDbGFzc109XCJmb3JtLmNvbnRyb2xzLnRlbXBvcmFyeVVzZXJTZWxlY3RlZEZyb21EYXRlLmVycm9ycyA/ICdoYXMtZXJyb3InIDogJydcIlxuICAgICAgICAgID5cbiAgICAgICAgICAgIDxsYWJlbFxuICAgICAgICAgICAgICBbdGl0bGVdPVwiJ0Zyb21gZGF0ZWAnIHwgdHJhbnNsYXRlXCJcbiAgICAgICAgICAgICAgZm9yPVwidGVtcG9yYXJ5VXNlclNlbGVjdGVkRnJvbURhdGVcIlxuICAgICAgICAgICAgICB0cmFuc2xhdGVcbiAgICAgICAgICAgID5cbiAgICAgICAgICAgICAgRnJvbWBkYXRlYFxuICAgICAgICAgICAgPC9sYWJlbD5cbiAgICAgICAgICAgIDxjOHktZGF0ZS10aW1lLXBpY2tlclxuICAgICAgICAgICAgICBpZD1cInRlbXBvcmFyeVVzZXJTZWxlY3RlZEZyb21EYXRlXCJcbiAgICAgICAgICAgICAgW21heERhdGVdPVwiZm9ybS52YWx1ZS50ZW1wb3JhcnlVc2VyU2VsZWN0ZWRUb0RhdGVcIlxuICAgICAgICAgICAgICBbcGxhY2Vob2xkZXJdPVwiJ0Zyb21gZGF0ZWAnIHwgdHJhbnNsYXRlXCJcbiAgICAgICAgICAgICAgW2Zvcm1Db250cm9sXT1cImZvcm0uY29udHJvbHMudGVtcG9yYXJ5VXNlclNlbGVjdGVkRnJvbURhdGVcIlxuICAgICAgICAgICAgICBbbmdDbGFzc109XCJmb3JtLmNvbnRyb2xzLnRlbXBvcmFyeVVzZXJTZWxlY3RlZEZyb21EYXRlLmVycm9ycyA/ICdoYXMtZXJyb3InIDogJydcIlxuICAgICAgICAgICAgPjwvYzh5LWRhdGUtdGltZS1waWNrZXI+XG4gICAgICAgICAgICA8Yzh5LW1lc3NhZ2VzIFtzaG93XT1cImZvcm0uY29udHJvbHMudGVtcG9yYXJ5VXNlclNlbGVjdGVkRnJvbURhdGUuZXJyb3JzXCI+XG4gICAgICAgICAgICAgIDxjOHktbWVzc2FnZVxuICAgICAgICAgICAgICAgIG5hbWU9XCJkYXRlQWZ0ZXJSYW5nZU1heFwiXG4gICAgICAgICAgICAgICAgW3RleHRdPVwiJ1RoaXMgZGF0ZSBpcyBhZnRlciB0aGUgbGF0ZXN0IGFsbG93ZWQgZGF0ZS4nIHwgdHJhbnNsYXRlXCJcbiAgICAgICAgICAgICAgPjwvYzh5LW1lc3NhZ2U+XG4gICAgICAgICAgICAgIDxjOHktbWVzc2FnZVxuICAgICAgICAgICAgICAgIG5hbWU9XCJpbnZhbGlkRGF0ZVRpbWVcIlxuICAgICAgICAgICAgICAgIFt0ZXh0XT1cIidUaGlzIGRhdGUgaXMgaW52YWxpZC4nIHwgdHJhbnNsYXRlXCJcbiAgICAgICAgICAgICAgPjwvYzh5LW1lc3NhZ2U+XG4gICAgICAgICAgICA8L2M4eS1tZXNzYWdlcz5cbiAgICAgICAgICA8L2M4eS1mb3JtLWdyb3VwPlxuXG4gICAgICAgICAgPGM4eS1mb3JtLWdyb3VwXG4gICAgICAgICAgICBjbGFzcz1cIm0tYi04XCJcbiAgICAgICAgICAgIFtuZ0NsYXNzXT1cImZvcm0uY29udHJvbHMudGVtcG9yYXJ5VXNlclNlbGVjdGVkVG9EYXRlLmVycm9ycyA/ICdoYXMtZXJyb3InIDogJydcIlxuICAgICAgICAgID5cbiAgICAgICAgICAgIDxsYWJlbFxuICAgICAgICAgICAgICBbdGl0bGVdPVwiJ1RvYGRhdGVgJyB8IHRyYW5zbGF0ZVwiXG4gICAgICAgICAgICAgIGZvcj1cInRlbXBvcmFyeVVzZXJTZWxlY3RlZFRvRGF0ZVwiXG4gICAgICAgICAgICAgIHRyYW5zbGF0ZVxuICAgICAgICAgICAgPlxuICAgICAgICAgICAgICBUb2BkYXRlYFxuICAgICAgICAgICAgPC9sYWJlbD5cbiAgICAgICAgICAgIDxjOHktZGF0ZS10aW1lLXBpY2tlclxuICAgICAgICAgICAgICBpZD1cInRlbXBvcmFyeVVzZXJTZWxlY3RlZFRvRGF0ZVwiXG4gICAgICAgICAgICAgIFttaW5EYXRlXT1cImZvcm0udmFsdWUudGVtcG9yYXJ5VXNlclNlbGVjdGVkRnJvbURhdGVcIlxuICAgICAgICAgICAgICBbcGxhY2Vob2xkZXJdPVwiJ1RvYGRhdGVgJyB8IHRyYW5zbGF0ZVwiXG4gICAgICAgICAgICAgIFtmb3JtQ29udHJvbF09XCJmb3JtLmNvbnRyb2xzLnRlbXBvcmFyeVVzZXJTZWxlY3RlZFRvRGF0ZVwiXG4gICAgICAgICAgICAgIFtuZ0NsYXNzXT1cImZvcm0uY29udHJvbHMudGVtcG9yYXJ5VXNlclNlbGVjdGVkVG9EYXRlLmVycm9ycyA/ICdoYXMtZXJyb3InIDogJydcIlxuICAgICAgICAgICAgPjwvYzh5LWRhdGUtdGltZS1waWNrZXI+XG4gICAgICAgICAgICA8Yzh5LW1lc3NhZ2VzIFtzaG93XT1cImZvcm0uY29udHJvbHMudGVtcG9yYXJ5VXNlclNlbGVjdGVkVG9EYXRlLmVycm9yc1wiPlxuICAgICAgICAgICAgICA8Yzh5LW1lc3NhZ2VcbiAgICAgICAgICAgICAgICBuYW1lPVwiZGF0ZUJlZm9yZVJhbmdlTWluXCJcbiAgICAgICAgICAgICAgICBbdGV4dF09XCInVGhpcyBkYXRlIGlzIGJlZm9yZSB0aGUgZWFybGllc3QgYWxsb3dlZCBkYXRlLicgfCB0cmFuc2xhdGVcIlxuICAgICAgICAgICAgICA+PC9jOHktbWVzc2FnZT5cbiAgICAgICAgICAgICAgPGM4eS1tZXNzYWdlXG4gICAgICAgICAgICAgICAgbmFtZT1cImludmFsaWREYXRlVGltZVwiXG4gICAgICAgICAgICAgICAgW3RleHRdPVwiJ1RoaXMgZGF0ZSBpcyBpbnZhbGlkLicgfCB0cmFuc2xhdGVcIlxuICAgICAgICAgICAgICA+PC9jOHktbWVzc2FnZT5cbiAgICAgICAgICAgIDwvYzh5LW1lc3NhZ2VzPlxuICAgICAgICAgIDwvYzh5LWZvcm0tZ3JvdXA+XG4gICAgICAgIDwvZGl2PlxuXG4gICAgICAgIDxkaXYgY2xhc3M9XCJwLTE2IGQtZmxleCBnYXAtOCBzZXBhcmF0b3ItdG9wXCI+XG4gICAgICAgICAgPGJ1dHRvblxuICAgICAgICAgICAgY2xhc3M9XCJidG4gYnRuLXByaW1hcnkgYnRuLXNtIGZsZXgtZ3Jvd1wiXG4gICAgICAgICAgICB0aXRsZT1cInt7ICdBcHBseScgfCB0cmFuc2xhdGUgfX1cIlxuICAgICAgICAgICAgdHlwZT1cImJ1dHRvblwiXG4gICAgICAgICAgICAoY2xpY2spPVwiYXBwbHlEYXRlRmlsdGVyKCk7IGRyb3Bkb3duLmlzT3BlbiA9IGZhbHNlXCJcbiAgICAgICAgICAgIFtkaXNhYmxlZF09XCIoZm9ybS5wcmlzdGluZSAmJiBmb3JtLnVudG91Y2hlZCkgfHwgZm9ybS5pbnZhbGlkXCJcbiAgICAgICAgICAgIHRyYW5zbGF0ZVxuICAgICAgICAgID5cbiAgICAgICAgICAgIEFwcGx5XG4gICAgICAgICAgPC9idXR0b24+XG4gICAgICAgIDwvZGl2PlxuICAgICAgPC9uZy1jb250YWluZXI+XG4gICAgPC91bD5cbiAgPC9kaXY+XG48L2Zvcm0+XG4iXX0=