@taiga-ui/kit
Version:
Taiga UI Angular main components kit
140 lines • 34.4 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 './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"] }], 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: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,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicHJldmlldy5jb21wb25lbnQuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi9wcm9qZWN0cy9raXQvY29tcG9uZW50cy9wcmV2aWV3L3ByZXZpZXcuY29tcG9uZW50LnRzIiwiLi4vLi4vLi4vLi4vLi4vcHJvamVjdHMva2l0L2NvbXBvbmVudHMvcHJldmlldy9wcmV2aWV3LnRlbXBsYXRlLmh0bWwiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUFDLFNBQVMsRUFBRSxJQUFJLEVBQUMsTUFBTSxpQkFBaUIsQ0FBQztBQUNoRCxPQUFPLEVBQ0gsdUJBQXVCLEVBQ3ZCLGlCQUFpQixFQUNqQixTQUFTLEVBQ1QsTUFBTSxFQUNOLEtBQUssR0FDUixNQUFNLGVBQWUsQ0FBQztBQUN2QixPQUFPLEVBQUMsa0JBQWtCLEVBQUMsTUFBTSxnQ0FBZ0MsQ0FBQztBQUNsRSxPQUFPLEVBQUMsZ0JBQWdCLEVBQUMsTUFBTSw4QkFBOEIsQ0FBQztBQUM5RCxPQUFPLEVBQUMsaUJBQWlCLEVBQUMsTUFBTSx5QkFBeUIsQ0FBQztBQUMxRCxPQUFPLEVBQUMsTUFBTSxFQUFDLE1BQU0sOEJBQThCLENBQUM7QUFFcEQsT0FBTyxFQUFDLE9BQU8sRUFBQyxNQUFNLCtCQUErQixDQUFDO0FBQ3RELE9BQU8sRUFBQyxrQkFBa0IsRUFBRSxpQkFBaUIsRUFBQyxNQUFNLDJCQUEyQixDQUFDO0FBQ2hGLE9BQU8sRUFBQyxnQkFBZ0IsRUFBQyxNQUFNLHlCQUF5QixDQUFDO0FBQ3pELE9BQU8sRUFBQyxRQUFRLEVBQUUsUUFBUSxFQUFDLE1BQU0sMEJBQTBCLENBQUM7QUFDNUQsT0FBTyxFQUFDLEtBQUssRUFBQyxNQUFNLG1DQUFtQyxDQUFDO0FBQ3hELE9BQU8sRUFBQyxTQUFTLEVBQUMsTUFBTSxrQ0FBa0MsQ0FBQztBQUMzRCxPQUFPLEVBQUMsT0FBTyxFQUFDLE1BQU0sZ0NBQWdDLENBQUM7QUFDdkQsT0FBTyxFQUFDLGlCQUFp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SUNqRGhDLHdxREF3REEsMHdCRHRCUSxTQUFTLDhDQUNULElBQUksNkZBQ0osU0FBUyx5WkFFVCxNQUFNLDBFQUNOLGdCQUFnQiwrREFDaEIsY0FBYyxpSUFDZCxPQUFPLDRFQUNQLGtCQUFrQixvUUFDbEIsZ0JBQWdCOztTQU1YLG1CQUFtQjs0RkFBbkIsbUJBQW1CO2tCQW5CL0IsU0FBUztpQ0FDTSxJQUFJLFlBQ04sYUFBYSxXQUNkO3dCQUNMLFNBQVM7d0JBQ1QsSUFBSTt3QkFDSixTQUFTO3dCQUNULE9BQU87d0JBQ1AsTUFBTTt3QkFDTixnQkFBZ0I7d0JBQ2hCLGNBQWM7d0JBQ2QsT0FBTzt3QkFDUCxrQkFBa0I7d0JBQ2xCLGdCQUFnQjtxQkFDbkIsbUJBR2dCLHVCQUF1QixDQUFDLE1BQU07OEJBMEN4QyxRQUFRO3NCQURkLEtBQUs7Z0JBSUMsU0FBUztzQkFEZixLQUFLIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHtBc3luY1BpcGUsIE5nSWZ9IGZyb20gJ0Bhbmd1bGFyL2NvbW1vbic7XG5pbXBvcnQge1xuICAgIENoYW5nZURldGVjdGlvblN0cmF0ZWd5LFxuICAgIENoYW5nZURldGVjdG9yUmVmLFxuICAgIENvbXBvbmVudCxcbiAgICBpbmplY3QsXG4gICAgSW5wdXQsXG59IGZyb20gJ0Bhbmd1bGFyL2NvcmUnO1xuaW1wb3J0IHtXYU11dGF0aW9uT2JzZXJ2ZXJ9IGZyb20gJ0BuZy13ZWItYXBpcy9tdXRhdGlvbi1vYnNlcnZlcic7XG5pbXBvcnQge1dhUmVzaXplT2JzZXJ2ZXJ9IGZyb20gJ0BuZy13ZWItYXBpcy9yZXNpemUtb2JzZXJ2ZXInO1xuaW1wb3J0IHtUVUlfRkFMU0VfSEFORExFUn0gZnJvbSAnQHRhaWdhLXVpL2Nkay9jb25zdGFudHMnO1xuaW1wb3J0IHtUdWlQYW59IGZyb20gJ0B0YWlnYS11aS9jZGsvZGlyZWN0aXZlcy9wYW4nO1xuaW1wb3J0IHR5cGUge1R1aVpvb21FdmVudH0gZnJvbSAnQHRhaWdhLXVpL2Nkay9kaXJlY3RpdmVzL3pvb20nO1xuaW1wb3J0IHtUdWlab29tfSBmcm9tICdAdGFpZ2EtdWkvY2RrL2RpcmVjdGl2ZXMvem9vbSc7XG5pbXBvcnQge3R1aURyYWdBbmREcm9wRnJvbSwgdHVpVHlwZWRGcm9tRXZlbnR9IGZyb20gJ0B0YWlnYS11aS9jZGsvb2JzZXJ2YWJsZXMnO1xuaW1wb3J0IHt0dWlJbmplY3RFbGVtZW50fSBmcm9tICdAdGFpZ2EtdWkvY2RrL3V0aWxzL2RvbSc7XG5pbXBvcnQge3R1aUNsYW1wLCB0dWlSb3VuZH0gZnJvbSAnQHRhaWdhLXVpL2Nkay91dGlscy9tYXRoJztcbmltcG9ydCB7dHVpUHh9IGZyb20gJ0B0YWlnYS11aS9jZGsvdXRpbHMvbWlzY2VsbGFuZW91cyc7XG5pbXBvcnQge1R1aUJ1dHRvbn0gZnJvbSAnQHRhaWdhLXVpL2NvcmUvY29tcG9uZW50cy9idXR0b24nO1xuaW1wb3J0IHtUdWlIaW50fSBmcm9tICdAdGFpZ2EtdWkvY29yZS9kaXJlY3RpdmVzL2hpbnQnO1xuaW1wb3J0IHtUVUlfUFJFVklFV19JQ09OUywgVFVJX1BSRVZJRVdfVEVYVFN9IGZyb20gJ0B0YWlnYS11aS9raXQvdG9rZW5zJztcbmltcG9ydCB7QmVoYXZpb3JTdWJqZWN0LCBjb21iaW5lTGF0ZXN0LCBtYXAsIG1lcmdlLCBzdGFydFdpdGh9IGZyb20gJ3J4anMnO1xuXG5pbXBvcnQge1R1aVByZXZpZXdBY3Rpb259IGZyb20gJy4vcHJldmlldy1hY3Rpb24vcHJldmlldy1hY3Rpb24uZGlyZWN0aXZlJztcbmltcG9ydCB7VHVpUHJldmlld1pvb219IGZyb20gJy4vem9vbS9wcmV2aWV3LXpvb20uY29tcG9uZW50JztcblxuY29uc3QgSU5JVElBTF9TQ0FMRV9DT0VGID0gMC44O1xuY29uc3QgRU1QVFlfQ09PUkRJTkFURVM6IFtudW1iZXIsIG51bWJlcl0gPSBbMCwgMF07XG5jb25zdCBST1RBVElPTl9BTkdMRSA9IDkwO1xuXG5AQ29tcG9uZW50KHtcbiAgICBzdGFuZGFsb25lOiB0cnVlLFxuICAgIHNlbGVjdG9yOiAndHVpLXByZXZpZXcnLFxuICAgIGltcG9ydHM6IFtcbiAgICAgICAgQXN5bmNQaXBlLFxuICAgICAgICBOZ0lmLFxuICAgICAgICBUdWlCdXR0b24sXG4gICAgICAgIFR1aUhpbnQsXG4gICAgICAgIFR1aVBhbixcbiAgICAgICAgVHVpUHJldmlld0FjdGlvbixcbiAgICAgICAgVHVpUHJldmlld1pvb20sXG4gICAgICAgIFR1aVpvb20sXG4gICAgICAgIFdhTXV0YXRpb25PYnNlcnZlcixcbiAgICAgICAgV2FSZXNpemVPYnNlcnZlcixcbiAgICBdLFxuICAgIHRlbXBsYXRlVXJsOiAnLi9wcmV2aWV3LnRlbXBsYXRlLmh0bWwnLFxuICAgIHN0eWxlVXJsczogWycuL3ByZXZpZXcuc3R5bGUubGVzcyddLFxuICAgIGNoYW5nZURldGVjdGlvbjogQ2hhbmdlRGV0ZWN0aW9uU3RyYXRlZ3kuT25QdXNoLFxufSlcbmV4cG9ydCBjbGFzcyBUdWlQcmV2aWV3Q29tcG9uZW50IHtcbiAgICBwcml2YXRlIHJlYWRvbmx5IGVsID0gdHVpSW5qZWN0RWxlbWVudCgpO1xuXG4gICAgcHJvdGVjdGVkIG1pblpvb20gPSAxO1xuICAgIHByb3RlY3RlZCB3aWR0aCA9IDA7XG4gICAgcHJvdGVjdGVkIGhlaWdodCA9IDA7XG4gICAgcHJvdGVjdGVkIHJlYWRvbmx5IHRleHRzJCA9IGluamVjdChUVUlfUFJFVklFV19URVhUUyk7XG4gICAgcHJvdGVjdGVkIHJlYWRvbmx5IGljb25zID0gaW5qZWN0KFRVSV9QUkVWSUVXX0lDT05TKTtcbiAgICBwcm90ZWN0ZWQgcmVhZG9ubHkgY2RyID0gaW5qZWN0KENoYW5nZURldGVjdG9yUmVmKTtcbiAgICBwcm90ZWN0ZWQgcmVhZG9ubHkgem9vbSQgPSBuZXcgQmVoYXZpb3JTdWJqZWN0PG51bWJlcj4odGhpcy5taW5ab29tKTtcbiAgICBwcm90ZWN0ZWQgcmVhZG9ubHkgcm90YXRpb24kID0gbmV3IEJlaGF2aW9yU3ViamVjdDxudW1iZXI+KDApO1xuICAgIHByb3RlY3RlZCByZWFkb25seSBjb29yZGluYXRlcyQgPSBuZXcgQmVoYXZpb3JTdWJqZWN0PHJlYWRvbmx5IFtudW1iZXIsIG51bWJlcl0+KFxuICAgICAgICBFTVBUWV9DT09SRElOQVRFUyxcbiAgICApO1xuXG4gICAgcHJvdGVjdGVkIHJlYWRvbmx5IHRyYW5zaXRpb25lZCQgPSBtZXJnZShcbiAgICAgICAgdHVpRHJhZ0FuZERyb3BGcm9tKHRoaXMuZWwpLnBpcGUobWFwKCh7c3RhZ2V9KSA9PiBzdGFnZSAhPT0gJ2NvbnRpbnVlcycpKSxcbiAgICAgICAgdHVpVHlwZWRGcm9tRXZlbnQodGhpcy5lbCwgJ3RvdWNobW92ZScsIHtcbiAgICAgICAgICAgIHBhc3NpdmU6IHRydWUsXG4gICAgICAgIH0pLnBpcGUobWFwKFRVSV9GQUxTRV9IQU5ETEVSKSksXG4gICAgICAgIHR1aVR5cGVkRnJvbUV2ZW50KHRoaXMuZWwsICd3aGVlbCcsIHtwYXNzaXZlOiB0cnVlfSkucGlwZShtYXAoVFVJX0ZBTFNFX0hBTkRMRVIpKSxcbiAgICApO1xuXG4gICAgcHJvdGVjdGVkIHJlYWRvbmx5IGN1cnNvciQgPSB0dWlEcmFnQW5kRHJvcEZyb20odGhpcy5lbCkucGlwZShcbiAgICAgICAgbWFwKCh7c3RhZ2V9KSA9PiAoc3RhZ2UgPT09ICdjb250aW51ZXMnID8gJ2dyYWJiaW5nJyA6ICdpbml0aWFsJykpLFxuICAgICAgICBzdGFydFdpdGgoJ2luaXRpYWwnKSxcbiAgICApO1xuXG4gICAgcHJvdGVjdGVkIHJlYWRvbmx5IHdyYXBwZXJUcmFuc2Zvcm0kID0gY29tYmluZUxhdGVzdChbXG4gICAgICAgIHRoaXMuY29vcmRpbmF0ZXMkLnBpcGUobWFwKChbeCwgeV0pID0+IGAke3R1aVB4KHgpfSwgJHt0dWlQeCh5KX1gKSksXG4gICAgICAgIHRoaXMuem9vbSQsXG4gICAgICAgIHRoaXMucm90YXRpb24kLFxuICAgIF0pLnBpcGUoXG4gICAgICAgIG1hcChcbiAgICAgICAgICAgIChbdHJhbnNsYXRlLCB6b29tLCByb3RhdGlvbl0pID0+XG4gICAgICAgICAgICAgICAgYHRyYW5zbGF0ZSgke3RyYW5zbGF0ZX0pIHNjYWxlKCR7em9vbX0pIHJvdGF0ZSgke3JvdGF0aW9ufWRlZylgLFxuICAgICAgICApLFxuICAgICk7XG5cbiAgICBASW5wdXQoKVxuICAgIHB1YmxpYyB6b29tYWJsZSA9IHRydWU7XG5cbiAgICBASW5wdXQoKVxuICAgIHB1YmxpYyByb3RhdGFibGUgPSBmYWxzZTtcblxuICAgIHByb3RlY3RlZCByb3RhdGUoKTogdm9pZCB7XG4gICAgICAgIHRoaXMucm90YXRpb24kLm5leHQodGhpcy5yb3RhdGlvbiQudmFsdWUgLSBST1RBVElPTl9BTkdMRSk7XG4gICAgfVxuXG4gICAgcHJvdGVjdGVkIG9uUGFuKGRlbHRhOiByZWFkb25seSBbbnVtYmVyLCBudW1iZXJdKTogdm9pZCB7XG4gICAgICAgIHRoaXMuY29vcmRpbmF0ZXMkLm5leHQoXG4gICAgICAgICAgICB0aGlzLmdldEd1YXJkZWRDb29yZGluYXRlcyhcbiAgICAgICAgICAgICAgICB0aGlzLmNvb3JkaW5hdGVzJC52YWx1ZVswXSArIGRlbHRhWzBdLFxuICAgICAgICAgICAgICAgIHRoaXMuY29vcmRpbmF0ZXMkLnZhbHVlWzFdICsgZGVsdGFbMV0sXG4gICAgICAgICAgICApLFxuICAgICAgICApO1xuICAgIH1cblxuICAgIHByb3RlY3RlZCBvbk11dGF0aW9uKGNvbnRlbnRXcmFwcGVyOiBIVE1MRWxlbWVudCk6IHZvaWQge1xuICAgICAgICBjb25zdCB7Y2xpZW50V2lkdGgsIGNsaWVudEhlaWdodH0gPSBjb250ZW50V3JhcHBlcjtcblxuICAgICAgICB0aGlzLnJlZnJlc2goY2xpZW50V2lkdGgsIGNsaWVudEhlaWdodCk7XG4gICAgfVxuXG4gICAgcHJvdGVjdGVkIG9uWm9vbSh7Y2xpZW50WCwgY2xpZW50WSwgZGVsdGF9OiBUdWlab29tRXZlbnQpOiB2b2lkIHtcbiAgICAgICAgaWYgKHRoaXMuem9vbWFibGUpIHtcbiAgICAgICAgICAgIHRoaXMucHJvY2Vzc1pvb20oY2xpZW50WCwgY2xpZW50WSwgZGVsdGEpO1xuICAgICAgICB9XG4gICAgfVxuXG4gICAgcHJvdGVjdGVkIG9uUmVzaXplKFtlbnRyeV06IHJlYWRvbmx5IFJlc2l6ZU9ic2VydmVyRW50cnlbXSk6IHZvaWQge1xuICAgICAgICBpZiAoZW50cnk/LmNvbnRlbnRSZWN0KSB7XG4gICAgICAgICAgICB0aGlzLnJlZnJlc2goZW50cnkuY29udGVudFJlY3Qud2lkdGgsIGVudHJ5LmNvbnRlbnRSZWN0LmhlaWdodCk7XG4gICAgICAgICAgICB0aGlzLmNkci5kZXRlY3RDaGFuZ2VzKCk7XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICBwcm90ZWN0ZWQgcmVzZXQoKTogdm9pZCB7XG4gICAgICAgIHRoaXMuem9vbSQubmV4dCh0aGlzLm1pblpvb20pO1xuICAgICAgICB0aGlzLmNvb3JkaW5hdGVzJC5uZXh0KEVNUFRZX0NPT1JESU5BVEVTKTtcbiAgICB9XG5cbiAgICBwcm90ZWN0ZWQgc2V0Wm9vbSh6b29tOiBudW1iZXIpOiB2b2lkIHtcbiAgICAgICAgdGhpcy56b29tJC5uZXh0KHpvb20pO1xuICAgICAgICBjb25zdCBbeCwgeV0gPSB0aGlzLmNvb3JkaW5hdGVzJC52YWx1ZTtcblxuICAgICAgICB0aGlzLmNvb3JkaW5hdGVzJC5uZXh0KHRoaXMuZ2V0R3VhcmRlZENvb3JkaW5hdGVzKHgsIHkpKTtcbiAgICB9XG5cbiAgICBwcml2YXRlIGdldCBvZmZzZXRzKCk6IHtvZmZzZXRYOiBudW1iZXI7IG9mZnNldFk6IG51bWJlcn0ge1xuICAgICAgICBjb25zdCBvZmZzZXRYID0gKCh0aGlzLnpvb20kLnZhbHVlIC0gdGhpcy5taW5ab29tKSAqIHRoaXMud2lkdGgpIC8gMjtcbiAgICAgICAgY29uc3Qgb2Zmc2V0WSA9ICgodGhpcy56b29tJC52YWx1ZSAtIHRoaXMubWluWm9vbSkgKiB0aGlzLmhlaWdodCkgLyAyO1xuXG4gICAgICAgIHJldHVybiB7b2Zmc2V0WCwgb2Zmc2V0WX07XG4gICAgfVxuXG4gICAgcHJpdmF0ZSBjYWxjdWxhdGVNaW5ab29tKFxuICAgICAgICBjb250ZW50SGVpZ2h0OiBudW1iZXIsXG4gICAgICAgIGNvbnRlbnRXaWR0aDogbnVtYmVyLFxuICAgICAgICBib3hIZWlnaHQ6IG51bWJlcixcbiAgICAgICAgYm94V2lkdGg6IG51bWJlcixcbiAgICApOiBudW1iZXIge1xuICAgICAgICBjb25zdCBiaWdTaXplID1cbiAgICAgICAgICAgIGNvbnRlbnRIZWlnaHQgPiBib3hIZWlnaHQgKiBJTklUSUFMX1NDQUxFX0NPRUYgfHxcbiAgICAgICAgICAgIGNvbnRlbnRXaWR0aCA+IGJveFdpZHRoICogSU5JVElBTF9TQ0FMRV9DT0VGO1xuICAgICAgICBjb25zdCB7Y2xpZW50SGVpZ2h0LCBjbGllbnRXaWR0aH0gPSB0aGlzLmVsO1xuXG4gICAgICAgIHJldHVybiBiaWdTaXplXG4gICAgICAgICAgICA/IHR1aVJvdW5kKFxuICAgICAgICAgICAgICAgICAgTWF0aC5taW4oXG4gICAgICAgICAgICAgICAgICAgICAgKGNsaWVudEhlaWdodCAqIElOSVRJQUxfU0NBTEVfQ09FRikgLyBjb250ZW50SGVpZ2h0LFxuICAgICAgICAgICAgICAgICAgICAgIChjbGllbnRXaWR0aCAqIElOSVRJQUxfU0NBTEVfQ09FRikgLyBjb250ZW50V2lkdGgsXG4gICAgICAgICAgICAgICAgICApLFxuICAgICAgICAgICAgICAgICAgMixcbiAgICAgICAgICAgICAgKVxuICAgICAgICAgICAgOiAxO1xuICAgIH1cblxuICAgIHByaXZhdGUgcmVmcmVzaCh3aWR0aDogbnVtYmVyLCBoZWlnaHQ6IG51bWJlcik6IHZvaWQge1xuICAgICAgICB0aGlzLndpZHRoID0gd2lkdGg7XG4gICAgICAgIHRoaXMuaGVpZ2h0ID0gaGVpZ2h0O1xuICAgICAgICB0aGlzLm1pblpvb20gPSB0aGlzLmNhbGN1bGF0ZU1pblpvb20oXG4gICAgICAgICAgICBoZWlnaHQsXG4gICAgICAgICAgICB3aWR0aCxcbiAgICAgICAgICAgIHRoaXMuZWwuY2xpZW50SGVpZ2h0LFxuICAgICAgICAgICAgdGhpcy5lbC5jbGllbnRXaWR0aCxcbiAgICAgICAgKTtcbiAgICAgICAgdGhpcy56b29tJC5uZXh0KHRoaXMubWluWm9vbSk7XG4gICAgICAgIHRoaXMuY29vcmRpbmF0ZXMkLm5leHQoRU1QVFlfQ09PUkRJTkFURVMpO1xuICAgICAgICB0aGlzLnJvdGF0aW9uJC5uZXh0KDApO1xuICAgIH1cblxuICAgIHByaXZhdGUgcHJvY2Vzc1pvb20oY2xpZW50WDogbnVtYmVyLCBjbGllbnRZOiBudW1iZXIsIGRlbHRhOiBudW1iZXIpOiB2b2lkIHtcbiAgICAgICAgY29uc3Qgb2xkU2NhbGUgPSB0aGlzLnpvb20kLnZhbHVlO1xuICAgICAgICBjb25zdCBuZXdTY2FsZSA9IHR1aUNsYW1wKG9sZFNjYWxlICsgZGVsdGEsIHRoaXMubWluWm9vbSwgMik7XG5cbiAgICAgICAgY29uc3QgY2VudGVyID0gdGhpcy5nZXRTY2FsZUNlbnRlcihcbiAgICAgICAgICAgIHtjbGllbnRYLCBjbGllbnRZfSxcbiAgICAgICAgICAgIHRoaXMuY29vcmRpbmF0ZXMkLnZhbHVlLFxuICAgICAgICAgICAgdGhpcy56b29tJC52YWx1ZSxcbiAgICAgICAgKTtcblxuICAgICAgICBjb25zdCBtb3ZlWCA9IGNlbnRlclswXSAqIG9sZFNjYWxlIC0gY2VudGVyWzBdICogbmV3U2NhbGU7XG4gICAgICAgIGNvbnN0IG1vdmVZID0gY2VudGVyWzFdICogb2xkU2NhbGUgLSBjZW50ZXJbMV0gKiBuZXdTY2FsZTtcblxuICAgICAgICB0aGlzLnpvb20kLm5leHQobmV3U2NhbGUpO1xuICAgICAgICB0aGlzLmNvb3JkaW5hdGVzJC5uZXh0KFxuICAgICAgICAgICAgdGhpcy5nZXRHdWFyZGVkQ29vcmRpbmF0ZXMoXG4gICAgICAgICAgICAgICAgdGhpcy5jb29yZGluYXRlcyQudmFsdWVbMF0gKyBtb3ZlWCxcbiAgICAgICAgICAgICAgICB0aGlzLmNvb3JkaW5hdGVzJC52YWx1ZVsxXSArIG1vdmVZLFxuICAgICAgICAgICAgKSxcbiAgICAgICAgKTtcbiAgICB9XG5cbiAgICBwcml2YXRlIGdldEd1YXJkZWRDb29yZGluYXRlcyh4OiBudW1iZXIsIHk6IG51bWJlcik6IHJlYWRvbmx5IFtudW1iZXIsIG51bWJlcl0ge1xuICAgICAgICBjb25zdCB7b2Zmc2V0WCwgb2Zmc2V0WX0gPSB0aGlzLm9mZnNldHM7XG5cbiAgICAgICAgcmV0dXJuIFt0dWlDbGFtcCh4LCAtb2Zmc2V0WCwgb2Zmc2V0WCksIHR1aUNsYW1wKHksIC1vZmZzZXRZLCBvZmZzZXRZKV07XG4gICAgfVxuXG4gICAgcHJpdmF0ZSBnZXRTY2FsZUNlbnRlcihcbiAgICAgICAge2NsaWVudFgsIGNsaWVudFl9OiB7Y2xpZW50WDogbnVtYmVyOyBjbGllbnRZOiBudW1iZXJ9LFxuICAgICAgICBbeCwgeV06IHJlYWRvbmx5IFtudW1iZXIsIG51bWJlcl0sXG4gICAgICAgIHNjYWxlOiBudW1iZXIsXG4gICAgKTogW251bWJlciwgbnVtYmVyXSB7XG4gICAgICAgIHJldHVybiBbXG4gICAgICAgICAgICAoY2xpZW50WCAtIHggLSB0aGlzLmVsLm9mZnNldFdpZHRoIC8gMikgLyBzY2FsZSxcbiAgICAgICAgICAgIChjbGllbnRZIC0geSAtIHRoaXMuZWwub2Zmc2V0SGVpZ2h0IC8gMikgLyBzY2FsZSxcbiAgICAgICAgXTtcbiAgICB9XG59XG4iLCI8bmctY29udGFpbmVyICpuZ0lmPVwidGV4dHMkIHwgYXN5bmMgYXMgdGV4dHNcIj5cbiAgICA8c2VjdGlvblxuICAgICAgICAjY29udGVudFdyYXBwZXJcbiAgICAgICAgYXR0cmlidXRlRmlsdGVyPVwic3JjXCJcbiAgICAgICAgY2hhcmFjdGVyRGF0YVxuICAgICAgICBjaGlsZExpc3RcbiAgICAgICAgc3VidHJlZVxuICAgICAgICBjbGFzcz1cInQtd3JhcHBlclwiXG4gICAgICAgIFtjbGFzcy50LW5vdC1pbnRlcmFjdGl2ZS1jb250ZW50XT1cInpvb21hYmxlXCJcbiAgICAgICAgW2NsYXNzLnQtdHJhbnNpdGl2ZV09XCJ0cmFuc2l0aW9uZWQkIHwgYXN5bmNcIlxuICAgICAgICBbc3R5bGUuY3Vyc29yXT1cImN1cnNvciQgfCBhc3luY1wiXG4gICAgICAgIFtzdHlsZS50cmFuc2Zvcm1dPVwid3JhcHBlclRyYW5zZm9ybSQgfCBhc3luY1wiXG4gICAgICAgICh0dWlQYW4pPVwib25QYW4oJGV2ZW50KVwiXG4gICAgICAgICh0dWlab29tKT1cIm9uWm9vbSgkZXZlbnQpXCJcbiAgICAgICAgKHdhTXV0YXRpb25PYnNlcnZlcik9XCJvbk11dGF0aW9uKGNvbnRlbnRXcmFwcGVyKVwiXG4gICAgICAgICh3YVJlc2l6ZU9ic2VydmVyKT1cIm9uUmVzaXplKCRldmVudClcIlxuICAgID5cbiAgICAgICAgPG5nLWNvbnRlbnQgLz5cbiAgICA8L3NlY3Rpb24+XG5cbiAgICA8aGVhZGVyIGNsYXNzPVwidC1oZWFkZXJcIj5cbiAgICAgICAgPGRpdiBjbGFzcz1cInQtdGl0bGVcIj5cbiAgICAgICAgICAgIDxuZy1jb250ZW50IHNlbGVjdD1cInR1aS1wcmV2aWV3LXRpdGxlXCIgLz5cbiAgICAgICAgPC9kaXY+XG5cbiAgICAgICAgPG5nLWNvbnRlbnQgc2VsZWN0PVwidHVpLXByZXZpZXctcGFnaW5hdGlvblwiIC8+XG5cbiAgICAgICAgPGRpdiBjbGFzcz1cInQtYWN0aW9uc1wiPlxuICAgICAgICAgICAgPG5nLWNvbnRlbnQgc2VsZWN0PVwiW3R1aVByZXZpZXdBY3Rpb25dXCIgLz5cbiAgICAgICAgPC9kaXY+XG4gICAgPC9oZWFkZXI+XG5cbiAgICA8Zm9vdGVyIGNsYXNzPVwidC1mb290ZXJcIj5cbiAgICAgICAgPGJ1dHRvblxuICAgICAgICAgICAgKm5nSWY9XCJyb3RhdGFibGVcIlxuICAgICAgICAgICAgdHVpSGludEFwcGVhcmFuY2U9XCJkYXJrXCJcbiAgICAgICAgICAgIHR1aUhpbnREZXNjcmliZVxuICAgICAgICAgICAgdHVpSGludERpcmVjdGlvbj1cInRvcC1yaWdodFwiXG4gICAgICAgICAgICB0dWlJY29uQnV0dG9uXG4gICAgICAgICAgICB0dWlQcmV2aWV3QWN0aW9uXG4gICAgICAgICAgICB0eXBlPVwiYnV0dG9uXCJcbiAgICAgICAgICAgIGNsYXNzPVwidC1yb3RhdGUtYnV0dG9uXCJcbiAgICAgICAgICAgIFtpY29uU3RhcnRdPVwiaWNvbnMucm90YXRlXCJcbiAgICAgICAgICAgIFt0dWlIaW50XT1cInRleHRzLnJvdGF0ZVwiXG4gICAgICAgICAgICAoY2xpY2spPVwicm90YXRlKClcIlxuICAgICAgICA+PC9idXR0b24+XG5cbiAgICAgICAgPHR1aS1wcmV2aWV3LXpvb21cbiAgICAgICAgICAgICpuZ0lmPVwiem9vbWFibGVcIlxuICAgICAgICAgICAgW21pbl09XCJtaW5ab29tXCJcbiAgICAgICAgICAgIFt2YWx1ZV09XCIoem9vbSQgfCBhc3luYykgfHwgMVwiXG4gICAgICAgICAgICAocmVzZXQpPVwicmVzZXQoKVwiXG4gICAgICAgICAgICAodmFsdWVDaGFuZ2UpPVwic2V0Wm9vbSgkZXZlbnQpXCJcbiAgICAgICAgLz5cbiAgICA8L2Zvb3Rlcj5cbjwvbmctY29udGFpbmVyPlxuIl19