UNPKG

@c8y/ngx-components

Version:

Angular modules for Cumulocity IoT applications

143 lines 30.3 kB
import { Component, EventEmitter, Input, Output, ViewChild } from '@angular/core'; import { BehaviorSubject, Subject } from 'rxjs'; import { FormBuilder } from '@angular/forms'; import { filter, takeUntil, tap } from 'rxjs/operators'; import { CountdownIntervalComponent, gettext } from '@c8y/ngx-components'; import { AlarmsViewService } from './alarms-view.service'; import * as i0 from "@angular/core"; import * as i1 from "@angular/forms"; import * as i2 from "./alarms-view.service"; import * as i3 from "@c8y/ngx-components"; import * as i4 from "@angular/common"; import * as i5 from "ngx-bootstrap/tooltip"; import * as i6 from "@ngx-translate/core"; export class AlarmsIntervalRefreshComponent { /** * * Set the value of `isIntervalEnabled` in response to user interactions with the alarm list scroll. * * * * This input setter allows you to control the `isIntervalEnabled` property, which is used to manage the state * * of a toggle button. When a user scrolls through the alarms list, you can update the `isIntervalEnabled` value * * using this setter. * * * * @param value - A boolean value representing the new state of the `isIntervalEnabled` property. * * - `true` indicates that the interval is enabled. * * - `false` indicates that the interval is disabled. */ set isIntervalToggleEnabled(value) { const shouldSetInterval = this.isIntervalToggleEnabled || this.doesUserCheckedIntervalToggle; const shouldToggleInterval = !this.isDisabled && this.isIntervalToggleEnabled && this.doesUserCheckedIntervalToggle && value; const intervalToggleControl = this.toggleIntervalForm.get('intervalToggle'); /** * We check if any interactions to toggle interval button were made. * When user interacts with toggle button, we need to ignore assigning value to the form. */ if (intervalToggleControl.dirty && !shouldSetInterval) { return; } /** * This condition checks if the interval toggle is enabled and if there has been user interaction, * and if the provided value is truthy. * If all conditions are met, the interval toggle should not be updated due to unnecessary update of countdown interval component */ if (shouldToggleInterval) { return; } intervalToggleControl.setValue(value); } /** * This getter allows you to access the current state of the `isIntervalEnabled` property, which reflects * the state of a toggle button. It retrieves the value from the associated form control, providing the * current state of the toggle button. */ get isIntervalToggleEnabled() { return !this.isDisabled && this.toggleIntervalForm.get('intervalToggle').value; } constructor(fb, alarmsViewService) { this.fb = fb; this.alarmsViewService = alarmsViewService; this.refreshIntervalsInMilliseconds = this.alarmsViewService.DEFAULT_INTERVAL_VALUES; this.DISABLE_AUTO_REFRESH = gettext('Disable auto refresh'); this.ENABLE_AUTO_REFRESH = gettext('Enable auto refresh'); this.SECONDS_UNTIL_REFRESH = gettext('{{ seconds }} s'); this.isDisabled = false; /** * Event emitter for notifying when a countdown timer has completed. */ this.onCountdownEnded = new EventEmitter(); this.toggleIntervalForm = this.initForm(); this.destroy$ = new Subject(); } ngOnInit() { this.listenToRefreshIntervalChange(); } ngAfterViewInit() { this.onIntervalToggleChange(); this.listenOnLoadingChanges(); } ngOnDestroy() { this.destroy$.next(); this.destroy$.complete(); } resetCountdown() { this.countdownIntervalComponent?.reset(); } trackUserClickOnIntervalToggle(target) { this.doesUserCheckedIntervalToggle = target.checked; } getTooltip() { return this.isDisabled ? gettext('Disabled') : this.isIntervalToggleEnabled ? this.DISABLE_AUTO_REFRESH : this.ENABLE_AUTO_REFRESH; } startCountdown() { this.countdownIntervalComponent.start(); } onIntervalToggleChange() { this.toggleIntervalForm .get('intervalToggle') .valueChanges.pipe(takeUntil(this.destroy$), filter(Boolean)) .subscribe(() => setTimeout(() => this.startCountdown())); } initForm() { return this.fb.group({ intervalToggle: true, refreshInterval: this.alarmsViewService.DEFAULT_INTERVAL_VALUE }); } listenToRefreshIntervalChange() { this.toggleIntervalForm .get('refreshInterval') .valueChanges.pipe(takeUntil(this.destroy$)) .subscribe(() => this.resetCountdown()); } listenOnLoadingChanges() { this.alarmsListLoading$ .pipe(tap(() => this.countdownIntervalComponent?.stop())) .subscribe(state => { !state && this.countdownIntervalComponent?.reset(); }); } static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: AlarmsIntervalRefreshComponent, deps: [{ token: i1.FormBuilder }, { token: i2.AlarmsViewService }], target: i0.ɵɵFactoryTarget.Component }); } static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.13", type: AlarmsIntervalRefreshComponent, selector: "c8y-alarms-interval-refresh", inputs: { isDisabled: "isDisabled", alarmsListLoading$: "alarmsListLoading$", isIntervalToggleEnabled: "isIntervalToggleEnabled" }, outputs: { onCountdownEnded: "onCountdownEnded" }, viewQueries: [{ propertyName: "countdownIntervalComponent", first: true, predicate: CountdownIntervalComponent, descendants: true }], ngImport: i0, template: "<form\n class=\"d-flex a-i-center fit-w fit-h\"\n [formGroup]=\"toggleIntervalForm\"\n>\n <label class=\"m-b-0 m-r-8 text-normal text-muted flex-no-shrink\">\n {{ 'Auto refresh' | translate }}\n </label>\n <div class=\"input-group\">\n <label\n class=\"toggle-countdown\"\n [class.toggle-countdown-disabled]=\"isDisabled\"\n [attr.aria-label]=\"getTooltip() | translate\"\n [tooltip]=\"getTooltip() | translate\"\n placement=\"bottom\"\n [adaptivePosition]=\"false\"\n [delay]=\"500\"\n >\n <input\n type=\"checkbox\"\n data-cy=\"c8y-alarms-interval-toggle\"\n formControlName=\"intervalToggle\"\n (click)=\"trackUserClickOnIntervalToggle($event.target)\"\n />\n <c8y-countdown-interval\n *ngIf=\"isIntervalToggleEnabled\"\n [countdownInterval]=\"toggleIntervalForm.value.refreshInterval\"\n (countdownEnded)=\"onCountdownEnded.emit()\"\n ></c8y-countdown-interval>\n <i\n c8yIcon=\"pause\"\n *ngIf=\"!isIntervalToggleEnabled\"\n ></i>\n </label>\n <div\n class=\"c8y-select-wrapper\"\n *ngIf=\"!isDisabled\"\n >\n <select\n class=\"form-control text-12\"\n [attr.aria-label]=\"'Refresh interval in seconds' | translate\"\n [tooltip]=\"'Refresh interval in seconds' | translate\"\n placement=\"bottom\"\n [adaptivePosition]=\"false\"\n [delay]=\"500\"\n [container]=\"'body'\"\n formControlName=\"refreshInterval\"\n data-cy=\"c8y-alarms-interval-selector\"\n >\n <option\n [disabled]=\"isDisabled\"\n *ngFor=\"let refreshInterval of refreshIntervalsInMilliseconds\"\n [ngValue]=\"refreshInterval\"\n >\n {{ SECONDS_UNTIL_REFRESH | translate: { seconds: refreshInterval / 1000 } }}\n </option>\n </select>\n <span></span>\n </div>\n <div class=\"input-group-btn\">\n <button\n class=\"btn btn-default\"\n style=\"border-left: 0\"\n [attr.aria-label]=\"'Refresh' | translate\"\n [tooltip]=\"'Refresh' | translate\"\n placement=\"bottom\"\n type=\"button\"\n [adaptivePosition]=\"false\"\n [delay]=\"500\"\n [disabled]=\"isDisabled || (alarmsListLoading$ | async)\"\n (click)=\"onCountdownEnded.emit()\"\n data-cy=\"c8y-alarms-reload-button\"\n >\n <i\n c8yIcon=\"refresh\"\n [ngClass]=\"{ 'icon-spin': alarmsListLoading$ | async }\"\n ></i>\n </button>\n </div>\n </div>\n</form>\n", dependencies: [{ kind: "directive", type: i3.IconDirective, selector: "[c8yIcon]", inputs: ["c8yIcon"] }, { kind: "directive", type: i4.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i4.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i4.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i1.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i1.NgSelectOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i1.ɵNgSelectMultipleOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i1.CheckboxControlValueAccessor, selector: "input[type=checkbox][formControlName],input[type=checkbox][formControl],input[type=checkbox][ngModel]" }, { kind: "directive", type: i1.SelectControlValueAccessor, selector: "select:not([multiple])[formControlName],select:not([multiple])[formControl],select:not([multiple])[ngModel]", inputs: ["compareWith"] }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i3.RequiredInputPlaceholderDirective, selector: "input[required], input[formControlName]" }, { kind: "directive", type: i1.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i1.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "component", type: i3.CountdownIntervalComponent, selector: "c8y-countdown-interval", inputs: ["countdownInterval"], outputs: ["countdownEnded"] }, { kind: "directive", type: i5.TooltipDirective, selector: "[tooltip], [tooltipHtml]", inputs: ["adaptivePosition", "tooltip", "placement", "triggers", "container", "containerClass", "boundariesElement", "isOpen", "isDisabled", "delay", "tooltipHtml", "tooltipPlacement", "tooltipIsOpen", "tooltipEnable", "tooltipAppendToBody", "tooltipAnimation", "tooltipClass", "tooltipContext", "tooltipPopupDelay", "tooltipFadeDuration", "tooltipTrigger"], outputs: ["tooltipChange", "onShown", "onHidden", "tooltipStateChanged"], exportAs: ["bs-tooltip"] }, { kind: "pipe", type: i4.AsyncPipe, name: "async" }, { kind: "pipe", type: i6.TranslatePipe, name: "translate" }] }); } } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: AlarmsIntervalRefreshComponent, decorators: [{ type: Component, args: [{ selector: 'c8y-alarms-interval-refresh', template: "<form\n class=\"d-flex a-i-center fit-w fit-h\"\n [formGroup]=\"toggleIntervalForm\"\n>\n <label class=\"m-b-0 m-r-8 text-normal text-muted flex-no-shrink\">\n {{ 'Auto refresh' | translate }}\n </label>\n <div class=\"input-group\">\n <label\n class=\"toggle-countdown\"\n [class.toggle-countdown-disabled]=\"isDisabled\"\n [attr.aria-label]=\"getTooltip() | translate\"\n [tooltip]=\"getTooltip() | translate\"\n placement=\"bottom\"\n [adaptivePosition]=\"false\"\n [delay]=\"500\"\n >\n <input\n type=\"checkbox\"\n data-cy=\"c8y-alarms-interval-toggle\"\n formControlName=\"intervalToggle\"\n (click)=\"trackUserClickOnIntervalToggle($event.target)\"\n />\n <c8y-countdown-interval\n *ngIf=\"isIntervalToggleEnabled\"\n [countdownInterval]=\"toggleIntervalForm.value.refreshInterval\"\n (countdownEnded)=\"onCountdownEnded.emit()\"\n ></c8y-countdown-interval>\n <i\n c8yIcon=\"pause\"\n *ngIf=\"!isIntervalToggleEnabled\"\n ></i>\n </label>\n <div\n class=\"c8y-select-wrapper\"\n *ngIf=\"!isDisabled\"\n >\n <select\n class=\"form-control text-12\"\n [attr.aria-label]=\"'Refresh interval in seconds' | translate\"\n [tooltip]=\"'Refresh interval in seconds' | translate\"\n placement=\"bottom\"\n [adaptivePosition]=\"false\"\n [delay]=\"500\"\n [container]=\"'body'\"\n formControlName=\"refreshInterval\"\n data-cy=\"c8y-alarms-interval-selector\"\n >\n <option\n [disabled]=\"isDisabled\"\n *ngFor=\"let refreshInterval of refreshIntervalsInMilliseconds\"\n [ngValue]=\"refreshInterval\"\n >\n {{ SECONDS_UNTIL_REFRESH | translate: { seconds: refreshInterval / 1000 } }}\n </option>\n </select>\n <span></span>\n </div>\n <div class=\"input-group-btn\">\n <button\n class=\"btn btn-default\"\n style=\"border-left: 0\"\n [attr.aria-label]=\"'Refresh' | translate\"\n [tooltip]=\"'Refresh' | translate\"\n placement=\"bottom\"\n type=\"button\"\n [adaptivePosition]=\"false\"\n [delay]=\"500\"\n [disabled]=\"isDisabled || (alarmsListLoading$ | async)\"\n (click)=\"onCountdownEnded.emit()\"\n data-cy=\"c8y-alarms-reload-button\"\n >\n <i\n c8yIcon=\"refresh\"\n [ngClass]=\"{ 'icon-spin': alarmsListLoading$ | async }\"\n ></i>\n </button>\n </div>\n </div>\n</form>\n" }] }], ctorParameters: () => [{ type: i1.FormBuilder }, { type: i2.AlarmsViewService }], propDecorators: { isDisabled: [{ type: Input }], alarmsListLoading$: [{ type: Input }], isIntervalToggleEnabled: [{ type: Input }], onCountdownEnded: [{ type: Output }], countdownIntervalComponent: [{ type: ViewChild, args: [CountdownIntervalComponent] }] } }); //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYWxhcm1zLWludGVydmFsLXJlZnJlc2guY29tcG9uZW50LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vYWxhcm1zL2FsYXJtcy1pbnRlcnZhbC1yZWZyZXNoLmNvbXBvbmVudC50cyIsIi4uLy4uLy4uL2FsYXJtcy9hbGFybXMtaW50ZXJ2YWwtcmVmcmVzaC5jb21wb25lbnQuaHRtbCJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBRUwsU0FBUyxFQUNULFlBQVksRUFDWixLQUFLLEVBR0wsTUFBTSxFQUNOLFNBQVMsRUFDVixNQUFNLGVBQWUsQ0FBQztBQUN2QixPQUFPLEVBQUUsZUFBZSxFQUFFLE9BQU8sRUFBRSxNQUFNLE1BQU0sQ0FBQztBQUNoRCxPQUFPLEVBQUUsV0FBVyxFQUFFLE1BQU0sZ0JBQWdCLENBQUM7QUFDN0MsT0FBTyxFQUFFLE1BQU0sRUFBRSxTQUFTLEVBQUUsR0FBRyxFQUFFLE1BQU0sZ0JBQWdCLENBQUM7QUFDeEQsT0FBTyxFQUFFLDBCQUEwQixFQUFFLE9BQU8sRUFBRSxNQUFNLHFCQUFxQixDQUFDO0FBQzFFLE9BQU8sRUFBRSxpQkFBaUIsRUFBRSxNQUFNLHVCQUF1QixDQUFDOzs7Ozs7OztBQU0xRCxNQUFNLE9BQU8sOEJBQThCO0lBWXpDOzs7Ozs7Ozs7O09BVUc7SUFDSCxJQUNJLHVCQUF1QixDQUFDLEtBQWM7UUFDeEMsTUFBTSxpQkFBaUIsR0FBRyxJQUFJLENBQUMsdUJBQXVCLElBQUksSUFBSSxDQUFDLDZCQUE2QixDQUFDO1FBQzdGLE1BQU0sb0JBQW9CLEdBQ3hCLENBQUMsSUFBSSxDQUFDLFVBQVU7WUFDaEIsSUFBSSxDQUFDLHVCQUF1QjtZQUM1QixJQUFJLENBQUMsNkJBQTZCO1lBQ2xDLEtBQUssQ0FBQztRQUNSLE1BQU0scUJBQXFCLEdBQUcsSUFBSSxDQUFDLGtCQUFrQixDQUFDLEdBQUcsQ0FBQyxnQkFBZ0IsQ0FBQyxDQUFDO1FBQzVFOzs7V0FHRztRQUNILElB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QjtRQUNuQyxJQUFJLENBQUMsa0JBQWtCO2FBQ3BCLEdBQUcsQ0FBQyxpQkFBaUIsQ0FBQzthQUN0QixZQUFZLENBQUMsSUFBSSxDQUFDLFNBQVMsQ0FBQyxJQUFJLENBQUMsUUFBUSxDQUFDLENBQUM7YUFDM0MsU0FBUyxDQUFDLEdBQUcsRUFBRSxDQUFDLElBQUksQ0FBQyxjQUFjLEVBQUUsQ0FBQyxDQUFDO0lBQzVDLENBQUM7SUFFTyxzQkFBc0I7UUFDNUIsSUFBSSxDQUFDLGtCQUFrQjthQUNwQixJQUFJLENBQUMsR0FBRyxDQUFDLEdBQUcsRUFBRSxDQUFDLElBQUksQ0FBQywwQkFBMEIsRUFBRSxJQUFJLEVBQUUsQ0FBQyxDQUFDO2FBQ3hELFNBQVMsQ0FBQyxLQUFLLENBQUMsRUFBRTtZQUNqQixDQUFDLEtBQUssSUFBSSxJQUFJLENBQUMsMEJBQTBCLEVBQUUsS0FBSyxFQUFFLENBQUM7UUFDckQsQ0FBQyxDQUFDLENBQUM7SUFDUCxDQUFDOytHQTVJVSw4QkFBOEI7bUdBQTlCLDhCQUE4QixzVEErRDlCLDBCQUEwQixnRENuRnZDLHlqRkFnRkE7OzRGRDVEYSw4QkFBOEI7a0JBSjFDLFNBQVM7K0JBQ0UsNkJBQTZCO2dIQVM5QixVQUFVO3NCQUFsQixLQUFLO2dCQUtOLGtCQUFrQjtzQkFEakIsS0FBSztnQkFjRix1QkFBdUI7c0JBRDFCLEtBQUs7Z0JBc0NOLGdCQUFnQjtzQkFEZixNQUFNO2dCQUlQLDBCQUEwQjtzQkFEekIsU0FBUzt1QkFBQywwQkFBMEIiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQge1xuICBBZnRlclZpZXdJbml0LFxuICBDb21wb25lbnQsXG4gIEV2ZW50RW1pdHRlcixcbiAgSW5wdXQsXG4gIE9uRGVzdHJveSxcbiAgT25Jbml0LFxuICBPdXRwdXQsXG4gIFZpZXdDaGlsZFxufSBmcm9tICdAYW5ndWxhci9jb3JlJztcbmltcG9ydCB7IEJlaGF2aW9yU3ViamVjdCwgU3ViamVjdCB9IGZyb20gJ3J4anMnO1xuaW1wb3J0IHsgRm9ybUJ1aWxkZXIgfSBmcm9tICdAYW5ndWxhci9mb3Jtcyc7XG5pbXBvcnQgeyBmaWx0ZXIsIHRha2VVbnRpbCwgdGFwIH0gZnJvbSAncnhqcy9vcGVyYXRvcnMnO1xuaW1wb3J0IHsgQ291bnRkb3duSW50ZXJ2YWxDb21wb25lbnQsIGdldHRleHQgfSBmcm9tICdAYzh5L25neC1jb21wb25lbnRzJztcbmltcG9ydCB7IEFsYXJtc1ZpZXdTZXJ2aWNlIH0gZnJvbSAnLi9hbGFybXMtdmlldy5zZXJ2aWNlJztcblxuQENvbXBvbmVudCh7XG4gIHNlbGVjdG9yOiAnYzh5LWFsYXJtcy1pbnRlcnZhbC1yZWZyZXNoJyxcbiAgdGVtcGxhdGVVcmw6ICcuL2FsYXJtcy1pbnRlcnZhbC1yZWZyZXNoLmNvbXBvbmVudC5odG1sJ1xufSlcbmV4cG9ydCBjbGFzcyBBbGFybXNJbnRlcnZhbFJlZnJlc2hDb21wb25lbnQgaW1wbGVtZW50cyBPbkluaXQsIEFmdGVyVmlld0luaXQsIE9uRGVzdHJveSB7XG4gIHJlYWRvbmx5IHJlZnJlc2hJbnRlcnZhbHNJbk1pbGxpc2Vjb25kcyA9IHRoaXMuYWxhcm1zVmlld1NlcnZpY2UuREVGQVVMVF9JTlRFUlZBTF9WQUxVRVM7XG4gIHJlYWRvbmx5IERJU0FCTEVfQVVUT19SRUZSRVNIID0gZ2V0dGV4dCgnRGlzYWJsZSBhdXRvIHJlZnJlc2gnKTtcbiAgcmVhZG9ubHkgRU5BQkxFX0FVVE9fUkVGUkVTSCA9IGdldHRleHQoJ0VuYWJsZSBhdXRvIHJlZnJlc2gnKTtcbiAgcmVhZG9ubHkgU0VDT05EU19VTlRJTF9SRUZSRVNIID0gZ2V0dGV4dCgne3sgc2Vjb25kcyB9fSBzJyk7XG5cbiAgQElucHV0KCkgaXNEaXNhYmxlZCA9IGZhbHNlO1xuICAvKipcbiAgICogQ29udHJvbHMgdGhlIGxvYWRpbmcgc3RhdGUgb2YgdGhlIGFsYXJtcyBsaXN0IHJlbG9hZCBidXR0b24uXG4gICAqL1xuICBASW5wdXQoKVxuICBhbGFybXNMaXN0TG9hZGluZyQ6IEJlaGF2aW9yU3ViamVjdDxib29sZWFuPjtcbiAgLyoqXG4gICAqICogU2V0IHRoZSB2YWx1ZSBvZiBgaXNJbnRlcnZhbEVuYWJsZWRgIGluIHJlc3BvbnNlIHRvIHVzZXIgaW50ZXJhY3Rpb25zIHdpdGggdGhlIGFsYXJtIGxpc3Qgc2Nyb2xsLlxuICAgKiAgKlxuICAgKiAgKiBUaGlzIGlucHV0IHNldHRlciBhbGxvd3MgeW91IHRvIGNvbnRyb2wgdGhlIGBpc0ludGVydmFsRW5hYmxlZGAgcHJvcGVydHksIHdoaWNoIGlzIHVzZWQgdG8gbWFuYWdlIHRoZSBzdGF0ZVxuICAgKiAgKiBvZiBhIHRvZ2dsZSBidXR0b24uIFdoZW4gYSB1c2VyIHNjcm9sbHMgdGhyb3VnaCB0aGUgYWxhcm1zIGxpc3QsIHlvdSBjYW4gdXBkYXRlIHRoZSBgaXNJbnRlcnZhbEVuYWJsZWRgIHZhbHVlXG4gICAqICAqIHVzaW5nIHRoaXMgc2V0dGVyLlxuICAgKiAgKlxuICAgKiAgKiBAcGFyYW0gdmFsdWUgLSBBIGJvb2xlYW4gdmFsdWUgcmVwcmVzZW50aW5nIHRoZSBuZXcgc3RhdGUgb2YgdGhlIGBpc0ludGVydmFsRW5hYmxlZGAgcHJvcGVydHkuXG4gICAqICAqICAgLSBgdHJ1ZWAgaW5kaWNhdGVzIHRoYXQgdGhlIGludGVydmFsIGlzIGVuYWJsZWQuXG4gICAqICAqICAgLSBgZmFsc2VgIGluZGljYXRlcyB0aGF0IHRoZSBpbnRlcnZhbCBpcyBkaXNhYmxlZC5cbiAgICovXG4gIEBJbnB1dCgpXG4gIHNldCBpc0ludGVydmFsVG9nZ2xlRW5hYmxlZCh2YWx1ZTogYm9vbGVhbikge1xuICAgIGNvbnN0IHNob3VsZFNldEludGVydmFsID0gdGhpcy5pc0ludGVydmFsVG9nZ2xlRW5hYmxlZCB8fCB0aGlzLmRvZXNVc2VyQ2hlY2tlZEludGVydmFsVG9nZ2xlO1xuICAgIGNvbnN0IHNob3VsZFRvZ2dsZUludGVydmFsID1cbiAgICAgICF0aGlzLmlzRGlzYWJsZWQgJiZcbiAgICAgIHRoaXMuaXNJbnRlcnZhbFRvZ2dsZUVuYWJsZWQgJiZcbiAgICAgIHRoaXMuZG9lc1VzZXJDaGVja2VkSW50ZXJ2YWxUb2dnbGUgJiZcbiAgICAgIHZhbHVlO1xuICAgIGNvbnN0IGludGVydmFsVG9nZ2xlQ29udHJvbCA9IHRoaXMudG9nZ2xlSW50ZXJ2YWxGb3JtLmdldCgnaW50ZXJ2YWxUb2dnbGUnKTtcbiAgICAvKipcbiAgICAgKiBXZSBjaGVjayBpZiBhbnkgaW50ZXJhY3Rpb25zIHRvIHRvZ2dsZSBpbnRlcnZhbCBidXR0b24gd2VyZSBtYWRlLlxuICAgICAqIFdoZW4gdXNlciBpbnRlcmFjdHMgd2l0aCB0b2dnbGUgYnV0dG9uLCB3ZSBuZWVkIHRvIGlnbm9yZSBhc3NpZ25pbmcgdmFsdWUgdG8gdGhlIGZvcm0uXG4gICAgICovXG4gICAgaWYgKGludGVydmFsVG9nZ2xlQ29udHJvbC5kaXJ0eSAmJiAhc2hvdWxkU2V0SW50ZXJ2YWwpIHtcbiAgICAgIHJldHVybjtcbiAgICB9XG4gICAgLyoqXG4gICAgICogVGhpcyBjb25kaXRpb24gY2hlY2tzIGlmIHRoZSBpbnRlcnZhbCB0b2dnbGUgaXMgZW5hYmxlZCBhbmQgaWYgdGhlcmUgaGFzIGJlZW4gdXNlciBpbnRlcmFjdGlvbixcbiAgICAgKiBhbmQgaWYgdGhlIHByb3ZpZGVkIHZhbHVlIGlzIHRydXRoeS5cbiAgICAgKiBJZiBhbGwgY29uZGl0aW9ucyBhcmUgbWV0LCB0aGUgaW50ZXJ2YWwgdG9nZ2xlIHNob3VsZCBub3QgYmUgdXBkYXRlZCBkdWUgdG8gdW5uZWNlc3NhcnkgdXBkYXRlIG9mIGNvdW50ZG93biBpbnRlcnZhbCBjb21wb25lbnRcbiAgICAgKi9cbiAgICBpZiAoc2hvdWxkVG9nZ2xlSW50ZXJ2YWwpIHtcbiAgICAgIHJldHVybjtcbiAgICB9XG4gICAgaW50ZXJ2YWxUb2dnbGVDb250cm9sLnNldFZhbHVlKHZhbHVlKTtcbiAgfVxuICAvKipcbiAgICogVGhpcyBnZXR0ZXIgYWxsb3dzIHlvdSB0byBhY2Nlc3MgdGhlIGN1cnJlbnQgc3RhdGUgb2YgdGhlIGBpc0ludGVydmFsRW5hYmxlZGAgcHJvcGVydHksIHdoaWNoIHJlZmxlY3RzXG4gICAqIHRoZSBzdGF0ZSBvZiBhIHRvZ2dsZSBidXR0b24uIEl0IHJldHJpZXZlcyB0aGUgdmFsdWUgZnJvbSB0aGUgYXNzb2NpYXRlZCBmb3JtIGNvbnRyb2wsIHByb3ZpZGluZyB0aGVcbiAgICogY3VycmVudCBzdGF0ZSBvZiB0aGUgdG9nZ2xlIGJ1dHRvbi5cbiAgICovXG4gIGdldCBpc0ludGVydmFsVG9nZ2xlRW5hYmxlZCgpOiBib29sZWFuIHtcbiAgICByZXR1cm4gIXRoaXMuaXNEaXNhYmxlZCAmJiB0aGlzLnRvZ2dsZUludGVydmFsRm9ybS5nZXQoJ2ludGVydmFsVG9nZ2xlJykudmFsdWU7XG4gIH1cbiAgLyoqXG4gICAqIEV2ZW50IGVtaXR0ZXIgZm9yIG5vdGlmeWluZyB3aGVuIGEgY291bnRkb3duIHRpbWVyIGhhcyBjb21wbGV0ZWQuXG4gICAqL1xuICBAT3V0cHV0KClcbiAgb25Db3VudGRvd25FbmRlZCA9IG5ldyBFdmVudEVtaXR0ZXI8dm9pZD4oKTtcblxuICBAVmlld0NoaWxkKENvdW50ZG93bkludGVydmFsQ29tcG9uZW50KVxuICBjb3VudGRvd25JbnRlcnZhbENvbXBvbmVudDogQ291bnRkb3duSW50ZXJ2YWxDb21wb25lbnQ7XG4gIHRvZ2dsZUludGVydmFsRm9ybSA9IHRoaXMuaW5pdEZvcm0oKTtcbiAgcHJpdmF0ZSBkZXN0cm95JDogU3ViamVjdDx2b2lkPiA9IG5ldyBTdWJqZWN0PHZvaWQ+KCk7XG4gIC8qKlxuICAgKiBJbmRpY2F0ZXMgd2hldGhlciB0aGUgdXNlciBoYXMgYmVlbiBpbnRlcmFjdGluZyB3aXRoIHRoZSBpbnRlcnZhbCB0b2dnbGUuXG4gICAqIFByb3BlcnR5IGhvbGRzIHRoZSBjdXJyZW50IHN0YXRlIG9mIHRoZSBpbnRlcnZhbCB0b2dnbGUgaW5wdXQgZWxlbWVudCBlbnRlcmVkIGJ5IHRoZSB1c2VyLFxuICAgKiBkaXN0aW5ndWlzaGluZyBpdCBmcm9tIGNoYW5nZXMgbWFkZSBwcm9ncmFtbWF0aWNhbGx5IChlLmcuIHZhbHVlIGZyb20gaXNJbnRlcnZhbFRvZ2dsZUVuYWJsZWQpLlxuICAgKi9cbiAgcHJpdmF0ZSBkb2VzVXNlckNoZWNrZWRJbnRlcnZhbFRvZ2dsZTogYm9vbGVhbjtcblxuICBjb25zdHJ1Y3RvcihcbiAgICBwcml2YXRlIGZiOiBGb3JtQnVpbGRlcixcbiAgICBwcml2YXRlIGFsYXJtc1ZpZXdTZXJ2aWNlOiBBbGFybXNWaWV3U2VydmljZVxuICApIHt9XG5cbiAgbmdPbkluaXQoKTogdm9pZCB7XG4gICAgdGhpcy5saXN0ZW5Ub1JlZnJlc2hJbnRlcnZhbENoYW5nZSgpO1xuICB9XG5cbiAgbmdBZnRlclZpZXdJbml0KCk6IHZvaWQge1xuICAgIHRoaXMub25JbnRlcnZhbFRvZ2dsZUNoYW5nZSgpO1xuICAgIHRoaXMubGlzdGVuT25Mb2FkaW5nQ2hhbmdlcygpO1xuICB9XG5cbiAgbmdPbkRlc3Ryb3koKTogdm9pZCB7XG4gICAgdGhpcy5kZXN0cm95JC5uZXh0KCk7XG4gICAgdGhpcy5kZXN0cm95JC5jb21wbGV0ZSgpO1xuICB9XG5cbiAgcmVzZXRDb3VudGRvd24oKTogdm9pZCB7XG4gICAgdGhpcy5jb3VudGRvd25JbnRlcnZhbENvbXBvbmVudD8ucmVzZXQoKTtcbiAgfVxuXG4gIHRyYWNrVXNlckNsaWNrT25JbnRlcnZhbFRvZ2dsZSh0YXJnZXQ6IEV2ZW50VGFyZ2V0KTogdm9pZCB7XG4gICAgdGhpcy5kb2VzVXNlckNoZWNrZWRJbnRlcnZhbFRvZ2dsZSA9ICh0YXJnZXQgYXMgSFRNTElucHV0RWxlbWVudCkuY2hlY2tlZDtcbiAgfVxuXG4gIGdldFRvb2x0aXAoKSB7XG4gICAgcmV0dXJuIHRoaXMuaXNEaXNhYmxlZFxuICAgICAgPyBnZXR0ZXh0KCdEaXNhYmxlZCcpXG4gICAgICA6IHRoaXMuaXNJbnRlcnZhbFRvZ2dsZUVuYWJsZWRcbiAgICAgICAgPyB0aGlzLkRJU0FCTEVfQVVUT19SRUZSRVNIXG4gICAgICAgIDogdGhpcy5FTkFCTEVfQVVUT19SRUZSRVNIO1xuICB9XG5cbiAgcHJpdmF0ZSBzdGFydENvdW50ZG93bigpOiB2b2lkIHtcbiAgICB0aGlzLmNvdW50ZG93bkludGVydmFsQ29tcG9uZW50LnN0YXJ0KCk7XG4gIH1cblxuICBwcml2YXRlIG9uSW50ZXJ2YWxUb2dnbGVDaGFuZ2UoKTogdm9pZCB7XG4gICAgdGhpcy50b2dnbGVJbnRlcnZhbEZvcm1cbiAgICAgIC5nZXQoJ2ludGVydmFsVG9nZ2xlJylcbiAgICAgIC52YWx1ZUNoYW5nZXMucGlwZSh0YWtlVW50aWwodGhpcy5kZXN0cm95JCksIGZpbHRlcihCb29sZWFuKSlcbiAgICAgIC5zdWJzY3JpYmUoKCkgPT4gc2V0VGltZW91dCgoKSA9PiB0aGlzLnN0YXJ0Q291bnRkb3duKCkpKTtcbiAgfVxuXG4gIHByaXZhdGUgaW5pdEZvcm0oKSB7XG4gICAgcmV0dXJuIHRoaXMuZmIuZ3JvdXAoe1xuICAgICAgaW50ZXJ2YWxUb2dnbGU6IHRydWUsXG4gICAgICByZWZyZXNoSW50ZXJ2YWw6IHRoaXMuYWxhcm1zVmlld1NlcnZpY2UuREVGQVVMVF9JTlRFUlZBTF9WQUxVRVxuICAgIH0pO1xuICB9XG5cbiAgcHJpdmF0ZSBsaXN0ZW5Ub1JlZnJlc2hJbnRlcnZhbENoYW5nZSgpOiB2b2lkIHtcbiAgICB0aGlzLnRvZ2dsZUludGVydmFsRm9ybVxuICAgICAgLmdldCgncmVmcmVzaEludGVydmFsJylcbiAgICAgIC52YWx1ZUNoYW5nZXMucGlwZSh0YWtlVW50aWwodGhpcy5kZXN0cm95JCkpXG4gICAgICAuc3Vic2NyaWJlKCgpID0+IHRoaXMucmVzZXRDb3VudGRvd24oKSk7XG4gIH1cblxuICBwcml2YXRlIGxpc3Rlbk9uTG9hZGluZ0NoYW5nZXMoKSB7XG4gICAgdGhpcy5hbGFybXNMaXN0TG9hZGluZyRcbiAgICAgIC5waXBlKHRhcCgoKSA9PiB0aGlzLmNvdW50ZG93bkludGVydmFsQ29tcG9uZW50Py5zdG9wKCkpKVxuICAgICAgLnN1YnNjcmliZShzdGF0ZSA9PiB7XG4gICAgICAgICFzdGF0ZSAmJiB0aGlzLmNvdW50ZG93bkludGVydmFsQ29tcG9uZW50Py5yZXNldCgpO1xuICAgICAgfSk7XG4gIH1cbn1cbiIsIjxmb3JtXG4gIGNsYXNzPVwiZC1mbGV4IGEtaS1jZW50ZXIgZml0LXcgZml0LWhcIlxuICBbZm9ybUdyb3VwXT1cInRvZ2dsZUludGVydmFsRm9ybVwiXG4+XG4gIDxsYWJlbCBjbGFzcz1cIm0tYi0wIG0tci04IHRleHQtbm9ybWFsIHRleHQtbXV0ZWQgZmxleC1uby1zaHJpbmtcIj5cbiAgICB7eyAnQXV0byByZWZyZXNoJyB8IHRyYW5zbGF0ZSB9fVxuICA8L2xhYmVsPlxuICA8ZGl2IGNsYXNzPVwiaW5wdXQtZ3JvdXBcIj5cbiAgICA8bGFiZWxcbiAgICAgIGNsYXNzPVwidG9nZ2xlLWNvdW50ZG93blwiXG4gICAgICBbY2xhc3MudG9nZ2xlLWNvdW50ZG93bi1kaXNhYmxlZF09XCJpc0Rpc2FibGVkXCJcbiAgICAgIFthdHRyLmFyaWEtbGFiZWxdPVwiZ2V0VG9vbHRpcCgpIHwgdHJhbnNsYXRlXCJcbiAgICAgIFt0b29sdGlwXT1cImdldFRvb2x0aXAoKSB8IHRyYW5zbGF0ZVwiXG4gICAgICBwbGFjZW1lbnQ9XCJib3R0b21cIlxuICAgICAgW2FkYXB0aXZlUG9zaXRpb25dPVwiZmFsc2VcIlxuICAgICAgW2RlbGF5XT1cIjUwMFwiXG4gICAgPlxuICAgICAgPGlucHV0XG4gICAgICAgIHR5cGU9XCJjaGVja2JveFwiXG4gICAgICAgIGRhdGEtY3k9XCJjOHktYWxhcm1zLWludGVydmFsLXRvZ2dsZVwiXG4gICAgICAgIGZvcm1Db250cm9sTmFtZT1cImludGVydmFsVG9nZ2xlXCJcbiAgICAgICAgKGNsaWNrKT1cInRyYWNrVXNlckNsaWNrT25JbnRlcnZhbFRvZ2dsZSgkZXZlbnQudGFyZ2V0KVwiXG4gICAgICAvPlxuICAgICAgPGM4eS1jb3VudGRvd24taW50ZXJ2YWxcbiAgICAgICAgKm5nSWY9XCJpc0ludGVydmFsVG9nZ2xlRW5hYmxlZFwiXG4gICAgICAgIFtjb3VudGRvd25JbnRlcnZhbF09XCJ0b2dnbGVJbnRlcnZhbEZvcm0udmFsdWUucmVmcmVzaEludGVydmFsXCJcbiAgICAgICAgKGNvdW50ZG93bkVuZGVkKT1cIm9uQ291bnRkb3duRW5kZWQuZW1pdCgpXCJcbiAgICAgID48L2M4eS1jb3VudGRvd24taW50ZXJ2YWw+XG4gICAgICA8aVxuICAgICAgICBjOHlJY29uPVwicGF1c2VcIlxuICAgICAgICAqbmdJZj1cIiFpc0ludGVydmFsVG9nZ2xlRW5hYmxlZFwiXG4gICAgICA+PC9pPlxuICAgIDwvbGFiZWw+XG4gICAgPGRpdlxuICAgICAgY2xhc3M9XCJjOHktc2VsZWN0LXdyYXBwZXJcIlxuICAgICAgKm5nSWY9XCIhaXNEaXNhYmxlZFwiXG4gICAgPlxuICAgICAgPHNlbGVjdFxuICAgICAgICBjbGFzcz1cImZvcm0tY29udHJvbCB0ZXh0LTEyXCJcbiAgICAgICAgW2F0dHIuYXJpYS1sYWJlbF09XCInUmVmcmVzaCBpbnRlcnZhbCBpbiBzZWNvbmRzJyB8IHRyYW5zbGF0ZVwiXG4gICAgICAgIFt0b29sdGlwXT1cIidSZWZyZXNoIGludGVydmFsIGluIHNlY29uZHMnIHwgdHJhbnNsYXRlXCJcbiAgICAgICAgcGxhY2VtZW50PVwiYm90dG9tXCJcbiAgICAgICAgW2FkYXB0aXZlUG9zaXRpb25dPVwiZmFsc2VcIlxuICAgICAgICBbZGVsYXldPVwiNTAwXCJcbiAgICAgICAgW2NvbnRhaW5lcl09XCInYm9keSdcIlxuICAgICAgICBmb3JtQ29udHJvbE5hbWU9XCJyZWZyZXNoSW50ZXJ2YWxcIlxuICAgICAgICBkYXRhLWN5PVwiYzh5LWFsYXJtcy1pbnRlcnZhbC1zZWxlY3RvclwiXG4gICAgICA+XG4gICAgICAgIDxvcHRpb25cbiAgICAgICAgICBbZGlzYWJsZWRdPVwiaXNEaXNhYmxlZFwiXG4gICAgICAgICAgKm5nRm9yPVwibGV0IHJlZnJlc2hJbnRlcnZhbCBvZiByZWZyZXNoSW50ZXJ2YWxzSW5NaWxsaXNlY29uZHNcIlxuICAgICAgICAgIFtuZ1ZhbHVlXT1cInJlZnJlc2hJbnRlcnZhbFwiXG4gICAgICAgID5cbiAgICAgICAgICB7eyBTRUNPTkRTX1VOVElMX1JFRlJFU0ggfCB0cmFuc2xhdGU6IHsgc2Vjb25kczogcmVmcmVzaEludGVydmFsIC8gMTAwMCB9IH19XG4gICAgICAgIDwvb3B0aW9uPlxuICAgICAgPC9zZWxlY3Q+XG4gICAgICA8c3Bhbj48L3NwYW4+XG4gICAgPC9kaXY+XG4gICAgPGRpdiBjbGFzcz1cImlucHV0LWdyb3VwLWJ0blwiPlxuICAgICAgPGJ1dHRvblxuICAgICAgICBjbGFzcz1cImJ0biBidG4tZGVmYXVsdFwiXG4gICAgICAgIHN0eWxlPVwiYm9yZGVyLWxlZnQ6IDBcIlxuICAgICAgICBbYXR0ci5hcmlhLWxhYmVsXT1cIidSZWZyZXNoJyB8IHRyYW5zbGF0ZVwiXG4gICAgICAgIFt0b29sdGlwXT1cIidSZWZyZXNoJyB8IHRyYW5zbGF0ZVwiXG4gICAgICAgIHBsYWNlbWVudD1cImJvdHRvbVwiXG4gICAgICAgIHR5cGU9XCJidXR0b25cIlxuICAgICAgICBbYWRhcHRpdmVQb3NpdGlvbl09XCJmYWxzZVwiXG4gICAgICAgIFtkZWxheV09XCI1MDBcIlxuICAgICAgICBbZGlzYWJsZWRdPVwiaXNEaXNhYmxlZCB8fCAoYWxhcm1zTGlzdExvYWRpbmckIHwgYXN5bmMpXCJcbiAgICAgICAgKGNsaWNrKT1cIm9uQ291bnRkb3duRW5kZWQuZW1pdCgpXCJcbiAgICAgICAgZGF0YS1jeT1cImM4eS1hbGFybXMtcmVsb2FkLWJ1dHRvblwiXG4gICAgICA+XG4gICAgICAgIDxpXG4gICAgICAgICAgYzh5SWNvbj1cInJlZnJlc2hcIlxuICAgICAgICAgIFtuZ0NsYXNzXT1cInsgJ2ljb24tc3Bpbic6IGFsYXJtc0xpc3RMb2FkaW5nJCB8IGFzeW5jIH1cIlxuICAgICAgICA+PC9pPlxuICAgICAgPC9idXR0b24+XG4gICAgPC9kaXY+XG4gIDwvZGl2PlxuPC9mb3JtPlxuIl19