UNPKG

@c8y/ngx-components

Version:

Angular modules for Cumulocity IoT applications

322 lines 94.4 kB
import { Component, Input } from '@angular/core';
import { ControlContainer, FormBuilder, FormControl, NgForm } from '@angular/forms';
import { ALARM_STATUS_LABELS, AlarmStatus, AlarmService, SEVERITY_LABELS } from '@c8y/client';
import { AlertService, gettext } from '@c8y/ngx-components';
import { ALARM_STATUS_ICON, AlarmsViewService, DEFAULT_SEVERITY_VALUES, DEFAULT_STATUS_VALUES } from '@c8y/ngx-components/alarms';
import { TranslateService } from '@ngx-translate/core';
import { isEqual, omit } from 'lodash-es';
import { BehaviorSubject } from 'rxjs';
import { debounceTime, pairwise, startWith } from 'rxjs/operators';
import { ALARM_ORDER_LABELS, ALARM_ORDER_VALUES, DATE_SELECTION, GLOBAL_INTERVAL_OPTION } from '../alarm-list-widget.model';
import { AlarmWidgetService, DEFAULT_PAGE_SIZE } from '../alarm-widget.service';
import * as i0 from "@angular/core";
import * as i1 from "../alarm-widget.service";
import * as i2 from "@c8y/client";
import * as i3 from "@c8y/ngx-components/alarms";
import * as i4 from "@c8y/ngx-components";
import * as i5 from "@angular/forms";
import * as i6 from "@ngx-translate/core";
import * as i7 from "@angular/common";
import * as i8 from "ngx-bootstrap/popover";
import * as i9 from "../severity-icon.pipe";
import * as i10 from "../sorting-description-popover-message.pipe";
export class AlarmListWidgetConfigComponent {
    constructor(alarmListWidgetService, alarmService, alarmsViewService, alertService, form, formBuilder, translateService) {
        this.alarmListWidgetService = alarmListWidgetService;
        this.alarmService = alarmService;
        this.alarmsViewService = alarmsViewService;
        this.alertService = alertService;
        this.form = form;
        this.formBuilder = formBuilder;
        this.translateService = translateService;
        this.REFRESH_INTERVAL_IN_MILLISECONDS = this.alarmsViewService.DEFAULT_INTERVAL_VALUES;
        this.SEVERITY_LABELS = SEVERITY_LABELS;
        this.STATUS_LABELS = ALARM_STATUS_LABELS;
        this.ACKNOWLEDGE_STATUS_VALUE = AlarmStatus.ACKNOWLEDGED;
        this.CLEARED_STATUS_VALUE = AlarmStatus.CLEARED;
        this.BELL_SLASH_ICON = ALARM_STATUS_ICON.BELL_SLASH;
        this.BELL_ICON = ALARM_STATUS_ICON.BELL;
        this.C8Y_ALERT_IDLE_ICON = ALARM_STATUS_ICON.ALERT_IDLE;
        this.ALARM_ORDER_LABELS = ALARM_ORDER_LABELS;
        this.GLOBAL_INTERVAL_OPTION = GLOBAL_INTERVAL_OPTION;
        this.alarms$ = new BehaviorSubject(null);
        this.orderList = Object.values(ALARM_ORDER_VALUES);
        this.severityList = Object.keys(SEVERITY_LABELS);
        this.showDateFilter = true;
        this.DATE_SELECTION = DATE_SELECTION;
        this.dateSelectionHelp = this.translateService.instant(gettext(`Choose how to select a date range, the available options are:
  <ul class="m-l-0 p-l-8 m-t-8 m-b-0">
    <li>
      <b>Widget configuration:</b>
      restricts the date selection only to the widget configuration
    </li>
    <li>
      <b>Widget and widget configuration:</b>
      restricts the date selection to the widget view and widget configuration only
    </li>
    <li>
      <b>Dashboard time range:</b>
      restricts date selection to the global dashboard configuration only
    </li>
  </ul>`));
        /**
         * Order does matter.
         */
        this.statusList = [AlarmStatus.ACTIVE, AlarmStatus.ACKNOWLEDGED, AlarmStatus.CLEARED];
    }
    async ngOnInit() {
        this.refreshTypeTitle = this.config.isRealtime
            ? this.translateService.instant(gettext('Realtime'))
            : this.translateService.instant(gettext('Auto refresh'));
        this.refreshTypePopoverMessage = this.config.isRealtime
            ? this.translateService.instant(gettext('Change the default state of realtime refresh.'))
            : this.translateService.instant(gettext('Change the state of interval automatic refresh and set the refresh frequency.'));
        this.initializeForm();
        if (!this.config.isRealtime) {
            this.updateConfigBasedOnRefreshOption();
        }
        this.config.isRealtime = !this.alarmsViewService.isIntervalRefresh();
        const isWidgetWithExistingConfig = this.config.order && this.config.severities && this.config.status;
        if (isWidgetWithExistingConfig) {
            await this.getAlarms(this.config);
        }
        else {
            /** Used when creating a new widget */
            await this.getAlarms(this.formGroup.value);
        }
        this.handlePreviewSubscription();
    }
    ngOnChanges(changes) {
        if (this.formGroup && changes.config) {
            this.formGroup.get('device').patchValue(this.config.device);
        }
    }
    ngOnDestroy() {
        this.formChangesSubscription?.unsubscribe();
    }
    onBeforeSave(config) {
        const { types } = this.formGroup.value;
        if (types.length > 1) {
            const stringTypes = types;
            if (this.isContainingOnlyEmptyTypes(stringTypes)) {
                this.formGroup.value.types = [''];
            }
            else {
                this.formGroup.value.types = this.filterEmptyTypes(stringTypes);
            }
        }
        /**
         * Applies only to converted legacy Alarm list widget
         */
        if (config['options']) {
            delete config['options'];
        }
        Object.assign(config, this.formGroup.value);
        return true;
    }
    onDateFilterChange(event) {
        this.formGroup.patchValue({
            dateFilter: event.selectedDates,
            interval: event.interval
        });
    }
    removeType(index) {
        if (this.types.controls.length === 1) {
            this.formGroup.get('types').reset();
        }
        else {
            this.types.removeAt(index);
        }
    }
    addType() {
        this.types.push(this.formBuilder.control(''));
    }
    updateRefreshOption() {
        this.config.refreshOption = this.refreshOption;
        this.formGroup.controls.refreshOption.setValue(this.refreshOption);
        const isGlobalInterval = this.refreshOption === GLOBAL_INTERVAL_OPTION;
        this.config.widgetInstanceGlobalAutoRefreshContext = isGlobalInterval;
        this.formGroup.controls.widgetInstanceGlobalAutoRefreshContext.setValue(isGlobalInterval);
        this.updateConfigBasedOnRefreshOption();
    }
    get types() {
        return this.formGroup.get('types');
    }
    dateSelectionChange(dateSelection) {
        if (dateSelection === DATE_SELECTION.CONFIG) {
            this.showDateFilter = true;
            this.formGroup.patchValue({
                displayDateSelection: false,
                widgetInstanceGlobalTimeContext: false
            });
        }
        else if (dateSelection === DATE_SELECTION.VIEW_AND_CONFIG) {
            this.showDateFilter = true;
            this.formGroup.patchValue({
                displayDateSelection: true,
                widgetInstanceGlobalTimeContext: false
            });
        }
        else if (dateSelection === DATE_SELECTION.DASHBOARD_CONTEXT) {
            this.showDateFilter = false;
            this.formGroup.patchValue({
                displayDateSelection: false,
                widgetInstanceGlobalTimeContext: true
            });
        }
    }
    filterEmptyTypes(types) {
        return types.filter((element) => element !== '' && element !== null);
    }
    isContainingOnlyEmptyTypes(types) {
        return types.every((element) => element === '' || element === null);
    }
    async getAlarms(config) {
        try {
            this.isLoading = true;
            const result = await this.alarmService.list(this.alarmListWidgetService.mapConfigToQueryFilter(config, DEFAULT_PAGE_SIZE));
            this.alarms$.next(result);
        }
        catch (error) {
            this.alertService.addServerFailure(error);
        }
        finally {
            this.isLoading = false;
        }
    }
    initializeForm() {
        this.formGroup = this.createForm();
        this.form.form.addControl('config', this.formGroup);
        this.formGroup.patchValue(this.config);
        this.initializeTypes(this.config.types);
        this.initDateSelection();
        this.refreshOption = this.config.refreshOption ?? 'interval';
    }
    createForm() {
        return this.formBuilder.group({
            status: this.formBuilder.group(DEFAULT_STATUS_VALUES, {
                validators: this.minSelectedCheckboxes(1)
            }),
            showAlarmsForChildren: true,
            types: this.formBuilder.array([]),
            severities: this.formBuilder.group(DEFAULT_SEVERITY_VALUES, {
                validators: this.minSelectedCheckboxes(1)
            }),
            order: ALARM_ORDER_VALUES.BY_ACTIVE,
            isAutoRefreshEnabled: [true],
            refreshInterval: !this.config.isRealtime
                ? new FormControl({
                    value: this.alarmsViewService.DEFAULT_INTERVAL_VALUE,
                    disabled: this.isAutorefershDisabled()
                })
                : new FormControl(undefined),
            device: this.config.device ? new FormControl(this.config.device) : new FormControl(undefined),
            dateFilter: this.config.dateFilter
                ? new FormControl(this.config.dateFilter)
                : new FormControl([new Date(0), new Date()]),
            displayDateSelection: this.config.displayDateSelection || false,
            widgetInstanceGlobalTimeContext: this.config.widgetInstanceGlobalTimeContext || false,
            interval: this.config.interval || 'none',
            refreshOption: this.config.isRealtime ? null : 'interval',
            widgetInstanceGlobalAutoRefreshContext: this.config.refreshOption === GLOBAL_INTERVAL_OPTION
        });
    }
    isAutorefershDisabled() {
        /**This check is required on widget creation */
        if (this.config.isAutoRefreshEnabled === undefined) {
            return false;
        }
        return !this.config.isAutoRefreshEnabled;
    }
    minSelectedCheckboxes(min = 1) {
        const validator = (formGroup) => {
            const totalSelected = Object.values(formGroup.controls).reduce((prev, next) => (next.value ? prev + next.value : prev), 0);
            return totalSelected >= min ? null : { required: true };
        };
        return validator;
    }
    initializeTypes(types) {
        const typesControl = this.formGroup.get('types');
        if (types) {
            types.forEach(type => {
                typesControl.push(this.formBuilder.control(type));
            });
        }
        else {
            typesControl.push(this.formBuilder.control(''));
        }
    }
    initDateSelection() {
        this.dateSelection = this.config?.widgetInstanceGlobalTimeContext
            ? DATE_SELECTION.DASHBOARD_CONTEXT
            : this.config?.displayDateSelection
                ? DATE_SELECTION.VIEW_AND_CONFIG
                : DATE_SELECTION.CONFIG;
        this.dateSelectionChange(this.dateSelection);
        const interval = this.config?.interval ?? 'none';
        if (interval === 'none' || interval === 'custom') {
            return;
        }
        this.config.dateFilter = this.alarmsViewService.getDateTimeContextByInterval(this.config.interval);
        this.formGroup.patchValue({
            dateFilter: this.config.dateFilter
        });
    }
    /**
     * Initializes and handles the form change subscription for the Alarm list preview at Widget's configuration.
     *
     * This method subscribes to form value changes with a debounce time of 500ms.
     * It compares the previous and current form values to determine if the changes are relevant.
     * If the only change is in the `isAutoRefreshEnabled` property, the change is ignored.
     */
    handlePreviewSubscription() {
        this.formChangesSubscription = this.formGroup.valueChanges
            .pipe(startWith(this.formGroup.value), pairwise(), debounceTime(500))
            .subscribe(([previousConfig, currentConfig]) => {
            const typedPreviousConfig = previousConfig;
            const typedCurrentConfig = currentConfig;
            if (this.isOnlyAutoRefreshOrIntervalChanged(typedPreviousConfig, typedCurrentConfig)) {
                return;
            }
            if (this.alarmListWidgetService.allValuesFalse(typedCurrentConfig.severities) ||
                this.alarmListWidgetService.allValuesFalse(typedCurrentConfig.status)) {
                this.alarms$.next({ data: [], res: null });
                return;
            }
            this.getAlarms(typedCurrentConfig);
        });
    }
    /**
     * Determines if the only changes between two `AlarmListWidgetConfig` objects are in the `isAutoRefreshEnabled` and `refreshInterval` properties.
     *
     * This method compares two configurations by omitting `isAutoRefreshEnabled` and `refreshInterval`.
     * It returns true if these are the only properties that differ between the previous and current configurations.
     * Note that `refreshInterval` is relevant only when the refresh type is set to an interval.
     *
     * @param previousConfig - The previous configuration of `AlarmListWidgetConfig`.
     * @param currentConfig - The current configuration of `AlarmListWidgetConfig`.
     * @returns `true` if the differences are confined to `isAutoRefreshEnabled` and `refreshInterval`, `false` otherwise.
     */
    isOnlyAutoRefreshOrIntervalChanged(previousConfig, currentConfig) {
        const prevConfigCopy = omit(previousConfig, 'isAutoRefreshEnabled', 'refreshInterval');
        const currentConfigCopy = omit(currentConfig, 'isAutoRefreshEnabled', 'refreshInterval');
        return isEqual(prevConfigCopy, currentConfigCopy);
    }
    updateConfigBasedOnRefreshOption() {
        const isInterval = this.refreshOption === 'interval';
        this.config.isAutoRefreshEnabled = isInterval;
        this.formGroup.controls.isAutoRefreshEnabled.setValue(isInterval);
        isInterval
            ? this.formGroup.get('refreshInterval').enable()
            : this.formGroup.get('refreshInterval').disable();
    }
    static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: AlarmListWidgetConfigComponent, deps: [{ token: i1.AlarmWidgetService }, { token: i2.AlarmService }, { token: i3.AlarmsViewService }, { token: i4.AlertService }, { token: i5.NgForm }, { token: i5.FormBuilder }, { token: i6.TranslateService }], target: i0.ɵɵFactoryTarget.Component }); }
    static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.13", type: AlarmListWidgetConfigComponent, selector: "c8y-alarm-list-widget-config", inputs: { config: "config" }, usesOnChanges: true, ngImport: i0, template: "<div\n  class=\"p-l-24 p-r-24\"\n  [style.pointer-events]=\"'auto'\"\n  [style.opacity]=\"1\"\n></div>\n\n<form\n  class=\"row\"\n  [formGroup]=\"formGroup\"\n>\n  <div class=\"form-group col-md-12\">\n    <div class=\"d-flex a-i-center\">\n      <label\n        class=\"m-b-0\"\n        translate\n      >\n        Date selection\n      </label>\n      <button\n        class=\"btn-help btn-help--sm\"\n        [attr.aria-label]=\"'Help' | translate\"\n        [popover]=\"dateSelectionHelpTemplate\"\n        placement=\"bottom\"\n        triggers=\"focus\"\n        container=\"body\"\n        [adaptivePosition]=\"false\"\n      ></button>\n    </div>\n    <div class=\"c8y-select-wrapper\">\n      <select\n        class=\"form-control input-sm\"\n        [ngModel]=\"dateSelection\"\n        (ngModelChange)=\"dateSelectionChange($event)\"\n        [ngModelOptions]=\"{ standalone: true }\"\n      >\n        <option\n          title=\"{{ 'Widget configuration' | translate }}\"\n          [value]=\"DATE_SELECTION.CONFIG\"\n        >\n          {{ 'Widget configuration' | translate }}\n        </option>\n        <option\n          title=\"{{ 'Widget and widget configuration' | translate }}\"\n          [value]=\"DATE_SELECTION.VIEW_AND_CONFIG\"\n        >\n          {{ 'Widget and widget configuration' | translate }}\n        </option>\n        <option\n          title=\"{{ 'Dashboard time range' | translate }}\"\n          [value]=\"DATE_SELECTION.DASHBOARD_CONTEXT\"\n        >\n          {{ 'Dashboard time range' | translate }}\n        </option>\n      </select>\n      <span></span>\n    </div>\n  </div>\n  <div class=\"col-md-6\">\n    <fieldset class=\"c8y-fieldset\">\n      <legend>{{ 'Order`of items on a list, noun`' | translate }}</legend>\n      <c8y-form-group class=\"m-b-0\">\n        <div\n          class=\"d-flex m-b-8 a-i-center\"\n          *ngFor=\"let order of orderList; let i = index\"\n        >\n          <label\n            class=\"c8y-radio gap-4\"\n            title=\"{{ ALARM_ORDER_LABELS[order] | translate }}\"\n          >\n            <input\n              type=\"radio\"\n              [value]=\"order\"\n              formControlName=\"order\"\n            />\n            <span class=\"a-s-center\"></span>\n            <span class=\"text-truncate\">{{ ALARM_ORDER_LABELS[order] | translate }}</span>\n          </label>\n          <button\n            class=\"btn-help btn-help--sm\"\n            [attr.aria-label]=\"'Help' | translate\"\n            [popover]=\"order | sortingDescriptionPopoverMessage | translate\"\n            placement=\"right\"\n            triggers=\"focus\"\n            container=\"body\"\n            type=\"button\"\n            [adaptivePosition]=\"true\"\n          ></button>\n        </div>\n      </c8y-form-group>\n    </fieldset>\n    <fieldset\n      class=\"c8y-fieldset\"\n      formArrayName=\"severities\"\n    >\n      <legend>{{ 'Severities' | translate }}</legend>\n      <c8y-form-group\n        [hasError]=\"formGroup.controls.severities.hasError('required')\"\n        [ngClass]=\"{\n          'm-b-8': !formGroup.controls.severities.hasError('required')\n        }\"\n      >\n        <ng-container *ngFor=\"let severityOption of severityList\">\n          <label\n            class=\"c8y-checkbox m-t-0 gap-4\"\n            [title]=\"SEVERITY_LABELS[severityOption] | translate\"\n          >\n            <input\n              type=\"checkbox\"\n              [formControlName]=\"severityOption\"\n              [name]=\"severityOption\"\n            />\n            <span class=\"a-s-center\"></span>\n            <ng-container *ngIf=\"{ result: severityOption | severityIcon } as severityIcon\">\n              <i\n                class=\"a-s-center m-r-4 icon-20 {{ severityIcon.result.iconClass }}\"\n                [c8yIcon]=\"severityIcon.result.c8yIcon\"\n              ></i>\n            </ng-container>\n            <span>{{ SEVERITY_LABELS[severityOption] | translate }}</span>\n          </label>\n        </ng-container>\n        <c8y-messages>\n          <c8y-message *ngIf=\"formGroup.controls.severities.hasError('required')\">\n            {{ 'Select at least one severity.' | translate }}\n          </c8y-message>\n        </c8y-messages>\n      </c8y-form-group>\n    </fieldset>\n    <ng-container *ngIf=\"showDateFilter\">\n      <fieldset class=\"c8y-fieldset\">\n        <legend>{{ 'Date filter' | translate }}</legend>\n        <c8y-form-group class=\"m-b-8\">\n          <c8y-alarms-date-filter\n            [updateQueryParams]=\"false\"\n            [DEFAULT_INTERVAL]=\"config.interval || 'none'\"\n            formControlName=\"dateFilter\"\n            (dateFilterChange)=\"onDateFilterChange($event)\"\n          ></c8y-alarms-date-filter>\n        </c8y-form-group>\n      </fieldset>\n    </ng-container>\n  </div>\n\n  <div class=\"col-md-6\">\n    <fieldset\n      class=\"c8y-fieldset\"\n      formArrayName=\"status\"\n    >\n      <legend>{{ 'Status' | translate }}</legend>\n      <c8y-form-group\n        [hasError]=\"formGroup.controls.status.hasError('required')\"\n        [ngClass]=\"{\n          'm-b-8': !formGroup.controls.status.hasError('required')\n        }\"\n      >\n        <ng-container *ngFor=\"let statusOption of statusList\">\n          <label\n            class=\"c8y-checkbox m-t-0 gap-4\"\n            [title]=\"STATUS_LABELS[statusOption] | translate\"\n          >\n            <input\n              type=\"checkbox\"\n              [formControlName]=\"statusOption\"\n              [name]=\"statusOption\"\n            />\n            <span class=\"a-s-center\"></span>\n            <i\n              class=\"a-s-center m-l-4 m-r-4 text-gray-dark c8y-icon icon-20\"\n              [c8yIcon]=\"\n                statusOption === CLEARED_STATUS_VALUE\n                  ? C8Y_ALERT_IDLE_ICON\n                  : statusOption === ACKNOWLEDGE_STATUS_VALUE\n                    ? BELL_SLASH_ICON\n                    : BELL_ICON\n              \"\n            ></i>\n            <span>{{ STATUS_LABELS[statusOption] | translate }}</span>\n          </label>\n        </ng-container>\n        <c8y-messages>\n          <c8y-message *ngIf=\"formGroup.controls.status.hasError('required')\">\n            {{ 'Select at least one status.' | translate }}\n          </c8y-message>\n        </c8y-messages>\n      </c8y-form-group>\n    </fieldset>\n\n    <fieldset class=\"c8y-fieldset\">\n      <legend>{{ 'Child devices' | translate }}</legend>\n      <c8y-form-group class=\"m-b-8\">\n        <label\n          class=\"c8y-switch\"\n          [title]=\"'Show alarms from child devices' | translate\"\n        >\n          <input\n            type=\"checkbox\"\n            formControlName=\"showAlarmsForChildren\"\n          />\n          <span></span>\n          <span>{{ 'Show alarms' | translate }}</span>\n          <span class=\"sr-only\">{{ 'Show alarms' | translate }}</span>\n        </label>\n      </c8y-form-group>\n    </fieldset>\n\n    <fieldset class=\"c8y-fieldset\">\n      <legend>{{ 'Types' | translate }}</legend>\n      <c8y-form-group\n        class=\"m-b-8\"\n        formArrayName=\"types\"\n      >\n        <div\n          class=\"input-group\"\n          *ngFor=\"let type of types.controls; let i = index\"\n        >\n          <input\n            class=\"form-control\"\n            type=\"text\"\n            [placeholder]=\"'e.g. {{ example }}' | translate: { example: 'c8y_Alarm' }\"\n            [formControlName]=\"i\"\n          />\n          <div class=\"input-group-btn\">\n            <button\n              class=\"btn btn-dot btn-dot--danger m-l-auto\"\n              [title]=\"'Remove' | translate\"\n              type=\"button\"\n              (click)=\"removeType(i)\"\n              [disabled]=\"types.controls?.length === 1 && !type.value\"\n            >\n              <i c8yIcon=\"minus-circle\"></i>\n            </button>\n          </div>\n          <div\n            class=\"input-group-btn\"\n            *ngIf=\"i === types.controls.length - 1\"\n          >\n            <button\n              class=\"btn btn-dot btn-dot--primary m-l-auto\"\n              [title]=\"'Add alarm type' | translate\"\n              type=\"button\"\n              (click)=\"addType()\"\n            >\n              <i c8yIcon=\"plus-circle\"></i>\n            </button>\n          </div>\n        </div>\n      </c8y-form-group>\n    </fieldset>\n    <fieldset class=\"c8y-fieldset\">\n      <legend class=\"d-flex\">\n        {{ refreshTypeTitle }}\n        <button\n          class=\"btn-help btn-help--sm\"\n          [attr.aria-label]=\"'Help' | translate\"\n          [popover]=\"refreshTypePopoverMessage\"\n          placement=\"top\"\n          triggers=\"focus\"\n          container=\"body\"\n          type=\"button\"\n          [adaptivePosition]=\"true\"\n        ></button>\n      </legend>\n      <c8y-form-group class=\"m-b-8 form-group-sm\">\n        <div class=\"d-flex gap-8 a-i-center\">\n          <ng-template #realtime>\n            <label class=\"c8y-switch\">\n              <input\n                id=\"refreshToggle\"\n                name=\"isAutoRefreshEnabled\"\n                type=\"checkbox\"\n                formControlName=\"isAutoRefreshEnabled\"\n              />\n              <span></span>\n              <span class=\"sr-only\">{{ 'Realtime refresh' | translate }}</span>\n            </label>\n          </ng-template>\n          <div\n            class=\"c8y-select-wrapper\"\n            *ngIf=\"!config.isRealtime; else realtime\"\n          >\n            <select\n              class=\"form-control\"\n              title=\"{{ 'Refresh options`options for refreshing a view`' | translate }}\"\n              [(ngModel)]=\"refreshOption\"\n              [ngModelOptions]=\"{ standalone: true }\"\n              (change)=\"updateRefreshOption()\"\n            >\n              <option value=\"none\">\n                {{ 'No automatic refresh' | translate }}\n              </option>\n              <option\n                [title]=\"'Refreshing after the given interval' | translate\"\n                value=\"interval\"\n              >\n                {{ 'Use refresh interval' | translate }}\n              </option>\n              <option\n                [title]=\"'Refreshing after the given interval, synchronized globally' | translate\"\n                value=\"global-interval\"\n              >\n                {{ 'Use global refresh interval' | translate }}\n              </option>\n            </select>\n          </div>\n          <ng-container\n            *ngIf=\"!config.isRealtime && config.refreshOption !== GLOBAL_INTERVAL_OPTION\"\n          >\n            <label\n              class=\"m-b-0\"\n              for=\"refreshInterval\"\n            >\n              {{ 'Interval' | translate }}\n            </label>\n            <div class=\"c8y-select-wrapper flex-grow\">\n              <select\n                class=\"form-control text-12\"\n                [title]=\"'Refresh interval in seconds' | translate\"\n                id=\"refreshInterval\"\n                formControlName=\"refreshInterval\"\n              >\n                <option\n                  *ngFor=\"let refreshInterval of REFRESH_INTERVAL_IN_MILLISECONDS\"\n                  [ngValue]=\"refreshInterval\"\n                >\n                  {{ '{{ seconds }} s' | translate: { seconds: refreshInterval / 1000 } }}\n                </option>\n              </select>\n            </div>\n          </ng-container>\n        </div>\n      </c8y-form-group>\n    </fieldset>\n  </div>\n</form>\n\n<div class=\"legend form-block m-b-0\">{{ 'Preview`of an alarm list`' | translate }}</div>\n<c8y-alarms-list\n  [alarms]=\"alarms$ | async\"\n  [isInitialLoading]=\"isLoading\"\n  [navigationOptions]=\"{\n    allowNavigationToAlarmsView: false,\n    alwaysNavigateToAllAlarms: false,\n    includeClearedQueryParams: false,\n    queryParamsHandling: 'merge'\n  }\"\n></c8y-alarms-list>\n\n<ng-template #dateSelectionHelpTemplate>\n  <div [innerHTML]=\"dateSelectionHelp\"></div>\n</ng-template>\n", dependencies: [{ kind: "component", type: i3.AlarmsListComponent, selector: "c8y-alarms-list", inputs: ["alarms", "hasPermissions", "typeFilters", "loadMoreMode", "navigationOptions", "isInitialLoading", "splitView"], outputs: ["onSelectedAlarm", "onScrollingStateChange"] }, { kind: "component", type: i3.AlarmsDateFilterComponent, selector: "c8y-alarms-date-filter", inputs: ["DEFAULT_INTERVAL", "updateQueryParams", "date"], outputs: ["dateFilterChange"] }, { kind: "directive", type: i4.IconDirective, selector: "[c8yIcon]", inputs: ["c8yIcon"] }, { kind: "directive", type: i4.C8yTranslateDirective, selector: "[translate],[ngx-translate]" }, { 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: i5.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i5.NgSelectOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i5.ɵNgSelectMultipleOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i5.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i5.CheckboxControlValueAccessor, selector: "input[type=checkbox][formControlName],input[type=checkbox][formControl],input[type=checkbox][ngModel]" }, { kind: "directive", type: i5.SelectControlValueAccessor, selector: "select:not([multiple])[formControlName],select:not([multiple])[formControl],select:not([multiple])[ngModel]", inputs: ["compareWith"] }, { kind: "directive", type: i5.RadioControlValueAccessor, selector: "input[type=radio][formControlName],input[type=radio][formControl],input[type=radio][ngModel]", inputs: ["name", "formControlName", "value"] }, { kind: "directive", type: i5.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i5.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i5.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "component", type: i4.FormGroupComponent, selector: "c8y-form-group", inputs: ["hasError", "hasWarning", "hasSuccess", "novalidation", "status"] }, { kind: "directive", type: i4.MessageDirective, selector: "c8y-message", inputs: ["name", "text"] }, { kind: "component", type: i4.MessagesComponent, selector: "c8y-messages", inputs: ["show", "defaults", "helpMessage"] }, { kind: "directive", type: i4.RequiredInputPlaceholderDirective, selector: "input[required], input[formControlName]" }, { kind: "directive", type: i8.PopoverDirective, selector: "[popover]", inputs: ["adaptivePosition", "boundariesElement", "popover", "popoverContext", "popoverTitle", "placement", "outsideClick", "triggers", "container", "containerClass", "isOpen", "delay"], outputs: ["onShown", "onHidden"], exportAs: ["bs-popover"] }, { kind: "directive", type: i5.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i5.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "directive", type: i5.FormArrayName, selector: "[formArrayName]", inputs: ["formArrayName"] }, { kind: "pipe", type: i4.C8yTranslatePipe, name: "translate" }, { kind: "pipe", type: i7.AsyncPipe, name: "async" }, { kind: "pipe", type: i9.SeverityIconPipe, name: "severityIcon" }, { kind: "pipe", type: i10.SortingDescriptionPopoverMessagePipe, name: "sortingDescriptionPopoverMessage" }], viewProviders: [{ provide: ControlContainer, useExisting: NgForm }] }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: AlarmListWidgetConfigComponent, decorators: [{
            type: Component,
            args: [{ selector: 'c8y-alarm-list-widget-config', viewProviders: [{ provide: ControlContainer, useExisting: NgForm }], template: "<div\n  class=\"p-l-24 p-r-24\"\n  [style.pointer-events]=\"'auto'\"\n  [style.opacity]=\"1\"\n></div>\n\n<form\n  class=\"row\"\n  [formGroup]=\"formGroup\"\n>\n  <div class=\"form-group col-md-12\">\n    <div class=\"d-flex a-i-center\">\n      <label\n        class=\"m-b-0\"\n        translate\n      >\n        Date selection\n      </label>\n      <button\n        class=\"btn-help btn-help--sm\"\n        [attr.aria-label]=\"'Help' | translate\"\n        [popover]=\"dateSelectionHelpTemplate\"\n        placement=\"bottom\"\n        triggers=\"focus\"\n        container=\"body\"\n        [adaptivePosition]=\"false\"\n      ></button>\n    </div>\n    <div class=\"c8y-select-wrapper\">\n      <select\n        class=\"form-control input-sm\"\n        [ngModel]=\"dateSelection\"\n        (ngModelChange)=\"dateSelectionChange($event)\"\n        [ngModelOptions]=\"{ standalone: true }\"\n      >\n        <option\n          title=\"{{ 'Widget configuration' | translate }}\"\n          [value]=\"DATE_SELECTION.CONFIG\"\n        >\n          {{ 'Widget configuration' | translate }}\n        </option>\n        <option\n          title=\"{{ 'Widget and widget configuration' | translate }}\"\n          [value]=\"DATE_SELECTION.VIEW_AND_CONFIG\"\n        >\n          {{ 'Widget and widget configuration' | translate }}\n        </option>\n        <option\n          title=\"{{ 'Dashboard time range' | translate }}\"\n          [value]=\"DATE_SELECTION.DASHBOARD_CONTEXT\"\n        >\n          {{ 'Dashboard time range' | translate }}\n        </option>\n      </select>\n      <span></span>\n    </div>\n  </div>\n  <div class=\"col-md-6\">\n    <fieldset class=\"c8y-fieldset\">\n      <legend>{{ 'Order`of items on a list, noun`' | translate }}</legend>\n      <c8y-form-group class=\"m-b-0\">\n        <div\n          class=\"d-flex m-b-8 a-i-center\"\n          *ngFor=\"let order of orderList; let i = index\"\n        >\n          <label\n            class=\"c8y-radio gap-4\"\n            title=\"{{ ALARM_ORDER_LABELS[order] | translate }}\"\n          >\n            <input\n              type=\"radio\"\n              [value]=\"order\"\n              formControlName=\"order\"\n            />\n            <span class=\"a-s-center\"></span>\n            <span class=\"text-truncate\">{{ ALARM_ORDER_LABELS[order] | translate }}</span>\n          </label>\n          <button\n            class=\"btn-help btn-help--sm\"\n            [attr.aria-label]=\"'Help' | translate\"\n            [popover]=\"order | sortingDescriptionPopoverMessage | translate\"\n            placement=\"right\"\n            triggers=\"focus\"\n            container=\"body\"\n            type=\"button\"\n            [adaptivePosition]=\"true\"\n          ></button>\n        </div>\n      </c8y-form-group>\n    </fieldset>\n    <fieldset\n      class=\"c8y-fieldset\"\n      formArrayName=\"severities\"\n    >\n      <legend>{{ 'Severities' | translate }}</legend>\n      <c8y-form-group\n        [hasError]=\"formGroup.controls.severities.hasError('required')\"\n        [ngClass]=\"{\n          'm-b-8': !formGroup.controls.severities.hasError('required')\n        }\"\n      >\n        <ng-container *ngFor=\"let severityOption of severityList\">\n          <label\n            class=\"c8y-checkbox m-t-0 gap-4\"\n            [title]=\"SEVERITY_LABELS[severityOption] | translate\"\n          >\n            <input\n              type=\"checkbox\"\n              [formControlName]=\"severityOption\"\n              [name]=\"severityOption\"\n            />\n            <span class=\"a-s-center\"></span>\n            <ng-container *ngIf=\"{ result: severityOption | severityIcon } as severityIcon\">\n              <i\n                class=\"a-s-center m-r-4 icon-20 {{ severityIcon.result.iconClass }}\"\n                [c8yIcon]=\"severityIcon.result.c8yIcon\"\n              ></i>\n            </ng-container>\n            <span>{{ SEVERITY_LABELS[severityOption] | translate }}</span>\n          </label>\n        </ng-container>\n        <c8y-messages>\n          <c8y-message *ngIf=\"formGroup.controls.severities.hasError('required')\">\n            {{ 'Select at least one severity.' | translate }}\n          </c8y-message>\n        </c8y-messages>\n      </c8y-form-group>\n    </fieldset>\n    <ng-container *ngIf=\"showDateFilter\">\n      <fieldset class=\"c8y-fieldset\">\n        <legend>{{ 'Date filter' | translate }}</legend>\n        <c8y-form-group class=\"m-b-8\">\n          <c8y-alarms-date-filter\n            [updateQueryParams]=\"false\"\n            [DEFAULT_INTERVAL]=\"config.interval || 'none'\"\n            formControlName=\"dateFilter\"\n            (dateFilterChange)=\"onDateFilterChange($event)\"\n          ></c8y-alarms-date-filter>\n        </c8y-form-group>\n      </fieldset>\n    </ng-container>\n  </div>\n\n  <div class=\"col-md-6\">\n    <fieldset\n      class=\"c8y-fieldset\"\n      formArrayName=\"status\"\n    >\n      <legend>{{ 'Status' | translate }}</legend>\n      <c8y-form-group\n        [hasError]=\"formGroup.controls.status.hasError('required')\"\n        [ngClass]=\"{\n          'm-b-8': !formGroup.controls.status.hasError('required')\n        }\"\n      >\n        <ng-container *ngFor=\"let statusOption of statusList\">\n          <label\n            class=\"c8y-checkbox m-t-0 gap-4\"\n            [title]=\"STATUS_LABELS[statusOption] | translate\"\n          >\n            <input\n              type=\"checkbox\"\n              [formControlName]=\"statusOption\"\n              [name]=\"statusOption\"\n            />\n            <span class=\"a-s-center\"></span>\n            <i\n              class=\"a-s-center m-l-4 m-r-4 text-gray-dark c8y-icon icon-20\"\n              [c8yIcon]=\"\n                statusOption === CLEARED_STATUS_VALUE\n                  ? C8Y_ALERT_IDLE_ICON\n                  : statusOption === ACKNOWLEDGE_STATUS_VALUE\n                    ? BELL_SLASH_ICON\n                    : BELL_ICON\n              \"\n            ></i>\n            <span>{{ STATUS_LABELS[statusOption] | translate }}</span>\n          </label>\n        </ng-container>\n        <c8y-messages>\n          <c8y-message *ngIf=\"formGroup.controls.status.hasError('required')\">\n            {{ 'Select at least one status.' | translate }}\n          </c8y-message>\n        </c8y-messages>\n      </c8y-form-group>\n    </fieldset>\n\n    <fieldset class=\"c8y-fieldset\">\n      <legend>{{ 'Child devices' | translate }}</legend>\n      <c8y-form-group class=\"m-b-8\">\n        <label\n          class=\"c8y-switch\"\n          [title]=\"'Show alarms from child devices' | translate\"\n        >\n          <input\n            type=\"checkbox\"\n            formControlName=\"showAlarmsForChildren\"\n          />\n          <span></span>\n          <span>{{ 'Show alarms' | translate }}</span>\n          <span class=\"sr-only\">{{ 'Show alarms' | translate }}</span>\n        </label>\n      </c8y-form-group>\n    </fieldset>\n\n    <fieldset class=\"c8y-fieldset\">\n      <legend>{{ 'Types' | translate }}</legend>\n      <c8y-form-group\n        class=\"m-b-8\"\n        formArrayName=\"types\"\n      >\n        <div\n          class=\"input-group\"\n          *ngFor=\"let type of types.controls; let i = index\"\n        >\n          <input\n            class=\"form-control\"\n            type=\"text\"\n            [placeholder]=\"'e.g. {{ example }}' | translate: { example: 'c8y_Alarm' }\"\n            [formControlName]=\"i\"\n          />\n          <div class=\"input-group-btn\">\n            <button\n              class=\"btn btn-dot btn-dot--danger m-l-auto\"\n              [title]=\"'Remove' | translate\"\n              type=\"button\"\n              (click)=\"removeType(i)\"\n              [disabled]=\"types.controls?.length === 1 && !type.value\"\n            >\n              <i c8yIcon=\"minus-circle\"></i>\n            </button>\n          </div>\n          <div\n            class=\"input-group-btn\"\n            *ngIf=\"i === types.controls.length - 1\"\n          >\n            <button\n              class=\"btn btn-dot btn-dot--primary m-l-auto\"\n              [title]=\"'Add alarm type' | translate\"\n              type=\"button\"\n              (click)=\"addType()\"\n            >\n              <i c8yIcon=\"plus-circle\"></i>\n            </button>\n          </div>\n        </div>\n      </c8y-form-group>\n    </fieldset>\n    <fieldset class=\"c8y-fieldset\">\n      <legend class=\"d-flex\">\n        {{ refreshTypeTitle }}\n        <button\n          class=\"btn-help btn-help--sm\"\n          [attr.aria-label]=\"'Help' | translate\"\n          [popover]=\"refreshTypePopoverMessage\"\n          placement=\"top\"\n          triggers=\"focus\"\n          container=\"body\"\n          type=\"button\"\n          [adaptivePosition]=\"true\"\n        ></button>\n      </legend>\n      <c8y-form-group class=\"m-b-8 form-group-sm\">\n        <div class=\"d-flex gap-8 a-i-center\">\n          <ng-template #realtime>\n            <label class=\"c8y-switch\">\n              <input\n                id=\"refreshToggle\"\n                name=\"isAutoRefreshEnabled\"\n                type=\"checkbox\"\n                formControlName=\"isAutoRefreshEnabled\"\n              />\n              <span></span>\n              <span class=\"sr-only\">{{ 'Realtime refresh' | translate }}</span>\n            </label>\n          </ng-template>\n          <div\n            class=\"c8y-select-wrapper\"\n            *ngIf=\"!config.isRealtime; else realtime\"\n          >\n            <select\n              class=\"form-control\"\n              title=\"{{ 'Refresh options`options for refreshing a view`' | translate }}\"\n              [(ngModel)]=\"refreshOption\"\n              [ngModelOptions]=\"{ standalone: true }\"\n              (change)=\"updateRefreshOption()\"\n            >\n              <option value=\"none\">\n                {{ 'No automatic refresh' | translate }}\n              </option>\n              <option\n                [title]=\"'Refreshing after the given interval' | translate\"\n                value=\"interval\"\n              >\n                {{ 'Use refresh interval' | translate }}\n              </option>\n              <option\n                [title]=\"'Refreshing after the given interval, synchronized globally' | translate\"\n                value=\"global-interval\"\n              >\n                {{ 'Use global refresh interval' | translate }}\n              </option>\n            </select>\n          </div>\n          <ng-container\n            *ngIf=\"!config.isRealtime && config.refreshOption !== GLOBAL_INTERVAL_OPTION\"\n          >\n            <label\n              class=\"m-b-0\"\n              for=\"refreshInterval\"\n            >\n              {{ 'Interval' | translate }}\n            </label>\n            <div class=\"c8y-select-wrapper flex-grow\">\n              <select\n                class=\"form-control text-12\"\n                [title]=\"'Refresh interval in seconds' | translate\"\n                id=\"refreshInterval\"\n                formControlName=\"refreshInterval\"\n              >\n                <option\n                  *ngFor=\"let refreshInterval of REFRESH_INTERVAL_IN_MILLISECONDS\"\n                  [ngValue]=\"refreshInterval\"\n                >\n                  {{ '{{ seconds }} s' | translate: { seconds: refreshInterval / 1000 } }}\n                </option>\n              </select>\n            </div>\n          </ng-container>\n        </div>\n      </c8y-form-group>\n    </fieldset>\n  </div>\n</form>\n\n<div class=\"legend form-block m-b-0\">{{ 'Preview`of an alarm list`' | translate }}</div>\n<c8y-alarms-list\n  [alarms]=\"alarms$ | async\"\n  [isInitialLoading]=\"isLoading\"\n  [navigationOptions]=\"{\n    allowNavigationToAlarmsView: false,\n    alwaysNavigateToAllAlarms: false,\n    includeClearedQueryParams: false,\n    queryParamsHandling: 'merge'\n  }\"\n></c8y-alarms-list>\n\n<ng-template #dateSelectionHelpTemplate>\n  <div [innerHTML]=\"dateSelectionHelp\"></div>\n</ng-template>\n" }]
        }], ctorParameters: () => [{ type: i1.AlarmWidgetService }, { type: i2.AlarmService }, { type: i3.AlarmsViewService }, { type: i4.AlertService }, { type: i5.NgForm }, { type: i5.FormBuilder }, { type: i6.TranslateService }], propDecorators: { config: [{
                type: Input
            }] } });
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYWxhcm0tbGlzdC13aWRnZXQtY29uZmlnLmNvbXBvbmVudC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uLy4uLy4uL3dpZGdldHMvaW1wbGVtZW50YXRpb25zL2FsYXJtcy9hbGFybS1saXN0LXdpZGdldC1jb25maWcvYWxhcm0tbGlzdC13aWRnZXQtY29uZmlnLmNvbXBvbmVudC50cyIsIi4uLy4uLy4uLy4uLy4uLy4uL3dpZGdldHMvaW1wbGVtZW50YXRpb25zL2FsYXJtcy9hbGFybS1saXN0LXdpZGdldC1jb25maWcvYWxhcm0tbGlzdC13aWRnZXQtY29uZmlnLmNvbXBvbmVudC5odG1sIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sRUFBRSxTQUFTLEVBQUUsS0FBSyxFQUErQyxNQUFNLGVBQWUsQ0FBQztBQUM5RixPQUFPLEVBQ0wsZ0JBQWdCLEVBRWhCLFdBQVcsRUFDWCxXQUFXLEVBRVgsTUFBTSxFQUVQLE1BQU0sZ0JBQWdCLENBQUM7QUFDeEIsT0FBTyxFQUNMLG1CQUFtQixFQUNuQixXQUFXLEVBQ1gsWUFBWSxFQUdaLGVBQWUsRUFDaEIsTUFBTSxhQUFhLENBQUM7QUFDckIsT0FBTyxFQUFFLFlBQVksRUFBZ0IsT0FBTyxFQUFFLE1BQU0scUJBQXFCLENBQUM7QUFDMUUsT0FBTyxFQUNMLGlCQUFpQixFQUNqQixpQkFBaUIsRUFDakIsdUJBQXVCLEVBQ3ZCLHFCQUFxQixFQUN0QixNQUFNLDRCQUE0QixDQUFDO0FBQ3BDLE9BQU8sRUFBRSxnQkFBZ0IsRUFBRSxNQUFNLHFCQUFxQixDQUFDO0FBQ3ZELE9BQU8sRUFBRSxPQUFPLEVBQUUsSUFBSSxFQUFFLE1BQU0sV0FBVyxDQUFDO0FBQzFDLE9BQU8sRUFBRSxlQUFlLEVBQTRCLE1BQU0sTUFBTSxDQUFDO0FBQ2pFLE9BQU8sRUFBRSxZQUFZLEVBQUUsUUFBUSxFQUFFLFNBQVMsRUFBRSxNQUFNLGdCQUFnQixDQUFDO0FBQ25FLE9BQU8sRUFDTCxr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SUFDdEQsQ0FBQzsrR0F2V1UsOEJBQThCO21HQUE5Qiw4QkFBOEIsdUhDOUMzQyxzM1hBOFZBLDRqSURsVGlCLENBQUMsRUFBRSxPQUFPLEVBQUUsZ0JBQWdCLEVBQUUsV0FBVyxFQUFFLE1BQU0sRUFBRSxDQUFDOzs0RkFFeEQsOEJBQThCO2tCQUwxQyxTQUFTOytCQUNFLDhCQUE4QixpQkFFekIsQ0FBQyxFQUFFLE9BQU8sRUFBRSxnQkFBZ0IsRUFBRSxXQUFXLEVBQUUsTUFBTSxFQUFFLENBQUM7MlBBRzFELE1BQU07c0JBQWQsS0FBSyIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IENvbXBvbmVudCwgSW5wdXQsIE9uQ2hhbmdlcywgT25EZXN0cm95LCBPbkluaXQsIFNpbXBsZUNoYW5nZXMgfSBmcm9tICdAYW5ndWxhci9jb3JlJztcbmltcG9ydCB7XG4gIENvbnRyb2xDb250YWluZXIsXG4gIEZvcm1BcnJheSxcbiAgRm9ybUJ1aWxkZXIsXG4gIEZvcm1Db250cm9sLFxuICBGb3JtR3JvdXAsXG4gIE5nRm9ybSxcbiAgVmFsaWRhdG9yRm5cbn0gZnJvbSAnQGFuZ3VsYXIvZm9ybXMnO1xuaW1wb3J0IHtcbiAgQUxBUk1fU1RBVFVTX0xBQkVMUyxcbiAgQWxhcm1TdGF0dXMsXG4gIEFsYXJtU2VydmljZSxcbiAgSUFsYXJtLFxuICBJUmVzdWx0TGlzdCxcbiAgU0VWRVJJVFlfTEFCRUxTXG59IGZyb20gJ0BjOHkvY2xpZW50JztcbmltcG9ydCB7IEFsZXJ0U2VydmljZSwgT25CZWZvcmVTYXZlLCBnZXR0ZXh0IH0gZnJvbSAnQGM4eS9uZ3gtY29tcG9uZW50cyc7XG5pbXBvcnQge1xuICBBTEFSTV9TVEFUVVNfSUNPTixcbiAgQWxhcm1zVmlld1NlcnZpY2UsXG4gIERFRkFVTFRfU0VWRVJJVFlfVkFMVUVTLFxuICBERUZBVUxUX1NUQVRVU19WQUxVRVNcbn0gZnJvbSAnQGM4eS9uZ3gtY29tcG9uZW50cy9hbGFybXMnO1xuaW1wb3J0IHsgVHJhbnNsYXRlU2VydmljZSB9IGZyb20gJ0BuZ3gtdHJhbnNsYXRlL2NvcmUnO1xuaW1wb3J0IHsgaXNFcXVhbCwgb21pdCB9IGZyb20gJ2xvZGFzaC1lcyc7XG5pbXBvcnQgeyBCZWhhdmlvclN1YmplY3QsIE9ic2VydmFibGUsIFN1YnNjcmlwdGlvbiB9IGZyb20gJ3J4anMnO1xuaW1wb3J0IHsgZGVib3VuY2VUaW1lLCBwYWlyd2lzZSwgc3RhcnRXaXRoIH0gZnJvbSAncnhqcy9vcGVyYXRvcnMnO1xuaW1wb3J0IHtcbiAgQUxBUk1fT1JERVJfTEFCRUxTLFxuICBBTEFSTV9PUkRFUl9WQUxVRVMsXG4gIEFsYXJtTGlzdFdpZGdldENvbmZpZyxcbiAgQWxhcm1PcmRlclR5cGUsXG4gIERBVEVfU0VMRUNUSU9OLFxuICBBbGFybUxpc3RSZWZyZXNoT3B0aW9uLFxuICBHTE9CQUxfSU5URVJWQUxfT1BUSU9OXG59IGZyb20gJy4uL2FsYXJtLWxpc3Qtd2lkZ2V0Lm1vZGVsJztcbmltcG9ydCB7IEFsYXJtV2lkZ2V0U2VydmljZSwgREVGQVVMVF9QQUdFX1NJWkUgfSBmcm9tICcuLi9hbGFybS13aWRnZXQuc2VydmljZSc7XG5pbXBvcnQgeyBJbnRlcnZhbCB9IGZyb20gJ0BjOHkvbmd4LWNvbXBvbmVudHMvaW50ZXJ2YWwtcGlja2VyJztcblxuQENvbXBvbmVudCh7XG4gIHNlbGVjdG9yOiAnYzh5LWFsYXJtLWxpc3Qtd2lkZ2V0LWNvbmZpZycsXG4gIHRlbXBsYXRlVXJsOiAnLi9hbGFybS1saXN0LXdpZGdldC1jb25maWcuY29tcG9uZW50Lmh0bWwnLFxuICB2aWV3UHJvdmlkZXJzOiBbeyBwcm92aWRlOiBDb250cm9sQ29udGFpbmVyLCB1c2VFeGlzdGluZzogTmdGb3JtIH1dXG59KVxuZXhwb3J0IGNsYXNzIEFsYXJtTGlzdFdpZGdldENvbmZpZ0NvbXBvbmVudCBpbXBsZW1lbnRzIE9uSW5pdCwgT25DaGFuZ2VzLCBPbkJlZm9yZVNhdmUsIE9uRGVzdHJveSB7XG4gIEBJbnB1dCgpIGNvbmZpZzogQWxhcm1MaXN0V2lkZ2V0Q29uZmlnO1xuXG4gIHJlYWRvbmx5IFJFRlJFU0hfSU5URVJWQUxfSU5fTUlMTElTRUNPTkRTID0gdGhpcy5hbGFybXNWaWV3U2VydmljZS5ERUZBVUxUX0lOVEVSVkFMX1ZBTFVFUztcbiAgcmVhZG9ubHkgU0VWRVJJVFlfTEFCRUxTID0gU0VWRVJJVFlfTEFCRUxTO1xuICByZWFkb25seSBTVEFUVVNfTEFCRUxTID0gQUxBUk1fU1RBVFVTX0xBQkVMUztcblxuICByZWFkb25seSBBQ0tOT1dMRURHRV9TVEFUVVNfVkFMVUUgPSBBbGFybVN0YXR1cy5BQ0tOT1dMRURHRUQ7XG4gIHJlYWRvbmx5IENMRUFSRURfU1RBVFVTX1ZBTFVFID0gQWxhcm1TdGF0dXMuQ0xFQVJFRDtcblxuICByZWFkb25seSBCRUxMX1NMQVNIX0lDT04gPSBBTEFSTV9TVEFUVVNfSUNPTi5CRUxMX1NMQVNIO1xuICByZWFkb25seSBCRUxMX0lDT04gPSBBTEFSTV9TVEFUVVNfSUNPTi5CRUxMO1xuICByZWFkb25seSBDOFlfQUxFUlRfSURMRV9JQ09OID0gQUxBUk1fU1RBVFVTX0lDT04uQUxFUlRfSURMRTtcblxuICByZWFkb25seSBBTEFSTV9PUkRFUl9MQUJFTFMgPSBBTEFSTV9PUkRFUl9MQUJFTFM7XG4gIHJlYWRvbmx5IEdMT0JBTF9JTlRFUlZBTF9PUFRJT04gPSBHTE9CQUxfSU5URVJWQUxfT1BUSU9OO1xuXG4gIGFsYXJtcyQ6IEJlaGF2aW9yU3ViamVjdDxJUmVzdWx0TGlzdDxJQWxhcm0+IHwgbnVsbD4gPSBuZXcgQmVoYXZpb3JTdWJqZWN0KG51bGwpO1xuICBmb3JtR3JvdXA6IFJldHVyblR5cGU8QWxhcm1MaXN0V2lkZ2V0Q29uZmlnQ29tcG9uZW50WydjcmVhdGVGb3JtJ10+O1xuXG4gIGlzTG9hZGluZzogYm9vbGVhbjtcbiAgb3JkZXJMaXN0ID0gT2JqZWN0LnZhbHVlcyhBTEFSTV9PUkRFUl9WQUxVRVMpO1xuICByZWZyZXNoVHlwZVBvcG92ZXJNZXNzYWdlOiBzdHJpbmc7XG4gIHJlZnJlc2hUeXBlVGl0bGU6IHN0cmluZztcbiAgc2V2ZXJpdHlMaXN0ID0gT2JqZWN0LmtleXMoU0VWRVJJVFlfTEFCRUxTKTtcbiAgc2hvd0RhdGVGaWx0ZXIgPSB0cnVlO1xuICBEQVRFX1NFTEVDVElPTiA9IERBVEVfU0VMRUNUSU9OO1xuICBkYXRlU2VsZWN0aW9uOiBEQVRFX1NFTEVDVElPTiB8IHVuZGVmaW5lZDtcbiAgZGF0ZVNlbGVjdGlvbkhlbHAgPSB0aGlzLnRyYW5zbGF0ZVNlcnZpY2UuaW5zdGFudChcbiAgICBnZXR0ZXh0KGBDaG9vc2UgaG93IHRvIHNlbGVjdCBhIGRhdGUgcmFuZ2UsIHRoZSBhdmFpbGFibGUgb3B0aW9ucyBhcmU6XG4gIDx1bCBjbGFzcz1cIm0tbC0wIHAtbC04IG0tdC04IG0tYi0wXCI+XG4gICAgPGxpPlxuICAgICAgPGI+V2lkZ2V0IGNvbmZpZ3VyYXRpb246PC9iPlxuICAgICAgcmVzdHJpY3RzIHRoZSBkYXRlIHNlbGVjdGlvbiBvbmx5IHRvIHRoZSB3aWRnZXQgY29uZmlndXJhdGlvblxuICAgIDwvbGk+XG4gICAgPGxpPlxuICAgICAgPGI+V2lkZ2V0IGFuZCB3aWRnZXQgY29uZmlndXJhdGlvbjo8L2I+XG4gICAgICByZXN0cmljdHMgdGhlIGRhdGUgc2VsZWN0aW9uIHRvIHRoZSB3aWRnZXQgdmlldyBhbmQgd2lkZ2V0IGNvbmZpZ3VyYXRpb24gb25seVxuICAgIDwvbGk+XG4gICAgPGxpPlxuICAgICAgPGI+RGFzaGJvYXJkIHRpbWUgcmFuZ2U6PC9iPlxuICAgICAgcmVzdHJpY3RzIGRhdGUgc2VsZWN0aW9uIHRvIHRoZSBnbG9iYWwgZGFzaGJvYXJkIGNvbmZpZ3VyYXRpb24gb25seVxuICAgIDwvbGk+XG4gIDwvdWw+YClcbiAgKTtcbiAgcmVmcmVzaE9wdGlvbjogQWxhcm1MaXN0UmVmcmVzaE9wdGlvbjtcbiAgLyoqXG4gICAqIE9yZGVyIGRvZXMgbWF0dGVyLlxuICAgKi9cbiAgc3RhdHVzTGlzdCA9IFtBbGFybVN0YXR1cy5BQ1RJVkUsIEFsYXJtU3RhdHVzLkFDS05PV0xFREdFRCwgQWxhcm1TdGF0dXMuQ0xFQVJFRF07XG5cbiAgcHJpdmF0ZSBmb3JtQ2hhbmdlc1N1YnNjcmlwdGlvbjogU3Vic2NyaXB0aW9uO1xuXG4gIGNvbnN0cnVjdG9yKFxuICAgIHByaXZhdGUgYWxhcm1MaXN0V2lkZ2V0U2VydmljZTogQWxhcm1XaWRnZXRTZXJ2aWNlLFxuICAgIHByaXZhdGUgYWxhcm1TZXJ2aWNlOiBBbGFybVNlcnZpY2UsXG4gICAgcHJpdmF0ZSBhbGFybXNWaWV3U2VydmljZTogQWxhcm1zVmlld1NlcnZpY2UsXG4gICAgcHJpdmF0ZSBhbGVydFNlcnZpY2U6IEFsZXJ0U2VydmljZSxcbiAgICBwcml2YXRlIGZvcm06IE5nRm9ybSxcbiAgICBwcml2YXRlIGZvcm1CdWlsZGVyOiBGb3JtQnVpbGRlcixcbiAgICBwcml2YXRlIHRyYW5zbGF0ZVNlcnZpY2U6IFRyYW5zbGF0ZVNlcnZpY2VcbiAgKSB7fVxuXG4gIGFzeW5jIG5nT25Jbml0KCk6IFByb21pc2U8dm9pZD4ge1xuICAgIHRoaXMucmVmcmVzaFR5cGVUaXRsZSA9IHRoaXMuY29uZmlnLmlzUmVhbHRpbWVcbiAgICAgID8gdGhpcy50cmFuc2xhdGVTZXJ2aWNlLmluc3RhbnQoZ2V0dGV4dCgnUmVhbHRpbWUnKSlcbiAgICAgIDogdGhpcy50cmFuc2xhdGVTZXJ2aWNlLmluc3RhbnQoZ2V0dGV4dCgnQXV0byByZWZyZXNoJykpO1xuXG4gICAgdGhpcy5yZWZyZXNoVHlwZVBvcG92ZXJNZXNzYWdlID0gdGhpcy5jb25maWcuaXNSZWFsdGltZVxuICAgICAgPyB0aGlzLnRyYW5zbGF0ZVNlcnZpY2UuaW5zdGFudChnZXR0ZXh0KCdDaGFuZ2UgdGhlIGRlZmF1bHQgc3RhdGUgb2YgcmVhbHRpbWUgcmVmcmVzaC4nKSlcbiAgICAgIDogdGhpcy50cmFuc2xhdGVTZXJ2aWNlLmluc3RhbnQoXG4gICAgICAgICAgZ2V0dGV4dCgnQ2hhbmdlIHRoZSBzdGF0ZSBvZiBpbnRlcnZhbCBhdXRvbWF0aWMgcmVmcmVzaCBhbmQgc2V0IHRoZSByZWZyZXNoIGZyZXF1ZW5jeS4nKVxuICAgICAgICApO1xuXG4gICAgdGhpcy5pbml0aWFsaXplRm9ybSgpO1xuXG4gICAgaWYgKCF0aGlzLmNvbmZpZy5pc1JlYWx0aW1lKSB7XG4gICAgICB0aGlzLnVwZGF0ZUNvbmZpZ0Jhc2VkT25SZWZyZXNoT3B0aW9uKCk7XG4gICAgfVxuICAgIHRoaXMuY29uZmlnLmlzUmVhbHRpbWUgPSAhdGhpcy5hbGFybXNWaWV3U2VydmljZS5pc0ludGVydmFsUmVmcmVzaCgpO1xuXG4gICAgY29uc3QgaXNXaWRnZXRXaXRoRXhpc3RpbmdDb25maWcgPVxuICAgICAgdGhpcy5jb25maWcub3JkZXIgJiYgdGhpcy5jb25maWcuc2V2ZXJpdGllcyAmJiB0aGlzLmNvbmZpZy5zdGF0dXM7XG5cbiAgICBpZiAoaXNXaWRnZXRXaXRoRXhpc3RpbmdDb25maWcpIHtcbiAgICAgIGF3YWl0IHRoaXMuZ2V0QWxhcm1zKHRoaXMuY29uZmlnKTtcbiAgICB9IGVsc2Uge1xuICAgICAgLyoqIFVzZWQgd2hlbiBjcmVhdGluZyBhIG5ldyB3aWRnZXQgKi9cbiAgICAgIGF3YWl0IHRoaXMuZ2V0QWxhcm1zKHRoaXMuZm9ybUdyb3VwLnZhbHVlIGFzIEFsYXJtTGlzdFdpZGdldENvbmZpZyk7XG4gICAgfVxuICAgIHRoaXMuaGFuZGxlUHJldmlld1N1YnNjcmlwdGlvbigpO1xuICB9XG5cbiAgbmdPbkNoYW5nZXMoY2hhbmdlczogU2ltcGxlQ2hhbmdlcyk6IHZvaWQge1xuICAgIGlmICh0aGlzLmZvcm1Hcm91cCAmJiBjaGFuZ2VzLmNvbmZpZykge1xuICAgICAgdGhpcy5mb3JtR3JvdXAuZ2V0KCdkZXZpY2UnKS5wYXRjaFZhbHVlKHRoaXMuY29uZmlnLmRldmljZSk7XG4gICAgfVxuICB9XG5cbiAgbmdPbkRlc3Ryb3koKTogdm9pZCB7XG4gICAgdGhpcy5mb3JtQ2hhbmdlc1N1YnNjcmlwdGlvbj8udW5zdWJzY3JpYmUoKTtcbiAgfVxuXG4gIG9uQmVmb3JlU2F2ZShjb25maWc/OiBBbGFybUxpc3RXaWRnZXRDb25maWcpOiBib29sZWFuIHwgUHJvbWlzZTxib29sZWFuPiB8IE9ic2VydmFibGU8Ym9vbGVhbj4ge1xuICAgIGNvbnN0IHsgdHlwZXMgfSA9IHRoaXMuZm9ybUdyb3VwLnZhbHVlO1xuICAgIGlmICh0eXBlcy5sZW5ndGggPiAxKSB7XG4gICAgICBjb25zdCBzdHJpbmdUeXBlcyA9IHR5cGVzIGFzIHN0cmluZ1tdO1xuXG4gICAgICBpZiAodGhpcy5pc0NvbnRhaW5pbmdPbmx5RW1wdHlUeXBlcyhzdHJpbmdUeXBlcykpIHtcbiAgICAgICAgdGhpcy5mb3JtR3JvdXAudmFsdWUudHlwZXMgPSBbJyddO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgdGhpcy5mb3JtR3JvdXAudmFsdWUudHlwZXMgPSB0aGlzLmZpbHRlckVtcHR5VHlwZXMoc3RyaW5nVHlwZXMpO1xuICAgICAgfVxuICAgIH1cblxuICAgIC8qKlxuICAgICAqIEFwcGxpZXMgb25seSB0byBjb252ZXJ0ZWQgbGVnYWN5IEFsYXJtIGxpc3Qgd2lkZ2V0XG4gICAgICovXG4gICAgaWYgKGNvbmZpZ1snb3B0aW9ucyddKSB7XG4gICAgICBkZWxldGUgY29uZmlnWydvcHRpb25zJ107XG4gICAgfVxuXG4gICAgT2JqZWN0LmFzc2lnbihjb25maWcsIHRoaXMuZm9ybUdyb3VwLnZhbHVlKTtcbiAgICByZXR1cm4gdHJ1ZTtcbiAgfVxuXG4gIG9uRGF0ZUZpbHRlckNoYW5nZShldmVudDogeyBzZWxlY3RlZERhdGVzOiBbRGF0ZSwgRGF0ZV07IGludGVydmFsOiBJbnRlcnZhbFsnaWQnXSB9KSB7XG4gICAgdGhpcy5mb3JtR3JvdXAucGF0Y2hWYWx1ZSh7XG4gICAgICBkYXRlRmlsdGVyOiBldmVudC5zZWxlY3RlZERhdGVzLFxuICAgICAgaW50ZXJ2YWw6IGV2ZW50LmludGVydmFsXG4gICAgfSk7XG4gIH1cblxuICByZW1vdmVUeXBlKGluZGV4OiBudW1iZXIpOiB2b2lkIHtcbiAgICBpZiAodGhpcy50eXBlcy5jb250cm9scy5sZW5ndGggPT09IDEpIHtcbiAgICAgIHRoaXMuZm9ybUdyb3VwLmdldCgndHlwZXMnKS5yZXNldCgpO1xuICAgIH0gZWxzZSB7XG4gICAgICB0aGlzLnR5cGVzLnJlbW92ZUF0KGluZGV4KTtcbiAgICB9XG4gIH1cblxuICBhZGRUeXBlKCk6IHZvaWQge1xuICAgIHRoaXMudHlwZXMucHVzaCh0aGlzLmZvcm1CdWlsZGVyLmNvbnRyb2woJycpKTtcbiAgfVxuXG4gIHVwZGF0ZVJlZnJlc2hPcHRpb24oKSB7XG4gICAgdGhpcy5jb25maWcucmVmcmVzaE9wdGlvbiA9IHRoaXMucmVmcmVzaE9wdGlvbjtcbiAgICB0aGlzLmZvcm1Hcm91cC5jb250cm9scy5yZWZyZXNoT3B0aW9uLnNldFZhbHVlKHRoaXMucmVmcmVzaE9wdGlvbik7XG4gICAgY29uc3QgaXNHbG9iYWxJbnRlcnZhbCA9IHRoaXMucmVmcmVzaE9wdGlvbiA9PT0gR0xPQkFMX0lOVEVSVkFMX09QVElPTjtcblxuICAgIHRoaXMuY29uZmlnLndpZGdldEluc3RhbmNlR2xvYmFsQXV0b1JlZnJlc2hDb250ZXh0ID0gaXNHbG9iYWxJbnRlcnZhbDtcbiAgICB0aGlzLmZvcm1Hcm91cC5jb250cm9scy53aWRnZXRJbnN0YW5jZUdsb2JhbEF1dG9SZWZyZXNoQ29udGV4dC5zZXRWYWx1ZShpc0dsb2JhbEludGVydmFsKTtcblxuICAgIHRoaXMudXBkYXRlQ29uZmlnQmFzZWRPblJlZnJlc2hPcHRpb24oKTtcbiAgfVxuXG4gIGdldCB0eXBlcygpOiBGb3JtQXJyYXkge1xuICAgIHJldHVybiB0aGlzLmZvcm1Hcm91cC5nZXQoJ3R5cGVzJykgYXMgRm9ybUFycmF5O1xuICB9XG5cbiAgZGF0ZVNlbGVjdGlvbkNoYW5nZShkYXRlU2VsZWN0aW9uOiBEQVRFX1NFTEVDVElPTik6IHZvaWQge1xuICAgIGlmIChkYXRlU2VsZWN0aW9uID09PSBEQVRFX1NFTEVDVElPTi5DT05GSUcpIHtcbiAgICAgIHRoaXMuc2hvd0RhdGVGaWx0ZXIgPSB0cnVlO1xuICAgICAgdGhpcy5mb3JtR3JvdXAucGF0Y2hWYWx1ZSh7XG4gICAgICAgIGRpc3BsYXlEYXRlU2VsZWN0aW9uOiBmYWxzZSxcbiAgICAgICAgd2lkZ2V0SW5zdGFuY2VHbG9iYWxUaW1lQ29udGV4dDogZmFsc2VcbiAgICAgIH0pO1xuICAgIH0gZWxzZSBpZiAoZGF0ZVNlbGVjdGlvbiA9PT0gREFURV9TRUxFQ1RJT04uVklFV19BTkRfQ09ORklHKSB7XG4gICAgICB0aGlzLnNob3dEYXRlRmlsdGVyID0gdHJ1ZTtcbiAgICAgIHRoaXMuZm9ybUdyb3VwLnBhdGNoVmFsdWUoe1xuICAgICAgICBkaXNwbGF5RGF0ZVNlbGVjdGlvbjogdHJ1ZSxcbiAgICAgICAgd2lkZ2V0SW5zdGFuY2VHbG9iYWxUaW1lQ29udGV4dDogZmFsc2VcbiAgICAgIH0pO1xuICAgIH0gZWxzZSBpZiAoZGF0ZVNlbGVjdGlvbiA9PT0gREFURV9TRUxFQ1RJT04uREFTSEJPQVJEX0NPTlRFWFQpIHtcbiAgICAgIHRoaXMuc2hvd0RhdGVGaWx0ZXIgPSBmYWxzZTtcbiAgICAgIHRoaXMuZm9ybUdyb3VwLnBhdGNoVmFsdWUoe1xuICAgICAgICBkaXNwbGF5RGF0ZVNlbGVjdGlvbjogZmFsc2UsXG4gICAgICAgIHdpZGdldEluc3RhbmNlR2xvYmFsVGltZUNvbnRleHQ6IHRydWVcbiAgICAgIH0pO1xuICAgIH1cbiAgfVxuXG4gIHByaXZhdGUgZmlsdGVyRW1wdHlUeXBlcyh0eXBlczogKHN0cmluZyB8IG51bGwpW10pOiBzdHJpbmdbXSB7XG4gICAgcmV0dXJuIHR5cGVzLmZpbHRlcigoZWxlbWVudDogc3RyaW5nIHwgbnVsbCkgPT4gZWxlbWVudCAhPT0gJycgJiYgZWxlbWVudCAhPT0gbnVsbCk7XG4gIH1cblxuICBwcml2YXRlIGlzQ29udGFpbmluZ09ubHlFbXB0eVR5cGVzKHR5cGVzOiAoc3RyaW5nIHwgbnVsbClbXSk6IGJvb2xlYW4ge1xuICAgIHJldHVybiB0eXBlcy5ldmVyeSgoZWxlbWVudDogc3RyaW5nIHwgbnVsbCkgPT4gZWxlbWVudCA9PT0gJycgfHwgZWxlbWVudCA9PT0gbnVsbCk7XG4gIH1cblxuICBwcml2YXRlIGFzeW5jIGdldEFsYXJtcyhjb25maWc6IEFsYXJtTGlzdFdpZGdldENvbmZpZyk6IFByb21pc2U8dm9pZD4ge1xuICAgIHRyeSB7XG4gICAgICB0aGlzLmlzTG9hZGluZyA9IHRydWU7XG4gICAgICBjb25zdCByZXN1bHQ6IElSZXN1bHRMaXN0PElBbGFybT4gPSBhd2FpdCB0aGlzLmFsYXJtU2VydmljZS5saXN0KFxuICAgICAgICB0aGlzLmFsYXJtTGlzdFdpZGdldFNlcnZpY2UubWFwQ29uZmlnVG9RdWVyeUZpbHRlcihjb25maWcsIERFRkFVTFRfUEFHRV9TSVpFKVxuICAgICAgKTtcblxuICAgICAgdGhpcy5hbGFybXMkLm5leHQocmVzdWx0KTtcbiAgICB9IGNhdGNoIChlcnJvcikge1xuICAgICAgdGhpcy5hbGVydFNlcnZpY2UuYWRkU2VydmVyRmFpbHVyZShlcnJvcik7XG4gICAgfSBmaW5hbGx5IHtcbiAgICAgIHRoaXMuaXNMb2FkaW5nID0gZmFsc2U7XG4gICAgfVxuICB9XG5cbiAgcHJpdmF0ZSBpbml0aWFsaXplRm9ybSgpOiB2b2lkIHtcbiAgICB0aGlzLmZvcm1Hcm91cCA9IHRoaXMuY3JlYXRlRm9ybSgpO1xuICAgIHRoaXMuZm9ybS5mb3JtLmFkZENvbnRyb2woJ2NvbmZpZycsIHRoaXMuZm9ybUdyb3VwKTtcbiAgICB0aGlzLmZvcm1Hcm91cC5wYXRjaFZhbHVlKHRoaXMuY29uZmlnKTtcbiAgICB0aGlzLmluaXRpYWxpemVUeXBlcyh0aGlzLmNvbmZpZy50eXBlcyk7XG4gICAgdGhpcy5pbml0RGF0ZVNlbGVjdGlvbigpO1xuICAgIHRoaXMucmVmcmVzaE9wdGlvbiA9IHRoaXMuY29uZmlnLnJlZnJlc2hPcHRpb24gPz8gJ2ludGVydmFsJztcbiAgfVxuXG4gIHByaXZhdGUgY3JlYXRlRm9ybSgpIHtcbiAgICByZXR1cm4gdGhpcy5mb3JtQnVpbGRlci5ncm91cCh7XG4gICAgICBzdGF0dXM6IHRoaXMuZm9ybUJ1aWxkZXIuZ3JvdXAoREVGQVVMVF9TVEFUVVNfVkFMVUVTLCB7XG4gICAgICAgIHZhbGlkYXRvcnM6IHRoaXMubWluU2VsZWN0ZWRDaGVja2JveGVzKDEpXG4gICAgICB9KSxcbiAgICAgIHNob3dBbGFybXNGb3JDaGlsZHJlbjogdHJ1ZSxcbiAgICAgIHR5cGVzOiB0aGlzLmZvcm1CdWlsZGVyLmFycmF5KFtdKSxcbiAgICAgIHNldmVyaXRpZXM6IHRoaXMuZm9ybUJ1aWxkZXIuZ3JvdXAoREVGQVVMVF9TRVZFUklUWV9WQUxVRVMsIHtcbiAgICAgICAgdmFsaWRhdG9yczogdGhpcy5taW5TZWxlY3RlZENoZWNrYm94ZXMoMSlcbiAgICAgIH0pLFxuICAgICAgb3JkZXI6IEFMQVJNX09SREVSX1ZBTFVFUy5CWV9BQ1RJVkUgYXMgQWxhcm1PcmRlclR5cGUsXG4gICAgICBpc0F1dG9SZWZyZXNoRW5hYmxlZDogW3RydWVdLFxuICAgICAgcmVmcmVzaEludGVydmFsOiAhdGhpcy5jb25maWcuaXNSZWFsdGltZVxuICAgICAgICA/IG5ldyBGb3JtQ29udHJvbCh7XG4gICAgICAgICAgICB2YWx1ZTogdGhpcy5hbGFybXNWaWV3U2VydmljZS5ERUZBVUxUX0lOVEVSVkFMX1ZBTFVFLFxuICAgICAgICAgICAgZGlzYWJsZWQ6IHRoaXMuaXNBdXRvcmVmZXJzaERpc2FibGVkKClcbiAgICAgICAgICB9KVxuICAgICAgICA6IG5ldyBGb3JtQ29udHJvbCh1bmRlZmluZWQpLFxuICAgICAgZGV2aWNlOiB0aGlzLmNvbmZpZy5kZXZpY2UgPyBuZXcgRm9ybUNvbnRyb2wodGhpcy5jb25maWcuZGV2aWNlKSA6IG5ldyBGb3JtQ29udHJvbCh1bmRlZmluZWQpLFxuICAgICAgZGF0ZUZpbHRlcjogdGhpcy5jb25maWcuZGF0ZUZpbHRlclxuICAgICAgICA/IG5ldyBGb3JtQ29udHJvbCh0aGlzLmNvbmZpZy5kYXRlRmlsdGVyKVxuICAgICAgICA6IG5ldyBGb3JtQ29udHJvbChbbmV3IERhdGUoMCksIG5ldyBEYXRlKCldKSxcbiAgICAgIGRpc3BsYXlEYXRlU2VsZWN0aW9uOiB0aGlzLmNvbmZpZy5kaXNwbGF5RGF0ZVNlbGVjdGlvbiB8fCBmYWxzZSxcbiAgICAgIHdpZGdldEluc3RhbmNlR2xvYmFsVGltZUNvbnRleHQ6IHRoaXMuY29uZmlnLndpZGdldEluc3RhbmNlR2xvYmFsVGltZUNvbnRleHQgfHwgZmFsc2UsXG4gICAgICBpbnRlcnZhbDogdGhpcy5jb25maWcuaW50ZXJ2YWwgfHwgJ25vbmUnLFxuICAgICAgcmVmcmVzaE9wdGlvbjogdGhpcy5jb25maWcuaXNSZWFsdGltZSA/IG51bGwgOiAnaW50ZXJ2YWwnLFxuICAgICAgd2lkZ2V0SW5zdGFuY2VHbG9iYWxBdXRvUmVmcmVzaENvbnRleHQ6IHRoaXMuY29uZmlnLnJlZnJlc2hPcHRpb24gPT09IEdMT0JBTF9JTlRFUlZBTF9PUFRJT05cbiAgICB9KTtcbiAgfVxuXG4gIHByaXZhdGUgaXNBdXRvcmVmZXJzaERpc2FibGVkKCk6IGJvb2xlYW4ge1xuICAgIC8qKlRoaXMgY2hlY2sgaXMgcmVxdWlyZWQgb24gd2lkZ2V0IGNyZWF0aW9uICovXG4gICAgaWYgKHRoaXMuY29uZmlnLmlzQXV0b1JlZnJlc2hFbmFibGVkID09PSB1bmRlZmluZWQpIHtcbiAgICAgIHJldHVybiBmYWxzZTtcbiAgICB9XG5cbiAgICByZXR1cm4gIXRoaXMuY29uZmlnLmlzQXV0b1JlZnJlc2hFbmFibGVkO1xuICB9XG5cbiAgcHJpdmF0ZSBtaW5TZWxlY3RlZENoZWNrYm94ZXMobWluID0gMSk6IFZhbGlkYXRvckZuIHtcbiAgICBjb25zdCB2YWxpZGF0b3I6IFZhbGlkYXRvckZuID0gKGZvcm1Hcm91cDogRm9ybUdyb3VwKSA9PiB7XG4gICAgICBjb25zdCB0b3RhbFNlbGVjdGVkID0gT2JqZWN0LnZhbHVlcyhmb3JtR3JvdXAuY29udHJvbHMpLnJlZHVjZShcbiAgICAgICAgKHByZXYsIG5leHQpID0+IChuZXh0LnZhbHVlID8gcHJldiArIG5leHQudmFsdWUgOiBwcmV2KSxcbiAgICAgICAgMFxuICAgICAgKTtcblxuICAgICAgcmV0dXJuIHRvdGFsU2VsZWN0ZWQgPj0gbWluID8gbnVsbCA6IHsgcmVxdWlyZWQ6IHRydWUgfTtcbiAgICB9O1xuXG4gICAgcmV0dXJuIHZhbGlkYXRvcjtcbiAgfVxuXG4gIHByaXZhdGUgaW5pdGlhbGl6ZVR5cGVzKHR5cGVzOiBzdHJpbmdbXSk6IHZvaWQge1xuICAgIGNvbnN0IHR5cGVzQ29udHJvbCA9IHRoaXMuZm9ybUdyb3VwLmdldCgndHlwZXMnKSBhcyBGb3JtQXJyYXk7XG4gICAgaWYgKHR5cGVzKSB7XG4gICAgICB0eXBlcy5mb3JFYWNoKHR5cGUgPT4ge1xuICAgICAgICB0eXBlc0NvbnRyb2wucHVzaCh0aGlzLmZvcm1CdWlsZGVyLmNvbnRyb2wodHlwZSkpO1xuICAgICAgfSk7XG4gICAgfSBlbHNlIHtcbiAgICAgIHR5cGVzQ29udHJvbC5wdXNoKHRoaXMuZm9ybUJ1aWxkZXIuY29udHJvbCgnJykpO1xuICAgIH1cbiAgfVxuXG4gIHByaXZhdGUgaW5pdERhdGVTZWxlY3Rpb24oKTogdm9pZCB7XG4gICAgdGhpcy5kYXRlU2VsZWN0aW9uID0gdGhpcy5jb25maWc/LndpZGdldEluc3RhbmNlR2xvYmFsVGltZUNvbnRleHRcbiAgICAgID8gREFURV9TRUxFQ1RJT04uREFTSEJPQVJEX0NPTlRFWFRcbiAgICAgIDogdGhpcy5jb25maWc/LmRpc3BsYXlEYXRlU2VsZWN0aW9uXG4gICAgICAgID8gREFURV9TRUxFQ1RJT04uVklFV19BTkRfQ09ORklHXG4gICAgICAgIDogREFURV9TRUxFQ1RJT04uQ09ORklHO1xuXG4gICAgdGhpcy5kYXRlU2VsZWN0aW9uQ2hhbmdlKHRoaXMuZGF0ZVNlbGVjdGlvbik7XG5cbiAgICBjb25zdCBpbnRlcnZhbCA9IHRoaXMuY29uZmlnPy5pbnRlcnZhbCA/PyAnbm9uZSc7XG4gICAgaWYgKGludGVydmFsID09PSAnbm9uZScgfHwgaW50ZXJ2YWwgPT09ICdjdXN0b20nKSB7XG4gICAgICByZXR1cm47XG4gICAgfVxuXG4gICAgdGhpcy5jb25maWcuZGF0ZUZpbHRlciA9IHRoaXMuYWxhcm1zVmlld1NlcnZpY2UuZ2V0RGF0ZVRpbWVDb250ZXh0QnlJbnRlcnZhbChcbiAgICAgIHRoaXMuY29uZmlnLmludGVydmFsXG4gICAgKTtcbiAgICB0aGlzLmZvcm1Hcm91cC5wYXRjaFZhbHVlKHtcbiAgICAgIGRhdGVGaWx0ZXI6IHRoaXMuY29uZmlnLmRhdGVGaWx0ZXJcbiAgICB9KTtcbiAgfVxuXG4gIC8qKlxuICAgKiBJbml0aWFsaXplcyBhbmQgaGFuZGxlcyB0aGUgZm9ybSBjaGFuZ2Ugc3Vic2NyaXB0aW9uIGZvciB0aGUgQWxhcm0gbGlzdCBwcmV2aWV3IGF0IFdpZGdldCdzIGNvbmZpZ3VyYXRpb24uXG4gICAqXG4gICAqIFRoaXMgbWV0aG9kIHN1YnNjcmliZXMgdG8gZm9ybSB2YWx1ZSBjaGFuZ2VzIHdpdGggYSBkZWJvdW5jZSB0aW1lIG9mIDUwMG1zLlxuICAgKiBJdCBjb21wYXJlcyB0aGUgcHJldmlvdXMgYW5kIGN1cnJlbnQgZm9ybSB2YWx1ZXMgdG8gZGV0ZXJtaW5lIGlmIHRoZSBjaGFuZ2VzIGFyZSByZWxldmFudC5cbiAgICogSWYgdGhlIG9ubHkgY2hhbmdlIGlzIGluIHRoZSBgaXNBdXRvUmVmcmVzaEVuYWJsZWRgIHByb3BlcnR5LCB0aGUgY2hhbmdlIGlzIGlnbm9yZWQuXG4gICAqL1xuICBwcml2YXRlIGhhbmRsZVByZXZpZXdTdWJzY3JpcHRpb24oKTogdm9pZCB7XG4gICAgdGhpcy5mb3JtQ2hhbmdlc1N1YnNjcmlwdGlvbiA9IHRoaXMuZm9ybUdyb3VwLnZhbHVlQ2hhbmdlc1xuICAgICAgLnBpcGUoc3RhcnRXaXRoKHRoaXMuZm9ybUdyb3VwLnZhbHVlKSwgcGFpcndpc2UoKSwgZGVib3VuY2VUaW1lKDUwMCkpXG4gICAgICAuc3Vic2NyaWJlKChbcHJldmlvdXNDb25maWcsIGN1cnJlbnRDb25maWddOiBbdW5rbm93biwgdW5rbm93bl0pID0+IHtcbiAgICAgICAgY29uc3QgdHlwZWRQcmV2aW91c0NvbmZpZzogQWxhcm1MaXN0V2lkZ2V0Q29uZmlnID0gcHJldmlvdXNDb25maWcgYXMgQWxhcm1MaXN0V2lkZ2V0Q29uZmlnO1xuICAgICAgICBjb25zdCB0eXBlZEN1cnJlbnRDb25maWc6IEFsYXJtTGlzdFdpZGdldENvbmZpZyA9IGN1cnJlbnRDb25maWcgYXMgQWxhcm1MaXN0V2lkZ2V0Q29uZmlnO1xuXG4gICAgICAgIGlmICh0aGlzLmlzT25seUF1dG9SZWZyZXNoT3JJbnRlcnZhbENoYW5nZWQodHlwZWRQcmV2aW91c0NvbmZpZywgdHlwZWRDdXJyZW50Q29uZmlnKSkge1xuICAgICAgICAgIHJldHVybjtcbiAgICAgICAgfVxuXG4gICAgICAgIGlmIChcbiAgICAgICAgICB0aGlzLmFsYXJtTGlzdFdpZGdldFNlcnZpY2UuYWxsVmFsdWVzRmFsc2UodHlwZWRDdXJyZW50Q29uZmlnLnNldmVyaXRpZXMpIHx8XG4gICAgICAgICAgdGhpcy5hbGFybUxpc3RXaWRnZXRTZXJ2aWNlLmFsbFZhbHVlc0ZhbHNlKHR5cGVkQ3VycmVudENvbmZpZy5zdGF0dXMpXG4gICAgICAgICkge1xuICAgICAgICAgIHRoaXMuYWxhcm1zJC5uZXh0KHsgZGF0YTogW10sIHJlczogbnVsbCB9KTtcbiAgICAgICAgICByZXR1cm47XG4gICAgICAgIH1cblxuICAgICAgICB0aGlzLmdldEFsYXJtcyh0eXBlZEN1cnJlbnRDb25maWcpO1xuICAgICAgfSk7XG4gIH1cblxuICAvKipcbiAgICogRGV0ZXJtaW5lcyBpZiB0aGUgb25seSBjaGFuZ2VzIGJldHdlZW4gdHdvIGBBbGFybUxpc3RXaWRnZXRDb25maWdgIG9iamVjdHMgYXJlIGluIHRoZSBgaXNBdXRvUmVmcmVzaEVuYWJsZWRgIGFuZCBgcmVmcmVzaEludGVydmFsYCBwcm9wZXJ0aWVzLlxuICAgKlxuICAgKiBUaGlzIG1ldGhvZCBjb21wYXJlcyB0d28gY29uZmlndXJhdGlvbnMgYnkgb21pdHRpbmcgYGlzQXV0b1JlZnJlc2hFbmFibGVkYCBhbmQgYHJlZnJlc2hJbnRlcnZhbGAuXG4gICAqIEl0IHJldHVybnMgdHJ1ZSBpZiB0aGVzZSBhcmUgdGhlIG9ubHkgcHJvcGVydGllcyB0aGF0IGRpZmZlciBiZXR3ZWVuIHRoZSBwcmV2aW91cyBhbmQgY3VycmVudCBjb25maWd1cmF0aW9ucy5cbiAgICogTm90ZSB0aGF0IGByZWZyZXNoSW50ZXJ2YWxgIGlzIHJlbGV2YW50IG9ubHkgd2hlbiB0aGUgcmVmcmVzaCB0eXBlIGlzIHNldCB0byBhbiBpbnRlcnZhbC5cbiAgICpcbiAgICogQHBhcmFtIHByZXZpb3VzQ29uZmlnIC0gVGhlIHByZXZpb3VzIGNvbmZpZ3VyYXRpb24gb2YgYEFsYXJtTGlzdFdpZGdldENvbmZpZ2AuXG4gICAqIEBwYXJhbSBjdXJyZW50Q29uZmlnIC0gVGhlIGN1cnJlbnQgY29uZmlndXJhdGlvbiBvZiBgQWxhcm1MaXN0V2lkZ2V0Q29uZmlnYC5cbiAgICogQHJldHVybnMgYHRydWVgIGlmIHRoZSBkaWZmZXJlbmNlcyBhcmUgY29uZmluZWQgdG8gYGlzQXV0b1JlZnJlc2hFbmFibGVkYCBhbmQgYHJlZnJlc2hJbnRlcnZhbGAsIGBmYWxzZWAgb3RoZXJ3aXNlLlxuICAgKi9cbiAgcHJpdmF0ZSBpc09ubHlBdXRvUmVmcmVzaE9ySW50ZXJ2YWxDaGFuZ2VkKFxuICAgIHByZXZpb3VzQ29uZmlnOiBBbGFybUxpc3RXaWRnZXRDb25maWcsXG4gICAgY3VycmVudENvbmZpZzogQWxhcm1MaXN0V2lkZ2V0Q29uZmlnXG4gICk6IGJvb2xlYW4ge1xuICAgIGNvbnN0IHByZXZDb25maWdDb3B5ID0gb21pdChwcmV2aW91c0NvbmZpZywgJ2lzQXV0b1JlZnJlc2hFbmFibGVkJywgJ3JlZnJlc2hJbnRlcnZhbCcpO1xuICAgIGNvbnN0IGN1cnJlbnRDb25maWdDb3B5ID0gb21pdChjdXJyZW50Q29uZmlnLCAnaXNBdXRvUmVmcmVzaEVuYWJsZWQnLCAncmVmcmVzaEludGVydmFsJyk7XG5cbiAgICByZXR1cm4gaXNFcXVhbChwcmV2Q29uZmlnQ29weSwgY3VycmVudENvbmZpZ0NvcHkpO1xuICB9XG5cbiAgcHJpdmF0ZSB1cGRhdGVDb25maWdCYXNlZE9uUmVmcmVzaE9wdGlvbigpIHtcbiAgICBjb25zdCBpc0ludGVydmFsID0gdGhpcy5yZWZyZXNoT3B0aW9uID09PSAnaW50ZXJ2YWwnO1xuXG4gICAgdGhpcy5jb25maWcuaXNBdXRvUmVmcmVzaEVuYWJsZWQgPSBpc0ludGVydmFsO1xuICAgIHRoaXMuZm9ybUdyb3VwLmNvbnRyb2xzLmlzQXV0b1JlZnJlc2hFbmFibGVkLnNldFZhbHVlKGlzSW50ZXJ2YWwpO1xuXG4gICAgaXNJbnRlcnZhbFxuICAgICAgPyB0aGlzLmZvcm1Hcm91cC5nZXQoJ3JlZnJlc2hJbnRlcnZhbCcpLmVuYWJsZSgpXG4gICAgICA6IHRoaXMuZm9ybUdyb3VwLmdldCgncmVmcmVzaEludGVydmFsJykuZGlzYWJsZSgpO1xuICB9XG59XG4iLCI8ZGl2XG4gIGNsYXNzPVwicC1sLTI0IHAtci0yNFwiXG4gIFtzdHlsZS5wb2ludGVyLWV2ZW50c109XCInYXV0bydcIlxuICBbc3R5bGUub3BhY2l0eV09XCIxXCJcbj48L2Rpdj5cblxuPGZvcm1cbiAgY2xhc3M9XCJyb3dcIlxuICBbZm9ybUdyb3VwXT1cImZvcm1Hcm91cFwiXG4+XG4gIDxkaXYgY2xhc3M9XCJmb3JtLWdyb3VwIGNvbC1tZC0xMlwiPlxuICAgIDxkaXYgY2xhc3M9XCJkLWZsZXggYS1pLWNlbnRlclwiPlxuICAgICAgPGxhYmVsXG4gICAgICAgIGNsYXNzPVwibS1iLTBcIlxuICAgICAgICB0cmFuc2xhdGVcbiAgICAgID5cbiAgICAgICAgRGF0ZSBzZWxlY3Rpb25cbiAgICAgIDwvbGFiZWw+XG4gICAgICA8YnV0dG9uXG4gICAgICAgIGNsYXNzPVwiYnRuLWhlbHAgYnRuLWhlbHAtLXNtXCJcbiAgICAgICAgW2F0dHIuYXJpYS1sYWJlbF09XCInSGVscCcgfCB0cmFuc2xhdGVcIlxuICAgICAgICBbcG9wb3Zlcl09XCJkYXRlU2VsZWN0aW9uSGVscFRlbXBsYXRlXCJcbiAgICAgICAgcGxhY2VtZW50PVwiYm90dG9tXCJcbiAgICAgICAgdHJpZ2dlcnM9XCJmb2N1c1wiXG4gICAgICAgIGNvbnRhaW5lcj1cImJvZHlcIlxuICAgICAgICBbYWRhcHRpdmVQb3NpdGlvbl09XCJmYWxzZVwiXG4gICAgICA+PC9idXR0b24+XG4gICAgPC9kaXY+XG4gICAgPGRpdiBjbGFzcz1cImM4eS1zZWxlY3Qtd3JhcHBlclwiPlxuICAgICAgPHNlbGVjdFxuICAgICAgICBjbGFzcz1cImZvcm0tY29udHJvbCBpbnB1dC1zbVwiXG4gICAgICAgIFtuZ01vZGVsXT1cImRhdGVTZWxlY3Rpb25cIlxuICAgICAgICAobmdNb2RlbENoYW5nZSk9XCJkYXRlU2VsZWN0aW9uQ2hhbmdlKCRldmVudClcIlxuICAgICAgICBbbmdNb2RlbE9wdGlvbnNdPVwieyBzdGFuZGFsb25lOiB0cnVlIH1cIlxuICAgICAgPlxuICAgICAgICA8b3B0aW9uXG4gICAgICAgICAgdGl0bGU9XCJ7eyAnV2lkZ2V0IGNvbmZpZ3VyYXRpb24nIHwgdHJhbnNsYXRlIH19XCJcbiAgICAgICAgICBbdmFsdWVdPVwiREFURV9TRUxFQ1RJT04uQ09ORklHXCJcbiAgICAgICAgPlxuICAgICAgICAgIHt7ICdXaWRnZXQgY29uZmlndXJhdGlvbicgfCB0cmFuc2xhdGUgfX1cbiAgICAgICAgPC9vcHRpb24+XG4gICAgICAgIDxvcHRpb25cbiAgICAgICAgICB0aXRsZT1cInt7ICdXaWRnZXQgYW5kIHdpZGdldCBjb25maWd1cmF0aW9uJyB8IHRyYW5zbGF0ZSB9fVwiXG4gICAgICAgICAgW3ZhbHVlXT1cIkRBVEVfU0VMRUNUSU9OLlZJRVdfQU5EX0NPTkZJR1wiXG4gICAgICAgID5cbiAgICAgICAgICB7eyAnV2lkZ2V0IGFuZCB3aWRnZXQgY29uZmlndXJhdGlvbicgfCB0cmFuc2xhdGUgfX1cbiAgICAgICAgPC9vcHRpb24+XG4gICAgICAgIDxvcHRpb25cbiAgICAgICAgICB0aXRsZT1cInt7ICdEYXNoYm9hcmQgdGltZSByYW5nZScgfCB0cmFuc2xhdGUgfX1cIlxuICAgICAgICAgIFt2YWx1ZV09XCJEQVRFX1NFTEVDVElPTi5EQVNIQk9BUkRfQ09OVEVYVFwiXG4gICAgICAgID5cbiAgICAgICAgICB7eyAnRGFzaGJvYXJkIHRpbWUgcmFuZ2UnIHwgdHJhbnNsYXRlIH19XG4gICAgICAgIDwvb3B0aW9uPlxuICAgICAgPC9zZWxlY3Q+XG4gICAgICA8c3Bhbj48L3NwYW4+XG4gICAgPC9kaXY+XG4gIDwvZGl2PlxuICA8ZGl2IGNsYXNzPVwiY29sLW1kLTZcIj5cbiAgICA8ZmllbGRzZXQgY2xhc3M9XCJjOHktZmllbGRzZXRcIj5cbiAgICAgIDxsZWdlbmQ+e3sgJ09yZGVyYG9mIGl0ZW1zIG9uIGEgbGlzdCwgbm91bmAnIHwgdHJhbnNsYXRlIH19PC9sZWdlbmQ+XG4gICAgICA8Yzh5LWZvcm0tZ3JvdXAgY2xhc3M9XCJtLWItMFwiPlxuICAgICAgICA8ZGl2XG4gICAgICAgICAgY2xhc3M9XCJkLWZsZXggbS1iLTggYS1pLWNlbnRlclwiXG4gICAgICAgICAgKm5nRm9yPVwibGV0IG9yZGVyIG9mIG9yZGVyTGlzdDsgbGV0IGkgPSBpbmRleFwiXG4gICAgICAgID5cbiAgICAgICAgICA8bGFiZWxcbiAgICAgICAgICAgIGNsYXNzPVwiYzh5LXJhZGlvIGdhcC00XCJcbiAgICAgICAgICAgIHRpdGxlPVwie3sgQUxBUk1fT1JERVJfTEFCRUxTW29yZGVyXSB8IHRyYW5zbGF0ZSB9fVwiXG4gICAgICAgICAgPlxuICAgICAgICAgICAgPGlucHV0XG4gICAgICAgICAgICAgIHR5cGU9XCJyYWRpb1wiXG4gICAgICAgICAgICAgIFt2YWx1ZV09XCJvcmRlclwiXG4gICAgICAgICAgICAgIGZvcm1Db250cm9sTmFtZT1cIm9yZGVyXCJcbiAgICAgICAgICAgIC8+XG4gICAgICAgICAgICA8c3BhbiBjbGFzcz1cImEtcy1jZW50ZXJcIj48L3NwYW4+XG4gICAgICAgICAgICA8c3BhbiBjbGFzcz1cInRleHQtdHJ1bmNhdGVcIj57eyBBTEFSTV9PUkRFUl9MQUJFTFNbb3JkZXJdIHwgdHJhbnNsYXRlIH19PC9zcGFuPlxuICAgICAgICAgIDwvbGFiZWw+XG4gICAgICAgICAgPGJ1dHRvblxuICAgICAgICAgICAgY2xhc3M9XCJidG4taGVscCBidG4taGVscC0tc21cIlxuICAgICAgICAgICAgW2F0dHIuYXJpYS1sYWJlbF09XCInSGVscCcgfCB0cmFuc2xhdGVcIlxuICAgICAgICAgICAgW3BvcG92ZXJdPVwib3JkZXIgfCBzb3J0aW5nRGVzY3JpcHRpb25Qb3BvdmVyTWVzc2FnZSB8IHRyYW5zbGF0ZVwiXG4gICAgICAgICAgICBwbGFjZW1lbnQ9XCJyaWdodFwiXG4gICAgICAgICAgICB0cmlnZ2Vycz1cImZvY3VzXCJcbiAgICAgICAgICAgIGNvbnRhaW5lcj1cImJvZHlcIlxuICAgICAgICAgICAgdHlwZT1cImJ1dHRvblwiXG4gICAgICAgICAgICBbYWRhcHRpdmVQb3NpdGlvbl09XCJ0cnVlXCJcbiAgICAgICAgICA+PC9idXR0b24+XG4gICAgICAgIDwvZGl2PlxuICAgICAgPC9jOHktZm9ybS1ncm91cD5cbiAgICA8L2ZpZWxkc2V0PlxuICAgIDxmaWVsZHNldFxuICAgICAgY2xhc3M9XCJjOHktZmllbGRzZXRcIlxuICAgICAgZm9ybUFycmF5TmFtZT1cInNldmVyaXRpZXNcIlxuICAgID5cbiAgICAgIDxsZWdlbmQ+e3sgJ1NldmVyaXRpZXMnIHwgdHJhbnNsYXRlIH19PC9sZWdlbmQ+XG4gICAgICA8Yzh5LWZvcm0tZ3JvdXBcbiAgICAgICAgW2hhc0Vycm9yXT1cImZvcm1Hcm91cC5jb250cm9scy5zZXZlcml0aWVzLmhhc0Vycm9yKCdyZXF1aXJlZCcpXCJcbiAgICAgICAgW25nQ2xhc3NdPVwie1xuICAgICAgICAgICdtLWItOCc6ICFmb3JtR3JvdXAuY29udHJvbHMuc2V2ZXJpdGllcy5oYXNFcnJvcigncmVxdWlyZWQnKVxuICAgICAgICB9XCJcbiAgICAgID5cbiAgICAgICAgPG5nLWNvbnRhaW5lciAqbmdGb3I9XCJsZXQgc2V2ZXJpdHlPcHRpb24gb2Ygc2V2ZXJpdHlMaXN0XCI+XG4gICAgICAgICAgPGxhYmVsXG4gICAgICAgICAgICBjbGFzcz1cImM4eS1jaGVja2JveCBtLXQtMCBnYXAtNFwiXG4gICAgICAgICAgICBbdGl0bGVdPVwiU0VWRVJJVFlfTEFCRUxTW3NldmVyaXR5T3B0aW9uXSB8IHRyYW5zbGF0ZVwiXG4gICAgICAgICAgPlxuICAgICAgICAgICAgPGlucHV0XG4gICAgICAgICAgICAgIHR5cGU9XCJjaGVja2JveFwiXG4gICAgICAgICAgICAgIFtmb3JtQ29udHJvbE5hbWVdPVwic2V2ZXJpdHlPcHRpb25cIlxuICAgICAgICAgICAgICBbbmFtZV09XCJzZXZlcml0eU9wdGlvblwiXG4gICAgICAgICAgICAvPlxuICAgICAgICAgICAgPHNwYW4gY2xhc3M9XCJhLXMtY2VudGVyXCI+PC9zcGFuPlxuICAgICAgICAgICAgPG5nLWNvbnRhaW5lciAqbmdJZj1cInsgcmVzdWx0OiBzZXZlcml0eU9wdGlvbiB8IHNldmVyaXR5SWNvbiB9IGFzIHNldmVyaXR5SWNvblwiPlxuICAgICAgICAgICAgICA8aVxuICAgICAgICAgICAgICAgIGNsYXNzPVwiYS1zLWNlbnRlciBtLXItNCBpY29uLTIwIHt7IHNldmVyaXR5SWNvbi5yZXN1bHQuaWNvbkNsYXNzIH19XCJcbiAgICAgICAgICAgICAgICBbYzh5SWNvbl09XCJzZXZlcml0eUljb24ucmVzdWx0LmM4eUljb25cIlxuICAgICAgICAgICAgICA+PC9pPlxuICAgICAgICAgICAgPC9uZy1jb250YWluZXI+XG4gICAgICAgICAgICA8c3Bhbj57eyBTRVZFUklUWV9MQUJFTFNbc2V2ZXJpdHlPcHRpb25dIHwgdHJhbnNsYXRlIH19PC9zcGFuPlxuICAgICAgICAgIDwvbGFiZWw+XG4gICAgICAgIDwvbmctY29udGFpbmVyPlxuICAgICAgICA8Yzh5LW1lc3NhZ2VzPlxuICAgICAgICAgIDxjOHktbWVzc2FnZSAqbmdJZj1cImZvcm1Hcm91cC5jb250cm9scy5zZXZlcml0aWVzLmhhc0Vycm9yKCdyZXF1aXJlZCcpXCI+XG4gICAgICAgICAgICB7eyAnU2VsZWN0IGF0IGxlYXN0IG9uZSBzZXZlcml0eS4nIHwgdHJhbnNsYXRlIH19XG4gICAgICAgICAgPC9jOHktbWVzc2FnZT5cbiAgICAgICAgPC9jOHktbWVzc2FnZXM+XG4gICAgICA8L2M4eS1mb3JtLWdyb3VwPlxuICAgIDwvZmllbGRzZXQ+XG4gICAgPG5nLWNvbnRhaW5lciAqbmdJZj1cInNob3dEYXRlRmlsdGVyXCI+XG4gICAgICA8ZmllbGRzZXQgY2xhc3M9XCJjOHktZmllbGRzZXRcIj5cbiAgICAgICAgPGxlZ2VuZD57eyAnRGF0ZSBmaWx0ZXInIHwgdHJhbnNsYXRlIH19PC9sZWdlbmQ+XG4gICAgICAgIDxjOHktZm9ybS1ncm91cCBjbGFzcz1cIm0tYi04XCI+XG4gICAgICAgICAgPGM4eS1hbGFybXMtZGF0ZS1maWx0ZXJcbiAgICAgICAgICAgIFt1cGRhdGVRdWVyeVBhcmFtc109XCJmYWxzZVwiXG4gICAgICAgICAgICBbREVGQVVMVF9JTlRFUlZBTF09XCJjb25maWcuaW50ZXJ2YWwgfHwgJ25vbmUnXCJcbiAgICAgICAgICAgIGZvcm1Db250cm9sTmFtZT1cImRhdGVGaWx0ZXJcIlxuICAgICAgICAgICAgKGRhdGVGaWx0ZXJDaGFuZ2UpPVwib25EYXRlRmlsdGVyQ2hhbmdlKCRldmVudClcIlxuICAgICAgICAgID48L2M4eS1hbGFybXMtZGF0ZS1maWx0ZXI+XG4gICAgICAgIDwvYzh5LWZvcm0tZ3JvdXA+XG4gICAgICA8L2ZpZWxkc2V0PlxuICAgIDwvbmctY29udGFpbmVyPlxuICA8L2Rpdj5cblxuICA8ZGl2IGNsYXNzPVwiY29sLW1kLTZcIj5cbiAgICA8ZmllbGRzZXRcbiAgICAgIGNsYXNzPVwiYzh5LWZpZWxkc2V0XCJcbiAgICAgIGZvcm1BcnJheU5hbWU9XCJzdGF0dXNcIlxuICAgID5cbiAgICAgIDxsZWdlbmQ+e3sgJ1N0YXR1cycgfCB0cmFuc2xhdGUgfX08L2xlZ2VuZD5cbiAgICAgIDxjOHktZm9ybS1ncm91cFxuICAgICAgICBbaGFzRXJyb3JdPVwiZm9ybUdyb3VwLmNvbnRyb2xzLnN0YXR1cy5oYXNFcnJvcigncmVxdWlyZWQnKVwiXG4gICAgICAgIFtuZ0NsYXNzXT1cIntcbiAgICAgICAgICAnbS1iLTgnOiAhZm9ybUdyb3VwLmNvbnRyb2xzLnN0YXR1cy5oYXNFcnJvcigncmVxdWlyZWQnKVxuICAgICAgICB9XCJcbiAgICAgID5cbiAgICAgICAgPG5nLWNvbnRhaW5lciAqbmdGb3I9XCJsZXQgc3RhdHVzT3B0aW9uIG9mIHN0YXR1c0xpc3RcIj5cbiAgICAgICAgICA8bGFiZWxcbiAgICAgICAgICAgIGNsYXNzPVwiYzh5LWNoZWNrYm94IG0tdC0wIGdhcC00XCJcbiAgICAgICAgICAgIFt0aXRsZV09XCJTVEFUVVNfTEFCRUxTW3N0YXR1c09wdGlvbl0gfCB0cmFuc2xhdGVcIlxuICAgICAgICAgID5cbiAgICAgICAgICAgIDxpbnB1dFxuICAgICAgICAgICAgICB0eXBlPVwiY2hlY2tib3hcIlxuICAgICAgICAgICAgICBbZm9ybUNvbnRyb2xOYW1lXT1cInN0YXR1c09wdGlvblwiXG4gICAgICAgICAgICAgIFtuYW1lXT1cInN0YXR1c09wdGlvblwiXG4gICAgICAgICAgICAvPlxuICAgICAgICAgICAgPHNwYW4gY2xhc3M9XCJhLXMtY2VudGVyXCI+PC9zcGFuPlxuICAgICAgICAgICAgPGlcbiAgICAgICAgICAgICAgY2xhc3M9XCJhLXMtY2VudGVyIG0tbC00IG0tci00IHRleHQtZ3JheS1kYXJrIGM4eS1pY29uIGljb24tMjBcIlxuICAgICAgICAgICAgICBbYzh5SWNvbl09XCJcbiAgICAgICAgICAgICAgICBzdGF0dXNPcHRpb24gPT09IENMRUFSRURfU1RBVFVTX1ZBTFVFXG4gICAgICAgICAgICAgICAgICA/IEM4WV9BTEVSVF9JRExFX0lDT05cbiAgICAgICAgICAgICAgICAgIDogc3RhdHVzT3B0aW9uID09PSBBQ0tOT1dMRURHRV9TVEFUVVNfVkFMVUVcbiAgICAgICAgICAgICAgICAgICAgPyBCRUxMX1NMQVNIX0lDT05cbiAgICAgICAgICAgICAgICAgICAgOiBCRUxMX0lDT05cbiAgICAgICAgICAgICAgXCJcbiAgICAgICAgICAgID48L2k+XG4gICAgICAgICAgICA8c3Bhbj57eyBTVEFUVVNfTEFCRUxTW3N0YXR1c09wdGlvbl0gfCB0cmFuc2xhdGUgfX08L3NwYW4+XG4gICAgICAgICAgPC9sYWJlbD5cbiAgICAgICAgPC9uZy1jb250YWluZXI+XG4gICAgICAgIDxjOHktbWVzc2FnZXM+XG4gICAgICAgICAgPGM4eS1tZXNzYWdlICpuZ0lmPVwiZm9ybUdyb3VwLmNvbnRyb2xzLnN0YXR1cy5oYXNFcnJvcigncmVxdWlyZWQnKVwiPlxuICAgICAgICAgICAge3sgJ1NlbGVjdCBhdCBsZWFzdCBvbmUgc3RhdHVzLicgfCB0cmFuc2xhdGUgfX1cbiAgICAgICAgICA8L2M4eS1tZXNzYWdlPlxuICAgICAgICA8L2M4eS1tZXNzYWdlcz5cbiAgICAgIDwvYzh5LWZvcm0tZ3JvdXA+XG4gICAgPC9maWVsZHNldD5cblxuICAgIDxmaWVsZHNldCBjbGFzcz1cImM4eS1maWVsZHNldFwiPlxuICAgICAgPGxlZ2VuZD57eyAnQ2hpbGQgZGV2aWNlcycgfCB0cmFuc2xhdGUgfX08L2xlZ2VuZD5cbiAgICAgIDxjOHktZm9ybS1ncm91cCBjbGFzcz1cIm0tYi04XCI+XG4gICAgICAgIDxsYWJlbFxuICAgICAgICAgIGNsYXNzPVwiYzh5LXN3aXRjaFwiXG4gICAgICAgICAgW3RpdGxlXT1cIidTaG93IGFsYXJtcyBmcm9tIGNoaWxkIGRldmljZXMnIHwgdHJhbnNsYXRlXCJcbiAgICAgICAgPlxuICAgICAgICAgIDxpbnB1dFxuICAgICAgICAgICAgdHlwZT1cImNoZWNrYm94XCJcbiAgICAgICAgICAgIGZvcm1Db250cm9sTmFtZT1cInNob3dBbGFybXNGb3JDaGlsZHJlblwiXG4gICAgICAgICAgLz5cbiAgICAgICAgICA8c3Bhbj48L3NwYW4+XG4gICAgICAgICAgPHNwYW4+e3sgJ1Nob3cgYWxhcm1zJyB8IHRyYW5zbGF0ZSB9fTwvc3Bhbj5cbiAgICAgICAgICA8c3BhbiBjbGFzcz1cInNyLW9ubHlcIj57eyAnU2hvdyBhbGFybXMnIHwgdHJhbnNsYXRlIH19PC9zcGFuPlxuICAgICAgICA8L2xhYmVsPlxuICAgICAgPC9jOHktZm9ybS1ncm91cD5cbiAgICA8L2ZpZWxkc2V0PlxuXG4gICAgPGZpZWxkc2V0IGNsYXNzPVwiYzh5LWZpZWxkc2V0XCI+XG4gICAgICA8bGVnZW5kPnt7ICdUeXBlcycgfCB0cmFuc2xhdGUgfX08L2xlZ2VuZD5cbiAgICAgIDxjOHktZm9ybS1ncm91cFxuICAgICAgICBjbGFzcz1cIm0tYi04XCJcbiAgICAgICAgZm9ybUFycmF5TmFtZT1cInR5cGVzXCJcbiAgICAgID5cbiAgICAgICAgPGRpdlxuICAgICAgICAgIGNsYXNzPVwiaW5wdXQtZ3JvdXBcIlxuICAgICAgICAgICpuZ0Zvcj1cImxldCB0eXBlIG9mIHR5cGVzLmNvbnRyb2xzOyBsZXQgaSA9IGluZGV4XCJcbiAgICAgICAgPlxuICAgICAgICAgIDxpbnB1dFxuICAgICAgICAgICAgY2xhc3M9XCJmb3JtLWNvbnRyb2xcIlxuICAgICAgICAgICAgdHlwZT1cInRleHRcIlxuICAgICAgICAgICAgW3BsYWNlaG9sZGVyXT1cIidlLmcuIHt7IGV4YW1wbGUgfX0nIHwgdHJhbnNsYXRlOiB7IGV4YW1wbGU6ICdjOHlfQWxhcm0nIH1cIlxuICAgICAgICAgICAgW2Zvcm1Db250cm9sTmFtZV09XCJpXCJcbiAgICAgICAgICAvPlxuICAgICAgICAgIDxkaXYgY2xhc3M9XCJpbnB1dC1ncm91cC1idG5cIj5cbiAgICAgICAgICAgIDxidXR0b25cbiAgICAgICAgICAgICAgY2xhc3M9XCJidG4gYnRuLWRvdCBidG4tZG90LS1kYW5nZXIgbS1sLWF1dG9cIlxuICAgICAgICAgICAgICBbdGl0bGVdPVwiJ1JlbW92ZScgfCB0cmFuc2xhdGVcIlxuICAgICAgICAgICAgICB0eXBlPVwiYnV0dG9uXCJcbiAgICAgICAgICAgICAgKGNsaWNrKT1cInJlbW92ZVR5cGUoaSlcIlxuICAgICAgICAgICAgICBbZGlzYWJsZWRdPVwidHlwZXMuY29udHJvbHM/Lmxlbmd0aCA9PT0gMSAmJiAhdHlwZS52YWx1ZVwiXG4gICAgICAgICAgICA+XG4gICAgICAgICAgICAgIDxpIGM4eUljb249XCJtaW51cy1jaXJjbGVcIj48L2k+XG4gICAgICAgICAgICA8L2J1dHRvbj5cbiAgICAgICAgICA8L2Rpdj5cbiAgICAgICAgICA8ZGl2XG4gICAgICAgICAgICBjbGFzcz1cImlucHV0LWdyb3VwLWJ0blwiXG4gICAgICAgICAgICAqbmdJZj1cImkgPT09IHR5cGVzLmNvbnRyb2xzLmxlbmd0aCAtIDFcIlxuICAgICAgICAgID5cbiAgICAgICAgICAgIDxidXR0b25cbiAgICAgICAgICAgICAgY2xhc3M9XCJidG4gYnRuLWRvdCBidG4tZG90LS1wcmltYXJ5IG0tbC1hdXRvXCJcbiAgICAgICAgICAgICAgW3RpdGxlXT1cIidBZGQgYWxhcm0gdHlwZScgfCB0cmFuc2xhdGVcIlxuICAgICAgICAgICAgICB0eXBlPVwiYnV0dG9uXCJcbiAgICAgICAgICAgICAgKGNsaWNrKT1cImFkZFR5cGUoKVwiXG4gICAgICAgICAgICA+XG4gICAgICAgICAgICAgIDxpIGM4eUljb249XCJwbHVzLWNpcmNsZVwiPjwvaT5cbiAgICAgICAgICAgIDwvYnV0dG9uPlxuICAgICAgICAgIDwvZGl2PlxuICAgICAgICA8L2Rpdj5cbiAgICAgIDwvYzh5LWZvcm0tZ3JvdXA+XG4gICAgPC9maWVsZHNldD5cbiAgICA8ZmllbGRzZXQgY2xhc3M9XCJjOHktZmllbGRzZXRcIj5cbiAgICAgIDxsZWdlbmQgY2xhc3M9XCJkLWZsZXhcIj5cbiAgICAgICAge3sgcmVmcmVzaFR5cGVUaXRsZSB9fVxuICAgICAgICA8YnV0dG9uXG4gICAgICAgICAgY2xhc3M9XCJidG4taGVscCBidG4taGVscC0tc21cIlxuICAgICAgICAgIFthdHRyLmFyaWEtbGFiZWxdPVwiJ0hlbHAnIHwgdHJhbnNsYXRlXCJcbiAgICAgICAgICBbcG9wb3Zlcl09XCJyZWZyZXNoVHlwZVBvcG92ZXJNZXNzYWdlXCJcbiAgICAgICAgICBwbGFjZW1lbnQ9XCJ0b3BcIlxuICAgICAgICAgIHRyaWdnZXJzPVwiZm9jdXNcIlxuICAgICAgICAgIGNvbnRhaW5lcj1cImJvZHlcIlxuICAgICAgICAgIHR5cGU9XCJidXR0b25cIlxuICAgICAgICAgIFthZGFwdGl2ZVBvc2l0aW9uXT1cInRydWVcIlxuICAgICAgICA+PC9idXR0b24+XG4gICAgICA8L2xlZ2VuZD5cbiAgICAgIDxjOHktZm9ybS1ncm91cCBjbGFzcz1cIm0tYi04IGZvcm0tZ3JvdXAtc21cIj5cbiAgICAgICAgPGRpdiBjbGFzcz1cImQtZmxleCBnYXAtOCBhLWktY2VudGVyXCI+XG4gICAgICAgICAgPG5nLXRlbXBsYXRlICNyZWFsdGltZT5cbiAgICAgICAgICAgIDxsYWJlbCBjbGFzcz1cImM4eS1zd2l0Y2hcIj5cbiAgICAgICAgICAgICAgPGlucHV0XG4gICAgICAgICAgICAgICAgaWQ9XCJyZWZyZXNoVG9nZ2xlXCJcbiAgICAgICAgICAgICAgICBuYW1lPVwiaXNBdXRvUmVmcmVzaEVuYWJsZWRcIlxuICAgICAgICAgICAgICAgIHR5cGU9XCJjaGVja2JveFwiXG4gICAgICAgICAgICAgICAgZm9ybUNvbnRyb2xOYW1lPVwiaXNBdXRvUmVmcmVzaEVuYWJsZWRcIlxuICAgICAgICAgICAgICAvPlxuICAgICAgICAgICAgICA8c3Bhbj48L3NwYW4+XG4gICAgICAgICAgICAgIDxzcGFuIGNsYXNzPVwic3Itb25seVwiPnt7ICdSZWFsdGltZSByZWZyZXNoJyB8IHRyYW5zbGF0ZSB9fTwvc3Bhbj5cbiAgICAgICAgICAgIDwvbGFiZWw+XG4gICAgICAgICAgPC9uZy10ZW1wbGF0ZT5cbiAgICAgICAgICA8ZGl2XG4gICAgICAgICAgICBjbGFzcz1cImM4eS1zZWxlY3Qtd3JhcHBlclwiXG4gICAgICAgICAgICAqbmdJZj1cIiFjb25maWcuaXNSZWFsdGltZTsgZWxzZSByZWFsdGltZVwiXG4gICAgICAgICAgPlxuICAgICAgICAgICAgPHNlbGVjdFxuICAgICAgICAgICAgICBjbGFzcz1cImZvcm0tY29udHJvbFwiXG4gICAgICAgICAgICAgIHRpdGxlPVwie3sgJ1JlZnJlc2ggb3B0aW9uc2BvcHRpb25zIGZvciByZWZyZXNoaW5nIGEgdmlld2AnIHwgdHJhbnNsYXRlIH19XCJcbiAgICAgICAgICAgICAgWyhuZ01vZGVsKV09XCJyZWZyZXNoT3B0aW9uXCJcbiAgICAgICAgICAgICAgW25nTW9kZWxPcHRpb25zXT1cInsgc3RhbmRhbG9uZTogdHJ1ZSB9XCJcbiAgICAgICAgICAgICAgKGNoYW5nZSk9XCJ1cGRhdGVSZWZyZXNoT3B0aW9uKClcIlxuICAgICAgICAgICAgPlxuICAgICAgICAgICAgICA8b3B0aW9uIHZhbHVlPVwibm9uZVwiPlxuICAgICAgICAgICAgICAgIHt7ICdObyBhdXRvbWF0aWMgcmVmcmVzaCcgfCB0cmFuc2xhdGUgfX1cbiAgICAgICAgICAgICAgPC9vcHRpb24+XG4gICAgICAgICAgICAgIDxvcHRpb25cbiAgICAgICAgICAgICAgICBbdGl0bGVdPVwiJ1JlZnJlc2hpbmcgYWZ0ZXIgdGhlIGdpdmVuIGludGVydmFsJyB8IHRyYW5zbGF0ZVwiXG4gICAgICAgICAgICAgICAgdmFsdWU9XCJpbnRlcnZhbFwiXG4gICAgICAgICAgICAgID5cbiAgICAgICAgICAgICAgICB7eyAnVXNlIHJlZnJlc2ggaW50ZXJ2YWwnIHwgdHJhbnNsYXRlIH19XG4gICAgICAgICAgICAgIDwvb3B0aW9uPlxuICAgICAgICAgICAgICA8b3B0aW9uXG4gICAgICAgICAgICAgICAgW3RpdGxlXT1cIidSZWZyZXNoaW5nIGFmdGVyIHRoZSBnaXZlbiBpbnRlcnZhbCwgc3luY2hyb25pemVkIGdsb2JhbGx5JyB8IHRyYW5zbGF0ZVwiXG4gICAgICAgICAgICAgICAgdmFsdWU9XCJnbG9iYWwtaW50ZXJ2YWxcIlxuICAgICAgICAgICAgICA+XG4gICAgICAgICAgICAgICAge3sgJ1VzZSBnbG9iYWwgcmVmcmVzaCBpbnRlcnZhbCcgfCB0cmFuc2xhdGUgfX1cbiAgICAgICAgICAgICAgPC9vcHRpb24+XG4gICAgICAgICAgICA8L3NlbGVjdD5cbiAgICAgICAgICA8L2Rpdj5cbiAgICAgICAgICA8bmctY29udGFpbmVyXG4gICAgICAgICAgICAqbmdJZj1cIiFjb25maWcuaXNSZWFsdGltZSAmJiBjb25maWcucmVmcmVzaE9wdGlvbiAhPT0gR0xPQkFMX0lOVEVSVkFMX09QVElPTlwiXG4gICAgICAgICAgPlxuICAgICAgICAgICAgPGxhYmVsXG4gICAgICAgICAgICAgIGNsYXNzPVwibS1iLTBcIlxuICAgICAgICAgICAgICBmb3I9XCJyZWZyZXNoSW50ZXJ2YWxcIlxuICAgICAgICAgICAgPlxuICAgICAgICAgICAgICB7eyAnSW50ZXJ2YWwnIHwgdHJhbnNsYXRlIH19XG4gICAgICAgICAgICA8L2xhYmVsPlxuICAgICAgICAgICAgPGRpdiBjbGFzcz1cImM4eS1zZWxlY3Qtd3JhcHBlciBmbGV4LWdyb3dcIj5cbiAgICAgICAgICAgICAgPHNlbGVjdFxuICAgICAgICAgICAgICAgIGNsYXNzPVwiZm9ybS1jb250cm9sIHRleHQtMTJcIlxuICAgICAgICAgICAgICAgIFt0aXRsZV09XCInUmVmcmVzaCBpbnRlcnZhbCBpbiBzZWNvbmRzJyB8IHRyYW5zbGF0ZVwiXG4gICAgICAgICAgICAgICAgaWQ9XCJyZWZyZXNoSW50ZXJ2YWxcIlxuICAgICAgICAgICAgICAgIGZvcm1Db250cm9sTmFtZT1cInJlZnJlc2hJbnRlcnZhbFwiXG4gICAgICAgICAgICAgID5cbiAgICAgICAgICAgICAgICA8b3B0aW9uXG4gICAgICAgICAgICAgICAgICAqbmdGb3I9XCJsZXQgcmVmcmVzaEludGVydmFsIG9mIFJFRlJFU0hfSU5URVJWQUxfSU5fTUlMTElTRUNPTkRTXCJcbiAgICAgICAgICAgICAgICAgIFtuZ1ZhbHVlXT1cInJlZnJlc2hJbnRlcnZhbFwiXG4gICAgICAgICAgICAgICAgPlxuICAgICAgICAgICAgICAgICAge3sgJ3t7IHNlY29uZHMgfX0gcycgfCB0cmFuc2xhdGU6IHsgc2Vjb25kczogcmVmcmVzaEludGVydmFsIC8gMTAwMCB9IH19XG4gICAgICAgICAgICAgICAgPC9vcHRpb24+XG4gICAgICAgICAgICAgIDwvc2VsZWN0PlxuICAgICAgICAgICAgPC9kaXY+XG4gICAgICAgICAgPC9uZy1jb250YWluZXI+XG4gICAgICAgIDwvZGl2PlxuICAgICAgPC9jOHktZm9ybS1ncm91cD5cbiAgICA8L2ZpZWxkc2V0PlxuICA8L2Rpdj5cbjwvZm9ybT5cblxuPGRpdiBjbGFzcz1cImxlZ2VuZCBmb3JtLWJsb2NrIG0tYi0wXCI+e3sgJ1ByZXZpZXdgb2YgYW4gYWxhcm0gbGlzdGAnIHwgdHJhbnNsYXRlIH19PC9kaXY+XG48Yzh5LWFsYXJtcy1saXN0XG4gIFthbGFybXNdPVwiYWxhcm1zJCB8IGFzeW5jXCJcbiAgW2lzSW5pdGlhbExvYWRpbmddPVwiaXNMb2FkaW5nXCJcbiAgW25hdmlnYXRpb25PcHRpb25zXT1cIntcbiAgICBhbGxvd05hdmlnYXRpb25Ub0FsYXJtc1ZpZXc6IGZhbHNlLFxuICAgIGFsd2F5c05hdmlnYXRlVG9BbGxBbGFybXM6IGZhbHNlLFxuICAgIGluY2x1ZGVDbGVhcmVkUXVlcnlQYXJhbXM6IGZhbHNlLFxuICAgIHF1ZXJ5UGFyYW1zSGFuZGxpbmc6ICdtZXJnZSdcbiAgfVwiXG4+PC9jOHktYWxhcm1zLWxpc3Q+XG5cbjxuZy10ZW1wbGF0ZSAjZGF0ZVNlbGVjdGlvbkhlbHBUZW1wbGF0ZT5cbiAgPGRpdiBbaW5uZXJIVE1MXT1cImRhdGVTZWxlY3Rpb25IZWxwXCI+PC9kaXY+XG48L25nLXRlbXBsYXRlPlxuIl19