UNPKG

@c8y/ngx-components

Version:

Angular modules for Cumulocity IoT applications

192 lines 35.3 kB
import { moveItemInArray } from '@angular/cdk/drag-drop'; import { Component, ContentChild, forwardRef, Input, Optional } from '@angular/core'; import { FormBuilder, NG_VALIDATORS, NG_VALUE_ACCESSOR } from '@angular/forms'; import { ContextRouteService, EmptyStateComponent, ViewContext } from '@c8y/ngx-components'; import { WidgetConfigComponent } from '@c8y/ngx-components/context-dashboard'; import { debounceTime, map, take, takeUntil } from 'rxjs/operators'; import { AlarmEventSelectorModalService } from '../alarm-event-selector-modal/alarm-event-selector-modal.service'; import { AlarmEventSelectorService } from '../alarm-event-selector.service'; import { Subject } from 'rxjs'; import { ActivatedRoute } from '@angular/router'; import * as i0 from "@angular/core"; import * as i1 from "../alarm-event-selector-modal/alarm-event-selector-modal.service"; import * as i2 from "../alarm-event-selector.service"; import * as i3 from "@angular/forms"; import * as i4 from "@angular/router"; import * as i5 from "@c8y/ngx-components"; import * as i6 from "@c8y/ngx-components/context-dashboard"; import * as i7 from "@angular/common"; import * as i8 from "@angular/cdk/drag-drop"; import * as i9 from "../alarm-event-selector-list-item/alarm-event-selector-list-item.component"; export class AlarmEventSelectionListComponent { constructor(alarmEventModalService, alarmEventSelectService, formBuilder, activatedRoute, contextRouteService, widgetComponent) { this.alarmEventModalService = alarmEventModalService; this.alarmEventSelectService = alarmEventSelectService; this.formBuilder = formBuilder; this.activatedRoute = activatedRoute; this.contextRouteService = contextRouteService; this.widgetComponent = widgetComponent; this.timelineType = 'ALARM'; this.canRemove = true; this.canEdit = true; this.canDragAndDrop = true; this.hideSource = false; this.inline = false; // TODO: @janhommes we should rename this to `isDropdownContained` or similar to make it more clear this.activeToggleAsSwitch = true; this.omitProperties = { color: false, label: false }; this.datapoints = []; /** * The configuration for the alarms-events selector modal. */ this.config = {}; this.destroy$ = new Subject(); this.formArray = this.formBuilder.array([]); } ngOnInit() { this.timelineTypeTexts = this.alarmEventSelectService.timelineTypeTexts(this.timelineType); this.title ??= this.timelineTypeTexts.listTitle; this.addButtonLabel ??= this.timelineTypeTexts.addButtonLabel; this.contextSourceId = this.initializeContextSourceId(); const context = this.widgetComponent?.context; if (context?.id) { const { name, id, c8y_IsDevice } = context; this.config.contextAsset = { name, id, c8y_IsDevice }; } } ngOnDestroy() { this.destroy$.next(); this.destroy$.complete(); } registerOnTouched(fn) { this.formArray.valueChanges.pipe(take(1)).subscribe(fn); } validate(_control) { return this.formArray.valid ? null : { formInvalid: {} }; } writeValue(val) { this.formArray.clear(); if (val?.length) { val.forEach(val => { const formgroup = this.formBuilder.group({ details: [] }); formgroup.patchValue({ details: val }); this.formArray.push(formgroup); }); } } registerOnChange(fn) { this.formArray.valueChanges .pipe(debounceTime(100), // debounce to avoid emitting of this.formArray.clear() map(res => this.transformValue(res)), takeUntil(this.destroy$)) .subscribe(fn); } add() { const allowChangingContext = !this.widgetComponent?.isDeviceTypeDashboard && this.config?.allowChangingContext !== false; this.alarmEventModalService .selectItems({ allowChangingContext, selectType: this.timelineType, selectedItems: this.transformValue(this.formArray.value), allowSearch: !this.config?.contextAsset, title: this.timelineTypeTexts.selectorTitle, saveButtonLabel: this.timelineTypeTexts.addButtonLabel, omitProperties: this.omitProperties, contextAsset: this.config?.contextAsset ? this.config.contextAsset : this.contextSourceId ? { id: this.contextSourceId } : null, ...(this.config || {}) }) .then(result => { this.writeValue(result); }, () => { // nothing to do, modal was closed }); } onItemRemoved(index) { this.formArray.removeAt(index); } drop(event) { const currentSorting = this.formArray.value; moveItemInArray(currentSorting, event.previousIndex, event.currentIndex); this.formArray.setValue(currentSorting); } transformValue(formArrayValue) { if (!formArrayValue) { return []; } return formArrayValue.map(tmp => Object.assign({}, ...Object.values(tmp))); } initializeContextSourceId() { const routeContext = this.contextRouteService.getContextData(this.activatedRoute); if (!routeContext) { return; } const { context, contextData } = routeContext; if ([ViewContext.Device, ViewContext.Group].includes(context)) { return contextData?.id; } } static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: AlarmEventSelectionListComponent, deps: [{ token: i1.AlarmEventSelectorModalService }, { token: i2.AlarmEventSelectorService }, { token: i3.FormBuilder }, { token: i4.ActivatedRoute, optional: true }, { token: i5.ContextRouteService, optional: true }, { token: i6.WidgetConfigComponent, optional: true }], target: i0.ɵɵFactoryTarget.Component }); } static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.13", type: AlarmEventSelectionListComponent, selector: "c8y-alarm-event-selection-list", inputs: { timelineType: "timelineType", canRemove: "canRemove", canEdit: "canEdit", canDragAndDrop: "canDragAndDrop", title: "title", addButtonLabel: "addButtonLabel", hideSource: "hideSource", inline: "inline", activeToggleAsSwitch: "activeToggleAsSwitch", omitProperties: "omitProperties", datapoints: "datapoints", config: "config" }, providers: [ { provide: NG_VALUE_ACCESSOR, multi: true, useExisting: forwardRef(() => AlarmEventSelectionListComponent) }, { provide: NG_VALIDATORS, useExisting: forwardRef(() => AlarmEventSelectionListComponent), multi: true } ], queries: [{ propertyName: "emptyState", first: true, predicate: EmptyStateComponent, descendants: true }], ngImport: i0, template: "<div\n class=\"card-header separator-top-bottom sticky-top bg-inherit\"\n *ngIf=\"!inline\"\n>\n <span class=\"card-title h4\">{{ title | translate }}</span>\n</div>\n\n<c8y-list-group\n class=\"flex-grow ff-scroll-fix cdk-droplist\"\n cdkDropList\n (cdkDropListDropped)=\"drop($event)\"\n [cdkDropListDisabled]=\"formArray.controls?.length < 2\"\n>\n <div\n class=\"p-t-8\"\n *ngIf=\"!formArray.controls?.length\"\n >\n <ng-content select=\"c8y-ui-empty-state\"></ng-content>\n <c8y-ui-empty-state\n class=\"p-t-8\"\n [icon]=\"timelineTypeTexts.emptyStateIcon\"\n [title]=\"timelineTypeTexts.emptyStateTitle | translate\"\n [subtitle]=\"timelineTypeTexts.emptyStateSubtitle | translate\"\n *ngIf=\"!emptyState\"\n [horizontal]=\"true\"\n ></c8y-ui-empty-state>\n </div>\n <div\n *ngFor=\"let itemForm of formArray.controls; let index = index\"\n [formGroup]=\"itemForm\"\n >\n <c8y-alarm-event-selector-list-item\n class=\"d-block\"\n cdkDrag\n [cdkDragDisabled]=\"!canDragAndDrop\"\n formControlName=\"details\"\n [showAddRemoveButton]=\"false\"\n [datapoints]=\"datapoints\"\n [optionToRemove]=\"canRemove\"\n [showActiveToggle]=\"true\"\n [timelineType]=\"timelineType\"\n [allowItemEdit]=\"canEdit\"\n [hideSource]=\"hideSource\"\n [displayAsSwitch]=\"activeToggleAsSwitch\"\n [omitProperties]=\"omitProperties\"\n (removed)=\"onItemRemoved(index)\"\n >\n <c8y-li-drag-handle\n title=\"{{ 'Click and drag to reorder' | translate }}\"\n cdkDragHandle\n *ngIf=\"canDragAndDrop\"\n >\n <i c8yIcon=\"drag-reorder\"></i>\n </c8y-li-drag-handle>\n </c8y-alarm-event-selector-list-item>\n </div>\n</c8y-list-group>\n\n<div class=\"card-footer bg-inherit\">\n <button\n class=\"btn btn-default btn-sm\"\n [title]=\"addButtonLabel | translate\"\n type=\"button\"\n [ngClass]=\"{ 'btn-block': inline }\"\n (click)=\"add()\"\n >\n <i\n c8yIcon=\"plus-circle\"\n *ngIf=\"canDragAndDrop\"\n ></i>\n {{ addButtonLabel | translate }}\n </button>\n</div>\n", dependencies: [{ kind: "component", type: i5.EmptyStateComponent, selector: "c8y-ui-empty-state", inputs: ["icon", "title", "subtitle", "horizontal"] }, { kind: "directive", type: i5.IconDirective, selector: "[c8yIcon]", inputs: ["c8yIcon"] }, { kind: "directive", type: i7.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i7.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i7.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i3.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i3.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "component", type: i5.ListGroupComponent, selector: "c8y-list-group" }, { kind: "component", type: i5.ListItemDragHandleComponent, selector: "c8y-list-item-drag-handle, c8y-li-drag-handle" }, { kind: "directive", type: i3.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i3.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "directive", type: i8.CdkDropList, selector: "[cdkDropList], cdk-drop-list", inputs: ["cdkDropListConnectedTo", "cdkDropListData", "cdkDropListOrientation", "id", "cdkDropListLockAxis", "cdkDropListDisabled", "cdkDropListSortingDisabled", "cdkDropListEnterPredicate", "cdkDropListSortPredicate", "cdkDropListAutoScrollDisabled", "cdkDropListAutoScrollStep", "cdkDropListElementContainer"], outputs: ["cdkDropListDropped", "cdkDropListEntered", "cdkDropListExited", "cdkDropListSorted"], exportAs: ["cdkDropList"] }, { kind: "directive", type: i8.CdkDrag, selector: "[cdkDrag]", inputs: ["cdkDragData", "cdkDragLockAxis", "cdkDragRootElement", "cdkDragBoundary", "cdkDragStartDelay", "cdkDragFreeDragPosition", "cdkDragDisabled", "cdkDragConstrainPosition", "cdkDragPreviewClass", "cdkDragPreviewContainer", "cdkDragScale"], outputs: ["cdkDragStarted", "cdkDragReleased", "cdkDragEnded", "cdkDragEntered", "cdkDragExited", "cdkDragDropped", "cdkDragMoved"], exportAs: ["cdkDrag"] }, { kind: "directive", type: i8.CdkDragHandle, selector: "[cdkDragHandle]", inputs: ["cdkDragHandleDisabled"] }, { kind: "component", type: i9.AlarmEventSelectorListItemComponent, selector: "c8y-alarm-event-selector-list-item", inputs: ["timelineType", "datapoints", "highlightText", "showAddRemoveButton", "isSelected", "optionToRemove", "showActiveToggle", "allowItemEdit", "hideSource", "displayAsSwitch", "omitProperties"], outputs: ["added", "removed"] }, { kind: "pipe", type: i5.C8yTranslatePipe, name: "translate" }] }); } } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: AlarmEventSelectionListComponent, decorators: [{ type: Component, args: [{ selector: 'c8y-alarm-event-selection-list', providers: [ { provide: NG_VALUE_ACCESSOR, multi: true, useExisting: forwardRef(() => AlarmEventSelectionListComponent) }, { provide: NG_VALIDATORS, useExisting: forwardRef(() => AlarmEventSelectionListComponent), multi: true } ], template: "<div\n class=\"card-header separator-top-bottom sticky-top bg-inherit\"\n *ngIf=\"!inline\"\n>\n <span class=\"card-title h4\">{{ title | translate }}</span>\n</div>\n\n<c8y-list-group\n class=\"flex-grow ff-scroll-fix cdk-droplist\"\n cdkDropList\n (cdkDropListDropped)=\"drop($event)\"\n [cdkDropListDisabled]=\"formArray.controls?.length < 2\"\n>\n <div\n class=\"p-t-8\"\n *ngIf=\"!formArray.controls?.length\"\n >\n <ng-content select=\"c8y-ui-empty-state\"></ng-content>\n <c8y-ui-empty-state\n class=\"p-t-8\"\n [icon]=\"timelineTypeTexts.emptyStateIcon\"\n [title]=\"timelineTypeTexts.emptyStateTitle | translate\"\n [subtitle]=\"timelineTypeTexts.emptyStateSubtitle | translate\"\n *ngIf=\"!emptyState\"\n [horizontal]=\"true\"\n ></c8y-ui-empty-state>\n </div>\n <div\n *ngFor=\"let itemForm of formArray.controls; let index = index\"\n [formGroup]=\"itemForm\"\n >\n <c8y-alarm-event-selector-list-item\n class=\"d-block\"\n cdkDrag\n [cdkDragDisabled]=\"!canDragAndDrop\"\n formControlName=\"details\"\n [showAddRemoveButton]=\"false\"\n [datapoints]=\"datapoints\"\n [optionToRemove]=\"canRemove\"\n [showActiveToggle]=\"true\"\n [timelineType]=\"timelineType\"\n [allowItemEdit]=\"canEdit\"\n [hideSource]=\"hideSource\"\n [displayAsSwitch]=\"activeToggleAsSwitch\"\n [omitProperties]=\"omitProperties\"\n (removed)=\"onItemRemoved(index)\"\n >\n <c8y-li-drag-handle\n title=\"{{ 'Click and drag to reorder' | translate }}\"\n cdkDragHandle\n *ngIf=\"canDragAndDrop\"\n >\n <i c8yIcon=\"drag-reorder\"></i>\n </c8y-li-drag-handle>\n </c8y-alarm-event-selector-list-item>\n </div>\n</c8y-list-group>\n\n<div class=\"card-footer bg-inherit\">\n <button\n class=\"btn btn-default btn-sm\"\n [title]=\"addButtonLabel | translate\"\n type=\"button\"\n [ngClass]=\"{ 'btn-block': inline }\"\n (click)=\"add()\"\n >\n <i\n c8yIcon=\"plus-circle\"\n *ngIf=\"canDragAndDrop\"\n ></i>\n {{ addButtonLabel | translate }}\n </button>\n</div>\n" }] }], ctorParameters: () => [{ type: i1.AlarmEventSelectorModalService }, { type: i2.AlarmEventSelectorService }, { type: i3.FormBuilder }, { type: i4.ActivatedRoute, decorators: [{ type: Optional }] }, { type: i5.ContextRouteService, decorators: [{ type: Optional }] }, { type: i6.WidgetConfigComponent, decorators: [{ type: Optional }] }], propDecorators: { timelineType: [{ type: Input }], canRemove: [{ type: Input }], canEdit: [{ type: Input }], canDragAndDrop: [{ type: Input }], title: [{ type: Input }], addButtonLabel: [{ type: Input }], hideSource: [{ type: Input }], inline: [{ type: Input }], activeToggleAsSwitch: [{ type: Input }], omitProperties: [{ type: Input }], datapoints: [{ type: Input }], emptyState: [{ type: ContentChild, args: [EmptyStateComponent] }], config: [{ type: Input }] } }); //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYWxhcm0tZXZlbnQtc2VsZWN0aW9uLWxpc3QuY29tcG9uZW50LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vYWxhcm0tZXZlbnQtc2VsZWN0b3IvYWxhcm0tZXZlbnQtc2VsZWN0aW9uLWxpc3QvYWxhcm0tZXZlbnQtc2VsZWN0aW9uLWxpc3QuY29tcG9uZW50LnRzIiwiLi4vLi4vLi4vLi4vYWxhcm0tZXZlbnQtc2VsZWN0b3IvYWxhcm0tZXZlbnQtc2VsZWN0aW9uLWxpc3QvYWxhcm0tZXZlbnQtc2VsZWN0aW9uLWxpc3QuY29tcG9uZW50Lmh0bWwiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUFlLGVBQWUsRUFBRSxNQUFNLHdCQUF3QixDQUFDO0FBQ3RFLE9BQU8sRUFDTCxTQUFTLEVBQ1QsWUFBWSxFQUNaLFVBQVUsRUFDVixLQUFLLEVBR0wsUUFBUSxFQUNULE1BQU0sZUFBZSxDQUFDO0FBQ3ZCLE9BQU8sRUFJTCxXQUFXLEVBQ1gsYUFBYSxFQUNiLGlCQUFpQixFQUdsQixNQUFNLGdCQUFnQixDQUFDO0FBQ3hCLE9BQU8sRUFBRSxtQkFBbUIsRUFBRSxtQkFBbUIsRUFBRSxXQUFXLEVBQUUsTUFBTSxxQkFBcUIsQ0FBQztBQUM1RixPQUFPLEVBQUUscUJBQXFCLEVBQUUsTUFBTSx1Q0FBdUMsQ0FBQztBQUM5RSxPQUFPLEVBQUUsWUFBWSxFQUFFLEdBQUcsRUFBRSxJQUFJLEVBQUUsU0FBUyxFQUFFLE1BQU0sZ0JBQWdCLENBQUM7QUFFcEUsT0FBTyxFQUFFLDhCQUE4QixFQUFFLE1BQU0sa0VBQWtFLENBQUM7QUFPbEgsT0FBTyxFQUFFLHlCQUF5QixFQUFFLE1BQU0saUNBQWlDLENBQUM7QUFDNUUsT0FBTyxFQUFFLE9BQU8sRUFBRSxNQUFNLE1BQU0sQ0FBQztBQUMvQixPQUFPLEVBQUUsY0FBYyxFQUFFLE1BQU0saUJBQWlCLENBQUM7Ozs7Ozs7Ozs7O0FBa0JqRCxNQUFNLE9BQU8sZ0NBQWdD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QWpCLEtBQUs7Z0JBQ0csT0FBTztzQkFBZixLQUFLO2dCQUNHLGNBQWM7c0JBQXRCLEtBQUs7Z0JBQ0csS0FBSztzQkFBYixLQUFLO2dCQUNHLGNBQWM7c0JBQXRCLEtBQUs7Z0JBQ0csVUFBVTtzQkFBbEIsS0FBSztnQkFDRyxNQUFNO3NCQUFkLEtBQUs7Z0JBQ0csb0JBQW9CO3NCQUE1QixLQUFLO2dCQUNHLGNBQWM7c0JBQXRCLEtBQUs7Z0JBQ0csVUFBVTtzQkFBbEIsS0FBSztnQkFDNkIsVUFBVTtzQkFBNUMsWUFBWTt1QkFBQyxtQkFBbUI7Z0JBS3hCLE1BQU07c0JBQWQsS0FBSyIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IENka0RyYWdEcm9wLCBtb3ZlSXRlbUluQXJyYXkgfSBmcm9tICdAYW5ndWxhci9jZGsvZHJhZy1kcm9wJztcbmltcG9ydCB7XG4gIENvbXBvbmVudCxcbiAgQ29udGVudENoaWxkLFxuICBmb3J3YXJkUmVmLFxuICBJbnB1dCxcbiAgT25EZXN0cm95LFxuICBPbkluaXQsXG4gIE9wdGlvbmFsXG59IGZyb20gJ0Bhbmd1bGFyL2NvcmUnO1xuaW1wb3J0IHtcbiAgQWJzdHJhY3RDb250cm9sLFxuICBDb250cm9sVmFsdWVBY2Nlc3NvcixcbiAgRm9ybUFycmF5LFxuICBGb3JtQnVpbGRlcixcbiAgTkdfVkFMSURBVE9SUyxcbiAgTkdfVkFMVUVfQUNDRVNTT1IsXG4gIFZhbGlkYXRpb25FcnJvcnMsXG4gIFZhbGlkYXRvclxufSBmcm9tICdAYW5ndWxhci9mb3Jtcyc7XG5pbXBvcnQgeyBDb250ZXh0Um91dGVTZXJ2aWNlLCBFbXB0eVN0YXRlQ29tcG9uZW50LCBWaWV3Q29udGV4dCB9IGZyb20gJ0BjOHkvbmd4LWNvbXBvbmVudHMnO1xuaW1wb3J0IHsgV2lkZ2V0Q29uZmlnQ29tcG9uZW50IH0gZnJvbSAnQGM4eS9uZ3gtY29tcG9uZW50cy9jb250ZXh0LWRhc2hib2FyZCc7XG5pbXBvcnQgeyBkZWJvdW5jZVRpbWUsIG1hcCwgdGFrZSwgdGFrZVVudGlsIH0gZnJvbSAncnhqcy9vcGVyYXRvcnMnO1xuaW1wb3J0IHsgQWxhcm1FdmVudFNlbGVjdG9yTW9kYWxPcHRpb25zIH0gZnJvbSAnLi4vYWxhcm0tZXZlbnQtc2VsZWN0b3ItbW9kYWwvYWxhcm0tZXZlbnQtc2VsZWN0b3ItbW9kYWwubW9kZWwnO1xuaW1wb3J0IHsgQWxhcm1FdmVudFNlbGVjdG9yTW9kYWxTZXJ2aWNlIH0gZnJvbSAnLi4vYWxhcm0tZXZlbnQtc2VsZWN0b3ItbW9kYWwvYWxhcm0tZXZlbnQtc2VsZWN0b3ItbW9kYWwuc2VydmljZSc7XG5pbXBvcnQge1xuICBBbGFybU9yRXZlbnQsXG4gIE9taXRTZWxlY3RvclByb3BlcnRpZXMsXG4gIFRpbWVsaW5lVHlwZSxcbiAgVGltZWxpbmVUeXBlVGV4dHNcbn0gZnJvbSAnLi4vYWxhcm0tZXZlbnQtc2VsZWN0b3IubW9kZWwnO1xuaW1wb3J0IHsgQWxhcm1FdmVudFNlbGVjdG9yU2VydmljZSB9IGZyb20gJy4uL2FsYXJtLWV2ZW50LXNlbGVjdG9yLnNlcnZpY2UnO1xuaW1wb3J0IHsgU3ViamVjdCB9IGZyb20gJ3J4anMnO1xuaW1wb3J0IHsgQWN0aXZhdGVkUm91dGUgfSBmcm9tICdAYW5ndWxhci9yb3V0ZXInO1xuXG5AQ29tcG9uZW50KHtcbiAgc2VsZWN0b3I6ICdjOHktYWxhcm0tZXZlbnQtc2VsZWN0aW9uLWxpc3QnLFxuICB0ZW1wbGF0ZVVybDogJy4vYWxhcm0tZXZlbnQtc2VsZWN0aW9uLWxpc3QuY29tcG9uZW50Lmh0bWwnLFxuICBwcm92aWRlcnM6IFtcbiAgICB7XG4gICAgICBwcm92aWRlOiBOR19WQUxVRV9BQ0NFU1NPUixcbiAgICAgIG11bHRpOiB0cnVlLFxuICAgICAgdXNlRXhpc3Rpbmc6IGZvcndhcmRSZWYoKCkgPT4gQWxhcm1FdmVudFNlbGVjdGlvbkxpc3RDb21wb25lbnQpXG4gICAgfSxcbiAgICB7XG4gICAgICBwcm92aWRlOiBOR19WQUxJREFUT1JTLFxuICAgICAgdXNlRXhpc3Rpbmc6IGZvcndhcmRSZWYoKCkgPT4gQWxhcm1FdmVudFNlbGVjdGlvbkxpc3RDb21wb25lbnQpLFxuICAgICAgbXVsdGk6IHRydWVcbiAgICB9XG4gIF1cbn0pXG5leHBvcnQgY2xhc3MgQWxhcm1FdmVudFNlbGVjdGlvbkxpc3RDb21wb25lbnRcbiAgaW1wbGVtZW50cyBDb250cm9sVmFsdWVBY2Nlc3NvciwgVmFsaWRhdG9yLCBPbkluaXQsIE9uRGVzdHJveVxue1xuICBASW5wdXQoKSB0aW1lbGluZVR5cGU6IFRpbWVsaW5lVHlwZSA9ICdBTEFSTSc7XG4gIEBJbnB1dCgpIGNhblJlbW92ZSA9IHRydWU7XG4gIEBJbnB1dCgpIGNhbkVkaXQgPSB0cnVlO1xuICBASW5wdXQoKSBjYW5EcmFnQW5kRHJvcCA9IHRydWU7XG4gIEBJbnB1dCgpIHRpdGxlOiBzdHJpbmc7XG4gIEBJbnB1dCgpIGFkZEJ1dHRvbkxhYmVsOiBzdHJpbmc7XG4gIEBJbnB1dCgpIGhpZGVTb3VyY2UgPSBmYWxzZTtcbiAgQElucHV0KCkgaW5saW5lID0gZmFsc2U7IC8vIFRPRE86IEBqYW5ob21tZXMgd2Ugc2hvdWxkIHJlbmFtZSB0aGlzIHRvIGBpc0Ryb3Bkb3duQ29udGFpbmVkYCBvciBzaW1pbGFyIHRvIG1ha2UgaXQgbW9yZSBjbGVhclxuICBASW5wdXQoKSBhY3RpdmVUb2dnbGVBc1N3aXRjaCA9IHRydWU7XG4gIEBJbnB1dCgpIG9taXRQcm9wZXJ0aWVzOiBPbWl0U2VsZWN0b3JQcm9wZXJ0aWVzID0geyBjb2xvcjogZmFsc2UsIGxhYmVsOiBmYWxzZSB9O1xuICBASW5wdXQoKSBkYXRhcG9pbnRzID0gW107XG4gIEBDb250ZW50Q2hpbGQoRW1wdHlTdGF0ZUNvbXBvbmVudCkgZW1wdHlTdGF0ZTogRW1wdHlTdGF0ZUNvbXBvbmVudDtcblxuICAvKipcbiAgICogVGhlIGNvbmZpZ3VyYXRpb24gZm9yIHRoZSBhbGFybXMtZXZlbnRzIHNlbGVjdG9yIG1vZGFsLlxuICAgKi9cbiAgQElucHV0KCkgY29uZmlnOiBQYXJ0aWFsPEFsYXJtRXZlbnRTZWxlY3Rvck1vZGFsT3B0aW9ucz4gPSB7fTtcblxuICBmb3JtQXJyYXk6IEZvcm1BcnJheTtcbiAgdGltZWxpbmVUeXBlVGV4dHM6IFRpbWVsaW5lVHlwZVRleHRzO1xuICBjb250ZXh0U291cmNlSWQ6IG51bWJlciB8IHN0cmluZyB8IG51bGw7XG5cbiAgcHJpdmF0ZSBkZXN0cm95JCA9IG5ldyBTdWJqZWN0PHZvaWQ+KCk7XG5cbiAgY29uc3RydWN0b3IoXG4gICAgcHJpdmF0ZSBhbGFybUV2ZW50TW9kYWxTZXJ2aWNlOiBBbGFybUV2ZW50U2VsZWN0b3JNb2RhbFNlcnZpY2UsXG4gICAgcHJpdmF0ZSBhbGFybUV2ZW50U2VsZWN0U2VydmljZTogQWxhcm1FdmVudFNlbGVjdG9yU2VydmljZSxcbiAgICBwcml2YXRlIGZvcm1CdWlsZGVyOiBGb3JtQnVpbGRlcixcbiAgICBAT3B0aW9uYWwoKSBwcml2YXRlIGFjdGl2YXRlZFJvdXRlOiBBY3RpdmF0ZWRSb3V0ZSxcbiAgICBAT3B0aW9uYWwoKSBwcml2YXRlIGNvbnRleHRSb3V0ZVNlcnZpY2U6IENvbnRleHRSb3V0ZVNlcnZpY2UsXG4gICAgQE9wdGlvbmFsKCkgcHJpdmF0ZSB3aWRnZXRDb21wb25lbnQ6IFdpZGdldENvbmZpZ0NvbXBvbmVudFxuICApIHtcbiAgICB0aGlzLmZvcm1BcnJheSA9IHRoaXMuZm9ybUJ1aWxkZXIuYXJyYXkoW10pO1xuICB9XG5cbiAgbmdPbkluaXQoKTogdm9pZCB7XG4gICAgdGhpcy50aW1lbGluZVR5cGVUZXh0cyA9IHRoaXMuYWxhcm1FdmVudFNlbGVjdFNlcnZpY2UudGltZWxpbmVUeXBlVGV4dHModGhpcy50aW1lbGluZVR5cGUpO1xuICAgIHRoaXMudGl0bGUgPz89IHRoaXMudGltZWxpbmVUeXBlVGV4dHMubGlzdFRpdGxlO1xuICAgIHRoaXMuYWRkQnV0dG9uTGFiZWwgPz89IHRoaXMudGltZWxpbmVUeXBlVGV4dHMuYWRkQnV0dG9uTGFiZWw7XG4gICAgdGhpcy5jb250ZXh0U291cmNlSWQgPSB0aGlzLmluaXRpYWxpemVDb250ZXh0U291cmNlSWQoKTtcbiAgICBjb25zdCBjb250ZXh0ID0gdGhpcy53aWRnZXRDb21wb25lbnQ/LmNvbnRleHQ7XG4gICAgaWYgKGNvbnRleHQ/LmlkKSB7XG4gICAgICBjb25zdCB7IG5hbWUsIGlkLCBjOHlfSXNEZXZpY2UgfSA9IGNvbnRleHQ7XG4gICAgICB0aGlzLmNvbmZpZy5jb250ZXh0QXNzZXQgPSB7IG5hbWUsIGlkLCBjOHlfSXNEZXZpY2UgfTtcbiAgICB9XG4gIH1cblxuICBuZ09uRGVzdHJveSgpOiB2b2lkIHtcbiAgICB0aGlzLmRlc3Ryb3kkLm5leHQoKTtcbiAgICB0aGlzLmRlc3Ryb3kkLmNvbXBsZXRlKCk7XG4gIH1cblxuICByZWdpc3Rlck9uVG91Y2hlZChmbjogYW55KTogdm9pZCB7XG4gICAgdGhpcy5mb3JtQXJyYXkudmFsdWVDaGFuZ2VzLnBpcGUodGFrZSgxKSkuc3Vic2NyaWJlKGZuKTtcbiAgfVxuXG4gIHZhbGlkYXRlKF9jb250cm9sOiBBYnN0cmFjdENvbnRyb2wpOiBWYWxpZGF0aW9uRXJyb3JzIHtcbiAgICByZXR1cm4gdGhpcy5mb3JtQXJyYXkudmFsaWQgPyBudWxsIDogeyBmb3JtSW52YWxpZDoge30gfTtcbiAgfVxuXG4gIHdyaXRlVmFsdWUodmFsOiBBbGFybU9yRXZlbnRbXSk6IHZvaWQge1xuICAgIHRoaXMuZm9ybUFycmF5LmNsZWFyKCk7XG4gICAgaWYgKHZhbD8ubGVuZ3RoKSB7XG4gICAgICB2YWwuZm9yRWFjaCh2YWwgPT4ge1xuICAgICAgICBjb25zdCBmb3JtZ3JvdXAgPSB0aGlzLmZvcm1CdWlsZGVyLmdyb3VwKHsgZGV0YWlsczogW10gfSk7XG4gICAgICAgIGZvcm1ncm91cC5wYXRjaFZhbHVlKHsgZGV0YWlsczogdmFsIH0pO1xuICAgICAgICB0aGlzLmZvcm1BcnJheS5wdXNoKGZvcm1ncm91cCk7XG4gICAgICB9KTtcbiAgICB9XG4gIH1cblxuICByZWdpc3Rlck9uQ2hhbmdlKGZuOiBhbnkpOiB2b2lkIHtcbiAgICB0aGlzLmZvcm1BcnJheS52YWx1ZUNoYW5nZXNcbiAgICAgIC5waXBlKFxuICAgICAgICBkZWJvdW5jZVRpbWUoMTAwKSwgLy8gZGVib3VuY2UgdG8gYXZvaWQgZW1pdHRpbmcgb2YgdGhpcy5mb3JtQXJyYXkuY2xlYXIoKVxuICAgICAgICBtYXAocmVzID0+IHRoaXMudHJhbnNmb3JtVmFsdWUocmVzKSksXG4gICAgICAgIHRha2VVbnRpbCh0aGlzLmRlc3Ryb3kkKVxuICAgICAgKVxuICAgICAgLnN1YnNjcmliZShmbik7XG4gIH1cblxuICBhZGQoKSB7XG4gICAgY29uc3QgYWxsb3dDaGFuZ2luZ0NvbnRleHQgPVxuICAgICAgIXRoaXMud2lkZ2V0Q29tcG9uZW50Py5pc0RldmljZVR5cGVEYXNoYm9hcmQgJiYgdGhpcy5jb25maWc/LmFsbG93Q2hhbmdpbmdDb250ZXh0ICE9PSBmYWxzZTtcbiAgICB0aGlzLmFsYXJtRXZlbnRNb2RhbFNlcnZpY2VcbiAgICAgIC5zZWxlY3RJdGVtcyh7XG4gICAgICAgIGFsbG93Q2hhbmdpbmdDb250ZXh0LFxuICAgICAgICBzZWxlY3RUeXBlOiB0aGlzLnRpbWVsaW5lVHlwZSxcbiAgICAgICAgc2VsZWN0ZWRJdGVtczogdGhpcy50cmFuc2Zvcm1WYWx1ZSh0aGlzLmZvcm1BcnJheS52YWx1ZSksXG4gICAgICAgIGFsbG93U2VhcmNoOiAhdGhpcy5jb25maWc/LmNvbnRleHRBc3NldCxcbiAgICAgICAgdGl0bGU6IHRoaXMudGltZWxpbmVUeXBlVGV4dHMuc2VsZWN0b3JUaXRsZSxcbiAgICAgICAgc2F2ZUJ1dHRvbkxhYmVsOiB0aGlzLnRpbWVsaW5lVHlwZVRleHRzLmFkZEJ1dHRvbkxhYmVsLFxuICAgICAgICBvbWl0UHJvcGVydGllczogdGhpcy5vbWl0UHJvcGVydGllcyxcbiAgICAgICAgY29udGV4dEFzc2V0OiB0aGlzLmNvbmZpZz8uY29udGV4dEFzc2V0XG4gICAgICAgICAgPyB0aGlzLmNvbmZpZy5jb250ZXh0QXNzZXRcbiAgICAgICAgICA6IHRoaXMuY29udGV4dFNvdXJjZUlkXG4gICAgICAgICAgICA/IHsgaWQ6IHRoaXMuY29udGV4dFNvdXJjZUlkIH1cbiAgICAgICAgICAgIDogbnVsbCxcbiAgICAgICAgLi4uKHRoaXMuY29uZmlnIHx8IHt9KVxuICAgICAgfSlcbiAgICAgIC50aGVuKFxuICAgICAgICByZXN1bHQgPT4ge1xuICAgICAgICAgIHRoaXMud3JpdGVWYWx1ZShyZXN1bHQpO1xuICAgICAgICB9LFxuICAgICAgICAoKSA9PiB7XG4gICAgICAgICAgLy8gbm90aGluZyB0byBkbywgbW9kYWwgd2FzIGNsb3NlZFxuICAgICAgICB9XG4gICAgICApO1xuICB9XG5cbiAgb25JdGVtUmVtb3ZlZChpbmRleDogbnVtYmVyKSB7XG4gICAgdGhpcy5mb3JtQXJyYXkucmVtb3ZlQXQoaW5kZXgpO1xuICB9XG5cbiAgZHJvcChldmVudDogQ2RrRHJhZ0Ryb3A8QWxhcm1PckV2ZW50W10+KSB7XG4gICAgY29uc3QgY3VycmVudFNvcnRpbmcgPSB0aGlzLmZvcm1BcnJheS52YWx1ZTtcbiAgICBtb3ZlSXRlbUluQXJyYXkoY3VycmVudFNvcnRpbmcsIGV2ZW50LnByZXZpb3VzSW5kZXgsIGV2ZW50LmN1cnJlbnRJbmRleCk7XG4gICAgdGhpcy5mb3JtQXJyYXkuc2V0VmFsdWUoY3VycmVudFNvcnRpbmcpO1xuICB9XG5cbiAgcHJpdmF0ZSB0cmFuc2Zvcm1WYWx1ZShmb3JtQXJyYXlWYWx1ZTogYW55W10pIHtcbiAgICBpZiAoIWZvcm1BcnJheVZhbHVlKSB7XG4gICAgICByZXR1cm4gW107XG4gICAgfVxuICAgIHJldHVybiBmb3JtQXJyYXlWYWx1ZS5tYXAodG1wID0+IE9iamVjdC5hc3NpZ24oe30sIC4uLk9iamVjdC52YWx1ZXModG1wKSkpO1xuICB9XG5cbiAgcHJpdmF0ZSBpbml0aWFsaXplQ29udGV4dFNvdXJjZUlkKCk6IG51bWJlciB8IHN0cmluZyB8IG51bGwge1xuICAgIGNvbnN0IHJvdXRlQ29udGV4dCA9IHRoaXMuY29udGV4dFJvdXRlU2VydmljZS5nZXRDb250ZXh0RGF0YSh0aGlzLmFjdGl2YXRlZFJvdXRlKTtcbiAgICBpZiAoIXJvdXRlQ29udGV4dCkge1xuICAgICAgcmV0dXJuO1xuICAgIH1cbiAgICBjb25zdCB7IGNvbnRleHQsIGNvbnRleHREYXRhIH0gPSByb3V0ZUNvbnRleHQ7XG4gICAgaWYgKFtWaWV3Q29udGV4dC5EZXZpY2UsIFZpZXdDb250ZXh0Lkdyb3VwXS5pbmNsdWRlcyhjb250ZXh0KSkge1xuICAgICAgcmV0dXJuIGNvbnRleHREYXRhPy5pZDtcbiAgICB9XG4gIH1cbn1cbiIsIjxkaXZcbiAgY2xhc3M9XCJjYXJkLWhlYWRlciBzZXBhcmF0b3ItdG9wLWJvdHRvbSBzdGlja3ktdG9wIGJnLWluaGVyaXRcIlxuICAqbmdJZj1cIiFpbmxpbmVcIlxuPlxuICA8c3BhbiBjbGFzcz1cImNhcmQtdGl0bGUgaDRcIj57eyB0aXRsZSB8IHRyYW5zbGF0ZSB9fTwvc3Bhbj5cbjwvZGl2PlxuXG48Yzh5LWxpc3QtZ3JvdXBcbiAgY2xhc3M9XCJmbGV4LWdyb3cgZmYtc2Nyb2xsLWZpeCBjZGstZHJvcGxpc3RcIlxuICBjZGtEcm9wTGlzdFxuICAoY2RrRHJvcExpc3REcm9wcGVkKT1cImRyb3AoJGV2ZW50KVwiXG4gIFtjZGtEcm9wTGlzdERpc2FibGVkXT1cImZvcm1BcnJheS5jb250cm9scz8ubGVuZ3RoIDwgMlwiXG4+XG4gIDxkaXZcbiAgICBjbGFzcz1cInAtdC04XCJcbiAgICAqbmdJZj1cIiFmb3JtQXJyYXkuY29udHJvbHM/Lmxlbmd0aFwiXG4gID5cbiAgICA8bmctY29udGVudCBzZWxlY3Q9XCJjOHktdWktZW1wdHktc3RhdGVcIj48L25nLWNvbnRlbnQ+XG4gICAgPGM4eS11aS1lbXB0eS1zdGF0ZVxuICAgICAgY2xhc3M9XCJwLXQtOFwiXG4gICAgICBbaWNvbl09XCJ0aW1lbGluZVR5cGVUZXh0cy5lbXB0eVN0YXRlSWNvblwiXG4gICAgICBbdGl0bGVdPVwidGltZWxpbmVUeXBlVGV4dHMuZW1wdHlTdGF0ZVRpdGxlIHwgdHJhbnNsYXRlXCJcbiAgICAgIFtzdWJ0aXRsZV09XCJ0aW1lbGluZVR5cGVUZXh0cy5lbXB0eVN0YXRlU3VidGl0bGUgfCB0cmFuc2xhdGVcIlxuICAgICAgKm5nSWY9XCIhZW1wdHlTdGF0ZVwiXG4gICAgICBbaG9yaXpvbnRhbF09XCJ0cnVlXCJcbiAgICA+PC9jOHktdWktZW1wdHktc3RhdGU+XG4gIDwvZGl2PlxuICA8ZGl2XG4gICAgKm5nRm9yPVwibGV0IGl0ZW1Gb3JtIG9mIGZvcm1BcnJheS5jb250cm9sczsgbGV0IGluZGV4ID0gaW5kZXhcIlxuICAgIFtmb3JtR3JvdXBdPVwiaXRlbUZvcm1cIlxuICA+XG4gICAgPGM4eS1hbGFybS1ldmVudC1zZWxlY3Rvci1saXN0LWl0ZW1cbiAgICAgIGNsYXNzPVwiZC1ibG9ja1wiXG4gICAgICBjZGtEcmFnXG4gICAgICBbY2RrRHJhZ0Rpc2FibGVkXT1cIiFjYW5EcmFnQW5kRHJvcFwiXG4gICAgICBmb3JtQ29udHJvbE5hbWU9XCJkZXRhaWxzXCJcbiAgICAgIFtzaG93QWRkUmVtb3ZlQnV0dG9uXT1cImZhbHNlXCJcbiAgICAgIFtkYXRhcG9pbnRzXT1cImRhdGFwb2ludHNcIlxuICAgICAgW29wdGlvblRvUmVtb3ZlXT1cImNhblJlbW92ZVwiXG4gICAgICBbc2hvd0FjdGl2ZVRvZ2dsZV09XCJ0cnVlXCJcbiAgICAgIFt0aW1lbGluZVR5cGVdPVwidGltZWxpbmVUeXBlXCJcbiAgICAgIFthbGxvd0l0ZW1FZGl0XT1cImNhbkVkaXRcIlxuICAgICAgW2hpZGVTb3VyY2VdPVwiaGlkZVNvdXJjZVwiXG4gICAgICBbZGlzcGxheUFzU3dpdGNoXT1cImFjdGl2ZVRvZ2dsZUFzU3dpdGNoXCJcbiAgICAgIFtvbWl0UHJvcGVydGllc109XCJvbWl0UHJvcGVydGllc1wiXG4gICAgICAocmVtb3ZlZCk9XCJvbkl0ZW1SZW1vdmVkKGluZGV4KVwiXG4gICAgPlxuICAgICAgPGM4eS1saS1kcmFnLWhhbmRsZVxuICAgICAgICB0aXRsZT1cInt7ICdDbGljayBhbmQgZHJhZyB0byByZW9yZGVyJyB8IHRyYW5zbGF0ZSB9fVwiXG4gICAgICAgIGNka0RyYWdIYW5kbGVcbiAgICAgICAgKm5nSWY9XCJjYW5EcmFnQW5kRHJvcFwiXG4gICAgICA+XG4gICAgICAgIDxpIGM4eUljb249XCJkcmFnLXJlb3JkZXJcIj48L2k+XG4gICAgICA8L2M4eS1saS1kcmFnLWhhbmRsZT5cbiAgICA8L2M4eS1hbGFybS1ldmVudC1zZWxlY3Rvci1saXN0LWl0ZW0+XG4gIDwvZGl2PlxuPC9jOHktbGlzdC1ncm91cD5cblxuPGRpdiBjbGFzcz1cImNhcmQtZm9vdGVyIGJnLWluaGVyaXRcIj5cbiAgPGJ1dHRvblxuICAgIGNsYXNzPVwiYnRuIGJ0bi1kZWZhdWx0IGJ0bi1zbVwiXG4gICAgW3RpdGxlXT1cImFkZEJ1dHRvbkxhYmVsIHwgdHJhbnNsYXRlXCJcbiAgICB0eXBlPVwiYnV0dG9uXCJcbiAgICBbbmdDbGFzc109XCJ7ICdidG4tYmxvY2snOiBpbmxpbmUgfVwiXG4gICAgKGNsaWNrKT1cImFkZCgpXCJcbiAgPlxuICAgIDxpXG4gICAgICBjOHlJY29uPVwicGx1cy1jaXJjbGVcIlxuICAgICAgKm5nSWY9XCJjYW5EcmFnQW5kRHJvcFwiXG4gICAgPjwvaT5cbiAgICB7eyBhZGRCdXR0b25MYWJlbCB8IHRyYW5zbGF0ZSB9fVxuICA8L2J1dHRvbj5cbjwvZGl2PlxuIl19