UNPKG

@taiga-ui/kit

Version:

Taiga UI Angular main components kit

142 lines 34.7 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 { 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 './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 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; this.initialScale = 0.8; } 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 * this.initialScale || contentWidth > boxWidth * this.initialScale; const { clientHeight, clientWidth } = this.el; return bigSize ? tuiRound(Math.min((clientHeight * this.initialScale) / contentHeight, (clientWidth * this.initialScale) / 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", initialScale: "initialScale" }, 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:max(1rem,env(safe-area-inset-top));display:flex;inline-size:100%;padding:0 1rem;box-sizing:border-box}.t-footer{position:absolute;bottom:max(1rem,env(safe-area-inset-bottom));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-inline-start:.625rem}.t-rotate-button{margin-inline-end:.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"] }], 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, 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:max(1rem,env(safe-area-inset-top));display:flex;inline-size:100%;padding:0 1rem;box-sizing:border-box}.t-footer{position:absolute;bottom:max(1rem,env(safe-area-inset-bottom));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-inline-start:.625rem}.t-rotate-button{margin-inline-end:.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 }], initialScale: [{ type: Input }] } }); //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicHJldmlldy5jb21wb25lbnQuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi9wcm9qZWN0cy9raXQvY29tcG9uZW50cy9wcmV2aWV3L3ByZXZpZXcuY29tcG9uZW50LnRzIiwiLi4vLi4vLi4vLi4vLi4vcHJvamVjdHMva2l0L2NvbXBvbmVudHMvcHJldmlldy9wcmV2aWV3LnRlbXBsYXRlLmh0bWwiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUFDLFNBQVMsRUFBRSxJQUFJLEVBQUMsTUFBTSxpQkFBaUIsQ0FBQztBQUNoRCxPQUFPLEVBQ0gsdUJBQXVCLEVBQ3ZCLGlCQUFpQixFQUNqQixTQUFTLEVBQ1QsTUFBTSxFQUNOLEtBQUssR0FDUixNQUFNLGVBQWUsQ0FBQztBQUN2QixPQUFPLEVBQUMsa0JBQWtCLEVBQUMsTUFBTSxnQ0FBZ0MsQ0FBQztBQUNsRSxPQUFPLEVBQUMsZ0JBQWdCLEVBQUMsTUFBTSw4QkFBOEIsQ0FBQztBQUM5RCxPQUFPLEVBQUMsaUJBQWlCLEVBQUMsTUFBTSx5QkFBeUIsQ0FBQztBQUMxRCxPQUFPLEVBQUMsTUFBTSxFQUFDLE1BQU0sOEJBQThCLENBQUM7QUFFcEQsT0FBTyxFQUFDLE9BQU8sRUFBQyxNQUFNLCtCQUErQixDQUFDO0FBQ3RELE9BQU8sRUFBQyxrQkFBa0IsRUFBRSxpQkFBaUIsRUFBQyxNQUFNLDJCQUEyQixDQUFDO0FBQ2hGLE9BQU8sRUFBQyxnQkFBZ0IsRUFBQyxNQUFNLHlCQUF5QixDQUFDO0FBQ3pELE9BQU8sRUFBQyxRQUFRLEVBQUUsUUFBUSxFQUFDLE1BQU0sMEJBQTBCLENBQUM7QUFDNUQsT0FBTyxFQUFDLEtBQUssRUFBQyxNQUFNLG1DQUFtQyxDQUFDO0FBQ3hELE9BQU8sRUFBQyxTQUFTLEVBQUMsTUFBTSxrQ0FBa0MsQ0FBQztBQUMzRCxPQUFPLEVBQUMsT0FBTyxFQUFDLE1BQU0sZ0NBQWdDLENBQUM7QUFDdkQsT0FBTyxFQUFDLGlCQUFp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NUtRLG1CQUFtQjttR0FBbkIsbUJBQW1CLCtKQ2hEaEMsd3FEQXdEQSxzMUJEdkJRLFNBQVMsOENBQ1QsSUFBSSw2RkFDSixTQUFTLHlaQUVULE1BQU0sMEVBQ04sZ0JBQWdCLCtEQUNoQixjQUFjLGlJQUNkLE9BQU8sNEVBQ1Asa0JBQWtCLG9RQUNsQixnQkFBZ0I7O1NBTVgsbUJBQW1COzRGQUFuQixtQkFBbUI7a0JBbkIvQixTQUFTO2lDQUNNLElBQUksWUFDTixhQUFhLFdBQ2Q7d0JBQ0wsU0FBUzt3QkFDVCxJQUFJO3dCQUNKLFNBQVM7d0JBQ1QsT0FBTzt3QkFDUCxNQUFNO3dCQUNOLGdCQUFnQjt3QkFDaEIsY0FBYzt3QkFDZCxPQUFPO3dCQUNQLGtCQUFrQjt3QkFDbEIsZ0JBQWdCO3FCQUNuQixtQkFHZ0IsdUJBQXVCLENBQUMsTUFBTTs4QkEwQ3hDLFFBQVE7c0JBRGQsS0FBSztnQkFJQyxTQUFTO3NCQURmLEtBQUs7Z0JBSUMsWUFBWTtzQkFEbEIsS0FBSyIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7QXN5bmNQaXBlLCBOZ0lmfSBmcm9tICdAYW5ndWxhci9jb21tb24nO1xuaW1wb3J0IHtcbiAgICBDaGFuZ2VEZXRlY3Rpb25TdHJhdGVneSxcbiAgICBDaGFuZ2VEZXRlY3RvclJlZixcbiAgICBDb21wb25lbnQsXG4gICAgaW5qZWN0LFxuICAgIElucHV0LFxufSBmcm9tICdAYW5ndWxhci9jb3JlJztcbmltcG9ydCB7V2FNdXRhdGlvbk9ic2VydmVyfSBmcm9tICdAbmctd2ViLWFwaXMvbXV0YXRpb24tb2JzZXJ2ZXInO1xuaW1wb3J0IHtXYVJlc2l6ZU9ic2VydmVyfSBmcm9tICdAbmctd2ViLWFwaXMvcmVzaXplLW9ic2VydmVyJztcbmltcG9ydCB7VFVJX0ZBTFNFX0hBTkRMRVJ9IGZyb20gJ0B0YWlnYS11aS9jZGsvY29uc3RhbnRzJztcbmltcG9ydCB7VHVpUGFufSBmcm9tICdAdGFpZ2EtdWkvY2RrL2RpcmVjdGl2ZXMvcGFuJztcbmltcG9ydCB0eXBlIHtUdWlab29tRXZlbnR9IGZyb20gJ0B0YWlnYS11aS9jZGsvZGlyZWN0aXZlcy96b29tJztcbmltcG9ydCB7VHVpWm9vbX0gZnJvbSAnQHRhaWdhLXVpL2Nkay9kaXJlY3RpdmVzL3pvb20nO1xuaW1wb3J0IHt0dWlEcmFnQW5kRHJvcEZyb20sIHR1aVR5cGVkRnJvbUV2ZW50fSBmcm9tICdAdGFpZ2EtdWkvY2RrL29ic2VydmFibGVzJztcbmltcG9ydCB7dHVpSW5qZWN0RWxlbWVudH0gZnJvbSAnQHRhaWdhLXVpL2Nkay91dGlscy9kb20nO1xuaW1wb3J0IHt0dWlDbGFtcCwgdHVpUm91bmR9IGZyb20gJ0B0YWlnYS11aS9jZGsvdXRpbHMvbWF0aCc7XG5pbXBvcnQge3R1aVB4fSBmcm9tICdAdGFpZ2EtdWkvY2RrL3V0aWxzL21pc2NlbGxhbmVvdXMnO1xuaW1wb3J0IHtUdWlCdXR0b259IGZyb20gJ0B0YWlnYS11aS9jb3JlL2NvbXBvbmVudHMvYnV0dG9uJztcbmltcG9ydCB7VHVpSGludH0gZnJvbSAnQHRhaWdhLXVpL2NvcmUvZGlyZWN0aXZlcy9oaW50JztcbmltcG9ydCB7VFVJX1BSRVZJRVdfSUNPTlMsIFRVSV9QUkVWSUVXX1RFWFRTfSBmcm9tICdAdGFpZ2EtdWkva2l0L3Rva2Vucyc7XG5pbXBvcnQge0JlaGF2aW9yU3ViamVjdCwgY29tYmluZUxhdGVzdCwgbWFwLCBtZXJnZSwgc3RhcnRXaXRofSBmcm9tICdyeGpzJztcblxuaW1wb3J0IHtUdWlQcmV2aWV3QWN0aW9ufSBmcm9tICcuL2FjdGlvbi9wcmV2aWV3LWFjdGlvbi5kaXJlY3RpdmUnO1xuaW1wb3J0IHtUdWlQcmV2aWV3Wm9vbX0gZnJvbSAnLi96b29tL3ByZXZpZXctem9vbS5jb21wb25lbnQnO1xuXG5jb25zdCBFTVBUWV9DT09SRElOQVRFUzogW251bWJlciwgbnVtYmVyXSA9IFswLCAwXTtcbmNvbnN0IFJPVEFUSU9OX0FOR0xFID0gOTA7XG5cbkBDb21wb25lbnQoe1xuICAgIHN0YW5kYWxvbmU6IHRydWUsXG4gICAgc2VsZWN0b3I6ICd0dWktcHJldmlldycsXG4gICAgaW1wb3J0czogW1xuICAgICAgICBBc3luY1BpcGUsXG4gICAgICAgIE5nSWYsXG4gICAgICAgIFR1aUJ1dHRvbixcbiAgICAgICAgVHVpSGludCxcbiAgICAgICAgVHVpUGFuLFxuICAgICAgICBUdWlQcmV2aWV3QWN0aW9uLFxuICAgICAgICBUdWlQcmV2aWV3Wm9vbSxcbiAgICAgICAgVHVpWm9vbSxcbiAgICAgICAgV2FNdXRhdGlvbk9ic2VydmVyLFxuICAgICAgICBXYVJlc2l6ZU9ic2VydmVyLFxuICAgIF0sXG4gICAgdGVtcGxhdGVVcmw6ICcuL3ByZXZpZXcudGVtcGxhdGUuaHRtbCcsXG4gICAgc3R5bGVVcmxzOiBbJy4vcHJldmlldy5zdHlsZS5sZXNzJ10sXG4gICAgY2hhbmdlRGV0ZWN0aW9uOiBDaGFuZ2VEZXRlY3Rpb25TdHJhdGVneS5PblB1c2gsXG59KVxuZXhwb3J0IGNsYXNzIFR1aVByZXZpZXdDb21wb25lbnQge1xuICAgIHByaXZhdGUgcmVhZG9ubHkgZWwgPSB0dWlJbmplY3RFbGVtZW50KCk7XG5cbiAgICBwcm90ZWN0ZWQgbWluWm9vbSA9IDE7XG4gICAgcHJvdGVjdGVkIHdpZHRoID0gMDtcbiAgICBwcm90ZWN0ZWQgaGVpZ2h0ID0gMDtcbiAgICBwcm90ZWN0ZWQgcmVhZG9ubHkgdGV4dHMkID0gaW5qZWN0KFRVSV9QUkVWSUVXX1RFWFRTKTtcbiAgICBwcm90ZWN0ZWQgcmVhZG9ubHkgaWNvbnMgPSBpbmplY3QoVFVJX1BSRVZJRVdfSUNPTlMpO1xuICAgIHByb3RlY3RlZCByZWFkb25seSBjZHIgPSBpbmplY3QoQ2hhbmdlRGV0ZWN0b3JSZWYpO1xuICAgIHByb3RlY3RlZCByZWFkb25seSB6b29tJCA9IG5ldyBCZWhhdmlvclN1YmplY3Q8bnVtYmVyPih0aGlzLm1pblpvb20pO1xuICAgIHByb3RlY3RlZCByZWFkb25seSByb3RhdGlvbiQgPSBuZXcgQmVoYXZpb3JTdWJqZWN0PG51bWJlcj4oMCk7XG4gICAgcHJvdGVjdGVkIHJlYWRvbmx5IGNvb3JkaW5hdGVzJCA9IG5ldyBCZWhhdmlvclN1YmplY3Q8cmVhZG9ubHkgW251bWJlciwgbnVtYmVyXT4oXG4gICAgICAgIEVNUFRZX0NPT1JESU5BVEVTLFxuICAgICk7XG5cbiAgICBwcm90ZWN0ZWQgcmVhZG9ubHkgdHJhbnNpdGlvbmVkJCA9IG1lcmdlKFxuICAgICAgICB0dWlEcmFnQW5kRHJvcEZyb20odGhpcy5lbCkucGlwZShtYXAoKHtzdGFnZX0pID0+IHN0YWdlICE9PSAnY29udGludWVzJykpLFxuICAgICAgICB0dWlUeXBlZEZyb21FdmVudCh0aGlzLmVsLCAndG91Y2htb3ZlJywge1xuICAgICAgICAgICAgcGFzc2l2ZTogdHJ1ZSxcbiAgICAgICAgfSkucGlwZShtYXAoVFVJX0ZBTFNFX0hBTkRMRVIpKSxcbiAgICAgICAgdHVpVHlwZWRGcm9tRXZlbnQodGhpcy5lbCwgJ3doZWVsJywge3Bhc3NpdmU6IHRydWV9KS5waXBlKG1hcChUVUlfRkFMU0VfSEFORExFUikpLFxuICAgICk7XG5cbiAgICBwcm90ZWN0ZWQgcmVhZG9ubHkgY3Vyc29yJCA9IHR1aURyYWdBbmREcm9wRnJvbSh0aGlzLmVsKS5waXBlKFxuICAgICAgICBtYXAoKHtzdGFnZX0pID0+IChzdGFnZSA9PT0gJ2NvbnRpbnVlcycgPyAnZ3JhYmJpbmcnIDogJ2luaXRpYWwnKSksXG4gICAgICAgIHN0YXJ0V2l0aCgnaW5pdGlhbCcpLFxuICAgICk7XG5cbiAgICBwcm90ZWN0ZWQgcmVhZG9ubHkgd3JhcHBlclRyYW5zZm9ybSQgPSBjb21iaW5lTGF0ZXN0KFtcbiAgICAgICAgdGhpcy5jb29yZGluYXRlcyQucGlwZShtYXAoKFt4LCB5XSkgPT4gYCR7dHVpUHgoeCl9LCAke3R1aVB4KHkpfWApKSxcbiAgICAgICAgdGhpcy56b29tJCxcbiAgICAgICAgdGhpcy5yb3RhdGlvbiQsXG4gICAgXSkucGlwZShcbiAgICAgICAgbWFwKFxuICAgICAgICAgICAgKFt0cmFuc2xhdGUsIHpvb20sIHJvdGF0aW9uXSkgPT5cbiAgICAgICAgICAgICAgICBgdHJhbnNsYXRlKCR7dHJhbnNsYXRlfSkgc2NhbGUoJHt6b29tfSkgcm90YXRlKCR7cm90YXRpb259ZGVnKWAsXG4gICAgICAgICksXG4gICAgKTtcblxuICAgIEBJbnB1dCgpXG4gICAgcHVibGljIHpvb21hYmxlID0gdHJ1ZTtcblxuICAgIEBJbnB1dCgpXG4gICAgcHVibGljIHJvdGF0YWJsZSA9IGZhbHNlO1xuXG4gICAgQElucHV0KClcbiAgICBwdWJsaWMgaW5pdGlhbFNjYWxlID0gMC44O1xuXG4gICAgcHJvdGVjdGVkIHJvdGF0ZSgpOiB2b2lkIHtcbiAgICAgICAgdGhpcy5yb3RhdGlvbiQubmV4dCh0aGlzLnJvdGF0aW9uJC52YWx1ZSAtIFJPVEFUSU9OX0FOR0xFKTtcbiAgICB9XG5cbiAgICBwcm90ZWN0ZWQgb25QYW4oZGVsdGE6IHJlYWRvbmx5IFtudW1iZXIsIG51bWJlcl0pOiB2b2lkIHtcbiAgICAgICAgdGhpcy5jb29yZGluYXRlcyQubmV4dChcbiAgICAgICAgICAgIHRoaXMuZ2V0R3VhcmRlZENvb3JkaW5hdGVzKFxuICAgICAgICAgICAgICAgIHRoaXMuY29vcmRpbmF0ZXMkLnZhbHVlWzBdICsgZGVsdGFbMF0sXG4gICAgICAgICAgICAgICAgdGhpcy5jb29yZGluYXRlcyQudmFsdWVbMV0gKyBkZWx0YVsxXSxcbiAgICAgICAgICAgICksXG4gICAgICAgICk7XG4gICAgfVxuXG4gICAgcHJvdGVjdGVkIG9uTXV0YXRpb24oY29udGVudFdyYXBwZXI6IEhUTUxFbGVtZW50KTogdm9pZCB7XG4gICAgICAgIGNvbnN0IHtjbGllbnRXaWR0aCwgY2xpZW50SGVpZ2h0fSA9IGNvbnRlbnRXcmFwcGVyO1xuXG4gICAgICAgIHRoaXMucmVmcmVzaChjbGllbnRXaWR0aCwgY2xpZW50SGVpZ2h0KTtcbiAgICB9XG5cbiAgICBwcm90ZWN0ZWQgb25ab29tKHtjbGllbnRYLCBjbGllbnRZLCBkZWx0YX06IFR1aVpvb21FdmVudCk6IHZvaWQge1xuICAgICAgICBpZiAodGhpcy56b29tYWJsZSkge1xuICAgICAgICAgICAgdGhpcy5wcm9jZXNzWm9vbShjbGllbnRYLCBjbGllbnRZLCBkZWx0YSk7XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICBwcm90ZWN0ZWQgb25SZXNpemUoW2VudHJ5XTogcmVhZG9ubHkgUmVzaXplT2JzZXJ2ZXJFbnRyeVtdKTogdm9pZCB7XG4gICAgICAgIGlmIChlbnRyeT8uY29udGVudFJlY3QpIHtcbiAgICAgICAgICAgIHRoaXMucmVmcmVzaChlbnRyeS5jb250ZW50UmVjdC53aWR0aCwgZW50cnkuY29udGVudFJlY3QuaGVpZ2h0KTtcbiAgICAgICAgICAgIHRoaXMuY2RyLmRldGVjdENoYW5nZXMoKTtcbiAgICAgICAgfVxuICAgIH1cblxuICAgIHByb3RlY3RlZCByZXNldCgpOiB2b2lkIHtcbiAgICAgICAgdGhpcy56b29tJC5uZXh0KHRoaXMubWluWm9vbSk7XG4gICAgICAgIHRoaXMuY29vcmRpbmF0ZXMkLm5leHQoRU1QVFlfQ09PUkRJTkFURVMpO1xuICAgIH1cblxuICAgIHByb3RlY3RlZCBzZXRab29tKHpvb206IG51bWJlcik6IHZvaWQge1xuICAgICAgICB0aGlzLnpvb20kLm5leHQoem9vbSk7XG4gICAgICAgIGNvbnN0IFt4LCB5XSA9IHRoaXMuY29vcmRpbmF0ZXMkLnZhbHVlO1xuXG4gICAgICAgIHRoaXMuY29vcmRpbmF0ZXMkLm5leHQodGhpcy5nZXRHdWFyZGVkQ29vcmRpbmF0ZXMoeCwgeSkpO1xuICAgIH1cblxuICAgIHByaXZhdGUgZ2V0IG9mZnNldHMoKToge29mZnNldFg6IG51bWJlcjsgb2Zmc2V0WTogbnVtYmVyfSB7XG4gICAgICAgIGNvbnN0IG9mZnNldFggPSAoKHRoaXMuem9vbSQudmFsdWUgLSB0aGlzLm1pblpvb20pICogdGhpcy53aWR0aCkgLyAyO1xuICAgICAgICBjb25zdCBvZmZzZXRZID0gKCh0aGlzLnpvb20kLnZhbHVlIC0gdGhpcy5taW5ab29tKSAqIHRoaXMuaGVpZ2h0KSAvIDI7XG5cbiAgICAgICAgcmV0dXJuIHtvZmZzZXRYLCBvZmZzZXRZfTtcbiAgICB9XG5cbiAgICBwcml2YXRlIGNhbGN1bGF0ZU1pblpvb20oXG4gICAgICAgIGNvbnRlbnRIZWlnaHQ6IG51bWJlcixcbiAgICAgICAgY29udGVudFdpZHRoOiBudW1iZXIsXG4gICAgICAgIGJveEhlaWdodDogbnVtYmVyLFxuICAgICAgICBib3hXaWR0aDogbnVtYmVyLFxuICAgICk6IG51bWJlciB7XG4gICAgICAgIGNvbnN0IGJpZ1NpemUgPVxuICAgICAgICAgICAgY29udGVudEhlaWdodCA+IGJveEhlaWdodCAqIHRoaXMuaW5pdGlhbFNjYWxlIHx8XG4gICAgICAgICAgICBjb250ZW50V2lkdGggPiBib3hXaWR0aCAqIHRoaXMuaW5pdGlhbFNjYWxlO1xuICAgICAgICBjb25zdCB7Y2xpZW50SGVpZ2h0LCBjbGllbnRXaWR0aH0gPSB0aGlzLmVsO1xuXG4gICAgICAgIHJldHVybiBiaWdTaXplXG4gICAgICAgICAgICA/IHR1aVJvdW5kKFxuICAgICAgICAgICAgICAgICAgTWF0aC5taW4oXG4gICAgICAgICAgICAgICAgICAgICAgKGNsaWVudEhlaWdodCAqIHRoaXMuaW5pdGlhbFNjYWxlKSAvIGNvbnRlbnRIZWlnaHQsXG4gICAgICAgICAgICAgICAgICAgICAgKGNsaWVudFdpZHRoICogdGhpcy5pbml0aWFsU2NhbGUpIC8gY29udGVudFdpZHRoLFxuICAgICAgICAgICAgICAgICAgKSxcbiAgICAgICAgICAgICAgICAgIDIsXG4gICAgICAgICAgICAgIClcbiAgICAgICAgICAgIDogMTtcbiAgICB9XG5cbiAgICBwcml2YXRlIHJlZnJlc2god2lkdGg6IG51bWJlciwgaGVpZ2h0OiBudW1iZXIpOiB2b2lkIHtcbiAgICAgICAgdGhpcy53aWR0aCA9IHdpZHRoO1xuICAgICAgICB0aGlzLmhlaWdodCA9IGhlaWdodDtcbiAgICAgICAgdGhpcy5taW5ab29tID0gdGhpcy5jYWxjdWxhdGVNaW5ab29tKFxuICAgICAgICAgICAgaGVpZ2h0LFxuICAgICAgICAgICAgd2lkdGgsXG4gICAgICAgICAgICB0aGlzLmVsLmNsaWVudEhlaWdodCxcbiAgICAgICAgICAgIHRoaXMuZWwuY2xpZW50V2lkdGgsXG4gICAgICAgICk7XG4gICAgICAgIHRoaXMuem9vbSQubmV4dCh0aGlzLm1pblpvb20pO1xuICAgICAgICB0aGlzLmNvb3JkaW5hdGVzJC5uZXh0KEVNUFRZX0NPT1JESU5BVEVTKTtcbiAgICAgICAgdGhpcy5yb3RhdGlvbiQubmV4dCgwKTtcbiAgICB9XG5cbiAgICBwcml2YXRlIHByb2Nlc3Nab29tKGNsaWVudFg6IG51bWJlciwgY2xpZW50WTogbnVtYmVyLCBkZWx0YTogbnVtYmVyKTogdm9pZCB7XG4gICAgICAgIGNvbnN0IG9sZFNjYWxlID0gdGhpcy56b29tJC52YWx1ZTtcbiAgICAgICAgY29uc3QgbmV3U2NhbGUgPSB0dWlDbGFtcChvbGRTY2FsZSArIGRlbHRhLCB0aGlzLm1pblpvb20sIDIpO1xuXG4gICAgICAgIGNvbnN0IGNlbnRlciA9IHRoaXMuZ2V0U2NhbGVDZW50ZXIoXG4gICAgICAgICAgICB7Y2xpZW50WCwgY2xpZW50WX0sXG4gICAgICAgICAgICB0aGlzLmNvb3JkaW5hdGVzJC52YWx1ZSxcbiAgICAgICAgICAgIHRoaXMuem9vbSQudmFsdWUsXG4gICAgICAgICk7XG5cbiAgICAgICAgY29uc3QgbW92ZVggPSBjZW50ZXJbMF0gKiBvbGRTY2FsZSAtIGNlbnRlclswXSAqIG5ld1NjYWxlO1xuICAgICAgICBjb25zdCBtb3ZlWSA9IGNlbnRlclsxXSAqIG9sZFNjYWxlIC0gY2VudGVyWzFdICogbmV3U2NhbGU7XG5cbiAgICAgICAgdGhpcy56b29tJC5uZXh0KG5ld1NjYWxlKTtcbiAgICAgICAgdGhpcy5jb29yZGluYXRlcyQubmV4dChcbiAgICAgICAgICAgIHRoaXMuZ2V0R3VhcmRlZENvb3JkaW5hdGVzKFxuICAgICAgICAgICAgICAgIHRoaXMuY29vcmRpbmF0ZXMkLnZhbHVlWzBdICsgbW92ZVgsXG4gICAgICAgICAgICAgICAgdGhpcy5jb29yZGluYXRlcyQudmFsdWVbMV0gKyBtb3ZlWSxcbiAgICAgICAgICAgICksXG4gICAgICAgICk7XG4gICAgfVxuXG4gICAgcHJpdmF0ZSBnZXRHdWFyZGVkQ29vcmRpbmF0ZXMoeDogbnVtYmVyLCB5OiBudW1iZXIpOiByZWFkb25seSBbbnVtYmVyLCBudW1iZXJdIHtcbiAgICAgICAgY29uc3Qge29mZnNldFgsIG9mZnNldFl9ID0gdGhpcy5vZmZzZXRzO1xuXG4gICAgICAgIHJldHVybiBbdHVpQ2xhbXAoeCwgLW9mZnNldFgsIG9mZnNldFgpLCB0dWlDbGFtcCh5LCAtb2Zmc2V0WSwgb2Zmc2V0WSldO1xuICAgIH1cblxuICAgIHByaXZhdGUgZ2V0U2NhbGVDZW50ZXIoXG4gICAgICAgIHtjbGllbnRYLCBjbGllbnRZfToge2NsaWVudFg6IG51bWJlcjsgY2xpZW50WTogbnVtYmVyfSxcbiAgICAgICAgW3gsIHldOiByZWFkb25seSBbbnVtYmVyLCBudW1iZXJdLFxuICAgICAgICBzY2FsZTogbnVtYmVyLFxuICAgICk6IFtudW1iZXIsIG51bWJlcl0ge1xuICAgICAgICByZXR1cm4gW1xuICAgICAgICAgICAgKGNsaWVudFggLSB4IC0gdGhpcy5lbC5vZmZzZXRXaWR0aCAvIDIpIC8gc2NhbGUsXG4gICAgICAgICAgICAoY2xpZW50WSAtIHkgLSB0aGlzLmVsLm9mZnNldEhlaWdodCAvIDIpIC8gc2NhbGUsXG4gICAgICAgIF07XG4gICAgfVxufVxuIiwiPG5nLWNvbnRhaW5lciAqbmdJZj1cInRleHRzJCB8IGFzeW5jIGFzIHRleHRzXCI+XG4gICAgPHNlY3Rpb25cbiAgICAgICAgI2NvbnRlbnRXcmFwcGVyXG4gICAgICAgIGF0dHJpYnV0ZUZpbHRlcj1cInNyY1wiXG4gICAgICAgIGNoYXJhY3RlckRhdGFcbiAgICAgICAgY2hpbGRMaXN0XG4gICAgICAgIHN1YnRyZWVcbiAgICAgICAgY2xhc3M9XCJ0LXdyYXBwZXJcIlxuICAgICAgICBbY2xhc3MudC1ub3QtaW50ZXJhY3RpdmUtY29udGVudF09XCJ6b29tYWJsZVwiXG4gICAgICAgIFtjbGFzcy50LXRyYW5zaXRpdmVdPVwidHJhbnNpdGlvbmVkJCB8IGFzeW5jXCJcbiAgICAgICAgW3N0eWxlLmN1cnNvcl09XCJjdXJzb3IkIHwgYXN5bmNcIlxuICAgICAgICBbc3R5bGUudHJhbnNmb3JtXT1cIndyYXBwZXJUcmFuc2Zvcm0kIHwgYXN5bmNcIlxuICAgICAgICAodHVpUGFuKT1cIm9uUGFuKCRldmVudClcIlxuICAgICAgICAodHVpWm9vbSk9XCJvblpvb20oJGV2ZW50KVwiXG4gICAgICAgICh3YU11dGF0aW9uT2JzZXJ2ZXIpPVwib25NdXRhdGlvbihjb250ZW50V3JhcHBlcilcIlxuICAgICAgICAod2FSZXNpemVPYnNlcnZlcik9XCJvblJlc2l6ZSgkZXZlbnQpXCJcbiAgICA+XG4gICAgICAgIDxuZy1jb250ZW50IC8+XG4gICAgPC9zZWN0aW9uPlxuXG4gICAgPGhlYWRlciBjbGFzcz1cInQtaGVhZGVyXCI+XG4gICAgICAgIDxkaXYgY2xhc3M9XCJ0LXRpdGxlXCI+XG4gICAgICAgICAgICA8bmctY29udGVudCBzZWxlY3Q9XCJ0dWktcHJldmlldy10aXRsZVwiIC8+XG4gICAgICAgIDwvZGl2PlxuXG4gICAgICAgIDxuZy1jb250ZW50IHNlbGVjdD1cInR1aS1wcmV2aWV3LXBhZ2luYXRpb25cIiAvPlxuXG4gICAgICAgIDxkaXYgY2xhc3M9XCJ0LWFjdGlvbnNcIj5cbiAgICAgICAgICAgIDxuZy1jb250ZW50IHNlbGVjdD1cIlt0dWlQcmV2aWV3QWN0aW9uXVwiIC8+XG4gICAgICAgIDwvZGl2PlxuICAgIDwvaGVhZGVyPlxuXG4gICAgPGZvb3RlciBjbGFzcz1cInQtZm9vdGVyXCI+XG4gICAgICAgIDxidXR0b25cbiAgICAgICAgICAgICpuZ0lmPVwicm90YXRhYmxlXCJcbiAgICAgICAgICAgIHR1aUhpbnRBcHBlYXJhbmNlPVwiZGFya1wiXG4gICAgICAgICAgICB0dWlIaW50RGVzY3JpYmVcbiAgICAgICAgICAgIHR1aUhpbnREaXJlY3Rpb249XCJ0b3AtcmlnaHRcIlxuICAgICAgICAgICAgdHVpSWNvbkJ1dHRvblxuICAgICAgICAgICAgdHVpUHJldmlld0FjdGlvblxuICAgICAgICAgICAgdHlwZT1cImJ1dHRvblwiXG4gICAgICAgICAgICBjbGFzcz1cInQtcm90YXRlLWJ1dHRvblwiXG4gICAgICAgICAgICBbaWNvblN0YXJ0XT1cImljb25zLnJvdGF0ZVwiXG4gICAgICAgICAgICBbdHVpSGludF09XCJ0ZXh0cy5yb3RhdGVcIlxuICAgICAgICAgICAgKGNsaWNrKT1cInJvdGF0ZSgpXCJcbiAgICAgICAgPjwvYnV0dG9uPlxuXG4gICAgICAgIDx0dWktcHJldmlldy16b29tXG4gICAgICAgICAgICAqbmdJZj1cInpvb21hYmxlXCJcbiAgICAgICAgICAgIFttaW5dPVwibWluWm9vbVwiXG4gICAgICAgICAgICBbdmFsdWVdPVwiKHpvb20kIHwgYXN5bmMpIHx8IDFcIlxuICAgICAgICAgICAgKHJlc2V0KT1cInJlc2V0KClcIlxuICAgICAgICAgICAgKHZhbHVlQ2hhbmdlKT1cInNldFpvb20oJGV2ZW50KVwiXG4gICAgICAgIC8+XG4gICAgPC9mb290ZXI+XG48L25nLWNvbnRhaW5lcj5cbiJdfQ==