UNPKG

@taiga-ui/kit

Version:

Taiga UI Angular main components kit

213 lines 40.3 kB
import { AsyncPipe, NgIf } from '@angular/common'; import { ChangeDetectionStrategy, Component, ElementRef, EventEmitter, inject, Input, Output, ViewChildren, } from '@angular/core'; import { EMPTY_QUERY } from '@taiga-ui/cdk/constants'; import { TuiLet } from '@taiga-ui/cdk/directives/let'; import { TuiRepeatTimes } from '@taiga-ui/cdk/directives/repeat-times'; import { tuiInjectElement } from '@taiga-ui/cdk/utils/dom'; import { tuiIsNativeFocusedIn } from '@taiga-ui/cdk/utils/focus'; import { tuiClamp } from '@taiga-ui/cdk/utils/math'; import { TuiButton } from '@taiga-ui/core/components/button'; import { TUI_SPIN_ICONS } from '@taiga-ui/core/tokens'; import { TUI_PAGINATION_TEXTS } from '@taiga-ui/kit/tokens'; import { PolymorpheusOutlet } from '@taiga-ui/polymorpheus'; import * as i0 from "@angular/core"; const DOTS_LENGTH = 1; const ACTIVE_ITEM_LENGTH = 1; class TuiPagination { constructor() { this.els = EMPTY_QUERY; this.el = tuiInjectElement(); this.texts$ = inject(TUI_PAGINATION_TEXTS); this.icons = inject(TUI_SPIN_ICONS); this.length = 1; this.focusable = true; this.size = 'l'; this.disabled = false; /** * Amount of visible pages around active page */ this.activePadding = 1; /** * Amount of visible pages at the edges */ this.sidePadding = 1; /** * Active page index */ this.index = 0; this.indexChange = new EventEmitter(); } get nativeFocusableElement() { if (this.disabled) { return null; } let activeElementIndex = 0; const { elementsLength } = this; for (let i = 0; i < elementsLength; i++) { const itemIndex = this.getItemIndexByElementIndex(i); if (itemIndex) { activeElementIndex++; } if (itemIndex === this.index) { break; } } return (this.els.find((_, index) => index === activeElementIndex)?.nativeElement ?? null); } get focused() { return tuiIsNativeFocusedIn(this.el); } get arrowIsDisabledLeft() { return this.index === 0; } get arrowIsDisabledRight() { return this.reverseIndex === 0; } /** * Number of items in a container. */ get elementsLength() { return this.itemsFit ? this.length : this.maxElementsLength; } get buttonSize() { return this.size === 'm' ? 'xs' : 's'; } elementIsFocusable(index) { return this.index === index && !this.focused; } /** * Get index by element index * @param elementIndex * @returns index or null (for '…') */ getItemIndexByElementIndex(elementIndex) { if (this.size === 's') { return elementIndex; } if (elementIndex < this.sidePadding) { return elementIndex; } if (elementIndex === this.sidePadding && this.hasCollapsedItems(this.index)) { return null; } const reverseElementIndex = this.lastElementIndex - elementIndex; if (reverseElementIndex === this.sidePadding && this.hasCollapsedItems(this.reverseIndex)) { return null; } if (reverseElementIndex < this.sidePadding) { return this.lastIndex - reverseElementIndex; } const computedIndex = this.index - this.maxHalfLength + elementIndex; return tuiClamp(computedIndex, elementIndex, this.lastIndex - reverseElementIndex); } getElementMode(index) { const fallback = this.size === 's' ? 'secondary' : 'flat'; return this.index === index ? 'primary' : fallback; } onElementClick(index) { this.updateIndex(index); } onElementKeyDownArrowLeft(element) { if (element === this.els.first.nativeElement) { return; } const previous = this.els.find((_, index, array) => array[index + 1]?.nativeElement === element); previous?.nativeElement.focus(); } onElementKeyDownArrowRight(element) { if (element === this.els.last.nativeElement) { return; } const next = this.els.find((_, index, array) => array[index - 1]?.nativeElement === element); next?.nativeElement.focus(); } onArrowClick(direction) { this.tryChangeTo(direction); this.focusActive(); } /** * Active index from the end */ get reverseIndex() { return this.lastIndex - this.index; } /** * Max number of elements in half (not counting the middle one). */ get maxHalfLength() { return this.sidePadding + DOTS_LENGTH + this.activePadding; } /** * Is there '...' anywhere */ get itemsFit() { return this.length <= this.maxElementsLength; } /** * Max number of elements */ get maxElementsLength() { return this.maxHalfLength * 2 + ACTIVE_ITEM_LENGTH; } get lastIndex() { return this.length - 1; } get lastElementIndex() { return this.elementsLength - 1; } /** * Are there collapsed items at that index * @param index * @returns there are collapsed items */ hasCollapsedItems(index) { return !this.itemsFit && index > this.maxHalfLength; } tryChangeTo(direction) { this.updateIndex(tuiClamp(this.index + (direction === 'right' ? 1 : -1), 0, this.lastIndex)); } focusActive() { const { nativeFocusableElement } = this; if (nativeFocusableElement) { nativeFocusableElement.focus(); } } updateIndex(index) { if (this.index === index) { return; } this.index = index; this.indexChange.emit(index); } static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: TuiPagination, deps: [], target: i0.ɵɵFactoryTarget.Component }); } static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "16.2.12", type: TuiPagination, isStandalone: true, selector: "tui-pagination", inputs: { length: "length", focusable: "focusable", size: "size", disabled: "disabled", activePadding: "activePadding", sidePadding: "sidePadding", content: "content", index: "index" }, outputs: { indexChange: "indexChange" }, viewQueries: [{ propertyName: "els", predicate: ["element"], descendants: true, read: ElementRef }], ngImport: i0, template: "<div class=\"t-content\">\n <ng-container *ngIf=\"size !== 's'; else smallButtons\">\n <ng-container *ngIf=\"texts$ | async as texts\">\n <button\n appearance=\"flat\"\n tabIndex=\"-1\"\n tuiIconButton\n type=\"button\"\n class=\"t-button\"\n [disabled]=\"arrowIsDisabledLeft\"\n [iconStart]=\"icons.decrement\"\n [size]=\"buttonSize\"\n (click)=\"onArrowClick('left')\"\n (mousedown.zoneless.prevent)=\"(0)\"\n >\n {{ texts[0] }}\n </button>\n <ng-container *tuiRepeatTimes=\"let elementIndex of elementsLength\">\n <ng-container *tuiLet=\"getItemIndexByElementIndex(elementIndex) as index\">\n <button\n *ngIf=\"index !== null; else dotsTemplate\"\n #element\n automation-id=\"tui-pagination__element\"\n tuiButton\n type=\"button\"\n class=\"t-button\"\n [appearance]=\"getElementMode(index)\"\n [disabled]=\"disabled\"\n [size]=\"buttonSize\"\n [tabIndex]=\"elementIsFocusable(index) ? 0 : -1\"\n (click)=\"onElementClick(index)\"\n (keydown.arrowLeft.prevent)=\"onElementKeyDownArrowLeft(element)\"\n (keydown.arrowRight.prevent)=\"onElementKeyDownArrowRight(element)\"\n >\n <ng-container *polymorpheusOutlet=\"content || index + 1 as text; context: {$implicit: index}\">\n {{ text }}\n </ng-container>\n </button>\n </ng-container>\n </ng-container>\n <button\n appearance=\"flat\"\n tabIndex=\"-1\"\n tuiIconButton\n type=\"button\"\n class=\"t-button\"\n [disabled]=\"arrowIsDisabledRight\"\n [iconStart]=\"icons.increment\"\n [size]=\"buttonSize\"\n (click)=\"onArrowClick('right')\"\n (mousedown.zoneless.prevent)=\"(0)\"\n >\n {{ texts[1] }}\n </button>\n </ng-container>\n </ng-container>\n <ng-template #smallButtons>\n <button\n *tuiRepeatTimes=\"let indexItem of length\"\n #element\n tuiButton\n type=\"button\"\n class=\"t-button t-button_small\"\n [appearance]=\"getElementMode(indexItem)\"\n [disabled]=\"disabled\"\n [tabIndex]=\"elementIsFocusable(indexItem) ? 0 : -1\"\n (click)=\"onElementClick(indexItem)\"\n (keydown.arrowLeft.prevent)=\"onElementKeyDownArrowLeft(element)\"\n (keydown.arrowRight.prevent)=\"onElementKeyDownArrowRight(element)\"\n >\n {{ indexItem + 1 }}\n </button>\n </ng-template>\n <ng-template #dotsTemplate>\n <div\n automation-id=\"tui-pagination__element\"\n class=\"t-dots\"\n [class.t-dots_small]=\"size === 'm'\"\n ></div>\n </ng-template>\n</div>\n", styles: [":host{display:block;font:var(--tui-font-text-s);color:var(--tui-text-primary);text-align:center}.t-content{display:flex;justify-content:center}.t-button{margin:0 .125rem;flex-shrink:0}.t-button[tuiButton]:not(.t-button_small){min-inline-size:var(--tui-height-s);padding:0 .5rem}.t-button[tuiButton]:not(.t-button_small)[data-size=xs]{min-inline-size:var(--tui-height-xs);padding:0 .375rem}.t-button:first-child{transform:scaleX(var(--tui-inline));margin-inline-start:0}.t-button:last-child{transform:scaleX(var(--tui-inline));margin-inline-end:0}.t-button[data-size=xs]{min-inline-size:var(--tui-height-xs);padding:0 .375rem}.t-button.t-button.t-button_small{inline-size:.5rem;block-size:.5rem;font-size:0;padding:0;margin:0}.t-button.t-button.t-button_small:not(:first-child){margin-inline-start:.5rem}.t-dots{inline-size:var(--tui-height-s);block-size:var(--tui-height-s);line-height:var(--tui-height-s);margin:0 .125rem;flex-shrink:0;color:var(--tui-text-action);text-align:center;cursor:default}.t-dots_small{inline-size:var(--tui-height-xs);block-size:var(--tui-height-xs);line-height:var(--tui-height-xs)}.t-dots:before{content:\"\\2026\"}\n"], dependencies: [{ kind: "pipe", type: AsyncPipe, name: "async" }, { kind: "directive", type: NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: PolymorpheusOutlet, selector: "[polymorpheusOutlet]", inputs: ["polymorpheusOutlet", "polymorpheusOutletContext"] }, { kind: "directive", type: TuiButton, selector: "a[tuiButton],button[tuiButton],a[tuiIconButton],button[tuiIconButton]", inputs: ["size"] }, { kind: "directive", type: TuiLet, selector: "[tuiLet]", inputs: ["tuiLet"] }, { kind: "directive", type: TuiRepeatTimes, selector: "[tuiRepeatTimes][tuiRepeatTimesOf]", inputs: ["tuiRepeatTimesOf"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); } } export { TuiPagination }; i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: TuiPagination, decorators: [{ type: Component, args: [{ standalone: true, selector: 'tui-pagination', imports: [AsyncPipe, NgIf, PolymorpheusOutlet, TuiButton, TuiLet, TuiRepeatTimes], changeDetection: ChangeDetectionStrategy.OnPush, template: "<div class=\"t-content\">\n <ng-container *ngIf=\"size !== 's'; else smallButtons\">\n <ng-container *ngIf=\"texts$ | async as texts\">\n <button\n appearance=\"flat\"\n tabIndex=\"-1\"\n tuiIconButton\n type=\"button\"\n class=\"t-button\"\n [disabled]=\"arrowIsDisabledLeft\"\n [iconStart]=\"icons.decrement\"\n [size]=\"buttonSize\"\n (click)=\"onArrowClick('left')\"\n (mousedown.zoneless.prevent)=\"(0)\"\n >\n {{ texts[0] }}\n </button>\n <ng-container *tuiRepeatTimes=\"let elementIndex of elementsLength\">\n <ng-container *tuiLet=\"getItemIndexByElementIndex(elementIndex) as index\">\n <button\n *ngIf=\"index !== null; else dotsTemplate\"\n #element\n automation-id=\"tui-pagination__element\"\n tuiButton\n type=\"button\"\n class=\"t-button\"\n [appearance]=\"getElementMode(index)\"\n [disabled]=\"disabled\"\n [size]=\"buttonSize\"\n [tabIndex]=\"elementIsFocusable(index) ? 0 : -1\"\n (click)=\"onElementClick(index)\"\n (keydown.arrowLeft.prevent)=\"onElementKeyDownArrowLeft(element)\"\n (keydown.arrowRight.prevent)=\"onElementKeyDownArrowRight(element)\"\n >\n <ng-container *polymorpheusOutlet=\"content || index + 1 as text; context: {$implicit: index}\">\n {{ text }}\n </ng-container>\n </button>\n </ng-container>\n </ng-container>\n <button\n appearance=\"flat\"\n tabIndex=\"-1\"\n tuiIconButton\n type=\"button\"\n class=\"t-button\"\n [disabled]=\"arrowIsDisabledRight\"\n [iconStart]=\"icons.increment\"\n [size]=\"buttonSize\"\n (click)=\"onArrowClick('right')\"\n (mousedown.zoneless.prevent)=\"(0)\"\n >\n {{ texts[1] }}\n </button>\n </ng-container>\n </ng-container>\n <ng-template #smallButtons>\n <button\n *tuiRepeatTimes=\"let indexItem of length\"\n #element\n tuiButton\n type=\"button\"\n class=\"t-button t-button_small\"\n [appearance]=\"getElementMode(indexItem)\"\n [disabled]=\"disabled\"\n [tabIndex]=\"elementIsFocusable(indexItem) ? 0 : -1\"\n (click)=\"onElementClick(indexItem)\"\n (keydown.arrowLeft.prevent)=\"onElementKeyDownArrowLeft(element)\"\n (keydown.arrowRight.prevent)=\"onElementKeyDownArrowRight(element)\"\n >\n {{ indexItem + 1 }}\n </button>\n </ng-template>\n <ng-template #dotsTemplate>\n <div\n automation-id=\"tui-pagination__element\"\n class=\"t-dots\"\n [class.t-dots_small]=\"size === 'm'\"\n ></div>\n </ng-template>\n</div>\n", styles: [":host{display:block;font:var(--tui-font-text-s);color:var(--tui-text-primary);text-align:center}.t-content{display:flex;justify-content:center}.t-button{margin:0 .125rem;flex-shrink:0}.t-button[tuiButton]:not(.t-button_small){min-inline-size:var(--tui-height-s);padding:0 .5rem}.t-button[tuiButton]:not(.t-button_small)[data-size=xs]{min-inline-size:var(--tui-height-xs);padding:0 .375rem}.t-button:first-child{transform:scaleX(var(--tui-inline));margin-inline-start:0}.t-button:last-child{transform:scaleX(var(--tui-inline));margin-inline-end:0}.t-button[data-size=xs]{min-inline-size:var(--tui-height-xs);padding:0 .375rem}.t-button.t-button.t-button_small{inline-size:.5rem;block-size:.5rem;font-size:0;padding:0;margin:0}.t-button.t-button.t-button_small:not(:first-child){margin-inline-start:.5rem}.t-dots{inline-size:var(--tui-height-s);block-size:var(--tui-height-s);line-height:var(--tui-height-s);margin:0 .125rem;flex-shrink:0;color:var(--tui-text-action);text-align:center;cursor:default}.t-dots_small{inline-size:var(--tui-height-xs);block-size:var(--tui-height-xs);line-height:var(--tui-height-xs)}.t-dots:before{content:\"\\2026\"}\n"] }] }], propDecorators: { els: [{ type: ViewChildren, args: ['element', { read: ElementRef }] }], length: [{ type: Input }], focusable: [{ type: Input }], size: [{ type: Input }], disabled: [{ type: Input }], activePadding: [{ type: Input }], sidePadding: [{ type: Input }], content: [{ type: Input }], index: [{ type: Input }], indexChange: [{ type: Output }] } }); //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicGFnaW5hdGlvbi5jb21wb25lbnQuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi9wcm9qZWN0cy9raXQvY29tcG9uZW50cy9wYWdpbmF0aW9uL3BhZ2luYXRpb24uY29tcG9uZW50LnRzIiwiLi4vLi4vLi4vLi4vLi4vcHJvamVjdHMva2l0L2NvbXBvbmVudHMvcGFnaW5hdGlvbi9wYWdpbmF0aW9uLnRlbXBsYXRlLmh0bWwiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUFDLFNBQVMsRUFBRSxJQUFJLEVBQUMsTUFBTSxpQkFBaUIsQ0FBQztBQUNoRCxPQUFPLEVBQ0gsdUJBQXVCLEVBQ3ZCLFNBQVMsRUFDVCxVQUFVLEVBQ1YsWUFBWSxFQUNaLE1BQU0sRUFDTixLQUFLLEVBQ0wsTUFBTSxFQUVOLFlBQVksR0FDZixNQUFNLGVBQWUsQ0FBQztBQUN2QixPQUFPLEVBQUMsV0FBVyxFQUFDLE1BQU0seUJBQXlCLENBQUM7QUFDcEQsT0FBTyxFQUFDLE1BQU0sRUFBQyxNQUFNLDhCQUE4QixDQUFDO0FBQ3BELE9BQU8sRUFBQyxjQUFjLEVBQUMsTUFBTSx1Q0FBdUMsQ0FBQztBQUVyRSxPQUFPLEVBQUMsZ0JBQWdCLEVBQUMsTUFBTSx5QkFBeUIsQ0FBQztBQUN6RCxPQUFPLEVBQUMsb0JBQW9CLEVBQUMsTUFBTSwyQkFBMkIsQ0FBQztBQUMvRCxPQUFPLEVBQUMsUUFBUSxFQUFDLE1BQU0sMEJBQTBCLENBQUM7QUFDbEQsT0FBTyxFQUFDLFNBQVMsRUFBQyxNQUFNLGtDQUFrQyxDQUFDO0FBQzNELE9BQU8sRUFBQyxjQUFjLEVBQUMsTUFBTSx1QkFBdUIsQ0FBQztBQU9yRCxPQUFPLEVBQUMsb0JBQW9CLEVBQUMsTUFBTSxzQkFBc0IsQ0FBQztBQUMxRCxPQUFPLEVBQTJCLGtCQUFrQixFQUFDLE1BQU0sd0JBQXdCLENBQUM7O0FBRXBGLE1BQU0sV0FBVyxHQUFHLENBQUMsQ0FBQztBQUN0QixNQUFNLGtC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TSxJQUFJLFlBQ04sZ0JBQWdCLFdBQ2pCLENBQUMsU0FBUyxFQUFFLElBQUksRUFBRSxrQkFBa0IsRUFBRSxTQUFTLEVBQUUsTUFBTSxFQUFFLGNBQWMsQ0FBQyxtQkFHaEUsdUJBQXVCLENBQUMsTUFBTTs4QkFJOUIsR0FBRztzQkFEbkIsWUFBWTt1QkFBQyxTQUFTLEVBQUUsRUFBQyxJQUFJLEVBQUUsVUFBVSxFQUFDO2dCQVNwQyxNQUFNO3NCQURaLEtBQUs7Z0JBSUMsU0FBUztzQkFEZixLQUFLO2dCQUlDLElBQUk7c0JBRFYsS0FBSztnQkFJVSxRQUFRO3NCQUR2QixLQUFLO2dCQU9DLGFBQWE7c0JBRG5CLEtBQUs7Z0JBT0MsV0FBVztzQkFEakIsS0FBSztnQkFPQyxPQUFPO3NCQURiLEtBQUs7Z0JBT0MsS0FBSztzQkFEWCxLQUFLO2dCQUlVLFdBQVc7c0JBRDFCLE1BQU0iLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQge0FzeW5jUGlwZSwgTmdJZn0gZnJvbSAnQGFuZ3VsYXIvY29tbW9uJztcbmltcG9ydCB7XG4gICAgQ2hhbmdlRGV0ZWN0aW9uU3RyYXRlZ3ksXG4gICAgQ29tcG9uZW50LFxuICAgIEVsZW1lbnRSZWYsXG4gICAgRXZlbnRFbWl0dGVyLFxuICAgIGluamVjdCxcbiAgICBJbnB1dCxcbiAgICBPdXRwdXQsXG4gICAgdHlwZSBRdWVyeUxpc3QsXG4gICAgVmlld0NoaWxkcmVuLFxufSBmcm9tICdAYW5ndWxhci9jb3JlJztcbmltcG9ydCB7RU1QVFlfUVVFUll9IGZyb20gJ0B0YWlnYS11aS9jZGsvY29uc3RhbnRzJztcbmltcG9ydCB7VHVpTGV0fSBmcm9tICdAdGFpZ2EtdWkvY2RrL2RpcmVjdGl2ZXMvbGV0JztcbmltcG9ydCB7VHVpUmVwZWF0VGltZXN9IGZyb20gJ0B0YWlnYS11aS9jZGsvZGlyZWN0aXZlcy9yZXBlYXQtdGltZXMnO1xuaW1wb3J0IHt0eXBlIFR1aUNvbnRleHR9IGZyb20gJ0B0YWlnYS11aS9jZGsvdHlwZXMnO1xuaW1wb3J0IHt0dWlJbmplY3RFbGVtZW50fSBmcm9tICdAdGFpZ2EtdWkvY2RrL3V0aWxzL2RvbSc7XG5pbXBvcnQge3R1aUlzTmF0aXZlRm9jdXNlZElufSBmcm9tICdAdGFpZ2EtdWkvY2RrL3V0aWxzL2ZvY3VzJztcbmltcG9ydCB7dHVpQ2xhbXB9IGZyb20gJ0B0YWlnYS11aS9jZGsvdXRpbHMvbWF0aCc7XG5pbXBvcnQge1R1aUJ1dHRvbn0gZnJvbSAnQHRhaWdhLXVpL2NvcmUvY29tcG9uZW50cy9idXR0b24nO1xuaW1wb3J0IHtUVUlfU1BJTl9JQ09OU30gZnJvbSAnQHRhaWdhLXVpL2NvcmUvdG9rZW5zJztcbmltcG9ydCB7XG4gICAgdHlwZSBUdWlIb3Jpem9udGFsRGlyZWN0aW9uLFxuICAgIHR5cGUgVHVpU2l6ZUwsXG4gICAgdHlwZSBUdWlTaXplUyxcbiAgICB0eXBlIFR1aVNpemVYUyxcbn0gZnJvbSAnQHRhaWdhLXVpL2NvcmUvdHlwZXMnO1xuaW1wb3J0IHtUVUlfUEFHSU5BVElPTl9URVhUU30gZnJvbSAnQHRhaWdhLXVpL2tpdC90b2tlbnMnO1xuaW1wb3J0IHt0eXBlIFBvbHltb3JwaGV1c0NvbnRlbnQsIFBvbHltb3JwaGV1c091dGxldH0gZnJvbSAnQHRhaWdhLXVpL3BvbHltb3JwaGV1cyc7XG5cbmNvbnN0IERPVFNfTEVOR1RIID0gMTtcbmNvbnN0IEFDVElWRV9JVEVNX0xFTkdUSCA9IDE7XG5cbkBDb21wb25lbnQoe1xuICAgIHN0YW5kYWxvbmU6IHRydWUsXG4gICAgc2VsZWN0b3I6ICd0dWktcGFnaW5hdGlvbicsXG4gICAgaW1wb3J0czogW0FzeW5jUGlwZSwgTmdJZiwgUG9seW1vcnBoZXVzT3V0bGV0LCBUdWlCdXR0b24sIFR1aUxldCwgVHVpUmVwZWF0VGltZXNdLFxuICAgIHRlbXBsYXRlVXJsOiAnLi9wYWdpbmF0aW9uLnRlbXBsYXRlLmh0bWwnLFxuICAgIHN0eWxlVXJsczogWycuL3BhZ2luYXRpb24uc3R5bGUubGVzcyddLFxuICAgIGNoYW5nZURldGVjdGlvbjogQ2hhbmdlRGV0ZWN0aW9uU3RyYXRlZ3kuT25QdXNoLFxufSlcbmV4cG9ydCBjbGFzcyBUdWlQYWdpbmF0aW9uIHtcbiAgICBAVmlld0NoaWxkcmVuKCdlbGVtZW50Jywge3JlYWQ6IEVsZW1lbnRSZWZ9KVxuICAgIHByaXZhdGUgcmVhZG9ubHkgZWxzOiBRdWVyeUxpc3Q8RWxlbWVudFJlZjxIVE1MRWxlbWVudD4+ID0gRU1QVFlfUVVFUlk7XG5cbiAgICBwcml2YXRlIHJlYWRvbmx5IGVsID0gdHVpSW5qZWN0RWxlbWVudCgpO1xuXG4gICAgcHJvdGVjdGVkIHJlYWRvbmx5IHRleHRzJCA9IGluamVjdChUVUlfUEFHSU5BVElPTl9URVhUUyk7XG4gICAgcHJvdGVjdGVkIHJlYWRvbmx5IGljb25zID0gaW5qZWN0KFRVSV9TUElOX0lDT05TKTtcblxuICAgIEBJbnB1dCgpXG4gICAgcHVibGljIGxlbmd0aCA9IDE7XG5cbiAgICBASW5wdXQoKVxuICAgIHB1YmxpYyBmb2N1c2FibGUgPSB0cnVlO1xuXG4gICAgQElucHV0KClcbiAgICBwdWJsaWMgc2l6ZTogVHVpU2l6ZUwgfCBUdWlTaXplUyA9ICdsJztcblxuICAgIEBJbnB1dCgpXG4gICAgcHVibGljIHJlYWRvbmx5IGRpc2FibGVkID0gZmFsc2U7XG5cbiAgICAvKipcbiAgICAgKiBBbW91bnQgb2YgdmlzaWJsZSBwYWdlcyBhcm91bmQgYWN0aXZlIHBhZ2VcbiAgICAgKi9cbiAgICBASW5wdXQoKVxuICAgIHB1YmxpYyBhY3RpdmVQYWRkaW5nID0gMTtcblxuICAgIC8qKlxuICAgICAqIEFtb3VudCBvZiB2aXNpYmxlIHBhZ2VzIGF0IHRoZSBlZGdlc1xuICAgICAqL1xuICAgIEBJbnB1dCgpXG4gICAgcHVibGljIHNpZGVQYWRkaW5nID0gMTtcblxuICAgIC8qKlxuICAgICAqIEN1c3RvbWl6YXRpb24gZm9yIHBhZ2UgbnVtYmVyIGRpc3BsYXkuXG4gICAgICovXG4gICAgQElucHV0KClcbiAgICBwdWJsaWMgY29udGVudDogUG9seW1vcnBoZXVzQ29udGVudDxUdWlDb250ZXh0PG51bWJlcj4+O1xuXG4gICAgLyoqXG4gICAgICogQWN0aXZlIHBhZ2UgaW5kZXhcbiAgICAgKi9cbiAgICBASW5wdXQoKVxuICAgIHB1YmxpYyBpbmRleCA9IDA7XG5cbiAgICBAT3V0cHV0KClcbiAgICBwdWJsaWMgcmVhZG9ubHkgaW5kZXhDaGFuZ2UgPSBuZXcgRXZlbnRFbWl0dGVyPG51bWJlcj4oKTtcblxuICAgIHB1YmxpYyBnZXQgbmF0aXZlRm9jdXNhYmxlRWxlbWVudCgpOiBIVE1MRWxlbWVudCB8IG51bGwge1xuICAgICAgICBpZiAodGhpcy5kaXNhYmxlZCkge1xuICAgICAgICAgICAgcmV0dXJuIG51bGw7XG4gICAgICAgIH1cblxuICAgICAgICBsZXQgYWN0aXZlRWxlbWVudEluZGV4ID0gMDtcbiAgICAgICAgY29uc3Qge2VsZW1lbnRzTGVuZ3RofSA9IHRoaXM7XG5cbiAgICAgICAgZm9yIChsZXQgaSA9IDA7IGkgPCBlbGVtZW50c0xlbmd0aDsgaSsrKSB7XG4gICAgICAgICAgICBjb25zdCBpdGVtSW5kZXggPSB0aGlzLmdldEl0ZW1JbmRleEJ5RWxlbWVudEluZGV4KGkpO1xuXG4gICAgICAgICAgICBpZiAoaXRlbUluZGV4KSB7XG4gICAgICAgICAgICAgICAgYWN0aXZlRWxlbWVudEluZGV4Kys7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIGlmIChpdGVtSW5kZXggPT09IHRoaXMuaW5kZXgpIHtcbiAgICAgICAgICAgICAgICBicmVhaztcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuXG4gICAgICAgIHJldHVybiAoXG4gICAgICAgICAgICB0aGlzLmVscy5maW5kKChfLCBpbmRleCkgPT4gaW5kZXggPT09IGFjdGl2ZUVsZW1lbnRJbmRleCk/Lm5hdGl2ZUVsZW1lbnQgPz9cbiAgICAgICAgICAgIG51bGxcbiAgICAgICAgKTtcbiAgICB9XG5cbiAgICBwdWJsaWMgZ2V0IGZvY3VzZWQoKTogYm9vbGVhbiB7XG4gICAgICAgIHJldHVybiB0dWlJc05hdGl2ZUZvY3VzZWRJbih0aGlzLmVsKTtcbiAgICB9XG5cbiAgICBwdWJsaWMgZ2V0IGFycm93SXNEaXNhYmxlZExlZnQoKTogYm9vbGVhbiB7XG4gICAgICAgIHJldHVybiB0aGlzLmluZGV4ID09PSAwO1xuICAgIH1cblxuICAgIHB1YmxpYyBnZXQgYXJyb3dJc0Rpc2FibGVkUmlnaHQoKTogYm9vbGVhbiB7XG4gICAgICAgIHJldHVybiB0aGlzLnJldmVyc2VJbmRleCA9PT0gMDtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBOdW1iZXIgb2YgaXRlbXMgaW4gYSBjb250YWluZXIuXG4gICAgICovXG4gICAgcHJvdGVjdGVkIGdldCBlbGVtZW50c0xlbmd0aCgpOiBudW1iZXIge1xuICAgICAgICByZXR1cm4gdGhpcy5pdGVtc0ZpdCA/IHRoaXMubGVuZ3RoIDogdGhpcy5tYXhFbGVtZW50c0xlbmd0aDtcbiAgICB9XG5cbiAgICBwcm90ZWN0ZWQgZ2V0IGJ1dHRvblNpemUoKTogVHVpU2l6ZVhTIHtcbiAgICAgICAgcmV0dXJuIHRoaXMuc2l6ZSA9PT0gJ20nID8gJ3hzJyA6ICdzJztcbiAgICB9XG5cbiAgICBwcm90ZWN0ZWQgZWxlbWVudElzRm9jdXNhYmxlKGluZGV4OiBudW1iZXIpOiBib29sZWFuIHtcbiAgICAgICAgcmV0dXJuIHRoaXMuaW5kZXggPT09IGluZGV4ICYmICF0aGlzLmZvY3VzZWQ7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogR2V0IGluZGV4IGJ5IGVsZW1lbnQgaW5kZXhcbiAgICAgKiBAcGFyYW0gZWxlbWVudEluZGV4XG4gICAgICogQHJldHVybnMgaW5kZXggb3IgbnVsbCAoZm9yICfigKYnKVxuICAgICAqL1xuICAgIHByb3RlY3RlZCBnZXRJdGVtSW5kZXhCeUVsZW1lbnRJbmRleChlbGVtZW50SW5kZXg6IG51bWJlcik6IG51bWJlciB8IG51bGwge1xuICAgICAgICBpZiAodGhpcy5zaXplID09PSAncycpIHtcbiAgICAgICAgICAgIHJldHVybiBlbGVtZW50SW5kZXg7XG4gICAgICAgIH1cblxuICAgICAgICBpZiAoZWxlbWVudEluZGV4IDwgdGhpcy5zaWRlUGFkZGluZykge1xuICAgICAgICAgICAgcmV0dXJuIGVsZW1lbnRJbmRleDtcbiAgICAgICAgfVxuXG4gICAgICAgIGlmIChlbGVtZW50SW5kZXggPT09IHRoaXMuc2lkZVBhZGRpbmcgJiYgdGhpcy5oYXNDb2xsYXBzZWRJdGVtcyh0aGlzLmluZGV4KSkge1xuICAgICAgICAgICAgcmV0dXJuIG51bGw7XG4gICAgICAgIH1cblxuICAgICAgICBjb25zdCByZXZlcnNlRWxlbWVudEluZGV4ID0gdGhpcy5sYXN0RWxlbWVudEluZGV4IC0gZWxlbWVudEluZGV4O1xuXG4gICAgICAgIGlmIChcbiAgICAgICAgICAgIHJldmVyc2VFbGVtZW50SW5kZXggPT09IHRoaXMuc2lkZVBhZGRpbmcgJiZcbiAgICAgICAgICAgIHRoaXMuaGFzQ29sbGFwc2VkSXRlbXModGhpcy5yZXZlcnNlSW5kZXgpXG4gICAgICAgICkge1xuICAgICAgICAgICAgcmV0dXJuIG51bGw7XG4gICAgICAgIH1cblxuICAgICAgICBpZiAocmV2ZXJzZUVsZW1lbnRJbmRleCA8IHRoaXMuc2lkZVBhZGRpbmcpIHtcbiAgICAgICAgICAgIHJldHVybiB0aGlzLmxhc3RJbmRleCAtIHJldmVyc2VFbGVtZW50SW5kZXg7XG4gICAgICAgIH1cblxuICAgICAgICBjb25zdCBjb21wdXRlZEluZGV4ID0gdGhpcy5pbmRleCAtIHRoaXMubWF4SGFsZkxlbmd0aCArIGVsZW1lbnRJbmRleDtcblxuICAgICAgICByZXR1cm4gdHVpQ2xhbXAoXG4gICAgICAgICAgICBjb21wdXRlZEluZGV4LFxuICAgICAgICAgICAgZWxlbWVudEluZGV4LFxuICAgICAgICAgICAgdGhpcy5sYXN0SW5kZXggLSByZXZlcnNlRWxlbWVudEluZGV4LFxuICAgICAgICApO1xuICAgIH1cblxuICAgIHByb3RlY3RlZCBnZXRFbGVtZW50TW9kZShpbmRleDogbnVtYmVyKTogc3RyaW5nIHtcbiAgICAgICAgY29uc3QgZmFsbGJhY2sgPSB0aGlzLnNpemUgPT09ICdzJyA/ICdzZWNvbmRhcnknIDogJ2ZsYXQnO1xuXG4gICAgICAgIHJldHVybiB0aGlzLmluZGV4ID09PSBpbmRleCA/ICdwcmltYXJ5JyA6IGZhbGxiYWNrO1xuICAgIH1cblxuICAgIHByb3RlY3RlZCBvbkVsZW1lbnRDbGljayhpbmRleDogbnVtYmVyKTogdm9pZCB7XG4gICAgICAgIHRoaXMudXBkYXRlSW5kZXgoaW5kZXgpO1xuICAgIH1cblxuICAgIHByb3RlY3RlZCBvbkVsZW1lbnRLZXlEb3duQXJyb3dMZWZ0KGVsZW1lbnQ6IEhUTUxFbGVtZW50KTogdm9pZCB7XG4gICAgICAgIGlmIChlbGVtZW50ID09PSB0aGlzLmVscy5maXJzdC5uYXRpdmVFbGVtZW50KSB7XG4gICAgICAgICAgICByZXR1cm47XG4gICAgICAgIH1cblxuICAgICAgICBjb25zdCBwcmV2aW91cyA9IHRoaXMuZWxzLmZpbmQoXG4gICAgICAgICAgICAoXywgaW5kZXgsIGFycmF5KSA9PiBhcnJheVtpbmRleCArIDFdPy5uYXRpdmVFbGVtZW50ID09PSBlbGVtZW50LFxuICAgICAgICApO1xuXG4gICAgICAgIHByZXZpb3VzPy5uYXRpdmVFbGVtZW50LmZvY3VzKCk7XG4gICAgfVxuXG4gICAgcHJvdGVjdGVkIG9uRWxlbWVudEtleURvd25BcnJvd1JpZ2h0KGVsZW1lbnQ6IEhUTUxFbGVtZW50KTogdm9pZCB7XG4gICAgICAgIGlmIChlbGVtZW50ID09PSB0aGlzLmVscy5sYXN0Lm5hdGl2ZUVsZW1lbnQpIHtcbiAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgfVxuXG4gICAgICAgIGNvbnN0IG5leHQgPSB0aGlzLmVscy5maW5kKFxuICAgICAgICAgICAgKF8sIGluZGV4LCBhcnJheSkgPT4gYXJyYXlbaW5kZXggLSAxXT8ubmF0aXZlRWxlbWVudCA9PT0gZWxlbWVudCxcbiAgICAgICAgKTtcblxuICAgICAgICBuZXh0Py5uYXRpdmVFbGVtZW50LmZvY3VzKCk7XG4gICAgfVxuXG4gICAgcHJvdGVjdGVkIG9uQXJyb3dDbGljayhkaXJlY3Rpb246IFR1aUhvcml6b250YWxEaXJlY3Rpb24pOiB2b2lkIHtcbiAgICAgICAgdGhpcy50cnlDaGFuZ2VUbyhkaXJlY3Rpb24pO1xuICAgICAgICB0aGlzLmZvY3VzQWN0aXZlKCk7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogQWN0aXZlIGluZGV4IGZyb20gdGhlIGVuZFxuICAgICAqL1xuICAgIHByaXZhdGUgZ2V0IHJldmVyc2VJbmRleCgpOiBudW1iZXIge1xuICAgICAgICByZXR1cm4gdGhpcy5sYXN0SW5kZXggLSB0aGlzLmluZGV4O1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIE1heCBudW1iZXIgb2YgZWxlbWVudHMgaW4gaGFsZiAobm90IGNvdW50aW5nIHRoZSBtaWRkbGUgb25lKS5cbiAgICAgKi9cbiAgICBwcml2YXRlIGdldCBtYXhIYWxmTGVuZ3RoKCk6IG51bWJlciB7XG4gICAgICAgIHJldHVybiB0aGlzLnNpZGVQYWRkaW5nICsgRE9UU19MRU5HVEggKyB0aGlzLmFjdGl2ZVBhZGRpbmc7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogSXMgdGhlcmUgJy4uLicgYW55d2hlcmVcbiAgICAgKi9cbiAgICBwcml2YXRlIGdldCBpdGVtc0ZpdCgpOiBib29sZWFuIHtcbiAgICAgICAgcmV0dXJuIHRoaXMubGVuZ3RoIDw9IHRoaXMubWF4RWxlbWVudHNMZW5ndGg7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogTWF4IG51bWJlciBvZiBlbGVtZW50c1xuICAgICAqL1xuICAgIHByaXZhdGUgZ2V0IG1heEVsZW1lbnRzTGVuZ3RoKCk6IG51bWJlciB7XG4gICAgICAgIHJldHVybiB0aGlzLm1heEhhbGZMZW5ndGggKiAyICsgQUNUSVZFX0lURU1fTEVOR1RIO1xuICAgIH1cblxuICAgIHByaXZhdGUgZ2V0IGxhc3RJbmRleCgpOiBudW1iZXIge1xuICAgICAgICByZXR1cm4gdGhpcy5sZW5ndGggLSAxO1xuICAgIH1cblxuICAgIHByaXZhdGUgZ2V0IGxhc3RFbGVtZW50SW5kZXgoKTogbnVtYmVyIHtcbiAgICAgICAgcmV0dXJuIHRoaXMuZWxlbWVudHNMZW5ndGggLSAxO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIEFyZSB0aGVyZSBjb2xsYXBzZWQgaXRlbXMgYXQgdGhhdCBpbmRleFxuICAgICAqIEBwYXJhbSBpbmRleFxuICAgICAqIEByZXR1cm5zIHRoZXJlIGFyZSBjb2xsYXBzZWQgaXRlbXNcbiAgICAgKi9cbiAgICBwcml2YXRlIGhhc0NvbGxhcHNlZEl0ZW1zKGluZGV4OiBudW1iZXIpOiBib29sZWFuIHtcbiAgICAgICAgcmV0dXJuICF0aGlzLml0ZW1zRml0ICYmIGluZGV4ID4gdGhpcy5tYXhIYWxmTGVuZ3RoO1xuICAgIH1cblxuICAgIHByaXZhdGUgdHJ5Q2hhbmdlVG8oZGlyZWN0aW9uOiBUdWlIb3Jpem9udGFsRGlyZWN0aW9uKTogdm9pZCB7XG4gICAgICAgIHRoaXMudXBkYXRlSW5kZXgoXG4gICAgICAgICAgICB0dWlDbGFtcCh0aGlzLmluZGV4ICsgKGRpcmVjdGlvbiA9PT0gJ3JpZ2h0JyA/IDEgOiAtMSksIDAsIHRoaXMubGFzdEluZGV4KSxcbiAgICAgICAgKTtcbiAgICB9XG5cbiAgICBwcml2YXRlIGZvY3VzQWN0aXZlKCk6IHZvaWQge1xuICAgICAgICBjb25zdCB7bmF0aXZlRm9jdXNhYmxlRWxlbWVudH0gPSB0aGlzO1xuXG4gICAgICAgIGlmIChuYXRpdmVGb2N1c2FibGVFbGVtZW50KSB7XG4gICAgICAgICAgICBuYXRpdmVGb2N1c2FibGVFbGVtZW50LmZvY3VzKCk7XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICBwcml2YXRlIHVwZGF0ZUluZGV4KGluZGV4OiBudW1iZXIpOiB2b2lkIHtcbiAgICAgICAgaWYgKHRoaXMuaW5kZXggPT09IGluZGV4KSB7XG4gICAgICAgICAgICByZXR1cm47XG4gICAgICAgIH1cblxuICAgICAgICB0aGlzLmluZGV4ID0gaW5kZXg7XG4gICAgICAgIHRoaXMuaW5kZXhDaGFuZ2UuZW1pdChpbmRleCk7XG4gICAgfVxufVxuIiwiPGRpdiBjbGFzcz1cInQtY29udGVudFwiPlxuICAgIDxuZy1jb250YWluZXIgKm5nSWY9XCJzaXplICE9PSAncyc7IGVsc2Ugc21hbGxCdXR0b25zXCI+XG4gICAgICAgIDxuZy1jb250YWluZXIgKm5nSWY9XCJ0ZXh0cyQgfCBhc3luYyBhcyB0ZXh0c1wiPlxuICAgICAgICAgICAgPGJ1dHRvblxuICAgICAgICAgICAgICAgIGFwcGVhcmFuY2U9XCJmbGF0XCJcbiAgICAgICAgICAgICAgICB0YWJJbmRleD1cIi0xXCJcbiAgICAgICAgICAgICAgICB0dWlJY29uQnV0dG9uXG4gICAgICAgICAgICAgICAgdHlwZT1cImJ1dHRvblwiXG4gICAgICAgICAgICAgICAgY2xhc3M9XCJ0LWJ1dHRvblwiXG4gICAgICAgICAgICAgICAgW2Rpc2FibGVkXT1cImFycm93SXNEaXNhYmxlZExlZnRcIlxuICAgICAgICAgICAgICAgIFtpY29uU3RhcnRdPVwiaWNvbnMuZGVjcmVtZW50XCJcbiAgICAgICAgICAgICAgICBbc2l6ZV09XCJidXR0b25TaXplXCJcbiAgICAgICAgICAgICAgICAoY2xpY2spPVwib25BcnJvd0NsaWNrKCdsZWZ0JylcIlxuICAgICAgICAgICAgICAgIChtb3VzZWRvd24uem9uZWxlc3MucHJldmVudCk9XCIoMClcIlxuICAgICAgICAgICAgPlxuICAgICAgICAgICAgICAgIHt7IHRleHRzWzBdIH19XG4gICAgICAgICAgICA8L2J1dHRvbj5cbiAgICAgICAgICAgIDxuZy1jb250YWluZXIgKnR1aVJlcGVhdFRpbWVzPVwibGV0IGVsZW1lbnRJbmRleCBvZiBlbGVtZW50c0xlbmd0aFwiPlxuICAgICAgICAgICAgICAgIDxuZy1jb250YWluZXIgKnR1aUxldD1cImdldEl0ZW1JbmRleEJ5RWxlbWVudEluZGV4KGVsZW1lbnRJbmRleCkgYXMgaW5kZXhcIj5cbiAgICAgICAgICAgICAgICAgICAgPGJ1dHRvblxuICAgICAgICAgICAgICAgICAgICAgICAgKm5nSWY9XCJpbmRleCAhPT0gbnVsbDsgZWxzZSBkb3RzVGVtcGxhdGVcIlxuICAgICAgICAgICAgICAgICAgICAgICAgI2VsZW1lbnRcbiAgICAgICAgICAgICAgICAgICAgICAgIGF1dG9tYXRpb24taWQ9XCJ0dWktcGFnaW5hdGlvbl9fZWxlbWVudFwiXG4gICAgICAgICAgICAgICAgICAgICAgICB0dWlCdXR0b25cbiAgICAgICAgICAgICAgICAgICAgICAgIHR5cGU9XCJidXR0b25cIlxuICAgICAgICAgICAgICAgICAgICAgICAgY2xhc3M9XCJ0LWJ1dHRvblwiXG4gICAgICAgICAgICAgICAgICAgICAgICBbYXBwZWFyYW5jZV09XCJnZXRFbGVtZW50TW9kZShpbmRleClcIlxuICAgICAgICAgICAgICAgICAgICAgICAgW2Rpc2FibGVkXT1cImRpc2FibGVkXCJcbiAgICAgICAgICAgICAgICAgICAgICAgIFtzaXplXT1cImJ1dHRvblNpemVcIlxuICAgICAgICAgICAgICAgICAgICAgICAgW3RhYkluZGV4XT1cImVsZW1lbnRJc0ZvY3VzYWJsZShpbmRleCkgPyAwIDogLTFcIlxuICAgICAgICAgICAgICAgICAgICAgICAgKGNsaWNrKT1cIm9uRWxlbWVudENsaWNrKGluZGV4KVwiXG4gICAgICAgICAgICAgICAgICAgICAgICAoa2V5ZG93bi5hcnJvd0xlZnQucHJldmVudCk9XCJvbkVsZW1lbnRLZXlEb3duQXJyb3dMZWZ0KGVsZW1lbnQpXCJcbiAgICAgICAgICAgICAgICAgICAgICAgIChrZXlkb3duLmFycm93UmlnaHQucHJldmVudCk9XCJvbkVsZW1lbnRLZXlEb3duQXJyb3dSaWdodChlbGVtZW50KVwiXG4gICAgICAgICAgICAgICAgICAgID5cbiAgICAgICAgICAgICAgICAgICAgICAgIDxuZy1jb250YWluZXIgKnBvbHltb3JwaGV1c091dGxldD1cImNvbnRlbnQgfHwgaW5kZXggKyAxIGFzIHRleHQ7IGNvbnRleHQ6IHskaW1wbGljaXQ6IGluZGV4fVwiPlxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHt7IHRleHQgfX1cbiAgICAgICAgICAgICAgICAgICAgICAgIDwvbmctY29udGFpbmVyPlxuICAgICAgICAgICAgICAgICAgICA8L2J1dHRvbj5cbiAgICAgICAgICAgICAgICA8L25nLWNvbnRhaW5lcj5cbiAgICAgICAgICAgIDwvbmctY29udGFpbmVyPlxuICAgICAgICAgICAgPGJ1dHRvblxuICAgICAgICAgICAgICAgIGFwcGVhcmFuY2U9XCJmbGF0XCJcbiAgICAgICAgICAgICAgICB0YWJJbmRleD1cIi0xXCJcbiAgICAgICAgICAgICAgICB0dWlJY29uQnV0dG9uXG4gICAgICAgICAgICAgICAgdHlwZT1cImJ1dHRvblwiXG4gICAgICAgICAgICAgICAgY2xhc3M9XCJ0LWJ1dHRvblwiXG4gICAgICAgICAgICAgICAgW2Rpc2FibGVkXT1cImFycm93SXNEaXNhYmxlZFJpZ2h0XCJcbiAgICAgICAgICAgICAgICBbaWNvblN0YXJ0XT1cImljb25zLmluY3JlbWVudFwiXG4gICAgICAgICAgICAgICAgW3NpemVdPVwiYnV0dG9uU2l6ZVwiXG4gICAgICAgICAgICAgICAgKGNsaWNrKT1cIm9uQXJyb3dDbGljaygncmlnaHQnKVwiXG4gICAgICAgICAgICAgICAgKG1vdXNlZG93bi56b25lbGVzcy5wcmV2ZW50KT1cIigwKVwiXG4gICAgICAgICAgICA+XG4gICAgICAgICAgICAgICAge3sgdGV4dHNbMV0gfX1cbiAgICAgICAgICAgIDwvYnV0dG9uPlxuICAgICAgICA8L25nLWNvbnRhaW5lcj5cbiAgICA8L25nLWNvbnRhaW5lcj5cbiAgICA8bmctdGVtcGxhdGUgI3NtYWxsQnV0dG9ucz5cbiAgICAgICAgPGJ1dHRvblxuICAgICAgICAgICAgKnR1aVJlcGVhdFRpbWVzPVwibGV0IGluZGV4SXRlbSBvZiBsZW5ndGhcIlxuICAgICAgICAgICAgI2VsZW1lbnRcbiAgICAgICAgICAgIHR1aUJ1dHRvblxuICAgICAgICAgICAgdHlwZT1cImJ1dHRvblwiXG4gICAgICAgICAgICBjbGFzcz1cInQtYnV0dG9uIHQtYnV0dG9uX3NtYWxsXCJcbiAgICAgICAgICAgIFthcHBlYXJhbmNlXT1cImdldEVsZW1lbnRNb2RlKGluZGV4SXRlbSlcIlxuICAgICAgICAgICAgW2Rpc2FibGVkXT1cImRpc2FibGVkXCJcbiAgICAgICAgICAgIFt0YWJJbmRleF09XCJlbGVtZW50SXNGb2N1c2FibGUoaW5kZXhJdGVtKSA/IDAgOiAtMVwiXG4gICAgICAgICAgICAoY2xpY2spPVwib25FbGVtZW50Q2xpY2soaW5kZXhJdGVtKVwiXG4gICAgICAgICAgICAoa2V5ZG93bi5hcnJvd0xlZnQucHJldmVudCk9XCJvbkVsZW1lbnRLZXlEb3duQXJyb3dMZWZ0KGVsZW1lbnQpXCJcbiAgICAgICAgICAgIChrZXlkb3duLmFycm93UmlnaHQucHJldmVudCk9XCJvbkVsZW1lbnRLZXlEb3duQXJyb3dSaWdodChlbGVtZW50KVwiXG4gICAgICAgID5cbiAgICAgICAgICAgIHt7IGluZGV4SXRlbSArIDEgfX1cbiAgICAgICAgPC9idXR0b24+XG4gICAgPC9uZy10ZW1wbGF0ZT5cbiAgICA8bmctdGVtcGxhdGUgI2RvdHNUZW1wbGF0ZT5cbiAgICAgICAgPGRpdlxuICAgICAgICAgICAgYXV0b21hdGlvbi1pZD1cInR1aS1wYWdpbmF0aW9uX19lbGVtZW50XCJcbiAgICAgICAgICAgIGNsYXNzPVwidC1kb3RzXCJcbiAgICAgICAgICAgIFtjbGFzcy50LWRvdHNfc21hbGxdPVwic2l6ZSA9PT0gJ20nXCJcbiAgICAgICAgPjwvZGl2PlxuICAgIDwvbmctdGVtcGxhdGU+XG48L2Rpdj5cbiJdfQ==