@taiga-ui/kit
Version:
Taiga UI Angular main components kit
142 lines • 34.7 kB
JavaScript
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"], outputs: ["tuiHintVisible"] }, { 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,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicHJldmlldy5jb21wb25lbnQuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi9wcm9qZWN0cy9raXQvY29tcG9uZW50cy9wcmV2aWV3L3ByZXZpZXcuY29tcG9uZW50LnRzIiwiLi4vLi4vLi4vLi4vLi4vcHJvamVjdHMva2l0L2NvbXBvbmVudHMvcHJldmlldy9wcmV2aWV3LnRlbXBsYXRlLmh0bWwiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUFDLFNBQVMsRUFBRSxJQUFJLEVBQUMsTUFBTSxpQkFBaUIsQ0FBQztBQUNoRCxPQUFPLEVBQ0gsdUJBQXVCLEVBQ3ZCLGlCQUFpQixFQUNqQixTQUFTLEVBQ1QsTUFBTSxFQUNOLEtBQUssR0FDUixNQUFNLGVBQWUsQ0FBQztBQUN2QixPQUFPLEVBQUMsa0JBQWtCLEVBQUMsTUFBTSxnQ0FBZ0MsQ0FBQztBQUNsRSxPQUFPLEVBQUMsZ0JBQWdCLEVBQUMsTUFBTSw4QkFBOEIsQ0FBQztBQUM5RCxPQUFPLEVBQUMsaUJBQWlCLEVBQUMsTUFBTSx5QkFBeUIsQ0FBQztBQUMxRCxPQUFPLEVBQUMsTUFBTSxFQUFDLE1BQU0sOEJBQThCLENBQUM7QUFDcEQsT0FBTyxFQUFDLE9BQU8sRUFBb0IsTUFBTSwrQkFBK0IsQ0FBQztBQUN6RSxPQUFPLEVBQUMsa0JBQWtCLEVBQUUsaUJBQWlCLEVBQUMsTUFBTSwyQkFBMkIsQ0FBQztBQUNoRixPQUFPLEVBQUMsZ0JBQWdCLEVBQUMsTUFBTSx5QkFBeUIsQ0FBQztBQUN6RCxPQUFPLEVBQUMsUUFBUSxFQUFFLFFBQVEsRUFBQyxNQUFNLDBCQUEwQixDQUFDO0FBQzVELE9BQU8sRUFBQyxLQUFLLEVBQUMsTUFBTSxtQ0FBbUMsQ0FBQztBQUN4RCxPQUFPLEVBQUMsU0FBUyxFQUFDLE1BQU0sa0NBQWtDLENBQUM7QUFDM0QsT0FBTyxFQUFDLE9BQU8sRUFBQyxNQUFNLGdDQUFnQyxDQUFDO0FBQ3ZELE9BQU8sRUFBQyxpQkFB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QTVLUSxtQkFBbUI7bUdBQW5CLG1CQUFtQiwrSkMvQ2hDLHdxREF3REEsczFCRHhCUSxTQUFTLDhDQUNULElBQUksNkZBQ0osU0FBUyxzYkFFVCxNQUFNLDBFQUNOLGdCQUFnQiwrREFDaEIsY0FBYyxpSUFDZCxPQUFPLDRFQUNQLGtCQUFrQixvUUFDbEIsZ0JBQWdCOztTQU1YLG1CQUFtQjs0RkFBbkIsbUJBQW1CO2tCQW5CL0IsU0FBUztpQ0FDTSxJQUFJLFlBQ04sYUFBYSxXQUNkO3dCQUNMLFNBQVM7d0JBQ1QsSUFBSTt3QkFDSixTQUFTO3dCQUNULE9BQU87d0JBQ1AsTUFBTTt3QkFDTixnQkFBZ0I7d0JBQ2hCLGNBQWM7d0JBQ2QsT0FBTzt3QkFDUCxrQkFBa0I7d0JBQ2xCLGdCQUFnQjtxQkFDbkIsbUJBR2dCLHVCQUF1QixDQUFDLE1BQU07OEJBMEN4QyxRQUFRO3NCQURkLEtBQUs7Z0JBSUMsU0FBUztzQkFEZixLQUFLO2dCQUlDLFlBQVk7c0JBRGxCLEtBQUsiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQge0FzeW5jUGlwZSwgTmdJZn0gZnJvbSAnQGFuZ3VsYXIvY29tbW9uJztcbmltcG9ydCB7XG4gICAgQ2hhbmdlRGV0ZWN0aW9uU3RyYXRlZ3ksXG4gICAgQ2hhbmdlRGV0ZWN0b3JSZWYsXG4gICAgQ29tcG9uZW50LFxuICAgIGluamVjdCxcbiAgICBJbnB1dCxcbn0gZnJvbSAnQGFuZ3VsYXIvY29yZSc7XG5pbXBvcnQge1dhTXV0YXRpb25PYnNlcnZlcn0gZnJvbSAnQG5nLXdlYi1hcGlzL211dGF0aW9uLW9ic2VydmVyJztcbmltcG9ydCB7V2FSZXNpemVPYnNlcnZlcn0gZnJvbSAnQG5nLXdlYi1hcGlzL3Jlc2l6ZS1vYnNlcnZlcic7XG5pbXBvcnQge1RVSV9GQUxTRV9IQU5ETEVSfSBmcm9tICdAdGFpZ2EtdWkvY2RrL2NvbnN0YW50cyc7XG5pbXBvcnQge1R1aVBhbn0gZnJvbSAnQHRhaWdhLXVpL2Nkay9kaXJlY3RpdmVzL3Bhbic7XG5pbXBvcnQge1R1aVpvb20sIHR5cGUgVHVpWm9vbUV2ZW50fSBmcm9tICdAdGFpZ2EtdWkvY2RrL2RpcmVjdGl2ZXMvem9vbSc7XG5pbXBvcnQge3R1aURyYWdBbmREcm9wRnJvbSwgdHVpVHlwZWRGcm9tRXZlbnR9IGZyb20gJ0B0YWlnYS11aS9jZGsvb2JzZXJ2YWJsZXMnO1xuaW1wb3J0IHt0dWlJbmplY3RFbGVtZW50fSBmcm9tICdAdGFpZ2EtdWkvY2RrL3V0aWxzL2RvbSc7XG5pbXBvcnQge3R1aUNsYW1wLCB0dWlSb3VuZH0gZnJvbSAnQHRhaWdhLXVpL2Nkay91dGlscy9tYXRoJztcbmltcG9ydCB7dHVpUHh9IGZyb20gJ0B0YWlnYS11aS9jZGsvdXRpbHMvbWlzY2VsbGFuZW91cyc7XG5pbXBvcnQge1R1aUJ1dHRvbn0gZnJvbSAnQHRhaWdhLXVpL2NvcmUvY29tcG9uZW50cy9idXR0b24nO1xuaW1wb3J0IHtUdWlIaW50fSBmcm9tICdAdGFpZ2EtdWkvY29yZS9kaXJlY3RpdmVzL2hpbnQnO1xuaW1wb3J0IHtUVUlfUFJFVklFV19JQ09OUywgVFVJX1BSRVZJRVdfVEVYVFN9IGZyb20gJ0B0YWlnYS11aS9raXQvdG9rZW5zJztcbmltcG9ydCB7QmVoYXZpb3JTdWJqZWN0LCBjb21iaW5lTGF0ZXN0LCBtYXAsIG1lcmdlLCBzdGFydFdpdGh9IGZyb20gJ3J4anMnO1xuXG5pbXBvcnQge1R1aVByZXZpZXdBY3Rpb259IGZyb20gJy4vYWN0aW9uL3ByZXZpZXctYWN0aW9uLmRpcmVjdGl2ZSc7XG5pbXBvcnQge1R1aVByZXZpZXdab29tfSBmcm9tICcuL3pvb20vcHJldmlldy16b29tLmNvbXBvbmVudCc7XG5cbmNvbnN0IEVNUFRZX0NPT1JESU5BVEVTOiBbbnVtYmVyLCBudW1iZXJdID0gWzAsIDBdO1xuY29uc3QgUk9UQVRJT05fQU5HTEUgPSA5MDtcblxuQENvbXBvbmVudCh7XG4gICAgc3RhbmRhbG9uZTogdHJ1ZSxcbiAgICBzZWxlY3RvcjogJ3R1aS1wcmV2aWV3JyxcbiAgICBpbXBvcnRzOiBbXG4gICAgICAgIEFzeW5jUGlwZSxcbiAgICAgICAgTmdJZixcbiAgICAgICAgVHVpQnV0dG9uLFxuICAgICAgICBUdWlIaW50LFxuICAgICAgICBUdWlQYW4sXG4gICAgICAgIFR1aVByZXZpZXdBY3Rpb24sXG4gICAgICAgIFR1aVByZXZpZXdab29tLFxuICAgICAgICBUdWlab29tLFxuICAgICAgICBXYU11dGF0aW9uT2JzZXJ2ZXIsXG4gICAgICAgIFdhUmVzaXplT2JzZXJ2ZXIsXG4gICAgXSxcbiAgICB0ZW1wbGF0ZVVybDogJy4vcHJldmlldy50ZW1wbGF0ZS5odG1sJyxcbiAgICBzdHlsZVVybHM6IFsnLi9wcmV2aWV3LnN0eWxlLmxlc3MnXSxcbiAgICBjaGFuZ2VEZXRlY3Rpb246IENoYW5nZURldGVjdGlvblN0cmF0ZWd5Lk9uUHVzaCxcbn0pXG5leHBvcnQgY2xhc3MgVHVpUHJldmlld0NvbXBvbmVudCB7XG4gICAgcHJpdmF0ZSByZWFkb25seSBlbCA9IHR1aUluamVjdEVsZW1lbnQoKTtcblxuICAgIHByb3RlY3RlZCBtaW5ab29tID0gMTtcbiAgICBwcm90ZWN0ZWQgd2lkdGggPSAwO1xuICAgIHByb3RlY3RlZCBoZWlnaHQgPSAwO1xuICAgIHByb3RlY3RlZCByZWFkb25seSB0ZXh0cyQgPSBpbmplY3QoVFVJX1BSRVZJRVdfVEVYVFMpO1xuICAgIHByb3RlY3RlZCByZWFkb25seSBpY29ucyA9IGluamVjdChUVUlfUFJFVklFV19JQ09OUyk7XG4gICAgcHJvdGVjdGVkIHJlYWRvbmx5IGNkciA9IGluamVjdChDaGFuZ2VEZXRlY3RvclJlZik7XG4gICAgcHJvdGVjdGVkIHJlYWRvbmx5IHpvb20kID0gbmV3IEJlaGF2aW9yU3ViamVjdDxudW1iZXI+KHRoaXMubWluWm9vbSk7XG4gICAgcHJvdGVjdGVkIHJlYWRvbmx5IHJvdGF0aW9uJCA9IG5ldyBCZWhhdmlvclN1YmplY3Q8bnVtYmVyPigwKTtcbiAgICBwcm90ZWN0ZWQgcmVhZG9ubHkgY29vcmRpbmF0ZXMkID0gbmV3IEJlaGF2aW9yU3ViamVjdDxyZWFkb25seSBbbnVtYmVyLCBudW1iZXJdPihcbiAgICAgICAgRU1QVFlfQ09PUkRJTkFURVMsXG4gICAgKTtcblxuICAgIHByb3RlY3RlZCByZWFkb25seSB0cmFuc2l0aW9uZWQkID0gbWVyZ2UoXG4gICAgICAgIHR1aURyYWdBbmREcm9wRnJvbSh0aGlzLmVsKS5waXBlKG1hcCgoe3N0YWdlfSkgPT4gc3RhZ2UgIT09ICdjb250aW51ZXMnKSksXG4gICAgICAgIHR1aVR5cGVkRnJvbUV2ZW50KHRoaXMuZWwsICd0b3VjaG1vdmUnLCB7XG4gICAgICAgICAgICBwYXNzaXZlOiB0cnVlLFxuICAgICAgICB9KS5waXBlKG1hcChUVUlfRkFMU0VfSEFORExFUikpLFxuICAgICAgICB0dWlUeXBlZEZyb21FdmVudCh0aGlzLmVsLCAnd2hlZWwnLCB7cGFzc2l2ZTogdHJ1ZX0pLnBpcGUobWFwKFRVSV9GQUxTRV9IQU5ETEVSKSksXG4gICAgKTtcblxuICAgIHByb3RlY3RlZCByZWFkb25seSBjdXJzb3IkID0gdHVpRHJhZ0FuZERyb3BGcm9tKHRoaXMuZWwpLnBpcGUoXG4gICAgICAgIG1hcCgoe3N0YWdlfSkgPT4gKHN0YWdlID09PSAnY29udGludWVzJyA/ICdncmFiYmluZycgOiAnaW5pdGlhbCcpKSxcbiAgICAgICAgc3RhcnRXaXRoKCdpbml0aWFsJyksXG4gICAgKTtcblxuICAgIHByb3RlY3RlZCByZWFkb25seSB3cmFwcGVyVHJhbnNmb3JtJCA9IGNvbWJpbmVMYXRlc3QoW1xuICAgICAgICB0aGlzLmNvb3JkaW5hdGVzJC5waXBlKG1hcCgoW3gsIHldKSA9PiBgJHt0dWlQeCh4KX0sICR7dHVpUHgoeSl9YCkpLFxuICAgICAgICB0aGlzLnpvb20kLFxuICAgICAgICB0aGlzLnJvdGF0aW9uJCxcbiAgICBdKS5waXBlKFxuICAgICAgICBtYXAoXG4gICAgICAgICAgICAoW3RyYW5zbGF0ZSwgem9vbSwgcm90YXRpb25dKSA9PlxuICAgICAgICAgICAgICAgIGB0cmFuc2xhdGUoJHt0cmFuc2xhdGV9KSBzY2FsZSgke3pvb219KSByb3RhdGUoJHtyb3RhdGlvbn1kZWcpYCxcbiAgICAgICAgKSxcbiAgICApO1xuXG4gICAgQElucHV0KClcbiAgICBwdWJsaWMgem9vbWFibGUgPSB0cnVlO1xuXG4gICAgQElucHV0KClcbiAgICBwdWJsaWMgcm90YXRhYmxlID0gZmFsc2U7XG5cbiAgICBASW5wdXQoKVxuICAgIHB1YmxpYyBpbml0aWFsU2NhbGUgPSAwLjg7XG5cbiAgICBwcm90ZWN0ZWQgcm90YXRlKCk6IHZvaWQge1xuICAgICAgICB0aGlzLnJvdGF0aW9uJC5uZXh0KHRoaXMucm90YXRpb24kLnZhbHVlIC0gUk9UQVRJT05fQU5HTEUpO1xuICAgIH1cblxuICAgIHByb3RlY3RlZCBvblBhbihkZWx0YTogcmVhZG9ubHkgW251bWJlciwgbnVtYmVyXSk6IHZvaWQge1xuICAgICAgICB0aGlzLmNvb3JkaW5hdGVzJC5uZXh0KFxuICAgICAgICAgICAgdGhpcy5nZXRHdWFyZGVkQ29vcmRpbmF0ZXMoXG4gICAgICAgICAgICAgICAgdGhpcy5jb29yZGluYXRlcyQudmFsdWVbMF0gKyBkZWx0YVswXSxcbiAgICAgICAgICAgICAgICB0aGlzLmNvb3JkaW5hdGVzJC52YWx1ZVsxXSArIGRlbHRhWzFdLFxuICAgICAgICAgICAgKSxcbiAgICAgICAgKTtcbiAgICB9XG5cbiAgICBwcm90ZWN0ZWQgb25NdXRhdGlvbihjb250ZW50V3JhcHBlcjogSFRNTEVsZW1lbnQpOiB2b2lkIHtcbiAgICAgICAgY29uc3Qge2NsaWVudFdpZHRoLCBjbGllbnRIZWlnaHR9ID0gY29udGVudFdyYXBwZXI7XG5cbiAgICAgICAgdGhpcy5yZWZyZXNoKGNsaWVudFdpZHRoLCBjbGllbnRIZWlnaHQpO1xuICAgIH1cblxuICAgIHByb3RlY3RlZCBvblpvb20oe2NsaWVudFgsIGNsaWVudFksIGRlbHRhfTogVHVpWm9vbUV2ZW50KTogdm9pZCB7XG4gICAgICAgIGlmICh0aGlzLnpvb21hYmxlKSB7XG4gICAgICAgICAgICB0aGlzLnByb2Nlc3Nab29tKGNsaWVudFgsIGNsaWVudFksIGRlbHRhKTtcbiAgICAgICAgfVxuICAgIH1cblxuICAgIHByb3RlY3RlZCBvblJlc2l6ZShbZW50cnldOiByZWFkb25seSBSZXNpemVPYnNlcnZlckVudHJ5W10pOiB2b2lkIHtcbiAgICAgICAgaWYgKGVudHJ5Py5jb250ZW50UmVjdCkge1xuICAgICAgICAgICAgdGhpcy5yZWZyZXNoKGVudHJ5LmNvbnRlbnRSZWN0LndpZHRoLCBlbnRyeS5jb250ZW50UmVjdC5oZWlnaHQpO1xuICAgICAgICAgICAgdGhpcy5jZHIuZGV0ZWN0Q2hhbmdlcygpO1xuICAgICAgICB9XG4gICAgfVxuXG4gICAgcHJvdGVjdGVkIHJlc2V0KCk6IHZvaWQge1xuICAgICAgICB0aGlzLnpvb20kLm5leHQodGhpcy5taW5ab29tKTtcbiAgICAgICAgdGhpcy5jb29yZGluYXRlcyQubmV4dChFTVBUWV9DT09SRElOQVRFUyk7XG4gICAgfVxuXG4gICAgcHJvdGVjdGVkIHNldFpvb20oem9vbTogbnVtYmVyKTogdm9pZCB7XG4gICAgICAgIHRoaXMuem9vbSQubmV4dCh6b29tKTtcbiAgICAgICAgY29uc3QgW3gsIHldID0gdGhpcy5jb29yZGluYXRlcyQudmFsdWU7XG5cbiAgICAgICAgdGhpcy5jb29yZGluYXRlcyQubmV4dCh0aGlzLmdldEd1YXJkZWRDb29yZGluYXRlcyh4LCB5KSk7XG4gICAgfVxuXG4gICAgcHJpdmF0ZSBnZXQgb2Zmc2V0cygpOiB7b2Zmc2V0WDogbnVtYmVyOyBvZmZzZXRZOiBudW1iZXJ9IHtcbiAgICAgICAgY29uc3Qgb2Zmc2V0WCA9ICgodGhpcy56b29tJC52YWx1ZSAtIHRoaXMubWluWm9vbSkgKiB0aGlzLndpZHRoKSAvIDI7XG4gICAgICAgIGNvbnN0IG9mZnNldFkgPSAoKHRoaXMuem9vbSQudmFsdWUgLSB0aGlzLm1pblpvb20pICogdGhpcy5oZWlnaHQpIC8gMjtcblxuICAgICAgICByZXR1cm4ge29mZnNldFgsIG9mZnNldFl9O1xuICAgIH1cblxuICAgIHByaXZhdGUgY2FsY3VsYXRlTWluWm9vbShcbiAgICAgICAgY29udGVudEhlaWdodDogbnVtYmVyLFxuICAgICAgICBjb250ZW50V2lkdGg6IG51bWJlcixcbiAgICAgICAgYm94SGVpZ2h0OiBudW1iZXIsXG4gICAgICAgIGJveFdpZHRoOiBudW1iZXIsXG4gICAgKTogbnVtYmVyIHtcbiAgICAgICAgY29uc3QgYmlnU2l6ZSA9XG4gICAgICAgICAgICBjb250ZW50SGVpZ2h0ID4gYm94SGVpZ2h0ICogdGhpcy5pbml0aWFsU2NhbGUgfHxcbiAgICAgICAgICAgIGNvbnRlbnRXaWR0aCA+IGJveFdpZHRoICogdGhpcy5pbml0aWFsU2NhbGU7XG4gICAgICAgIGNvbnN0IHtjbGllbnRIZWlnaHQsIGNsaWVudFdpZHRofSA9IHRoaXMuZWw7XG5cbiAgICAgICAgcmV0dXJuIGJpZ1NpemVcbiAgICAgICAgICAgID8gdHVpUm91bmQoXG4gICAgICAgICAgICAgICAgICBNYXRoLm1pbihcbiAgICAgICAgICAgICAgICAgICAgICAoY2xpZW50SGVpZ2h0ICogdGhpcy5pbml0aWFsU2NhbGUpIC8gY29udGVudEhlaWdodCxcbiAgICAgICAgICAgICAgICAgICAgICAoY2xpZW50V2lkdGggKiB0aGlzLmluaXRpYWxTY2FsZSkgLyBjb250ZW50V2lkdGgsXG4gICAgICAgICAgICAgICAgICApLFxuICAgICAgICAgICAgICAgICAgMixcbiAgICAgICAgICAgICAgKVxuICAgICAgICAgICAgOiAxO1xuICAgIH1cblxuICAgIHByaXZhdGUgcmVmcmVzaCh3aWR0aDogbnVtYmVyLCBoZWlnaHQ6IG51bWJlcik6IHZvaWQge1xuICAgICAgICB0aGlzLndpZHRoID0gd2lkdGg7XG4gICAgICAgIHRoaXMuaGVpZ2h0ID0gaGVpZ2h0O1xuICAgICAgICB0aGlzLm1pblpvb20gPSB0aGlzLmNhbGN1bGF0ZU1pblpvb20oXG4gICAgICAgICAgICBoZWlnaHQsXG4gICAgICAgICAgICB3aWR0aCxcbiAgICAgICAgICAgIHRoaXMuZWwuY2xpZW50SGVpZ2h0LFxuICAgICAgICAgICAgdGhpcy5lbC5jbGllbnRXaWR0aCxcbiAgICAgICAgKTtcbiAgICAgICAgdGhpcy56b29tJC5uZXh0KHRoaXMubWluWm9vbSk7XG4gICAgICAgIHRoaXMuY29vcmRpbmF0ZXMkLm5leHQoRU1QVFlfQ09PUkRJTkFURVMpO1xuICAgICAgICB0aGlzLnJvdGF0aW9uJC5uZXh0KDApO1xuICAgIH1cblxuICAgIHByaXZhdGUgcHJvY2Vzc1pvb20oY2xpZW50WDogbnVtYmVyLCBjbGllbnRZOiBudW1iZXIsIGRlbHRhOiBudW1iZXIpOiB2b2lkIHtcbiAgICAgICAgY29uc3Qgb2xkU2NhbGUgPSB0aGlzLnpvb20kLnZhbHVlO1xuICAgICAgICBjb25zdCBuZXdTY2FsZSA9IHR1aUNsYW1wKG9sZFNjYWxlICsgZGVsdGEsIHRoaXMubWluWm9vbSwgMik7XG5cbiAgICAgICAgY29uc3QgY2VudGVyID0gdGhpcy5nZXRTY2FsZUNlbnRlcihcbiAgICAgICAgICAgIHtjbGllbnRYLCBjbGllbnRZfSxcbiAgICAgICAgICAgIHRoaXMuY29vcmRpbmF0ZXMkLnZhbHVlLFxuICAgICAgICAgICAgdGhpcy56b29tJC52YWx1ZSxcbiAgICAgICAgKTtcblxuICAgICAgICBjb25zdCBtb3ZlWCA9IGNlbnRlclswXSAqIG9sZFNjYWxlIC0gY2VudGVyWzBdICogbmV3U2NhbGU7XG4gICAgICAgIGNvbnN0IG1vdmVZID0gY2VudGVyWzFdICogb2xkU2NhbGUgLSBjZW50ZXJbMV0gKiBuZXdTY2FsZTtcblxuICAgICAgICB0aGlzLnpvb20kLm5leHQobmV3U2NhbGUpO1xuICAgICAgICB0aGlzLmNvb3JkaW5hdGVzJC5uZXh0KFxuICAgICAgICAgICAgdGhpcy5nZXRHdWFyZGVkQ29vcmRpbmF0ZXMoXG4gICAgICAgICAgICAgICAgdGhpcy5jb29yZGluYXRlcyQudmFsdWVbMF0gKyBtb3ZlWCxcbiAgICAgICAgICAgICAgICB0aGlzLmNvb3JkaW5hdGVzJC52YWx1ZVsxXSArIG1vdmVZLFxuICAgICAgICAgICAgKSxcbiAgICAgICAgKTtcbiAgICB9XG5cbiAgICBwcml2YXRlIGdldEd1YXJkZWRDb29yZGluYXRlcyh4OiBudW1iZXIsIHk6IG51bWJlcik6IHJlYWRvbmx5IFtudW1iZXIsIG51bWJlcl0ge1xuICAgICAgICBjb25zdCB7b2Zmc2V0WCwgb2Zmc2V0WX0gPSB0aGlzLm9mZnNldHM7XG5cbiAgICAgICAgcmV0dXJuIFt0dWlDbGFtcCh4LCAtb2Zmc2V0WCwgb2Zmc2V0WCksIHR1aUNsYW1wKHksIC1vZmZzZXRZLCBvZmZzZXRZKV07XG4gICAgfVxuXG4gICAgcHJpdmF0ZSBnZXRTY2FsZUNlbnRlcihcbiAgICAgICAge2NsaWVudFgsIGNsaWVudFl9OiB7Y2xpZW50WDogbnVtYmVyOyBjbGllbnRZOiBudW1iZXJ9LFxuICAgICAgICBbeCwgeV06IHJlYWRvbmx5IFtudW1iZXIsIG51bWJlcl0sXG4gICAgICAgIHNjYWxlOiBudW1iZXIsXG4gICAgKTogW251bWJlciwgbnVtYmVyXSB7XG4gICAgICAgIHJldHVybiBbXG4gICAgICAgICAgICAoY2xpZW50WCAtIHggLSB0aGlzLmVsLm9mZnNldFdpZHRoIC8gMikgLyBzY2FsZSxcbiAgICAgICAgICAgIChjbGllbnRZIC0geSAtIHRoaXMuZWwub2Zmc2V0SGVpZ2h0IC8gMikgLyBzY2FsZSxcbiAgICAgICAgXTtcbiAgICB9XG59XG4iLCI8bmctY29udGFpbmVyICpuZ0lmPVwidGV4dHMkIHwgYXN5bmMgYXMgdGV4dHNcIj5cbiAgICA8c2VjdGlvblxuICAgICAgICAjY29udGVudFdyYXBwZXJcbiAgICAgICAgYXR0cmlidXRlRmlsdGVyPVwic3JjXCJcbiAgICAgICAgY2hhcmFjdGVyRGF0YVxuICAgICAgICBjaGlsZExpc3RcbiAgICAgICAgc3VidHJlZVxuICAgICAgICBjbGFzcz1cInQtd3JhcHBlclwiXG4gICAgICAgIFtjbGFzcy50LW5vdC1pbnRlcmFjdGl2ZS1jb250ZW50XT1cInpvb21hYmxlXCJcbiAgICAgICAgW2NsYXNzLnQtdHJhbnNpdGl2ZV09XCJ0cmFuc2l0aW9uZWQkIHwgYXN5bmNcIlxuICAgICAgICBbc3R5bGUuY3Vyc29yXT1cImN1cnNvciQgfCBhc3luY1wiXG4gICAgICAgIFtzdHlsZS50cmFuc2Zvcm1dPVwid3JhcHBlclRyYW5zZm9ybSQgfCBhc3luY1wiXG4gICAgICAgICh0dWlQYW4pPVwib25QYW4oJGV2ZW50KVwiXG4gICAgICAgICh0dWlab29tKT1cIm9uWm9vbSgkZXZlbnQpXCJcbiAgICAgICAgKHdhTXV0YXRpb25PYnNlcnZlcik9XCJvbk11dGF0aW9uKGNvbnRlbnRXcmFwcGVyKVwiXG4gICAgICAgICh3YVJlc2l6ZU9ic2VydmVyKT1cIm9uUmVzaXplKCRldmVudClcIlxuICAgID5cbiAgICAgICAgPG5nLWNvbnRlbnQgLz5cbiAgICA8L3NlY3Rpb24+XG5cbiAgICA8aGVhZGVyIGNsYXNzPVwidC1oZWFkZXJcIj5cbiAgICAgICAgPGRpdiBjbGFzcz1cInQtdGl0bGVcIj5cbiAgICAgICAgICAgIDxuZy1jb250ZW50IHNlbGVjdD1cInR1aS1wcmV2aWV3LXRpdGxlXCIgLz5cbiAgICAgICAgPC9kaXY+XG5cbiAgICAgICAgPG5nLWNvbnRlbnQgc2VsZWN0PVwidHVpLXByZXZpZXctcGFnaW5hdGlvblwiIC8+XG5cbiAgICAgICAgPGRpdiBjbGFzcz1cInQtYWN0aW9uc1wiPlxuICAgICAgICAgICAgPG5nLWNvbnRlbnQgc2VsZWN0PVwiW3R1aVByZXZpZXdBY3Rpb25dXCIgLz5cbiAgICAgICAgPC9kaXY+XG4gICAgPC9oZWFkZXI+XG5cbiAgICA8Zm9vdGVyIGNsYXNzPVwidC1mb290ZXJcIj5cbiAgICAgICAgPGJ1dHRvblxuICAgICAgICAgICAgKm5nSWY9XCJyb3RhdGFibGVcIlxuICAgICAgICAgICAgdHVpSGludEFwcGVhcmFuY2U9XCJkYXJrXCJcbiAgICAgICAgICAgIHR1aUhpbnREZXNjcmliZVxuICAgICAgICAgICAgdHVpSGludERpcmVjdGlvbj1cInRvcC1yaWdodFwiXG4gICAgICAgICAgICB0dWlJY29uQnV0dG9uXG4gICAgICAgICAgICB0dWlQcmV2aWV3QWN0aW9uXG4gICAgICAgICAgICB0eXBlPVwiYnV0dG9uXCJcbiAgICAgICAgICAgIGNsYXNzPVwidC1yb3RhdGUtYnV0dG9uXCJcbiAgICAgICAgICAgIFtpY29uU3RhcnRdPVwiaWNvbnMucm90YXRlXCJcbiAgICAgICAgICAgIFt0dWlIaW50XT1cInRleHRzLnJvdGF0ZVwiXG4gICAgICAgICAgICAoY2xpY2spPVwicm90YXRlKClcIlxuICAgICAgICA+PC9idXR0b24+XG5cbiAgICAgICAgPHR1aS1wcmV2aWV3LXpvb21cbiAgICAgICAgICAgICpuZ0lmPVwiem9vbWFibGVcIlxuICAgICAgICAgICAgW21pbl09XCJtaW5ab29tXCJcbiAgICAgICAgICAgIFt2YWx1ZV09XCIoem9vbSQgfCBhc3luYykgfHwgMVwiXG4gICAgICAgICAgICAocmVzZXQpPVwicmVzZXQoKVwiXG4gICAgICAgICAgICAodmFsdWVDaGFuZ2UpPVwic2V0Wm9vbSgkZXZlbnQpXCJcbiAgICAgICAgLz5cbiAgICA8L2Zvb3Rlcj5cbjwvbmctY29udGFpbmVyPlxuIl19