UNPKG

@c8y/ngx-components

Version:

Angular modules for Cumulocity IoT applications

165 lines 34.2 kB
import { Component, ElementRef, HostBinding, Input, ViewChild } from '@angular/core'; import { DomSanitizer } from '@angular/platform-browser'; import { Subject } from 'rxjs'; import { debounceTime, distinctUntilChanged, map, takeUntil } from 'rxjs/operators'; import * as i0 from "@angular/core"; import * as i1 from "@angular/platform-browser"; import * as i2 from "@angular/common"; import * as i3 from "../i18n/c8y-translate.pipe"; import * as i4 from "../common/date.pipe"; export class RangeDisplayComponent { get inlineStyle() { this.config = this.config || {}; if (!this.config.min) { this.config.min = 0; } if (!this.config.max && this.config.max !== 0) { this.config.max = 100; } if (this.config.fractionSize !== undefined) { this.config.current = parseFloat(this.config.current.toFixed(this.config.fractionSize)); } return this.sanitizer.bypassSecurityTrustStyle(` --range-min: ${this.config.min}; --range-max: ${this.config.max}; --range-display-tooltip-translate: translate(${this.tooltipShift}, -56px); --range-display-tooltip-bg: var(${this.getTooltipBackground()}); --full-range: ${this.config.max - this.config.min}; --measurement-target: ${((this.config.target - this.config.min) * 100) / (this.config.max - this.config.min)}%; --measurement-current: ${((this.config.current - this.config.min) * 100) / (this.config.max - this.config.min)}%; --range-y-min: ${((this.config.yellowRangeMin - this.config.min) * 100) / (this.config.max - this.config.min)}%; --range-y-max: ${((this.config.yellowRangeMax - this.config.min) / (this.config.max - this.config.min)) * 100}%; --range-r-min: ${((this.config.redRangeMin - this.config.min) * 100) / (this.config.max - this.config.min)}%; --range-r-max: ${((this.config.redRangeMax - this.config.min) / (this.config.max - this.config.min)) * 100}%; `); } constructor(sanitizer) { this.sanitizer = sanitizer; this.config = {}; this.display = 'full'; this.currentRangeWidthChanged = new Subject(); // width of current range is changing within 150ms, see style declaration for .range-display__range__current this.CURRENT_RANGE_WIDTH_TRANSITION_TIME = 150; this.DEFAULT_TOOLTIP_SHIFT = '50%'; this.MIN_TOOLTIP_SHIFT = 10; this.tooltipShift = this.DEFAULT_TOOLTIP_SHIFT; this.destroyed$ = new Subject(); } ngOnChanges() { // It's necessary to handle tooltip shifting both in OnChanges and AfterViewInit. In case of Linear gauge widget, view is // rendered first (so as elements needed for calculating shifting) and config orientation is set later on. // In other cases it's possible that orientation is defined on initialization of class and view elements are rendered later. this.setupTooltipShiftingIfPossible(); } ngAfterViewInit() { this.setupTooltipShiftingIfPossible(); } ngOnDestroy() { this.currentRangeWidthObserver?.disconnect(); this.destroyed$.next(); this.destroyed$.complete(); } checkTarget() { return (this.config.target !== undefined && this.config.target !== null && this.config.target >= this.config.min && this.config.target <= this.config.max); } rulerCalc(index) { const num = this.config.min + ((this.config.max - this.config.min) / 10) * index; if (this.config.fractionSize !== undefined) { return parseFloat(num.toFixed(this.config.fractionSize)); } return parseFloat(num.toFixed(2)); } trackByIndex(index) { return index; } isRedRangeDisplayed() { const { redRangeMin, redRangeMax } = this.config; return this.isRangeDisplayed(redRangeMin, redRangeMax); } isYellowRangeDisplayed() { const { yellowRangeMin, yellowRangeMax } = this.config; return this.isRangeDisplayed(yellowRangeMin, yellowRangeMax); } isRangeDisplayed(rangeMin, rangeMax) { return rangeMin === 0 || rangeMax === 0 || (rangeMin && rangeMax); } setupTooltipShifting() { this.currentRangeWidthObserver = new ResizeObserver(([val]) => { if (getComputedStyle(val.target, null).display === 'block') { this.currentRangeWidthChanged.next(val.target); } }); this.currentRangeWidthObserver.observe(this.currentRangeElement.nativeElement); this.currentRangeWidthChanged .pipe(debounceTime(this.CURRENT_RANGE_WIDTH_TRANSITION_TIME), map((rangeElement) => parseInt(getComputedStyle(rangeElement, null).width)), distinctUntilChanged(), takeUntil(this.destroyed$)) .subscribe(rangeElementWidth => { this.setTooltipShiftValue(rangeElementWidth); }); } setTooltipShiftValue(rangeElementWidth) { const tooltipWidth = parseInt(getComputedStyle(this.currentRangeElement.nativeElement, ':after').width); const currentRangeWidth = rangeElementWidth; const rangeDisplayWidth = parseInt(getComputedStyle(this.rangeDisplay.nativeElement, null).getPropertyValue('width')); const rangeDisplayPaddingLeft = parseInt(getComputedStyle(this.rangeDisplay.nativeElement, null).getPropertyValue('padding-left')); const tooltipOverflowsLeftEdge = tooltipWidth / 2 > rangeDisplayPaddingLeft + currentRangeWidth; const tooltipOverflowsRightEdge = tooltipWidth / 2 > rangeDisplayWidth - rangeDisplayPaddingLeft - currentRangeWidth; if (tooltipOverflowsLeftEdge) { this.tooltipShift = `${tooltipWidth - this.MIN_TOOLTIP_SHIFT}px`; } else if (tooltipOverflowsRightEdge) { this.tooltipShift = `${this.MIN_TOOLTIP_SHIFT}px`; } else { this.tooltipShift = this.DEFAULT_TOOLTIP_SHIFT; } } setupTooltipShiftingIfPossible() { if (this.config?.orientation === 'horizontal' && !this.currentRangeWidthObserver && this.rangeDisplay && this.currentRangeElement) { this.setupTooltipShifting(); } } getTooltipBackground() { const current = this.config.current; switch (true) { case this.isValueInRange(current, this.config.redRangeMin, this.config.redRangeMax): return '--c8y-palette-status-danger'; case this.isValueInRange(current, this.config.yellowRangeMin, this.config.yellowRangeMax): return '--c8y-palette-status-warning'; default: return '--c8y-brand-10'; } } isValueInRange(value, min, max) { return min != null && max != null && value >= min && value <= max; } static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: RangeDisplayComponent, deps: [{ token: i1.DomSanitizer }], target: i0.ɵɵFactoryTarget.Component }); } static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.13", type: RangeDisplayComponent, selector: "c8y-range-display", inputs: { config: "config", display: "display" }, host: { properties: { "attr.style": "this.inlineStyle" } }, viewQueries: [{ propertyName: "rangeDisplay", first: true, predicate: ["rangeDisplay"], descendants: true }, { propertyName: "currentRangeElement", first: true, predicate: ["currentRangeElement"], descendants: true }], usesOnChanges: true, ngImport: i0, template: "<div\n [ngClass]=\"{\n 'range-display--vertical': config.orientation === 'vertical',\n 'range-display--compact': display === 'compact',\n 'range-display--inline': display === 'inline'\n }\"\n attr.data-label=\"{{ config.unit }}\"\n>\n <div\n class=\"range-display\"\n #rangeDisplay\n >\n <div class=\"range-display__range\">\n <div class=\"range-display__range__unit\">\n {{ config.unit }}\n </div>\n <div\n *ngIf=\"isYellowRangeDisplayed()\"\n class=\"range-display__range__min\"\n ></div>\n <div\n *ngIf=\"isRedRangeDisplayed()\"\n class=\"range-display__range__max\"\n ></div>\n <div\n *ngIf=\"checkTarget()\"\n class=\"range-display__range__target\"\n attr.data-label=\"{{ config.target }} {{ config.unit }}\"\n title=\"{{ 'Target' | translate }}: {{ config.target }} {{ config.unit }}\"\n ></div>\n <div\n [ngStyle]=\"{\n display:\n config.current != undefined &&\n config.current >= config.min &&\n config.current <= config.max\n ? 'block'\n : 'none'\n }\"\n #currentRangeElement\n class=\"range-display__range__current\"\n attr.data-label=\"{{ config.current }} {{ config.unit }} &#xa;{{ config.time | c8yDate }}\"\n title=\"{{ 'Current' | translate }}: {{ config.current }} {{ config.unit }} | {{\n config.time | c8yDate\n }}\"\n ></div>\n </div>\n <div class=\"range-display__ruler\">\n <div\n *ngFor=\"let x of [].constructor(10); let index = index; trackBy: trackByIndex\"\n attr.data-label=\"{{ rulerCalc(index) }}\"\n class=\"range-display__tick\"\n ></div>\n <div\n attr.data-label=\"{{ config.max ?? 100 | number }}\"\n class=\"range-display__tick\"\n ></div>\n </div>\n </div>\n</div>\n", dependencies: [{ kind: "directive", type: i2.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i2.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i2.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i2.NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }, { kind: "pipe", type: i3.C8yTranslatePipe, name: "translate" }, { kind: "pipe", type: i2.DecimalPipe, name: "number" }, { kind: "pipe", type: i4.DatePipe, name: "c8yDate" }] }); } } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: RangeDisplayComponent, decorators: [{ type: Component, args: [{ selector: 'c8y-range-display', template: "<div\n [ngClass]=\"{\n 'range-display--vertical': config.orientation === 'vertical',\n 'range-display--compact': display === 'compact',\n 'range-display--inline': display === 'inline'\n }\"\n attr.data-label=\"{{ config.unit }}\"\n>\n <div\n class=\"range-display\"\n #rangeDisplay\n >\n <div class=\"range-display__range\">\n <div class=\"range-display__range__unit\">\n {{ config.unit }}\n </div>\n <div\n *ngIf=\"isYellowRangeDisplayed()\"\n class=\"range-display__range__min\"\n ></div>\n <div\n *ngIf=\"isRedRangeDisplayed()\"\n class=\"range-display__range__max\"\n ></div>\n <div\n *ngIf=\"checkTarget()\"\n class=\"range-display__range__target\"\n attr.data-label=\"{{ config.target }} {{ config.unit }}\"\n title=\"{{ 'Target' | translate }}: {{ config.target }} {{ config.unit }}\"\n ></div>\n <div\n [ngStyle]=\"{\n display:\n config.current != undefined &&\n config.current >= config.min &&\n config.current <= config.max\n ? 'block'\n : 'none'\n }\"\n #currentRangeElement\n class=\"range-display__range__current\"\n attr.data-label=\"{{ config.current }} {{ config.unit }} &#xa;{{ config.time | c8yDate }}\"\n title=\"{{ 'Current' | translate }}: {{ config.current }} {{ config.unit }} | {{\n config.time | c8yDate\n }}\"\n ></div>\n </div>\n <div class=\"range-display__ruler\">\n <div\n *ngFor=\"let x of [].constructor(10); let index = index; trackBy: trackByIndex\"\n attr.data-label=\"{{ rulerCalc(index) }}\"\n class=\"range-display__tick\"\n ></div>\n <div\n attr.data-label=\"{{ config.max ?? 100 | number }}\"\n class=\"range-display__tick\"\n ></div>\n </div>\n </div>\n</div>\n" }] }], ctorParameters: () => [{ type: i1.DomSanitizer }], propDecorators: { config: [{ type: Input }], display: [{ type: Input }], inlineStyle: [{ type: HostBinding, args: ['attr.style'] }], rangeDisplay: [{ type: ViewChild, args: ['rangeDisplay', { static: false }] }], currentRangeElement: [{ type: ViewChild, args: ['currentRangeElement', { static: false }] }] } }); //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicmFuZ2UtZGlzcGxheS5jb21wb25lbnQuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi9jb3JlL3JhbmdlLWRpc3BsYXkvcmFuZ2UtZGlzcGxheS5jb21wb25lbnQudHMiLCIuLi8uLi8uLi8uLi9jb3JlL3JhbmdlLWRpc3BsYXkvcmFuZ2UtZGlzcGxheS5jb21wb25lbnQuaHRtbCJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBRUwsU0FBUyxFQUNULFVBQVUsRUFDVixXQUFXLEVBQ1gsS0FBSyxFQUdMLFNBQVMsRUFDVixNQUFNLGVBQWUsQ0FBQztBQUN2QixPQUFPLEVBQUUsWUFBWSxFQUFFLE1BQU0sMkJBQTJCLENBQUM7QUFDekQsT0FBTyxFQUFFLE9BQU8sRUFBRSxNQUFNLE1BQU0sQ0FBQztBQUMvQixPQUFPLEVBQUUsWUFBWSxFQUFFLG9CQUFvQixFQUFFLEdBQUcsRUFBRSxTQUFTLEVBQUUsTUFBTSxnQkFBZ0IsQ0FBQzs7Ozs7O0FBT3BGLE1BQU0sT0FBTyxxQkFBcUI7SUFVaEMsSUFDSSxXQUFXO1FBQ2IsSUFBSSxDQUFDLE1BQU0sR0FBRyxJQUFJLENBQUMsTUFBTSxJQUFJLEVBQUUsQ0FBQztRQUNoQyxJQUFJLENBQUMsSUFBSSxDQUFDLE1BQU0sQ0FBQyxHQUFHLEVBQUUsQ0FBQztZQUNyQixJQUFJLENBQUMsTUFBTSxDQUFDLEdBQUcsR0FBRyxDQUFDLENBQUM7UUFDdEIsQ0FBQztRQUNELElBQUksQ0FBQyxJQUFJLENBQUMsTUFBTSxDQUFDLEdBQUcsSUFBSSxJQUFJLENBQUMsTUFBTSxDQUFDLEdBQUcsS0FBSyxDQUFDLEVBQUUsQ0FBQztZQUM5QyxJQUFJLENBQUMsTUFBTSxDQUFDLEdBQUcsR0FBRyxHQUFHLENBQUM7UUFDeEIsQ0FBQztRQUNELElBQUksSUFBSSxDQUFDLE1BQU0sQ0FBQyxZQUFZLEtBQUssU0FBUyxFQUFFLENBQUM7WUFDM0MsSUFBSSxDQUFDLE1BQU0sQ0FBQyxPQUFP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Z0JBU0YsV0FBVztzQkFEZCxXQUFXO3VCQUFDLFlBQVk7Z0JBNkNqQixZQUFZO3NCQURuQixTQUFTO3VCQUFDLGNBQWMsRUFBRSxFQUFFLE1BQU0sRUFBRSxLQUFLLEVBQUU7Z0JBR3BDLG1CQUFtQjtzQkFEMUIsU0FBUzt1QkFBQyxxQkFBcUIsRUFBRSxFQUFFLE1BQU0sRUFBRSxLQUFLLEVBQUUiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQge1xuICBBZnRlclZpZXdJbml0LFxuICBDb21wb25lbnQsXG4gIEVsZW1lbnRSZWYsXG4gIEhvc3RCaW5kaW5nLFxuICBJbnB1dCxcbiAgT25DaGFuZ2VzLFxuICBPbkRlc3Ryb3ksXG4gIFZpZXdDaGlsZFxufSBmcm9tICdAYW5ndWxhci9jb3JlJztcbmltcG9ydCB7IERvbVNhbml0aXplciB9IGZyb20gJ0Bhbmd1bGFyL3BsYXRmb3JtLWJyb3dzZXInO1xuaW1wb3J0IHsgU3ViamVjdCB9IGZyb20gJ3J4anMnO1xuaW1wb3J0IHsgZGVib3VuY2VUaW1lLCBkaXN0aW5jdFVudGlsQ2hhbmdlZCwgbWFwLCB0YWtlVW50aWwgfSBmcm9tICdyeGpzL29wZXJhdG9ycyc7XG5pbXBvcnQgeyBSYW5nZURpc3BsYXkgfSBmcm9tICcuL3JhbmdlLWRpc3BsYXkubW9kZWwnO1xuXG5AQ29tcG9uZW50KHtcbiAgc2VsZWN0b3I6ICdjOHktcmFuZ2UtZGlzcGxheScsXG4gIHRlbXBsYXRlVXJsOiAnLi9yYW5nZS1kaXNwbGF5LmNvbXBvbmVudC5odG1sJ1xufSlcbmV4cG9ydCBjbGFzcyBSYW5nZURpc3BsYXlDb21wb25lbnQgaW1wbGVtZW50cyBBZnRlclZpZXdJbml0LCBPbkRlc3Ryb3ksIE9uQ2hhbmdlcyB7XG4gIEBJbnB1dCgpIGNvbmZpZzogUmFuZ2VEaXNwbGF5ID0ge307XG4gIEBJbnB1dCgpIGRpc3BsYXk6ICdmdWxsJyB8ICdjb21wYWN0JyB8ICdpbmxpbmUnID0gJ2Z1bGwnO1xuICBwcml2YXRlIGN1cnJlbnRSYW5nZVdpZHRoT2JzZXJ2ZXI6IFJlc2l6ZU9ic2VydmVyO1xuICBwcml2YXRlIGN1cnJlbnRSYW5nZVdpZHRoQ2hhbmdlZCA9IG5ldyBTdWJqZWN0PEVsZW1lbnQ+KCk7XG4gIC8vIHdpZHRoIG9mIGN1cnJlbnQgcmFuZ2UgaXMgY2hhbmdpbmcgd2l0aGluIDE1MG1zLCBzZWUgc3R5bGUgZGVjbGFyYXRpb24gZm9yIC5yYW5nZS1kaXNwbGF5X19yYW5nZV9fY3VycmVudFxuICBwcml2YXRlIHJlYWRvbmx5IENVUlJFTlRfUkFOR0VfV0lEVEhfVFJBTlNJVElPTl9USU1FID0gMTUwO1xuICBwcml2YXRlIHJlYWRvbmx5IERFRkFVTFRfVE9PTFRJUF9TSElGVCA9ICc1MCUnO1xuICBwcml2YXRlIHJlYWRvbmx5IE1JTl9UT09MVElQX1NISUZUID0gMTA7XG4gIHByaXZhdGUgdG9vbHRpcFNoaWZ0ID0gdGhpcy5ERUZBVUxUX1RPT0xUSVBfU0hJRlQ7XG4gIEBIb3N0QmluZGluZygnYXR0ci5zdHlsZScpXG4gIGdldCBpbmxpbmVTdHlsZSgpIHtcbiAgICB0aGlzLmNvbmZpZyA9IHRoaXMuY29uZmlnIHx8IHt9O1xuICAgIGlmICghdGhpcy5jb25maWcubWluKSB7XG4gICAgICB0aGlzLmNvbmZpZy5taW4gPSAwO1xuICAgIH1cbiAgICBpZiAoIXRoaXMuY29uZmlnLm1heCAmJiB0aGlzLmNvbmZpZy5tYXggIT09IDApIHtcbiAgICAgIHRoaXMuY29uZmlnLm1heCA9IDEwMDtcbiAgICB9XG4gICAgaWYgKHRoaXMuY29uZmlnLmZyYWN0aW9uU2l6ZSAhPT0gdW5kZWZpbmVkKSB7XG4gICAgICB0aGlzLmNvbmZpZy5jdXJyZW50ID0gcGFyc2VGbG9hdCh0aGlzLmNvbmZpZy5jdXJyZW50LnRvRml4ZWQodGhpcy5jb25maWcuZnJhY3Rpb25TaXplKSk7XG4gICAgfVxuICAgIHJldHVybiB0aGlzLnNhbml0aXplci5ieXBhc3NTZWN1cml0eVRydXN0U3R5bGUoXG4gICAgICBgXG4gICAgICAgICAgLS1yYW5nZS1taW46ICR7dGhpcy5jb25maWcubWlufTtcbiAgICAgICAgICAtLXJhbmdlLW1heDogJHt0aGlzLmNvbmZpZy5tYXh9O1xuICAgICAgICAgIC0tcmFuZ2UtZGlzcGxheS10b29sdGlwLXRyYW5zbGF0ZTogdHJhbnNsYXRlKCR7dGhpcy50b29sdGlwU2hpZnR9LCAtNTZweCk7XG4gICAgICAgICAgLS1yYW5nZS1kaXNwbGF5LXRvb2x0aXAtYmc6IHZhcigke3RoaXMuZ2V0VG9vbHRpcEJhY2tncm91bmQoKX0pO1xuICAgICAgICAgIC0tZnVsbC1yYW5nZTogJHt0aGlzLmNvbmZpZy5tYXggLSB0aGlzLmNvbmZpZy5taW59O1xuICAgICAgICAgIC0tbWVhc3VyZW1lbnQtdGFyZ2V0OiAke1xuICAgICAgICAgICAgKCh0aGlzLmNvbmZpZy50YXJnZXQgLSB0aGlzLmNvbmZpZy5taW4pICogMTAwKSAvICh0aGlzLmNvbmZpZy5tYXggLSB0aGlzLmNvbmZpZy5taW4pXG4gICAgICAgICAgfSU7XG4gICAgICAgICAgLS1tZWFzdXJlbWVudC1jdXJyZW50OiAke1xuICAgICAgICAgICAgKCh0aGlzLmNvbmZpZy5jdXJyZW50IC0gdGhpcy5jb25maWcubWluKSAqIDEwMCkgLyAodGhpcy5jb25maWcubWF4IC0gdGhpcy5jb25maWcubWluKVxuICAgICAgICAgIH0lO1xuICAgICAgICAgIC0tcmFuZ2UteS1taW46ICR7XG4gICAgICAgICAgICAoKHRoaXMuY29uZmlnLnllbGxvd1JhbmdlTWluIC0gdGhpcy5jb25maWcubWluKSAqIDEwMCkgL1xuICAgICAgICAgICAgKHRoaXMuY29uZmlnLm1heCAtIHRoaXMuY29uZmlnLm1pbilcbiAgICAgICAgICB9JTtcbiAgICAgICAgICAtLXJhbmdlLXktbWF4OiAke1xuICAgICAgICAgICAgKCh0aGlzLmNvbmZpZy55ZWxsb3dSYW5nZU1heCAtIHRoaXMuY29uZmlnLm1pbikgLyAodGhpcy5jb25maWcubWF4IC0gdGhpcy5jb25maWcubWluKSkgKlxuICAgICAgICAgICAgMTAwXG4gICAgICAgICAgfSU7XG4gICAgICAgICAgLS1yYW5nZS1yLW1pbjogJHtcbiAgICAgICAgICAgICgodGhpcy5jb25maWcucmVkUmFuZ2VNaW4gLSB0aGlzLmNvbmZpZy5taW4pICogMTAwKSAvXG4gICAgICAgICAgICAodGhpcy5jb25maWcubWF4IC0gdGhpcy5jb25maWcubWluKVxuICAgICAgICAgIH0lO1xuICAgICAgICAgIC0tcmFuZ2Utci1tYXg6ICR7XG4gICAgICAgICAgICAoKHRoaXMuY29uZmlnLnJlZFJhbmdlTWF4IC0gdGhpcy5jb25maWcubWluKSAvICh0aGlzLmNvbmZpZy5tYXggLSB0aGlzLmNvbmZpZy5taW4pKSAqXG4gICAgICAgICAgICAxMDBcbiAgICAgICAgICB9JTtcbiAgICAgICAgYFxuICAgICk7XG4gIH1cbiAgQFZpZXdDaGlsZCgncmFuZ2VEaXNwbGF5JywgeyBzdGF0aWM6IGZhbHNlIH0pXG4gIHByaXZhdGUgcmFuZ2VEaXNwbGF5OiBFbGVtZW50UmVmO1xuICBAVmlld0NoaWxkKCdjdXJyZW50UmFuZ2VFbGVtZW50JywgeyBzdGF0aWM6IGZhbHNlIH0pXG4gIHByaXZhdGUgY3VycmVudFJhbmdlRWxlbWVudDogRWxlbWVudFJlZjtcbiAgcHJpdmF0ZSBkZXN0cm95ZWQkID0gbmV3IFN1YmplY3Q8dm9pZD4oKTtcbiAgY29uc3RydWN0b3IocHJpdmF0ZSBzYW5pdGl6ZXI6IERvbVNhbml0aXplcikge31cblxuICBuZ09uQ2hhbmdlcygpIHtcbiAgICAvLyBJdCdzIG5lY2Vzc2FyeSB0byBoYW5kbGUgdG9vbHRpcCBzaGlmdGluZyBib3RoIGluIE9uQ2hhbmdlcyBhbmQgQWZ0ZXJWaWV3SW5pdC4gSW4gY2FzZSBvZiBMaW5lYXIgZ2F1Z2Ugd2lkZ2V0LCB2aWV3IGlzXG4gICAgLy8gcmVuZGVyZWQgZmlyc3QgKHNvIGFzIGVsZW1lbnRzIG5lZWRlZCBmb3IgY2FsY3VsYXRpbmcgc2hpZnRpbmcpIGFuZCBjb25maWcgb3JpZW50YXRpb24gaXMgc2V0IGxhdGVyIG9uLlxuICAgIC8vIEluIG90aGVyIGNhc2VzIGl0J3MgcG9zc2libGUgdGhhdCBvcmllbnRhdGlvbiBpcyBkZWZpbmVkIG9uIGluaXRpYWxpemF0aW9uIG9mIGNsYXNzIGFuZCB2aWV3IGVsZW1lbnRzIGFyZSByZW5kZXJlZCBsYXRlci5cbiAgICB0aGlzLnNldHVwVG9vbHRpcFNoaWZ0aW5nSWZQb3NzaWJsZSgpO1xuICB9XG5cbiAgbmdBZnRlclZpZXdJbml0KCkge1xuICAgIHRoaXMuc2V0dXBUb29sdGlwU2hpZnRpbmdJZlBvc3NpYmxlKCk7XG4gIH1cblxuICBuZ09uRGVzdHJveSgpIHtcbiAgICB0aGlzLmN1cnJlbnRSYW5nZVdpZHRoT2JzZXJ2ZXI/LmRpc2Nvbm5lY3QoKTtcbiAgICB0aGlzLmRlc3Ryb3llZCQubmV4dCgpO1xuICAgIHRoaXMuZGVzdHJveWVkJC5jb21wbGV0ZSgpO1xuICB9XG5cbiAgY2hlY2tUYXJnZXQoKTogYm9vbGVhbiB7XG4gICAgcmV0dXJuIChcbiAgICAgIHRoaXMuY29uZmlnLnRhcmdldCAhPT0gdW5kZWZpbmVkICYmXG4gICAgICB0aGlzLmNvbmZpZy50YXJnZXQgIT09IG51bGwgJiZcbiAgICAgIHRoaXMuY29uZmlnLnRhcmdldCA+PSB0aGlzLmNvbmZpZy5taW4gJiZcbiAgICAgIHRoaXMuY29uZmlnLnRhcmdldCA8PSB0aGlzLmNvbmZpZy5tYXhcbiAgICApO1xuICB9XG5cbiAgcnVsZXJDYWxjKGluZGV4KSB7XG4gICAgY29uc3QgbnVtOiBudW1iZXIgPSB0aGlzLmNvbmZpZy5taW4gKyAoKHRoaXMuY29uZmlnLm1heCAtIHRoaXMuY29uZmlnLm1pbikgLyAxMCkgKiBpbmRleDtcbiAgICBpZiAodGhpcy5jb25maWcuZnJhY3Rpb25TaXplICE9PSB1bmRlZmluZWQpIHtcbiAgICAgIHJldHVybiBwYXJzZUZsb2F0KG51bS50b0ZpeGVkKHRoaXMuY29uZmlnLmZyYWN0aW9uU2l6ZSkpO1xuICAgIH1cbiAgICByZXR1cm4gcGFyc2VGbG9hdChudW0udG9GaXhlZCgyKSk7XG4gIH1cblxuICB0cmFja0J5SW5kZXgoaW5kZXg6IG51bWJlcik6IG51bWJlciB7XG4gICAgcmV0dXJuIGluZGV4O1xuICB9XG5cbiAgaXNSZWRSYW5nZURpc3BsYXllZCgpIHtcbiAgICBjb25zdCB7IHJlZFJhbmdlTWluLCByZWRSYW5nZU1heCB9ID0gdGhpcy5jb25maWc7XG4gICAgcmV0dXJuIHRoaXMuaXNSYW5nZURpc3BsYXllZChyZWRSYW5nZU1pbiwgcmVkUmFuZ2VNYXgpO1xuICB9XG5cbiAgaXNZZWxsb3dSYW5nZURpc3BsYXllZCgpIHtcbiAgICBjb25zdCB7IHllbGxvd1JhbmdlTWluLCB5ZWxsb3dSYW5nZU1heCB9ID0gdGhpcy5jb25maWc7XG4gICAgcmV0dXJuIHRoaXMuaXNSYW5nZURpc3BsYXllZCh5ZWxsb3dSYW5nZU1pbiwgeWVsbG93UmFuZ2VNYXgpO1xuICB9XG5cbiAgaXNSYW5nZURpc3BsYXllZChyYW5nZU1pbiwgcmFuZ2VNYXgpIHtcbiAgICByZXR1cm4gcmFuZ2VNaW4gPT09IDAgfHwgcmFuZ2VNYXggPT09IDAgfHwgKHJhbmdlTWluICYmIHJhbmdlTWF4KTtcbiAgfVxuXG4gIHByaXZhdGUgc2V0dXBUb29sdGlwU2hpZnRpbmcoKSB7XG4gICAgdGhpcy5jdXJyZW50UmFuZ2VXaWR0aE9ic2VydmVyID0gbmV3IFJlc2l6ZU9ic2VydmVyKChbdmFsXSkgPT4ge1xuICAgICAgaWYgKGdldENvbXB1dGVkU3R5bGUodmFsLnRhcmdldCwgbnVsbCkuZGlzcGxheSA9PT0gJ2Jsb2NrJykge1xuICAgICAgICB0aGlzLmN1cnJlbnRSYW5nZVdpZHRoQ2hhbmdlZC5uZXh0KHZhbC50YXJnZXQpO1xuICAgICAgfVxuICAgIH0pO1xuXG4gICAgdGhpcy5jdXJyZW50UmFuZ2VXaWR0aE9ic2VydmVyLm9ic2VydmUodGhpcy5jdXJyZW50UmFuZ2VFbGVtZW50Lm5hdGl2ZUVsZW1lbnQpO1xuXG4gICAgdGhpcy5jdXJyZW50UmFuZ2VXaWR0aENoYW5nZWRcbiAgICAgIC5waXBlKFxuICAgICAgICBkZWJvdW5jZVRpbWUodGhpcy5DVVJSRU5UX1JBTkdFX1dJRFRIX1RSQU5TSVRJT05fVElNRSksXG4gICAgICAgIG1hcCgocmFuZ2VFbGVtZW50OiBFbGVtZW50KSA9PiBwYXJzZUludChnZXRDb21wdXRlZFN0eWxlKHJhbmdlRWxlbWVudCwgbnVsbCkud2lkdGgpKSxcbiAgICAgICAgZGlzdGluY3RVbnRpbENoYW5nZWQoKSxcbiAgICAgICAgdGFrZVVudGlsKHRoaXMuZGVzdHJveWVkJClcbiAgICAgIClcbiAgICAgIC5zdWJzY3JpYmUocmFuZ2VFbGVtZW50V2lkdGggPT4ge1xuICAgICAgICB0aGlzLnNldFRvb2x0aXBTaGlmdFZhbHVlKHJhbmdlRWxlbWVudFdpZHRoKTtcbiAgICAgIH0pO1xuICB9XG5cbiAgcHJpdmF0ZSBzZXRUb29sdGlwU2hpZnRWYWx1ZShyYW5nZUVsZW1lbnRXaWR0aDogbnVtYmVyKSB7XG4gICAgY29uc3QgdG9vbHRpcFdpZHRoID0gcGFyc2VJbnQoXG4gICAgICBnZXRDb21wdXRlZFN0eWxlKHRoaXMuY3VycmVudFJhbmdlRWxlbWVudC5uYXRpdmVFbGVtZW50LCAnOmFmdGVyJykud2lkdGhcbiAgICApO1xuICAgIGNvbnN0IGN1cnJlbnRSYW5nZVdpZHRoID0gcmFuZ2VFbGVtZW50V2lkdGg7XG4gICAgY29uc3QgcmFuZ2VEaXNwbGF5V2lkdGggPSBwYXJzZUludChcbiAgICAgIGdldENvbXB1dGVkU3R5bGUodGhpcy5yYW5nZURpc3BsYXkubmF0aXZlRWxlbWVudCwgbnVsbCkuZ2V0UHJvcGVydHlWYWx1ZSgnd2lkdGgnKVxuICAgICk7XG4gICAgY29uc3QgcmFuZ2VEaXNwbGF5UGFkZGluZ0xlZnQgPSBwYXJzZUludChcbiAgICAgIGdldENvbXB1dGVkU3R5bGUodGhpcy5yYW5nZURpc3BsYXkubmF0aXZlRWxlbWVudCwgbnVsbCkuZ2V0UHJvcGVydHlWYWx1ZSgncGFkZGluZy1sZWZ0JylcbiAgICApO1xuICAgIGNvbnN0IHRvb2x0aXBPdmVyZmxvd3NMZWZ0RWRnZSA9IHRvb2x0aXBXaWR0aCAvIDIgPiByYW5nZURpc3BsYXlQYWRkaW5nTGVmdCArIGN1cnJlbnRSYW5nZVdpZHRoO1xuICAgIGNvbnN0IHRvb2x0aXBPdmVyZmxvd3NSaWdodEVkZ2UgPVxuICAgICAgdG9vbHRpcFdpZHRoIC8gMiA+IHJhbmdlRGlzcGxheVdpZHRoIC0gcmFuZ2VEaXNwbGF5UGFkZGluZ0xlZnQgLSBjdXJyZW50UmFuZ2VXaWR0aDtcbiAgICBpZiAodG9vbHRpcE92ZXJmbG93c0xlZnRFZGdlKSB7XG4gICAgICB0aGlzLnRvb2x0aXBTaGlmdCA9IGAke3Rvb2x0aXBXaWR0aCAtIHRoaXMuTUlOX1RPT0xUSVBfU0hJRlR9cHhgO1xuICAgIH0gZWxzZSBpZiAodG9vbHRpcE92ZXJmbG93c1JpZ2h0RWRnZSkge1xuICAgICAgdGhpcy50b29sdGlwU2hpZnQgPSBgJHt0aGlzLk1JTl9UT09MVElQX1NISUZUfXB4YDtcbiAgICB9IGVsc2Uge1xuICAgICAgdGhpcy50b29sdGlwU2hpZnQgPSB0aGlzLkRFRkFVTFRfVE9PTFRJUF9TSElGVDtcbiAgICB9XG4gIH1cblxuICBwcml2YXRlIHNldHVwVG9vbHRpcFNoaWZ0aW5nSWZQb3NzaWJsZSgpIHtcbiAgICBpZiAoXG4gICAgICB0aGlzLmNvbmZpZz8ub3JpZW50YXRpb24gPT09ICdob3Jpem9udGFsJyAmJlxuICAgICAgIXRoaXMuY3VycmVudFJhbmdlV2lkdGhPYnNlcnZlciAmJlxuICAgICAgdGhpcy5yYW5nZURpc3BsYXkgJiZcbiAgICAgIHRoaXMuY3VycmVudFJhbmdlRWxlbWVudFxuICAgICkge1xuICAgICAgdGhpcy5zZXR1cFRvb2x0aXBTaGlmdGluZygpO1xuICAgIH1cbiAgfVxuXG4gIHByaXZhdGUgZ2V0VG9vbHRpcEJhY2tncm91bmQoKTogc3RyaW5nIHtcbiAgICBjb25zdCBjdXJyZW50ID0gdGhpcy5jb25maWcuY3VycmVudDtcbiAgICBzd2l0Y2ggKHRydWUpIHtcbiAgICAgIGNhc2UgdGhpcy5pc1ZhbHVlSW5SYW5nZShjdXJyZW50LCB0aGlzLmNvbmZpZy5yZWRSYW5nZU1pbiwgdGhpcy5jb25maWcucmVkUmFuZ2VNYXgpOlxuICAgICAgICByZXR1cm4gJy0tYzh5LXBhbGV0dGUtc3RhdHVzLWRhbmdlcic7XG4gICAgICBjYXNlIHRoaXMuaXNWYWx1ZUluUmFuZ2UoY3VycmVudCwgdGhpcy5jb25maWcueWVsbG93UmFuZ2VNaW4sIHRoaXMuY29uZmlnLnllbGxvd1JhbmdlTWF4KTpcbiAgICAgICAgcmV0dXJuICctLWM4eS1wYWxldHRlLXN0YXR1cy13YXJuaW5nJztcbiAgICAgIGRlZmF1bHQ6XG4gICAgICAgIHJldHVybiAnLS1jOHktYnJhbmQtMTAnO1xuICAgIH1cbiAgfVxuXG4gIHByaXZhdGUgaXNWYWx1ZUluUmFuZ2UodmFsdWU6IG51bWJlciwgbWluOiBudW1iZXIsIG1heDogbnVtYmVyKTogYm9vbGVhbiB7XG4gICAgcmV0dXJuIG1pbiAhPSBudWxsICYmIG1heCAhPSBudWxsICYmIHZhbHVlID49IG1pbiAmJiB2YWx1ZSA8PSBtYXg7XG4gIH1cbn1cbiIsIjxkaXZcbiAgW25nQ2xhc3NdPVwie1xuICAgICdyYW5nZS1kaXNwbGF5LS12ZXJ0aWNhbCc6IGNvbmZpZy5vcmllbnRhdGlvbiA9PT0gJ3ZlcnRpY2FsJyxcbiAgICAncmFuZ2UtZGlzcGxheS0tY29tcGFjdCc6IGRpc3BsYXkgPT09ICdjb21wYWN0JyxcbiAgICAncmFuZ2UtZGlzcGxheS0taW5saW5lJzogZGlzcGxheSA9PT0gJ2lubGluZSdcbiAgfVwiXG4gIGF0dHIuZGF0YS1sYWJlbD1cInt7IGNvbmZpZy51bml0IH19XCJcbj5cbiAgPGRpdlxuICAgIGNsYXNzPVwicmFuZ2UtZGlzcGxheVwiXG4gICAgI3JhbmdlRGlzcGxheVxuICA+XG4gICAgPGRpdiBjbGFzcz1cInJhbmdlLWRpc3BsYXlfX3JhbmdlXCI+XG4gICAgICA8ZGl2IGNsYXNzPVwicmFuZ2UtZGlzcGxheV9fcmFuZ2VfX3VuaXRcIj5cbiAgICAgICAge3sgY29uZmlnLnVuaXQgfX1cbiAgICAgIDwvZGl2PlxuICAgICAgPGRpdlxuICAgICAgICAqbmdJZj1cImlzWWVsbG93UmFuZ2VEaXNwbGF5ZWQoKVwiXG4gICAgICAgIGNsYXNzPVwicmFuZ2UtZGlzcGxheV9fcmFuZ2VfX21pblwiXG4gICAgICA+PC9kaXY+XG4gICAgICA8ZGl2XG4gICAgICAgICpuZ0lmPVwiaXNSZWRSYW5nZURpc3BsYXllZCgpXCJcbiAgICAgICAgY2xhc3M9XCJyYW5nZS1kaXNwbGF5X19yYW5nZV9fbWF4XCJcbiAgICAgID48L2Rpdj5cbiAgICAgIDxkaXZcbiAgICAgICAgKm5nSWY9XCJjaGVja1RhcmdldCgpXCJcbiAgICAgICAgY2xhc3M9XCJyYW5nZS1kaXNwbGF5X19yYW5nZV9fdGFyZ2V0XCJcbiAgICAgICAgYXR0ci5kYXRhLWxhYmVsPVwie3sgY29uZmlnLnRhcmdldCB9fSB7eyBjb25maWcudW5pdCB9fVwiXG4gICAgICAgIHRpdGxlPVwie3sgJ1RhcmdldCcgfCB0cmFuc2xhdGUgfX06IHt7IGNvbmZpZy50YXJnZXQgfX0ge3sgY29uZmlnLnVuaXQgfX1cIlxuICAgICAgPjwvZGl2PlxuICAgICAgPGRpdlxuICAgICAgICBbbmdTdHlsZV09XCJ7XG4gICAgICAgICAgZGlzcGxheTpcbiAgICAgICAgICAgIGNvbmZpZy5jdXJyZW50ICE9IHVuZGVmaW5lZCAmJlxuICAgICAgICAgICAgY29uZmlnLmN1cnJlbnQgPj0gY29uZmlnLm1pbiAmJlxuICAgICAgICAgICAgY29uZmlnLmN1cnJlbnQgPD0gY29uZmlnLm1heFxuICAgICAgICAgICAgICA/ICdibG9jaydcbiAgICAgICAgICAgICAgOiAnbm9uZSdcbiAgICAgICAgfVwiXG4gICAgICAgICNjdXJyZW50UmFuZ2VFbGVtZW50XG4gICAgICAgIGNsYXNzPVwicmFuZ2UtZGlzcGxheV9fcmFuZ2VfX2N1cnJlbnRcIlxuICAgICAgICBhdHRyLmRhdGEtbGFiZWw9XCJ7eyBjb25maWcuY3VycmVudCB9fSB7eyBjb25maWcudW5pdCB9fSAmI3hhO3t7IGNvbmZpZy50aW1lIHwgYzh5RGF0ZSB9fVwiXG4gICAgICAgIHRpdGxlPVwie3sgJ0N1cnJlbnQnIHwgdHJhbnNsYXRlIH19OiB7eyBjb25maWcuY3VycmVudCB9fSB7eyBjb25maWcudW5pdCB9fSB8IHt7XG4gICAgICAgICAgY29uZmlnLnRpbWUgfCBjOHlEYXRlXG4gICAgICAgIH19XCJcbiAgICAgID48L2Rpdj5cbiAgICA8L2Rpdj5cbiAgICA8ZGl2IGNsYXNzPVwicmFuZ2UtZGlzcGxheV9fcnVsZXJcIj5cbiAgICAgIDxkaXZcbiAgICAgICAgKm5nRm9yPVwibGV0IHggb2YgW10uY29uc3RydWN0b3IoMTApOyBsZXQgaW5kZXggPSBpbmRleDsgdHJhY2tCeTogdHJhY2tCeUluZGV4XCJcbiAgICAgICAgYXR0ci5kYXRhLWxhYmVsPVwie3sgcnVsZXJDYWxjKGluZGV4KSB9fVwiXG4gICAgICAgIGNsYXNzPVwicmFuZ2UtZGlzcGxheV9fdGlja1wiXG4gICAgICA+PC9kaXY+XG4gICAgICA8ZGl2XG4gICAgICAgIGF0dHIuZGF0YS1sYWJlbD1cInt7IGNvbmZpZy5tYXggPz8gMTAwIHwgbnVtYmVyIH19XCJcbiAgICAgICAgY2xhc3M9XCJyYW5nZS1kaXNwbGF5X190aWNrXCJcbiAgICAgID48L2Rpdj5cbiAgICA8L2Rpdj5cbiAgPC9kaXY+XG48L2Rpdj5cbiJdfQ==