UNPKG

@taiga-ui/kit

Version:

Taiga UI Angular main components kit

141 lines 34.8 kB
import { AsyncPipe, NgIf } from '@angular/common'; import { ChangeDetectionStrategy, ChangeDetectorRef, Component, inject, Input, } from '@angular/core'; import { WaMutationObserver } from '@ng-web-apis/mutation-observer'; import { WaResizeObserver } from '@ng-web-apis/resize-observer'; import { TUI_FALSE_HANDLER } from '@taiga-ui/cdk/constants'; import { TuiPan } from '@taiga-ui/cdk/directives/pan'; import { TuiZoom } from '@taiga-ui/cdk/directives/zoom'; import { tuiDragAndDropFrom, tuiTypedFromEvent } from '@taiga-ui/cdk/observables'; import { tuiInjectElement } from '@taiga-ui/cdk/utils/dom'; import { tuiClamp, tuiRound } from '@taiga-ui/cdk/utils/math'; import { tuiPx } from '@taiga-ui/cdk/utils/miscellaneous'; import { tuiSlideInTop } from '@taiga-ui/core/animations'; import { TuiButton } from '@taiga-ui/core/components/button'; import { TuiHint } from '@taiga-ui/core/directives/hint'; import { TUI_PREVIEW_ICONS, TUI_PREVIEW_TEXTS } from '@taiga-ui/kit/tokens'; import { BehaviorSubject, combineLatest, map, merge, startWith } from 'rxjs'; import { TuiPreviewAction } from './preview-action/preview-action.directive'; import { TuiPreviewZoom } from './zoom/preview-zoom.component'; import * as i0 from "@angular/core"; import * as i1 from "@taiga-ui/core/directives/hint"; const INITIAL_SCALE_COEF = 0.8; const EMPTY_COORDINATES = [0, 0]; const ROTATION_ANGLE = 90; class TuiPreviewComponent { constructor() { this.el = tuiInjectElement(); this.minZoom = 1; this.width = 0; this.height = 0; this.texts$ = inject(TUI_PREVIEW_TEXTS); this.icons = inject(TUI_PREVIEW_ICONS); this.cdr = inject(ChangeDetectorRef); this.zoom$ = new BehaviorSubject(this.minZoom); this.rotation$ = new BehaviorSubject(0); this.coordinates$ = new BehaviorSubject(EMPTY_COORDINATES); this.transitioned$ = merge(tuiDragAndDropFrom(this.el).pipe(map(({ stage }) => stage !== 'continues')), tuiTypedFromEvent(this.el, 'touchmove', { passive: true, }).pipe(map(TUI_FALSE_HANDLER)), tuiTypedFromEvent(this.el, 'wheel', { passive: true }).pipe(map(TUI_FALSE_HANDLER))); this.cursor$ = tuiDragAndDropFrom(this.el).pipe(map(({ stage }) => (stage === 'continues' ? 'grabbing' : 'initial')), startWith('initial')); this.wrapperTransform$ = combineLatest([ this.coordinates$.pipe(map(([x, y]) => `${tuiPx(x)}, ${tuiPx(y)}`)), this.zoom$, this.rotation$, ]).pipe(map(([translate, zoom, rotation]) => `translate(${translate}) scale(${zoom}) rotate(${rotation}deg)`)); this.zoomable = true; this.rotatable = false; } rotate() { this.rotation$.next(this.rotation$.value - ROTATION_ANGLE); } onPan(delta) { this.coordinates$.next(this.getGuardedCoordinates(this.coordinates$.value[0] + delta[0], this.coordinates$.value[1] + delta[1])); } onMutation(contentWrapper) { const { clientWidth, clientHeight } = contentWrapper; this.refresh(clientWidth, clientHeight); } onZoom({ clientX, clientY, delta }) { if (this.zoomable) { this.processZoom(clientX, clientY, delta); } } onResize([entry]) { if (entry?.contentRect) { this.refresh(entry.contentRect.width, entry.contentRect.height); this.cdr.detectChanges(); } } reset() { this.zoom$.next(this.minZoom); this.coordinates$.next(EMPTY_COORDINATES); } setZoom(zoom) { this.zoom$.next(zoom); const [x, y] = this.coordinates$.value; this.coordinates$.next(this.getGuardedCoordinates(x, y)); } get offsets() { const offsetX = ((this.zoom$.value - this.minZoom) * this.width) / 2; const offsetY = ((this.zoom$.value - this.minZoom) * this.height) / 2; return { offsetX, offsetY }; } calculateMinZoom(contentHeight, contentWidth, boxHeight, boxWidth) { const bigSize = contentHeight > boxHeight * INITIAL_SCALE_COEF || contentWidth > boxWidth * INITIAL_SCALE_COEF; const { clientHeight, clientWidth } = this.el; return bigSize ? tuiRound(Math.min((clientHeight * INITIAL_SCALE_COEF) / contentHeight, (clientWidth * INITIAL_SCALE_COEF) / contentWidth), 2) : 1; } refresh(width, height) { this.width = width; this.height = height; this.minZoom = this.calculateMinZoom(height, width, this.el.clientHeight, this.el.clientWidth); this.zoom$.next(this.minZoom); this.coordinates$.next(EMPTY_COORDINATES); this.rotation$.next(0); } processZoom(clientX, clientY, delta) { const oldScale = this.zoom$.value; const newScale = tuiClamp(oldScale + delta, this.minZoom, 2); const center = this.getScaleCenter({ clientX, clientY }, this.coordinates$.value, this.zoom$.value); const moveX = center[0] * oldScale - center[0] * newScale; const moveY = center[1] * oldScale - center[1] * newScale; this.zoom$.next(newScale); this.coordinates$.next(this.getGuardedCoordinates(this.coordinates$.value[0] + moveX, this.coordinates$.value[1] + moveY)); } getGuardedCoordinates(x, y) { const { offsetX, offsetY } = this.offsets; return [tuiClamp(x, -offsetX, offsetX), tuiClamp(y, -offsetY, offsetY)]; } getScaleCenter({ clientX, clientY }, [x, y], scale) { return [ (clientX - x - this.el.offsetWidth / 2) / scale, (clientY - y - this.el.offsetHeight / 2) / scale, ]; } static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: TuiPreviewComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); } static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "16.2.12", type: TuiPreviewComponent, isStandalone: true, selector: "tui-preview", inputs: { zoomable: "zoomable", rotatable: "rotatable" }, ngImport: i0, template: "<ng-container *ngIf=\"texts$ | async as texts\">\n <section\n #contentWrapper\n attributeFilter=\"src\"\n characterData\n childList\n subtree\n class=\"t-wrapper\"\n [class.t-not-interactive-content]=\"zoomable\"\n [class.t-transitive]=\"transitioned$ | async\"\n [style.cursor]=\"cursor$ | async\"\n [style.transform]=\"wrapperTransform$ | async\"\n (tuiPan)=\"onPan($event)\"\n (tuiZoom)=\"onZoom($event)\"\n (waMutationObserver)=\"onMutation(contentWrapper)\"\n (waResizeObserver)=\"onResize($event)\"\n >\n <ng-content />\n </section>\n\n <header class=\"t-header\">\n <div class=\"t-title\">\n <ng-content select=\"tui-preview-title\" />\n </div>\n\n <ng-content select=\"tui-preview-pagination\" />\n\n <div class=\"t-actions\">\n <ng-content select=\"[tuiPreviewAction]\" />\n </div>\n </header>\n\n <footer class=\"t-footer\">\n <button\n *ngIf=\"rotatable\"\n tuiHintAppearance=\"dark\"\n tuiHintDescribe\n tuiHintDirection=\"top-right\"\n tuiIconButton\n tuiPreviewAction\n type=\"button\"\n class=\"t-rotate-button\"\n [iconStart]=\"icons.rotate\"\n [tuiHint]=\"texts.rotate\"\n (click)=\"rotate()\"\n ></button>\n\n <tui-preview-zoom\n *ngIf=\"zoomable\"\n [min]=\"minZoom\"\n [value]=\"(zoom$ | async) || 1\"\n (reset)=\"reset()\"\n (valueChange)=\"setZoom($event)\"\n />\n </footer>\n</ng-container>\n", styles: [":host{position:relative;display:flex;justify-content:center;align-items:center;inline-size:100%;block-size:100%;-webkit-user-select:none;user-select:none}.t-header{position:fixed;top:1rem;display:flex;inline-size:100%;padding:0 1rem;box-sizing:border-box}.t-footer{position:absolute;bottom:1rem;display:flex;inline-size:100%;padding:0 1rem;box-sizing:border-box;justify-content:center}.t-actions{display:flex;flex:1;justify-content:flex-end}.t-actions ::ng-deep>*{margin-left:.625rem}.t-rotate-button{margin-right:.3125rem}.t-title{flex:1}:host-context(tui-root._mobile) .t-title{display:none}.t-not-interactive-content ::ng-deep>*{pointer-events:none}.t-wrapper{will-change:transform}.t-transitive{transition-duration:.3s}\n"], dependencies: [{ kind: "pipe", type: AsyncPipe, name: "async" }, { kind: "directive", type: NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: TuiButton, selector: "a[tuiButton],button[tuiButton],a[tuiIconButton],button[tuiIconButton]", inputs: ["size"] }, { kind: "directive", type: i1.TuiHintDirective, selector: "[tuiHint]:not(ng-container):not(ng-template)", inputs: ["tuiHintContext", "tuiHintAppearance", "tuiHint"] }, { kind: "directive", type: i1.TuiHintDescribe, selector: "[tuiHintDescribe]", inputs: ["tuiHintDescribe"] }, { kind: "directive", type: TuiPan, selector: "[tuiPan]", outputs: ["tuiPan"] }, { kind: "directive", type: TuiPreviewAction, selector: "[tuiPreviewAction]" }, { kind: "component", type: TuiPreviewZoom, selector: "tui-preview-zoom", inputs: ["min", "max", "value"], outputs: ["valueChange", "reset"] }, { kind: "directive", type: TuiZoom, selector: "[tuiZoom]", outputs: ["tuiZoom"] }, { kind: "directive", type: WaMutationObserver, selector: "[waMutationObserver]", inputs: ["attributeFilter", "attributeOldValue", "attributes", "characterData", "characterDataOldValue", "childList", "subtree"], outputs: ["waMutationObserver"], exportAs: ["MutationObserver"] }, { kind: "directive", type: WaResizeObserver, selector: "[waResizeObserver]", inputs: ["box"], outputs: ["waResizeObserver"] }], animations: [tuiSlideInTop], changeDetection: i0.ChangeDetectionStrategy.OnPush }); } } export { TuiPreviewComponent }; i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: TuiPreviewComponent, decorators: [{ type: Component, args: [{ standalone: true, selector: 'tui-preview', imports: [ AsyncPipe, NgIf, TuiButton, TuiHint, TuiPan, TuiPreviewAction, TuiPreviewZoom, TuiZoom, WaMutationObserver, WaResizeObserver, ], changeDetection: ChangeDetectionStrategy.OnPush, animations: [tuiSlideInTop], template: "<ng-container *ngIf=\"texts$ | async as texts\">\n <section\n #contentWrapper\n attributeFilter=\"src\"\n characterData\n childList\n subtree\n class=\"t-wrapper\"\n [class.t-not-interactive-content]=\"zoomable\"\n [class.t-transitive]=\"transitioned$ | async\"\n [style.cursor]=\"cursor$ | async\"\n [style.transform]=\"wrapperTransform$ | async\"\n (tuiPan)=\"onPan($event)\"\n (tuiZoom)=\"onZoom($event)\"\n (waMutationObserver)=\"onMutation(contentWrapper)\"\n (waResizeObserver)=\"onResize($event)\"\n >\n <ng-content />\n </section>\n\n <header class=\"t-header\">\n <div class=\"t-title\">\n <ng-content select=\"tui-preview-title\" />\n </div>\n\n <ng-content select=\"tui-preview-pagination\" />\n\n <div class=\"t-actions\">\n <ng-content select=\"[tuiPreviewAction]\" />\n </div>\n </header>\n\n <footer class=\"t-footer\">\n <button\n *ngIf=\"rotatable\"\n tuiHintAppearance=\"dark\"\n tuiHintDescribe\n tuiHintDirection=\"top-right\"\n tuiIconButton\n tuiPreviewAction\n type=\"button\"\n class=\"t-rotate-button\"\n [iconStart]=\"icons.rotate\"\n [tuiHint]=\"texts.rotate\"\n (click)=\"rotate()\"\n ></button>\n\n <tui-preview-zoom\n *ngIf=\"zoomable\"\n [min]=\"minZoom\"\n [value]=\"(zoom$ | async) || 1\"\n (reset)=\"reset()\"\n (valueChange)=\"setZoom($event)\"\n />\n </footer>\n</ng-container>\n", styles: [":host{position:relative;display:flex;justify-content:center;align-items:center;inline-size:100%;block-size:100%;-webkit-user-select:none;user-select:none}.t-header{position:fixed;top:1rem;display:flex;inline-size:100%;padding:0 1rem;box-sizing:border-box}.t-footer{position:absolute;bottom:1rem;display:flex;inline-size:100%;padding:0 1rem;box-sizing:border-box;justify-content:center}.t-actions{display:flex;flex:1;justify-content:flex-end}.t-actions ::ng-deep>*{margin-left:.625rem}.t-rotate-button{margin-right:.3125rem}.t-title{flex:1}:host-context(tui-root._mobile) .t-title{display:none}.t-not-interactive-content ::ng-deep>*{pointer-events:none}.t-wrapper{will-change:transform}.t-transitive{transition-duration:.3s}\n"] }] }], propDecorators: { zoomable: [{ type: Input }], rotatable: [{ type: Input }] } }); //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicHJldmlldy5jb21wb25lbnQuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi9wcm9qZWN0cy9raXQvY29tcG9uZW50cy9wcmV2aWV3L3ByZXZpZXcuY29tcG9uZW50LnRzIiwiLi4vLi4vLi4vLi4vLi4vcHJvamVjdHMva2l0L2NvbXBvbmVudHMvcHJldmlldy9wcmV2aWV3LnRlbXBsYXRlLmh0bWwiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUFDLFNBQVMsRUFBRSxJQUFJLEVBQUMsTUFBTSxpQkFBaUIsQ0FBQztBQUNoRCxPQUFPLEVBQ0gsdUJBQXVCLEVBQ3ZCLGlCQUFpQixFQUNqQixTQUFTLEVBQ1QsTUFBTSxFQUNOLEtBQUssR0FDUixNQUFNLGVBQWUsQ0FBQztBQUN2QixPQUFPLEVBQUMsa0JBQWtCLEVBQUMsTUFBTSxnQ0FBZ0MsQ0FBQztBQUNsRSxPQUFPLEVBQUMsZ0JBQWdCLEVBQUMsTUFBTSw4QkFBOEIsQ0FBQztBQUM5RCxPQUFPLEVBQUMsaUJBQWlCLEVBQUMsTUFBTSx5QkFBeUIsQ0FBQztBQUMxRCxPQUFPLEVBQUMsTUFBTSxFQUFDLE1BQU0sOEJBQThCLENBQUM7QUFFcEQsT0FBTyxFQUFDLE9BQU8sRUFBQyxNQUFNLCtCQUErQixDQUFDO0FBQ3RELE9BQU8sRUFBQyxrQkFBa0IsRUFBRSxpQkFBaUIsRUFBQyxNQUFNLDJCQUEyQixDQUFDO0FBQ2hGLE9BQU8sRUFBQyxnQkFBZ0IsRUFBQyxNQUFNLHlCQUF5QixDQUFDO0FBQ3pELE9BQU8sRUFBQyxRQUFRLEVBQUUsUUFBUSxFQUFDLE1BQU0sMEJBQTBCLENBQUM7QUFDNUQsT0FBTyxFQUFDLEtBQUssRUFBQyxNQUFNLG1DQUFtQyxDQUFDO0FBQ3hELE9BQU8sRUFBQyxhQUFhLEVBQUMsTUFBTSwyQkFBMkIsQ0FBQztBQUN4RCxPQUFPLEVBQUMsU0FBUyxFQUFDLE1BQU0sa0NBQWtDLENBQUM7QUFDM0QsT0FBTyxFQUFDLE9BQU8s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QUFDO0lBQ04sQ0FBQzsrR0F6S1EsbUJBQW1CO21HQUFuQixtQkFBbUIsaUlDbkRoQyx3cURBd0RBLDB3QkRyQlEsU0FBUyw4Q0FDVCxJQUFJLDZGQUNKLFNBQVMseVpBRVQsTUFBTSwwRUFDTixnQkFBZ0IsK0RBQ2hCLGNBQWMsaUlBQ2QsT0FBTyw0RUFDUCxrQkFBa0Isb1FBQ2xCLGdCQUFnQixpR0FLUixDQUFDLGFBQWEsQ0FBQzs7U0FFbEIsbUJBQW1COzRGQUFuQixtQkFBbUI7a0JBcEIvQixTQUFTO2lDQUNNLElBQUksWUFDTixhQUFhLFdBQ2Q7d0JBQ0wsU0FBUzt3QkFDVCxJQUFJO3dCQUNKLFNBQVM7d0JBQ1QsT0FBTzt3QkFDUCxNQUFNO3dCQUNOLGdCQUFnQjt3QkFDaEIsY0FBYzt3QkFDZCxPQUFPO3dCQUNQLGtCQUFrQjt3QkFDbEIsZ0JBQWdCO3FCQUNuQixtQkFHZ0IsdUJBQXVCLENBQUMsTUFBTSxjQUNuQyxDQUFDLGFBQWEsQ0FBQzs4QkEwQ3BCLFFBQVE7c0JBRGQsS0FBSztnQkFJQyxTQUFTO3NCQURmLEtBQUsiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQge0FzeW5jUGlwZSwgTmdJZn0gZnJvbSAnQGFuZ3VsYXIvY29tbW9uJztcbmltcG9ydCB7XG4gICAgQ2hhbmdlRGV0ZWN0aW9uU3RyYXRlZ3ksXG4gICAgQ2hhbmdlRGV0ZWN0b3JSZWYsXG4gICAgQ29tcG9uZW50LFxuICAgIGluamVjdCxcbiAgICBJbnB1dCxcbn0gZnJvbSAnQGFuZ3VsYXIvY29yZSc7XG5pbXBvcnQge1dhTXV0YXRpb25PYnNlcnZlcn0gZnJvbSAnQG5nLXdlYi1hcGlzL211dGF0aW9uLW9ic2VydmVyJztcbmltcG9ydCB7V2FSZXNpemVPYnNlcnZlcn0gZnJvbSAnQG5nLXdlYi1hcGlzL3Jlc2l6ZS1vYnNlcnZlcic7XG5pbXBvcnQge1RVSV9GQUxTRV9IQU5ETEVSfSBmcm9tICdAdGFpZ2EtdWkvY2RrL2NvbnN0YW50cyc7XG5pbXBvcnQge1R1aVBhbn0gZnJvbSAnQHRhaWdhLXVpL2Nkay9kaXJlY3RpdmVzL3Bhbic7XG5pbXBvcnQgdHlwZSB7VHVpWm9vbUV2ZW50fSBmcm9tICdAdGFpZ2EtdWkvY2RrL2RpcmVjdGl2ZXMvem9vbSc7XG5pbXBvcnQge1R1aVpvb219IGZyb20gJ0B0YWlnYS11aS9jZGsvZGlyZWN0aXZlcy96b29tJztcbmltcG9ydCB7dHVpRHJhZ0FuZERyb3BGcm9tLCB0dWlUeXBlZEZyb21FdmVudH0gZnJvbSAnQHRhaWdhLXVpL2Nkay9vYnNlcnZhYmxlcyc7XG5pbXBvcnQge3R1aUluamVjdEVsZW1lbnR9IGZyb20gJ0B0YWlnYS11aS9jZGsvdXRpbHMvZG9tJztcbmltcG9ydCB7dHVpQ2xhbXAsIHR1aVJvdW5kfSBmcm9tICdAdGFpZ2EtdWkvY2RrL3V0aWxzL21hdGgnO1xuaW1wb3J0IHt0dWlQeH0gZnJvbSAnQHRhaWdhLXVpL2Nkay91dGlscy9taXNjZWxsYW5lb3VzJztcbmltcG9ydCB7dHVpU2xpZGVJblRvcH0gZnJvbSAnQHRhaWdhLXVpL2NvcmUvYW5pbWF0aW9ucyc7XG5pbXBvcnQge1R1aUJ1dHRvbn0gZnJvbSAnQHRhaWdhLXVpL2NvcmUvY29tcG9uZW50cy9idXR0b24nO1xuaW1wb3J0IHtUdWlIaW50fSBmcm9tICdAdGFpZ2EtdWkvY29yZS9kaXJlY3RpdmVzL2hpbnQnO1xuaW1wb3J0IHtUVUlfUFJFVklFV19JQ09OUywgVFVJX1BSRVZJRVdfVEVYVFN9IGZyb20gJ0B0YWlnYS11aS9raXQvdG9rZW5zJztcbmltcG9ydCB7QmVoYXZpb3JTdWJqZWN0LCBjb21iaW5lTGF0ZXN0LCBtYXAsIG1lcmdlLCBzdGFydFdpdGh9IGZyb20gJ3J4anMnO1xuXG5pbXBvcnQge1R1aVByZXZpZXdBY3Rpb259IGZyb20gJy4vcHJldmlldy1hY3Rpb24vcHJldmlldy1hY3Rpb24uZGlyZWN0aXZlJztcbmltcG9ydCB7VHVpUHJldmlld1pvb219IGZyb20gJy4vem9vbS9wcmV2aWV3LXpvb20uY29tcG9uZW50JztcblxuY29uc3QgSU5JVElBTF9TQ0FMRV9DT0VGID0gMC44O1xuY29uc3QgRU1QVFlfQ09PUkRJTkFURVM6IFtudW1iZXIsIG51bWJlcl0gPSBbMCwgMF07XG5jb25zdCBST1RBVElPTl9BTkdMRSA9IDkwO1xuXG5AQ29tcG9uZW50KHtcbiAgICBzdGFuZGFsb25lOiB0cnVlLFxuICAgIHNlbGVjdG9yOiAndHVpLXByZXZpZXcnLFxuICAgIGltcG9ydHM6IFtcbiAgICAgICAgQXN5bmNQaXBlLFxuICAgICAgICBOZ0lmLFxuICAgICAgICBUdWlCdXR0b24sXG4gICAgICAgIFR1aUhpbnQsXG4gICAgICAgIFR1aVBhbixcbiAgICAgICAgVHVpUHJldmlld0FjdGlvbixcbiAgICAgICAgVHVpUHJldmlld1pvb20sXG4gICAgICAgIFR1aVpvb20sXG4gICAgICAgIFdhTXV0YXRpb25PYnNlcnZlcixcbiAgICAgICAgV2FSZXNpemVPYnNlcnZlcixcbiAgICBdLFxuICAgIHRlbXBsYXRlVXJsOiAnLi9wcmV2aWV3LnRlbXBsYXRlLmh0bWwnLFxuICAgIHN0eWxlVXJsczogWycuL3ByZXZpZXcuc3R5bGUubGVzcyddLFxuICAgIGNoYW5nZURldGVjdGlvbjogQ2hhbmdlRGV0ZWN0aW9uU3RyYXRlZ3kuT25QdXNoLFxuICAgIGFuaW1hdGlvbnM6IFt0dWlTbGlkZUluVG9wXSxcbn0pXG5leHBvcnQgY2xhc3MgVHVpUHJldmlld0NvbXBvbmVudCB7XG4gICAgcHJpdmF0ZSByZWFkb25seSBlbCA9IHR1aUluamVjdEVsZW1lbnQoKTtcblxuICAgIHByb3RlY3RlZCBtaW5ab29tID0gMTtcbiAgICBwcm90ZWN0ZWQgd2lkdGggPSAwO1xuICAgIHByb3RlY3RlZCBoZWlnaHQgPSAwO1xuICAgIHByb3RlY3RlZCByZWFkb25seSB0ZXh0cyQgPSBpbmplY3QoVFVJX1BSRVZJRVdfVEVYVFMpO1xuICAgIHByb3RlY3RlZCByZWFkb25seSBpY29ucyA9IGluamVjdChUVUlfUFJFVklFV19JQ09OUyk7XG4gICAgcHJvdGVjdGVkIHJlYWRvbmx5IGNkciA9IGluamVjdChDaGFuZ2VEZXRlY3RvclJlZik7XG4gICAgcHJvdGVjdGVkIHJlYWRvbmx5IHpvb20kID0gbmV3IEJlaGF2aW9yU3ViamVjdDxudW1iZXI+KHRoaXMubWluWm9vbSk7XG4gICAgcHJvdGVjdGVkIHJlYWRvbmx5IHJvdGF0aW9uJCA9IG5ldyBCZWhhdmlvclN1YmplY3Q8bnVtYmVyPigwKTtcbiAgICBwcm90ZWN0ZWQgcmVhZG9ubHkgY29vcmRpbmF0ZXMkID0gbmV3IEJlaGF2aW9yU3ViamVjdDxyZWFkb25seSBbbnVtYmVyLCBudW1iZXJdPihcbiAgICAgICAgRU1QVFlfQ09PUkRJTkFURVMsXG4gICAgKTtcblxuICAgIHByb3RlY3RlZCByZWFkb25seSB0cmFuc2l0aW9uZWQkID0gbWVyZ2UoXG4gICAgICAgIHR1aURyYWdBbmREcm9wRnJvbSh0aGlzLmVsKS5waXBlKG1hcCgoe3N0YWdlfSkgPT4gc3RhZ2UgIT09ICdjb250aW51ZXMnKSksXG4gICAgICAgIHR1aVR5cGVkRnJvbUV2ZW50KHRoaXMuZWwsICd0b3VjaG1vdmUnLCB7XG4gICAgICAgICAgICBwYXNzaXZlOiB0cnVlLFxuICAgICAgICB9KS5waXBlKG1hcChUVUlfRkFMU0VfSEFORExFUikpLFxuICAgICAgICB0dWlUeXBlZEZyb21FdmVudCh0aGlzLmVsLCAnd2hlZWwnLCB7cGFzc2l2ZTogdHJ1ZX0pLnBpcGUobWFwKFRVSV9GQUxTRV9IQU5ETEVSKSksXG4gICAgKTtcblxuICAgIHByb3RlY3RlZCByZWFkb25seSBjdXJzb3IkID0gdHVpRHJhZ0FuZERyb3BGcm9tKHRoaXMuZWwpLnBpcGUoXG4gICAgICAgIG1hcCgoe3N0YWdlfSkgPT4gKHN0YWdlID09PSAnY29udGludWVzJyA/ICdncmFiYmluZycgOiAnaW5pdGlhbCcpKSxcbiAgICAgICAgc3RhcnRXaXRoKCdpbml0aWFsJyksXG4gICAgKTtcblxuICAgIHByb3RlY3RlZCByZWFkb25seSB3cmFwcGVyVHJhbnNmb3JtJCA9IGNvbWJpbmVMYXRlc3QoW1xuICAgICAgICB0aGlzLmNvb3JkaW5hdGVzJC5waXBlKG1hcCgoW3gsIHldKSA9PiBgJHt0dWlQeCh4KX0sICR7dHVpUHgoeSl9YCkpLFxuICAgICAgICB0aGlzLnpvb20kLFxuICAgICAgICB0aGlzLnJvdGF0aW9uJCxcbiAgICBdKS5waXBlKFxuICAgICAgICBtYXAoXG4gICAgICAgICAgICAoW3RyYW5zbGF0ZSwgem9vbSwgcm90YXRpb25dKSA9PlxuICAgICAgICAgICAgICAgIGB0cmFuc2xhdGUoJHt0cmFuc2xhdGV9KSBzY2FsZSgke3pvb219KSByb3RhdGUoJHtyb3RhdGlvbn1kZWcpYCxcbiAgICAgICAgKSxcbiAgICApO1xuXG4gICAgQElucHV0KClcbiAgICBwdWJsaWMgem9vbWFibGUgPSB0cnVlO1xuXG4gICAgQElucHV0KClcbiAgICBwdWJsaWMgcm90YXRhYmxlID0gZmFsc2U7XG5cbiAgICBwcm90ZWN0ZWQgcm90YXRlKCk6IHZvaWQge1xuICAgICAgICB0aGlzLnJvdGF0aW9uJC5uZXh0KHRoaXMucm90YXRpb24kLnZhbHVlIC0gUk9UQVRJT05fQU5HTEUpO1xuICAgIH1cblxuICAgIHByb3RlY3RlZCBvblBhbihkZWx0YTogcmVhZG9ubHkgW251bWJlciwgbnVtYmVyXSk6IHZvaWQge1xuICAgICAgICB0aGlzLmNvb3JkaW5hdGVzJC5uZXh0KFxuICAgICAgICAgICAgdGhpcy5nZXRHdWFyZGVkQ29vcmRpbmF0ZXMoXG4gICAgICAgICAgICAgICAgdGhpcy5jb29yZGluYXRlcyQudmFsdWVbMF0gKyBkZWx0YVswXSxcbiAgICAgICAgICAgICAgICB0aGlzLmNvb3JkaW5hdGVzJC52YWx1ZVsxXSArIGRlbHRhWzFdLFxuICAgICAgICAgICAgKSxcbiAgICAgICAgKTtcbiAgICB9XG5cbiAgICBwcm90ZWN0ZWQgb25NdXRhdGlvbihjb250ZW50V3JhcHBlcjogSFRNTEVsZW1lbnQpOiB2b2lkIHtcbiAgICAgICAgY29uc3Qge2NsaWVudFdpZHRoLCBjbGllbnRIZWlnaHR9ID0gY29udGVudFdyYXBwZXI7XG5cbiAgICAgICAgdGhpcy5yZWZyZXNoKGNsaWVudFdpZHRoLCBjbGllbnRIZWlnaHQpO1xuICAgIH1cblxuICAgIHByb3RlY3RlZCBvblpvb20oe2NsaWVudFgsIGNsaWVudFksIGRlbHRhfTogVHVpWm9vbUV2ZW50KTogdm9pZCB7XG4gICAgICAgIGlmICh0aGlzLnpvb21hYmxlKSB7XG4gICAgICAgICAgICB0aGlzLnByb2Nlc3Nab29tKGNsaWVudFgsIGNsaWVudFksIGRlbHRhKTtcbiAgICAgICAgfVxuICAgIH1cblxuICAgIHByb3RlY3RlZCBvblJlc2l6ZShbZW50cnldOiByZWFkb25seSBSZXNpemVPYnNlcnZlckVudHJ5W10pOiB2b2lkIHtcbiAgICAgICAgaWYgKGVudHJ5Py5jb250ZW50UmVjdCkge1xuICAgICAgICAgICAgdGhpcy5yZWZyZXNoKGVudHJ5LmNvbnRlbnRSZWN0LndpZHRoLCBlbnRyeS5jb250ZW50UmVjdC5oZWlnaHQpO1xuICAgICAgICAgICAgdGhpcy5jZHIuZGV0ZWN0Q2hhbmdlcygpO1xuICAgICAgICB9XG4gICAgfVxuXG4gICAgcHJvdGVjdGVkIHJlc2V0KCk6IHZvaWQge1xuICAgICAgICB0aGlzLnpvb20kLm5leHQodGhpcy5taW5ab29tKTtcbiAgICAgICAgdGhpcy5jb29yZGluYXRlcyQubmV4dChFTVBUWV9DT09SRElOQVRFUyk7XG4gICAgfVxuXG4gICAgcHJvdGVjdGVkIHNldFpvb20oem9vbTogbnVtYmVyKTogdm9pZCB7XG4gICAgICAgIHRoaXMuem9vbSQubmV4dCh6b29tKTtcbiAgICAgICAgY29uc3QgW3gsIHldID0gdGhpcy5jb29yZGluYXRlcyQudmFsdWU7XG5cbiAgICAgICAgdGhpcy5jb29yZGluYXRlcyQubmV4dCh0aGlzLmdldEd1YXJkZWRDb29yZGluYXRlcyh4LCB5KSk7XG4gICAgfVxuXG4gICAgcHJpdmF0ZSBnZXQgb2Zmc2V0cygpOiB7b2Zmc2V0WDogbnVtYmVyOyBvZmZzZXRZOiBudW1iZXJ9IHtcbiAgICAgICAgY29uc3Qgb2Zmc2V0WCA9ICgodGhpcy56b29tJC52YWx1ZSAtIHRoaXMubWluWm9vbSkgKiB0aGlzLndpZHRoKSAvIDI7XG4gICAgICAgIGNvbnN0IG9mZnNldFkgPSAoKHRoaXMuem9vbSQudmFsdWUgLSB0aGlzLm1pblpvb20pICogdGhpcy5oZWlnaHQpIC8gMjtcblxuICAgICAgICByZXR1cm4ge29mZnNldFgsIG9mZnNldFl9O1xuICAgIH1cblxuICAgIHByaXZhdGUgY2FsY3VsYXRlTWluWm9vbShcbiAgICAgICAgY29udGVudEhlaWdodDogbnVtYmVyLFxuICAgICAgICBjb250ZW50V2lkdGg6IG51bWJlcixcbiAgICAgICAgYm94SGVpZ2h0OiBudW1iZXIsXG4gICAgICAgIGJveFdpZHRoOiBudW1iZXIsXG4gICAgKTogbnVtYmVyIHtcbiAgICAgICAgY29uc3QgYmlnU2l6ZSA9XG4gICAgICAgICAgICBjb250ZW50SGVpZ2h0ID4gYm94SGVpZ2h0ICogSU5JVElBTF9TQ0FMRV9DT0VGIHx8XG4gICAgICAgICAgICBjb250ZW50V2lkdGggPiBib3hXaWR0aCAqIElOSVRJQUxfU0NBTEVfQ09FRjtcbiAgICAgICAgY29uc3Qge2NsaWVudEhlaWdodCwgY2xpZW50V2lkdGh9ID0gdGhpcy5lbDtcblxuICAgICAgICByZXR1cm4gYmlnU2l6ZVxuICAgICAgICAgICAgPyB0dWlSb3VuZChcbiAgICAgICAgICAgICAgICAgIE1hdGgubWluKFxuICAgICAgICAgICAgICAgICAgICAgIChjbGllbnRIZWlnaHQgKiBJTklUSUFMX1NDQUxFX0NPRUYpIC8gY29udGVudEhlaWdodCxcbiAgICAgICAgICAgICAgICAgICAgICAoY2xpZW50V2lkdGggKiBJTklUSUFMX1NDQUxFX0NPRUYpIC8gY29udGVudFdpZHRoLFxuICAgICAgICAgICAgICAgICAgKSxcbiAgICAgICAgICAgICAgICAgIDIsXG4gICAgICAgICAgICAgIClcbiAgICAgICAgICAgIDogMTtcbiAgICB9XG5cbiAgICBwcml2YXRlIHJlZnJlc2god2lkdGg6IG51bWJlciwgaGVpZ2h0OiBudW1iZXIpOiB2b2lkIHtcbiAgICAgICAgdGhpcy53aWR0aCA9IHdpZHRoO1xuICAgICAgICB0aGlzLmhlaWdodCA9IGhlaWdodDtcbiAgICAgICAgdGhpcy5taW5ab29tID0gdGhpcy5jYWxjdWxhdGVNaW5ab29tKFxuICAgICAgICAgICAgaGVpZ2h0LFxuICAgICAgICAgICAgd2lkdGgsXG4gICAgICAgICAgICB0aGlzLmVsLmNsaWVudEhlaWdodCxcbiAgICAgICAgICAgIHRoaXMuZWwuY2xpZW50V2lkdGgsXG4gICAgICAgICk7XG4gICAgICAgIHRoaXMuem9vbSQubmV4dCh0aGlzLm1pblpvb20pO1xuICAgICAgICB0aGlzLmNvb3JkaW5hdGVzJC5uZXh0KEVNUFRZX0NPT1JESU5BVEVTKTtcbiAgICAgICAgdGhpcy5yb3RhdGlvbiQubmV4dCgwKTtcbiAgICB9XG5cbiAgICBwcml2YXRlIHByb2Nlc3Nab29tKGNsaWVudFg6IG51bWJlciwgY2xpZW50WTogbnVtYmVyLCBkZWx0YTogbnVtYmVyKTogdm9pZCB7XG4gICAgICAgIGNvbnN0IG9sZFNjYWxlID0gdGhpcy56b29tJC52YWx1ZTtcbiAgICAgICAgY29uc3QgbmV3U2NhbGUgPSB0dWlDbGFtcChvbGRTY2FsZSArIGRlbHRhLCB0aGlzLm1pblpvb20sIDIpO1xuXG4gICAgICAgIGNvbnN0IGNlbnRlciA9IHRoaXMuZ2V0U2NhbGVDZW50ZXIoXG4gICAgICAgICAgICB7Y2xpZW50WCwgY2xpZW50WX0sXG4gICAgICAgICAgICB0aGlzLmNvb3JkaW5hdGVzJC52YWx1ZSxcbiAgICAgICAgICAgIHRoaXMuem9vbSQudmFsdWUsXG4gICAgICAgICk7XG5cbiAgICAgICAgY29uc3QgbW92ZVggPSBjZW50ZXJbMF0gKiBvbGRTY2FsZSAtIGNlbnRlclswXSAqIG5ld1NjYWxlO1xuICAgICAgICBjb25zdCBtb3ZlWSA9IGNlbnRlclsxXSAqIG9sZFNjYWxlIC0gY2VudGVyWzFdICogbmV3U2NhbGU7XG5cbiAgICAgICAgdGhpcy56b29tJC5uZXh0KG5ld1NjYWxlKTtcbiAgICAgICAgdGhpcy5jb29yZGluYXRlcyQubmV4dChcbiAgICAgICAgICAgIHRoaXMuZ2V0R3VhcmRlZENvb3JkaW5hdGVzKFxuICAgICAgICAgICAgICAgIHRoaXMuY29vcmRpbmF0ZXMkLnZhbHVlWzBdICsgbW92ZVgsXG4gICAgICAgICAgICAgICAgdGhpcy5jb29yZGluYXRlcyQudmFsdWVbMV0gKyBtb3ZlWSxcbiAgICAgICAgICAgICksXG4gICAgICAgICk7XG4gICAgfVxuXG4gICAgcHJpdmF0ZSBnZXRHdWFyZGVkQ29vcmRpbmF0ZXMoeDogbnVtYmVyLCB5OiBudW1iZXIpOiByZWFkb25seSBbbnVtYmVyLCBudW1iZXJdIHtcbiAgICAgICAgY29uc3Qge29mZnNldFgsIG9mZnNldFl9ID0gdGhpcy5vZmZzZXRzO1xuXG4gICAgICAgIHJldHVybiBbdHVpQ2xhbXAoeCwgLW9mZnNldFgsIG9mZnNldFgpLCB0dWlDbGFtcCh5LCAtb2Zmc2V0WSwgb2Zmc2V0WSldO1xuICAgIH1cblxuICAgIHByaXZhdGUgZ2V0U2NhbGVDZW50ZXIoXG4gICAgICAgIHtjbGllbnRYLCBjbGllbnRZfToge2NsaWVudFg6IG51bWJlcjsgY2xpZW50WTogbnVtYmVyfSxcbiAgICAgICAgW3gsIHldOiByZWFkb25seSBbbnVtYmVyLCBudW1iZXJdLFxuICAgICAgICBzY2FsZTogbnVtYmVyLFxuICAgICk6IFtudW1iZXIsIG51bWJlcl0ge1xuICAgICAgICByZXR1cm4gW1xuICAgICAgICAgICAgKGNsaWVudFggLSB4IC0gdGhpcy5lbC5vZmZzZXRXaWR0aCAvIDIpIC8gc2NhbGUsXG4gICAgICAgICAgICAoY2xpZW50WSAtIHkgLSB0aGlzLmVsLm9mZnNldEhlaWdodCAvIDIpIC8gc2NhbGUsXG4gICAgICAgIF07XG4gICAgfVxufVxuIiwiPG5nLWNvbnRhaW5lciAqbmdJZj1cInRleHRzJCB8IGFzeW5jIGFzIHRleHRzXCI+XG4gICAgPHNlY3Rpb25cbiAgICAgICAgI2NvbnRlbnRXcmFwcGVyXG4gICAgICAgIGF0dHJpYnV0ZUZpbHRlcj1cInNyY1wiXG4gICAgICAgIGNoYXJhY3RlckRhdGFcbiAgICAgICAgY2hpbGRMaXN0XG4gICAgICAgIHN1YnRyZWVcbiAgICAgICAgY2xhc3M9XCJ0LXdyYXBwZXJcIlxuICAgICAgICBbY2xhc3MudC1ub3QtaW50ZXJhY3RpdmUtY29udGVudF09XCJ6b29tYWJsZVwiXG4gICAgICAgIFtjbGFzcy50LXRyYW5zaXRpdmVdPVwidHJhbnNpdGlvbmVkJCB8IGFzeW5jXCJcbiAgICAgICAgW3N0eWxlLmN1cnNvcl09XCJjdXJzb3IkIHwgYXN5bmNcIlxuICAgICAgICBbc3R5bGUudHJhbnNmb3JtXT1cIndyYXBwZXJUcmFuc2Zvcm0kIHwgYXN5bmNcIlxuICAgICAgICAodHVpUGFuKT1cIm9uUGFuKCRldmVudClcIlxuICAgICAgICAodHVpWm9vbSk9XCJvblpvb20oJGV2ZW50KVwiXG4gICAgICAgICh3YU11dGF0aW9uT2JzZXJ2ZXIpPVwib25NdXRhdGlvbihjb250ZW50V3JhcHBlcilcIlxuICAgICAgICAod2FSZXNpemVPYnNlcnZlcik9XCJvblJlc2l6ZSgkZXZlbnQpXCJcbiAgICA+XG4gICAgICAgIDxuZy1jb250ZW50IC8+XG4gICAgPC9zZWN0aW9uPlxuXG4gICAgPGhlYWRlciBjbGFzcz1cInQtaGVhZGVyXCI+XG4gICAgICAgIDxkaXYgY2xhc3M9XCJ0LXRpdGxlXCI+XG4gICAgICAgICAgICA8bmctY29udGVudCBzZWxlY3Q9XCJ0dWktcHJldmlldy10aXRsZVwiIC8+XG4gICAgICAgIDwvZGl2PlxuXG4gICAgICAgIDxuZy1jb250ZW50IHNlbGVjdD1cInR1aS1wcmV2aWV3LXBhZ2luYXRpb25cIiAvPlxuXG4gICAgICAgIDxkaXYgY2xhc3M9XCJ0LWFjdGlvbnNcIj5cbiAgICAgICAgICAgIDxuZy1jb250ZW50IHNlbGVjdD1cIlt0dWlQcmV2aWV3QWN0aW9uXVwiIC8+XG4gICAgICAgIDwvZGl2PlxuICAgIDwvaGVhZGVyPlxuXG4gICAgPGZvb3RlciBjbGFzcz1cInQtZm9vdGVyXCI+XG4gICAgICAgIDxidXR0b25cbiAgICAgICAgICAgICpuZ0lmPVwicm90YXRhYmxlXCJcbiAgICAgICAgICAgIHR1aUhpbnRBcHBlYXJhbmNlPVwiZGFya1wiXG4gICAgICAgICAgICB0dWlIaW50RGVzY3JpYmVcbiAgICAgICAgICAgIHR1aUhpbnREaXJlY3Rpb249XCJ0b3AtcmlnaHRcIlxuICAgICAgICAgICAgdHVpSWNvbkJ1dHRvblxuICAgICAgICAgICAgdHVpUHJldmlld0FjdGlvblxuICAgICAgICAgICAgdHlwZT1cImJ1dHRvblwiXG4gICAgICAgICAgICBjbGFzcz1cInQtcm90YXRlLWJ1dHRvblwiXG4gICAgICAgICAgICBbaWNvblN0YXJ0XT1cImljb25zLnJvdGF0ZVwiXG4gICAgICAgICAgICBbdHVpSGludF09XCJ0ZXh0cy5yb3RhdGVcIlxuICAgICAgICAgICAgKGNsaWNrKT1cInJvdGF0ZSgpXCJcbiAgICAgICAgPjwvYnV0dG9uPlxuXG4gICAgICAgIDx0dWktcHJldmlldy16b29tXG4gICAgICAgICAgICAqbmdJZj1cInpvb21hYmxlXCJcbiAgICAgICAgICAgIFttaW5dPVwibWluWm9vbVwiXG4gICAgICAgICAgICBbdmFsdWVdPVwiKHpvb20kIHwgYXN5bmMpIHx8IDFcIlxuICAgICAgICAgICAgKHJlc2V0KT1cInJlc2V0KClcIlxuICAgICAgICAgICAgKHZhbHVlQ2hhbmdlKT1cInNldFpvb20oJGV2ZW50KVwiXG4gICAgICAgIC8+XG4gICAgPC9mb290ZXI+XG48L25nLWNvbnRhaW5lcj5cbiJdfQ==