@taiga-ui/kit
Version:
Taiga UI Angular main components kit
140 lines • 34.5 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 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: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
}] } });
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicHJldmlldy5jb21wb25lbnQuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi9wcm9qZWN0cy9raXQvY29tcG9uZW50cy9wcmV2aWV3L3ByZXZpZXcuY29tcG9uZW50LnRzIiwiLi4vLi4vLi4vLi4vLi4vcHJvamVjdHMva2l0L2NvbXBvbmVudHMvcHJldmlldy9wcmV2aWV3LnRlbXBsYXRlLmh0bWwiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUFDLFNBQVMsRUFBRSxJQUFJLEVBQUMsTUFBTSxpQkFBaUIsQ0FBQztBQUNoRCxPQUFPLEVBQ0gsdUJBQXVCLEVBQ3ZCLGlCQUFpQixFQUNqQixTQUFTLEVBQ1QsTUFBTSxFQUNOLEtBQUssR0FDUixNQUFNLGVBQWUsQ0FBQztBQUN2QixPQUFPLEVBQUMsa0JBQWtCLEVBQUMsTUFBTSxnQ0FBZ0MsQ0FBQztBQUNsRSxPQUFPLEVBQUMsZ0JBQWdCLEVBQUMsTUFBTSw4QkFBOEIsQ0FBQztBQUM5RCxPQUFPLEVBQUMsaUJBQWlCLEVBQUMsTUFBTSx5QkFBeUIsQ0FBQztBQUMxRCxPQUFPLEVBQUMsTUFBTSxFQUFDLE1BQU0sOEJBQThCLENBQUM7QUFFcEQsT0FBTyxFQUFDLE9BQU8sRUFBQyxNQUFNLCtCQUErQixDQUFDO0FBQ3RELE9BQU8sRUFBQyxrQkFBa0IsRUFBRSxpQkFBaUIsRUFBQyxNQUFNLDJCQUEyQixDQUFDO0FBQ2hGLE9BQU8sRUFBQyxnQkFBZ0IsRUFBQyxNQUFNLHlCQUF5QixDQUFDO0FBQ3pELE9BQU8sRUFBQyxRQUFRLEVBQUUsUUFBUSxFQUFDLE1BQU0sMEJBQTBCLENBQUM7QUFDNUQsT0FBTyxFQUFDLEtBQUssRUFBQyxNQUFNLG1DQUFtQyxDQUFDO0FBQ3hELE9BQU8sRUFBQyxTQUFTLEVBQUMsTUFBTSxrQ0FBa0MsQ0FBQztBQUMzRCxPQUFPLEVBQUMsT0FBTyxFQUFDLE1BQU0sZ0NBQWdDLENBQUM7QUFDdkQsT0FBTyxFQUFDLGlCQUFp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SUNqRGhDLHdxREF3REEsczFCRHRCUSxTQUFTLDhDQUNULElBQUksNkZBQ0osU0FBUyx5WkFFVCxNQUFNLDBFQUNOLGdCQUFnQiwrREFDaEIsY0FBYyxpSUFDZCxPQUFPLDRFQUNQLGtCQUFrQixvUUFDbEIsZ0JBQWdCOztTQU1YLG1CQUFtQjs0RkFBbkIsbUJBQW1CO2tCQW5CL0IsU0FBUztpQ0FDTSxJQUFJLFlBQ04sYUFBYSxXQUNkO3dCQUNMLFNBQVM7d0JBQ1QsSUFBSTt3QkFDSixTQUFTO3dCQUNULE9BQU87d0JBQ1AsTUFBTTt3QkFDTixnQkFBZ0I7d0JBQ2hCLGNBQWM7d0JBQ2QsT0FBTzt3QkFDUCxrQkFBa0I7d0JBQ2xCLGdCQUFnQjtxQkFDbkIsbUJBR2dCLHVCQUF1QixDQUFDLE1BQU07OEJBMEN4QyxRQUFRO3NCQURkLEtBQUs7Z0JBSUMsU0FBUztzQkFEZixLQUFLIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHtBc3luY1BpcGUsIE5nSWZ9IGZyb20gJ0Bhbmd1bGFyL2NvbW1vbic7XG5pbXBvcnQge1xuICAgIENoYW5nZURldGVjdGlvblN0cmF0ZWd5LFxuICAgIENoYW5nZURldGVjdG9yUmVmLFxuICAgIENvbXBvbmVudCxcbiAgICBpbmplY3QsXG4gICAgSW5wdXQsXG59IGZyb20gJ0Bhbmd1bGFyL2NvcmUnO1xuaW1wb3J0IHtXYU11dGF0aW9uT2JzZXJ2ZXJ9IGZyb20gJ0BuZy13ZWItYXBpcy9tdXRhdGlvbi1vYnNlcnZlcic7XG5pbXBvcnQge1dhUmVzaXplT2JzZXJ2ZXJ9IGZyb20gJ0BuZy13ZWItYXBpcy9yZXNpemUtb2JzZXJ2ZXInO1xuaW1wb3J0IHtUVUlfRkFMU0VfSEFORExFUn0gZnJvbSAnQHRhaWdhLXVpL2Nkay9jb25zdGFudHMnO1xuaW1wb3J0IHtUdWlQYW59IGZyb20gJ0B0YWlnYS11aS9jZGsvZGlyZWN0aXZlcy9wYW4nO1xuaW1wb3J0IHR5cGUge1R1aVpvb21FdmVudH0gZnJvbSAnQHRhaWdhLXVpL2Nkay9kaXJlY3RpdmVzL3pvb20nO1xuaW1wb3J0IHtUdWlab29tfSBmcm9tICdAdGFpZ2EtdWkvY2RrL2RpcmVjdGl2ZXMvem9vbSc7XG5pbXBvcnQge3R1aURyYWdBbmREcm9wRnJvbSwgdHVpVHlwZWRGcm9tRXZlbnR9IGZyb20gJ0B0YWlnYS11aS9jZGsvb2JzZXJ2YWJsZXMnO1xuaW1wb3J0IHt0dWlJbmplY3RFbGVtZW50fSBmcm9tICdAdGFpZ2EtdWkvY2RrL3V0aWxzL2RvbSc7XG5pbXBvcnQge3R1aUNsYW1wLCB0dWlSb3VuZH0gZnJvbSAnQHRhaWdhLXVpL2Nkay91dGlscy9tYXRoJztcbmltcG9ydCB7dHVpUHh9IGZyb20gJ0B0YWlnYS11aS9jZGsvdXRpbHMvbWlzY2VsbGFuZW91cyc7XG5pbXBvcnQge1R1aUJ1dHRvbn0gZnJvbSAnQHRhaWdhLXVpL2NvcmUvY29tcG9uZW50cy9idXR0b24nO1xuaW1wb3J0IHtUdWlIaW50fSBmcm9tICdAdGFpZ2EtdWkvY29yZS9kaXJlY3RpdmVzL2hpbnQnO1xuaW1wb3J0IHtUVUlfUFJFVklFV19JQ09OUywgVFVJX1BSRVZJRVdfVEVYVFN9IGZyb20gJ0B0YWlnYS11aS9raXQvdG9rZW5zJztcbmltcG9ydCB7QmVoYXZpb3JTdWJqZWN0LCBjb21iaW5lTGF0ZXN0LCBtYXAsIG1lcmdlLCBzdGFydFdpdGh9IGZyb20gJ3J4anMnO1xuXG5pbXBvcnQge1R1aVByZXZpZXdBY3Rpb259IGZyb20gJy4vYWN0aW9uL3ByZXZpZXctYWN0aW9uLmRpcmVjdGl2ZSc7XG5pbXBvcnQge1R1aVByZXZpZXdab29tfSBmcm9tICcuL3pvb20vcHJldmlldy16b29tLmNvbXBvbmVudCc7XG5cbmNvbnN0IElOSVRJQUxfU0NBTEVfQ09FRiA9IDAuODtcbmNvbnN0IEVNUFRZX0NPT1JESU5BVEVTOiBbbnVtYmVyLCBudW1iZXJdID0gWzAsIDBdO1xuY29uc3QgUk9UQVRJT05fQU5HTEUgPSA5MDtcblxuQENvbXBvbmVudCh7XG4gICAgc3RhbmRhbG9uZTogdHJ1ZSxcbiAgICBzZWxlY3RvcjogJ3R1aS1wcmV2aWV3JyxcbiAgICBpbXBvcnRzOiBbXG4gICAgICAgIEFzeW5jUGlwZSxcbiAgICAgICAgTmdJZixcbiAgICAgICAgVHVpQnV0dG9uLFxuICAgICAgICBUdWlIaW50LFxuICAgICAgICBUdWlQYW4sXG4gICAgICAgIFR1aVByZXZpZXdBY3Rpb24sXG4gICAgICAgIFR1aVByZXZpZXdab29tLFxuICAgICAgICBUdWlab29tLFxuICAgICAgICBXYU11dGF0aW9uT2JzZXJ2ZXIsXG4gICAgICAgIFdhUmVzaXplT2JzZXJ2ZXIsXG4gICAgXSxcbiAgICB0ZW1wbGF0ZVVybDogJy4vcHJldmlldy50ZW1wbGF0ZS5odG1sJyxcbiAgICBzdHlsZVVybHM6IFsnLi9wcmV2aWV3LnN0eWxlLmxlc3MnXSxcbiAgICBjaGFuZ2VEZXRlY3Rpb246IENoYW5nZURldGVjdGlvblN0cmF0ZWd5Lk9uUHVzaCxcbn0pXG5leHBvcnQgY2xhc3MgVHVpUHJldmlld0NvbXBvbmVudCB7XG4gICAgcHJpdmF0ZSByZWFkb25seSBlbCA9IHR1aUluamVjdEVsZW1lbnQoKTtcblxuICAgIHByb3RlY3RlZCBtaW5ab29tID0gMTtcbiAgICBwcm90ZWN0ZWQgd2lkdGggPSAwO1xuICAgIHByb3RlY3RlZCBoZWlnaHQgPSAwO1xuICAgIHByb3RlY3RlZCByZWFkb25seSB0ZXh0cyQgPSBpbmplY3QoVFVJX1BSRVZJRVdfVEVYVFMpO1xuICAgIHByb3RlY3RlZCByZWFkb25seSBpY29ucyA9IGluamVjdChUVUlfUFJFVklFV19JQ09OUyk7XG4gICAgcHJvdGVjdGVkIHJlYWRvbmx5IGNkciA9IGluamVjdChDaGFuZ2VEZXRlY3RvclJlZik7XG4gICAgcHJvdGVjdGVkIHJlYWRvbmx5IHpvb20kID0gbmV3IEJlaGF2aW9yU3ViamVjdDxudW1iZXI+KHRoaXMubWluWm9vbSk7XG4gICAgcHJvdGVjdGVkIHJlYWRvbmx5IHJvdGF0aW9uJCA9IG5ldyBCZWhhdmlvclN1YmplY3Q8bnVtYmVyPigwKTtcbiAgICBwcm90ZWN0ZWQgcmVhZG9ubHkgY29vcmRpbmF0ZXMkID0gbmV3IEJlaGF2aW9yU3ViamVjdDxyZWFkb25seSBbbnVtYmVyLCBudW1iZXJdPihcbiAgICAgICAgRU1QVFlfQ09PUkRJTkFURVMsXG4gICAgKTtcblxuICAgIHByb3RlY3RlZCByZWFkb25seSB0cmFuc2l0aW9uZWQkID0gbWVyZ2UoXG4gICAgICAgIHR1aURyYWdBbmREcm9wRnJvbSh0aGlzLmVsKS5waXBlKG1hcCgoe3N0YWdlfSkgPT4gc3RhZ2UgIT09ICdjb250aW51ZXMnKSksXG4gICAgICAgIHR1aVR5cGVkRnJvbUV2ZW50KHRoaXMuZWwsICd0b3VjaG1vdmUnLCB7XG4gICAgICAgICAgICBwYXNzaXZlOiB0cnVlLFxuICAgICAgICB9KS5waXBlKG1hcChUVUlfRkFMU0VfSEFORExFUikpLFxuICAgICAgICB0dWlUeXBlZEZyb21FdmVudCh0aGlzLmVsLCAnd2hlZWwnLCB7cGFzc2l2ZTogdHJ1ZX0pLnBpcGUobWFwKFRVSV9GQUxTRV9IQU5ETEVSKSksXG4gICAgKTtcblxuICAgIHByb3RlY3RlZCByZWFkb25seSBjdXJzb3IkID0gdHVpRHJhZ0FuZERyb3BGcm9tKHRoaXMuZWwpLnBpcGUoXG4gICAgICAgIG1hcCgoe3N0YWdlfSkgPT4gKHN0YWdlID09PSAnY29udGludWVzJyA/ICdncmFiYmluZycgOiAnaW5pdGlhbCcpKSxcbiAgICAgICAgc3RhcnRXaXRoKCdpbml0aWFsJyksXG4gICAgKTtcblxuICAgIHByb3RlY3RlZCByZWFkb25seSB3cmFwcGVyVHJhbnNmb3JtJCA9IGNvbWJpbmVMYXRlc3QoW1xuICAgICAgICB0aGlzLmNvb3JkaW5hdGVzJC5waXBlKG1hcCgoW3gsIHldKSA9PiBgJHt0dWlQeCh4KX0sICR7dHVpUHgoeSl9YCkpLFxuICAgICAgICB0aGlzLnpvb20kLFxuICAgICAgICB0aGlzLnJvdGF0aW9uJCxcbiAgICBdKS5waXBlKFxuICAgICAgICBtYXAoXG4gICAgICAgICAgICAoW3RyYW5zbGF0ZSwgem9vbSwgcm90YXRpb25dKSA9PlxuICAgICAgICAgICAgICAgIGB0cmFuc2xhdGUoJHt0cmFuc2xhdGV9KSBzY2FsZSgke3pvb219KSByb3RhdGUoJHtyb3RhdGlvbn1kZWcpYCxcbiAgICAgICAgKSxcbiAgICApO1xuXG4gICAgQElucHV0KClcbiAgICBwdWJsaWMgem9vbWFibGUgPSB0cnVlO1xuXG4gICAgQElucHV0KClcbiAgICBwdWJsaWMgcm90YXRhYmxlID0gZmFsc2U7XG5cbiAgICBwcm90ZWN0ZWQgcm90YXRlKCk6IHZvaWQge1xuICAgICAgICB0aGlzLnJvdGF0aW9uJC5uZXh0KHRoaXMucm90YXRpb24kLnZhbHVlIC0gUk9UQVRJT05fQU5HTEUpO1xuICAgIH1cblxuICAgIHByb3RlY3RlZCBvblBhbihkZWx0YTogcmVhZG9ubHkgW251bWJlciwgbnVtYmVyXSk6IHZvaWQge1xuICAgICAgICB0aGlzLmNvb3JkaW5hdGVzJC5uZXh0KFxuICAgICAgICAgICAgdGhpcy5nZXRHdWFyZGVkQ29vcmRpbmF0ZXMoXG4gICAgICAgICAgICAgICAgdGhpcy5jb29yZGluYXRlcyQudmFsdWVbMF0gKyBkZWx0YVswXSxcbiAgICAgICAgICAgICAgICB0aGlzLmNvb3JkaW5hdGVzJC52YWx1ZVsxXSArIGRlbHRhWzFdLFxuICAgICAgICAgICAgKSxcbiAgICAgICAgKTtcbiAgICB9XG5cbiAgICBwcm90ZWN0ZWQgb25NdXRhdGlvbihjb250ZW50V3JhcHBlcjogSFRNTEVsZW1lbnQpOiB2b2lkIHtcbiAgICAgICAgY29uc3Qge2NsaWVudFdpZHRoLCBjbGllbnRIZWlnaHR9ID0gY29udGVudFdyYXBwZXI7XG5cbiAgICAgICAgdGhpcy5yZWZyZXNoKGNsaWVudFdpZHRoLCBjbGllbnRIZWlnaHQpO1xuICAgIH1cblxuICAgIHByb3RlY3RlZCBvblpvb20oe2NsaWVudFgsIGNsaWVudFksIGRlbHRhfTogVHVpWm9vbUV2ZW50KTogdm9pZCB7XG4gICAgICAgIGlmICh0aGlzLnpvb21hYmxlKSB7XG4gICAgICAgICAgICB0aGlzLnByb2Nlc3Nab29tKGNsaWVudFgsIGNsaWVudFksIGRlbHRhKTtcbiAgICAgICAgfVxuICAgIH1cblxuICAgIHByb3RlY3RlZCBvblJlc2l6ZShbZW50cnldOiByZWFkb25seSBSZXNpemVPYnNlcnZlckVudHJ5W10pOiB2b2lkIHtcbiAgICAgICAgaWYgKGVudHJ5Py5jb250ZW50UmVjdCkge1xuICAgICAgICAgICAgdGhpcy5yZWZyZXNoKGVudHJ5LmNvbnRlbnRSZWN0LndpZHRoLCBlbnRyeS5jb250ZW50UmVjdC5oZWlnaHQpO1xuICAgICAgICAgICAgdGhpcy5jZHIuZGV0ZWN0Q2hhbmdlcygpO1xuICAgICAgICB9XG4gICAgfVxuXG4gICAgcHJvdGVjdGVkIHJlc2V0KCk6IHZvaWQge1xuICAgICAgICB0aGlzLnpvb20kLm5leHQodGhpcy5taW5ab29tKTtcbiAgICAgICAgdGhpcy5jb29yZGluYXRlcyQubmV4dChFTVBUWV9DT09SRElOQVRFUyk7XG4gICAgfVxuXG4gICAgcHJvdGVjdGVkIHNldFpvb20oem9vbTogbnVtYmVyKTogdm9pZCB7XG4gICAgICAgIHRoaXMuem9vbSQubmV4dCh6b29tKTtcbiAgICAgICAgY29uc3QgW3gsIHldID0gdGhpcy5jb29yZGluYXRlcyQudmFsdWU7XG5cbiAgICAgICAgdGhpcy5jb29yZGluYXRlcyQubmV4dCh0aGlzLmdldEd1YXJkZWRDb29yZGluYXRlcyh4LCB5KSk7XG4gICAgfVxuXG4gICAgcHJpdmF0ZSBnZXQgb2Zmc2V0cygpOiB7b2Zmc2V0WDogbnVtYmVyOyBvZmZzZXRZOiBudW1iZXJ9IHtcbiAgICAgICAgY29uc3Qgb2Zmc2V0WCA9ICgodGhpcy56b29tJC52YWx1ZSAtIHRoaXMubWluWm9vbSkgKiB0aGlzLndpZHRoKSAvIDI7XG4gICAgICAgIGNvbnN0IG9mZnNldFkgPSAoKHRoaXMuem9vbSQudmFsdWUgLSB0aGlzLm1pblpvb20pICogdGhpcy5oZWlnaHQpIC8gMjtcblxuICAgICAgICByZXR1cm4ge29mZnNldFgsIG9mZnNldFl9O1xuICAgIH1cblxuICAgIHByaXZhdGUgY2FsY3VsYXRlTWluWm9vbShcbiAgICAgICAgY29udGVudEhlaWdodDogbnVtYmVyLFxuICAgICAgICBjb250ZW50V2lkdGg6IG51bWJlcixcbiAgICAgICAgYm94SGVpZ2h0OiBudW1iZXIsXG4gICAgICAgIGJveFdpZHRoOiBudW1iZXIsXG4gICAgKTogbnVtYmVyIHtcbiAgICAgICAgY29uc3QgYmlnU2l6ZSA9XG4gICAgICAgICAgICBjb250ZW50SGVpZ2h0ID4gYm94SGVpZ2h0ICogSU5JVElBTF9TQ0FMRV9DT0VGIHx8XG4gICAgICAgICAgICBjb250ZW50V2lkdGggPiBib3hXaWR0aCAqIElOSVRJQUxfU0NBTEVfQ09FRjtcbiAgICAgICAgY29uc3Qge2NsaWVudEhlaWdodCwgY2xpZW50V2lkdGh9ID0gdGhpcy5lbDtcblxuICAgICAgICByZXR1cm4gYmlnU2l6ZVxuICAgICAgICAgICAgPyB0dWlSb3VuZChcbiAgICAgICAgICAgICAgICAgIE1hdGgubWluKFxuICAgICAgICAgICAgICAgICAgICAgIChjbGllbnRIZWlnaHQgKiBJTklUSUFMX1NDQUxFX0NPRUYpIC8gY29udGVudEhlaWdodCxcbiAgICAgICAgICAgICAgICAgICAgICAoY2xpZW50V2lkdGggKiBJTklUSUFMX1NDQUxFX0NPRUYpIC8gY29udGVudFdpZHRoLFxuICAgICAgICAgICAgICAgICAgKSxcbiAgICAgICAgICAgICAgICAgIDIsXG4gICAgICAgICAgICAgIClcbiAgICAgICAgICAgIDogMTtcbiAgICB9XG5cbiAgICBwcml2YXRlIHJlZnJlc2god2lkdGg6IG51bWJlciwgaGVpZ2h0OiBudW1iZXIpOiB2b2lkIHtcbiAgICAgICAgdGhpcy53aWR0aCA9IHdpZHRoO1xuICAgICAgICB0aGlzLmhlaWdodCA9IGhlaWdodDtcbiAgICAgICAgdGhpcy5taW5ab29tID0gdGhpcy5jYWxjdWxhdGVNaW5ab29tKFxuICAgICAgICAgICAgaGVpZ2h0LFxuICAgICAgICAgICAgd2lkdGgsXG4gICAgICAgICAgICB0aGlzLmVsLmNsaWVudEhlaWdodCxcbiAgICAgICAgICAgIHRoaXMuZWwuY2xpZW50V2lkdGgsXG4gICAgICAgICk7XG4gICAgICAgIHRoaXMuem9vbSQubmV4dCh0aGlzLm1pblpvb20pO1xuICAgICAgICB0aGlzLmNvb3JkaW5hdGVzJC5uZXh0KEVNUFRZX0NPT1JESU5BVEVTKTtcbiAgICAgICAgdGhpcy5yb3RhdGlvbiQubmV4dCgwKTtcbiAgICB9XG5cbiAgICBwcml2YXRlIHByb2Nlc3Nab29tKGNsaWVudFg6IG51bWJlciwgY2xpZW50WTogbnVtYmVyLCBkZWx0YTogbnVtYmVyKTogdm9pZCB7XG4gICAgICAgIGNvbnN0IG9sZFNjYWxlID0gdGhpcy56b29tJC52YWx1ZTtcbiAgICAgICAgY29uc3QgbmV3U2NhbGUgPSB0dWlDbGFtcChvbGRTY2FsZSArIGRlbHRhLCB0aGlzLm1pblpvb20sIDIpO1xuXG4gICAgICAgIGNvbnN0IGNlbnRlciA9IHRoaXMuZ2V0U2NhbGVDZW50ZXIoXG4gICAgICAgICAgICB7Y2xpZW50WCwgY2xpZW50WX0sXG4gICAgICAgICAgICB0aGlzLmNvb3JkaW5hdGVzJC52YWx1ZSxcbiAgICAgICAgICAgIHRoaXMuem9vbSQudmFsdWUsXG4gICAgICAgICk7XG5cbiAgICAgICAgY29uc3QgbW92ZVggPSBjZW50ZXJbMF0gKiBvbGRTY2FsZSAtIGNlbnRlclswXSAqIG5ld1NjYWxlO1xuICAgICAgICBjb25zdCBtb3ZlWSA9IGNlbnRlclsxXSAqIG9sZFNjYWxlIC0gY2VudGVyWzFdICogbmV3U2NhbGU7XG5cbiAgICAgICAgdGhpcy56b29tJC5uZXh0KG5ld1NjYWxlKTtcbiAgICAgICAgdGhpcy5jb29yZGluYXRlcyQubmV4dChcbiAgICAgICAgICAgIHRoaXMuZ2V0R3VhcmRlZENvb3JkaW5hdGVzKFxuICAgICAgICAgICAgICAgIHRoaXMuY29vcmRpbmF0ZXMkLnZhbHVlWzBdICsgbW92ZVgsXG4gICAgICAgICAgICAgICAgdGhpcy5jb29yZGluYXRlcyQudmFsdWVbMV0gKyBtb3ZlWSxcbiAgICAgICAgICAgICksXG4gICAgICAgICk7XG4gICAgfVxuXG4gICAgcHJpdmF0ZSBnZXRHdWFyZGVkQ29vcmRpbmF0ZXMoeDogbnVtYmVyLCB5OiBudW1iZXIpOiByZWFkb25seSBbbnVtYmVyLCBudW1iZXJdIHtcbiAgICAgICAgY29uc3Qge29mZnNldFgsIG9mZnNldFl9ID0gdGhpcy5vZmZzZXRzO1xuXG4gICAgICAgIHJldHVybiBbdHVpQ2xhbXAoeCwgLW9mZnNldFgsIG9mZnNldFgpLCB0dWlDbGFtcCh5LCAtb2Zmc2V0WSwgb2Zmc2V0WSldO1xuICAgIH1cblxuICAgIHByaXZhdGUgZ2V0U2NhbGVDZW50ZXIoXG4gICAgICAgIHtjbGllbnRYLCBjbGllbnRZfToge2NsaWVudFg6IG51bWJlcjsgY2xpZW50WTogbnVtYmVyfSxcbiAgICAgICAgW3gsIHldOiByZWFkb25seSBbbnVtYmVyLCBudW1iZXJdLFxuICAgICAgICBzY2FsZTogbnVtYmVyLFxuICAgICk6IFtudW1iZXIsIG51bWJlcl0ge1xuICAgICAgICByZXR1cm4gW1xuICAgICAgICAgICAgKGNsaWVudFggLSB4IC0gdGhpcy5lbC5vZmZzZXRXaWR0aCAvIDIpIC8gc2NhbGUsXG4gICAgICAgICAgICAoY2xpZW50WSAtIHkgLSB0aGlzLmVsLm9mZnNldEhlaWdodCAvIDIpIC8gc2NhbGUsXG4gICAgICAgIF07XG4gICAgfVxufVxuIiwiPG5nLWNvbnRhaW5lciAqbmdJZj1cInRleHRzJCB8IGFzeW5jIGFzIHRleHRzXCI+XG4gICAgPHNlY3Rpb25cbiAgICAgICAgI2NvbnRlbnRXcmFwcGVyXG4gICAgICAgIGF0dHJpYnV0ZUZpbHRlcj1cInNyY1wiXG4gICAgICAgIGNoYXJhY3RlckRhdGFcbiAgICAgICAgY2hpbGRMaXN0XG4gICAgICAgIHN1YnRyZWVcbiAgICAgICAgY2xhc3M9XCJ0LXdyYXBwZXJcIlxuICAgICAgICBbY2xhc3MudC1ub3QtaW50ZXJhY3RpdmUtY29udGVudF09XCJ6b29tYWJsZVwiXG4gICAgICAgIFtjbGFzcy50LXRyYW5zaXRpdmVdPVwidHJhbnNpdGlvbmVkJCB8IGFzeW5jXCJcbiAgICAgICAgW3N0eWxlLmN1cnNvcl09XCJjdXJzb3IkIHwgYXN5bmNcIlxuICAgICAgICBbc3R5bGUudHJhbnNmb3JtXT1cIndyYXBwZXJUcmFuc2Zvcm0kIHwgYXN5bmNcIlxuICAgICAgICAodHVpUGFuKT1cIm9uUGFuKCRldmVudClcIlxuICAgICAgICAodHVpWm9vbSk9XCJvblpvb20oJGV2ZW50KVwiXG4gICAgICAgICh3YU11dGF0aW9uT2JzZXJ2ZXIpPVwib25NdXRhdGlvbihjb250ZW50V3JhcHBlcilcIlxuICAgICAgICAod2FSZXNpemVPYnNlcnZlcik9XCJvblJlc2l6ZSgkZXZlbnQpXCJcbiAgICA+XG4gICAgICAgIDxuZy1jb250ZW50IC8+XG4gICAgPC9zZWN0aW9uPlxuXG4gICAgPGhlYWRlciBjbGFzcz1cInQtaGVhZGVyXCI+XG4gICAgICAgIDxkaXYgY2xhc3M9XCJ0LXRpdGxlXCI+XG4gICAgICAgICAgICA8bmctY29udGVudCBzZWxlY3Q9XCJ0dWktcHJldmlldy10aXRsZVwiIC8+XG4gICAgICAgIDwvZGl2PlxuXG4gICAgICAgIDxuZy1jb250ZW50IHNlbGVjdD1cInR1aS1wcmV2aWV3LXBhZ2luYXRpb25cIiAvPlxuXG4gICAgICAgIDxkaXYgY2xhc3M9XCJ0LWFjdGlvbnNcIj5cbiAgICAgICAgICAgIDxuZy1jb250ZW50IHNlbGVjdD1cIlt0dWlQcmV2aWV3QWN0aW9uXVwiIC8+XG4gICAgICAgIDwvZGl2PlxuICAgIDwvaGVhZGVyPlxuXG4gICAgPGZvb3RlciBjbGFzcz1cInQtZm9vdGVyXCI+XG4gICAgICAgIDxidXR0b25cbiAgICAgICAgICAgICpuZ0lmPVwicm90YXRhYmxlXCJcbiAgICAgICAgICAgIHR1aUhpbnRBcHBlYXJhbmNlPVwiZGFya1wiXG4gICAgICAgICAgICB0dWlIaW50RGVzY3JpYmVcbiAgICAgICAgICAgIHR1aUhpbnREaXJlY3Rpb249XCJ0b3AtcmlnaHRcIlxuICAgICAgICAgICAgdHVpSWNvbkJ1dHRvblxuICAgICAgICAgICAgdHVpUHJldmlld0FjdGlvblxuICAgICAgICAgICAgdHlwZT1cImJ1dHRvblwiXG4gICAgICAgICAgICBjbGFzcz1cInQtcm90YXRlLWJ1dHRvblwiXG4gICAgICAgICAgICBbaWNvblN0YXJ0XT1cImljb25zLnJvdGF0ZVwiXG4gICAgICAgICAgICBbdHVpSGludF09XCJ0ZXh0cy5yb3RhdGVcIlxuICAgICAgICAgICAgKGNsaWNrKT1cInJvdGF0ZSgpXCJcbiAgICAgICAgPjwvYnV0dG9uPlxuXG4gICAgICAgIDx0dWktcHJldmlldy16b29tXG4gICAgICAgICAgICAqbmdJZj1cInpvb21hYmxlXCJcbiAgICAgICAgICAgIFttaW5dPVwibWluWm9vbVwiXG4gICAgICAgICAgICBbdmFsdWVdPVwiKHpvb20kIHwgYXN5bmMpIHx8IDFcIlxuICAgICAgICAgICAgKHJlc2V0KT1cInJlc2V0KClcIlxuICAgICAgICAgICAgKHZhbHVlQ2hhbmdlKT1cInNldFpvb20oJGV2ZW50KVwiXG4gICAgICAgIC8+XG4gICAgPC9mb290ZXI+XG48L25nLWNvbnRhaW5lcj5cbiJdfQ==