UNPKG

ngx-ui-builder

Version:

Angular - Render component ui with configurations

119 lines 32 kB
import { ChangeDetectionStrategy, Component, Input } from '@angular/core'; import { BehaviorSubject, filter, map, Subject, takeUntil } from 'rxjs'; import * as i0 from "@angular/core"; import * as i1 from "@angular/common"; import * as i2 from "@angular/forms"; class NubPaginationComponent { set configs(configs) { this.localConfigs = { ...this.localConfigs, ...configs }; } ; constructor() { this.DOTS = '...'; this.localConfigs = { pageSizes: [5, 10, 20, 50, 100], pageSize: 10, page: 1, siblingCount: 2, showRefreshButton: false, showPageSizesConfig: false, }; this.pagination$ = new BehaviorSubject(this.localConfigs); this.pageArray$ = new BehaviorSubject([]); this._componentDestroy = new Subject(); } ngOnInit() { this.pagination$.next(this.localConfigs); this.refresh(); this.pagination$.pipe(takeUntil(this._componentDestroy)).subscribe((pagination => { Object.assign(this.localConfigs, pagination); })); } ngOnDestroy() { this._componentDestroy.next(); this._componentDestroy.complete(); } buildPageArray() { return this.pagination$.pipe(takeUntil(this._componentDestroy), filter(pagination => !!pagination), map(pagination => { const totalPageCount = Math.round((pagination?.totalItems ?? 0) / (pagination?.pageSize ?? 10)); // siblingCount + firstPage + lastPage + currentPage + 2*DOTS const totalPageNumbers = (pagination?.siblingCount ?? 1) + 5; // [1..totalPageCount] if (totalPageNumbers >= totalPageCount) { return this.range(1, totalPageCount); } const leftSiblingIndex = Math.max((pagination?.page ?? 1) - (pagination?.siblingCount ?? 1), 1); const rightSiblingIndex = Math.min((pagination?.page ?? 1) + (pagination?.siblingCount ?? 1), totalPageCount); const shouldShowLeftDots = leftSiblingIndex > 2; const shouldShowRightDots = rightSiblingIndex < totalPageCount - 2; const firstPageIndex = 1; const lastPageIndex = totalPageCount; if (!shouldShowLeftDots && shouldShowRightDots) { const leftItemCount = 3 + 2 * (pagination?.siblingCount ?? 1); const leftRange = this.range(1, leftItemCount); return [...leftRange, this.DOTS, totalPageCount]; } if (shouldShowLeftDots && !shouldShowRightDots) { const rightItemCount = 3 + 2 * (pagination?.siblingCount ?? 1); const rightRange = this.range(totalPageCount - rightItemCount + 1, totalPageCount); return [firstPageIndex, this.DOTS, ...rightRange]; } if (shouldShowLeftDots && shouldShowRightDots) { const middleRange = this.range(leftSiblingIndex, rightSiblingIndex); return [firstPageIndex, this.DOTS, ...middleRange, this.DOTS, lastPageIndex]; } return new Array(totalPageCount); })); } async setPageSize() { await this.refresh(); const pagination = this.buildOptions(); if (this.localConfigs.afterChangePageSize) { this.localConfigs.afterChangePageSize(pagination); } else { this.goToPage(0); } } goToPage(pageIndex) { const pagination = this.buildOptions(pageIndex); this.pagination$.next({ ...pagination, }); if (this.localConfigs.afterChangePage) { this.localConfigs.afterChangePage(pagination); } this.refresh(); } refresh() { this.buildPageArray().subscribe(data => { this.pageArray$.next(data); }); } onRefresh() { this.refresh(); } buildOptions(pageIndex = 0) { return { pageSizes: this.localConfigs.pageSizes, pageSize: this.localConfigs.pageSize, page: pageIndex + 1, siblingCount: this.localConfigs.siblingCount, totalItems: this.localConfigs.totalItems, }; } range(start, end) { const length = end - start + 1; return Array.from({ length }, (_, idx) => idx + start); } static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.1.5", ngImport: i0, type: NubPaginationComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); } static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "16.1.5", type: NubPaginationComponent, selector: "nub-pagination", inputs: { configs: "configs" }, ngImport: i0, template: "<div class=\"pagination-container\">\n\n <button class=\"btn-refresh\" (click)=\"onRefresh()\">Refresh</button>\n\n <!-- Pagination Section -->\n <div class=\"settings\">\n <label>\n {{localConfigs.labelSettingsItemsPerPage || 'Items per page'}}:\n <select [(ngModel)]=\"localConfigs.pageSize\" (change)=\"setPageSize()\">\n <option *ngFor=\"let page of (pagination$ | async)!.pageSizes\">\n <span>{{ page }}</span>\n </option>\n </select>\n </label>\n </div>\n\n <div class=\"pagination\" *ngIf=\"pagination$ | async\">\n <ng-container *ngTemplateOutlet=\"firstTemplate\"></ng-container>\n <ng-container *ngTemplateOutlet=\"previousTemplate\"></ng-container>\n <ng-container *ngFor=\"let page of pageArray$ | async; let i = index\">\n <ng-container *ngIf=\"page === DOTS\">\n <ng-container *ngTemplateOutlet=\"dotTemplate\"></ng-container>\n </ng-container>\n <ng-container *ngIf=\"page !== DOTS\">\n <ng-container *ngTemplateOutlet=\"pageNumberTemplate; context: {$implicit: page}\"></ng-container>\n </ng-container>\n </ng-container>\n <ng-container *ngTemplateOutlet=\"nextTemplate\"></ng-container>\n <ng-container *ngTemplateOutlet=\"lastTemplate\"></ng-container>\n </div>\n</div>\n\n<ng-template #firstTemplate>\n <div (click)=\"goToPage(0)\">\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n fill=\"none\" viewBox=\"0 0 24 24\"\n stroke-width=\"1.5\"\n stroke=\"currentColor\"\n class=\"page-icon\"\n >\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M18.75 19.5l-7.5-7.5 7.5-7.5m-6 15L5.25 12l7.5-7.5\"/>\n </svg>\n </div>\n</ng-template>\n\n<ng-template #lastTemplate>\n <div (click)=\"goToPage(localConfigs.totalItems! / localConfigs.pageSize!)\">\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n fill=\"none\"\n viewBox=\"0 0 24 24\"\n stroke-width=\"1.5\"\n stroke=\"currentColor\"\n class=\"page-icon\"\n >\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M11.25 4.5l7.5 7.5-7.5 7.5m-6-15l7.5 7.5-7.5 7.5\"/>\n </svg>\n </div>\n</ng-template>\n\n<ng-template #previousTemplate>\n <div (click)=\"goToPage(localConfigs.page! > 1 ? localConfigs.page! - 2 : 0)\">\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n fill=\"none\"\n viewBox=\"0 0 24 24\"\n stroke-width=\"1.5\"\n stroke=\"currentColor\"\n class=\"page-icon\"\n >\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M15.75 19.5L8.25 12l7.5-7.5\"/>\n </svg>\n </div>\n</ng-template>\n\n<ng-template #nextTemplate>\n <div (click)=\"goToPage(localConfigs.page!)\">\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n fill=\"none\"\n viewBox=\"0 0 24 24\"\n stroke-width=\"1.5\"\n stroke=\"currentColor\"\n class=\"page-icon\"\n >\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M8.25 4.5l7.5 7.5-7.5 7.5\"/>\n </svg>\n </div>\n</ng-template>\n\n<ng-template #pageNumberTemplate let-page>\n <div\n class=\"page-number\"\n [ngClass]=\"{ 'active': (pagination$ | async)?.page === page }\"\n (click)=\"goToPage(page - 1)\"\n >\n <span>{{page}}</span>\n </div>\n</ng-template>\n\n<ng-template #dotTemplate>\n <div class=\"page-dot\">\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"18\" height=\"14\" viewBox=\"0 0 18 14\">\n <text id=\"_.\" data-name=\"\u2026.\" transform=\"translate(9 11)\" fill=\"#6badb9\" font-size=\"1em\" font-family=\"Helvetica\">\n <tspan x=\"-8.945\" y=\"0\">\u2026.</tspan>\n </text>\n </svg>\n </div>\n</ng-template>\n", styles: [":host{max-width:100vw;width:100%}.btn-refresh{margin-right:5px}.page-icon{aspect-ratio:1 / 1;width:24px;cursor:pointer}.active{font-weight:700}.pagination-container{display:flex}.pagination{display:flex;align-items:center}.pagination .page-number{aspect-ratio:1 / 1;flex:0 0 24px;border:1px solid gray;text-align:center;line-height:1.7em}.pagination .page-number:not(.active){cursor:pointer}.pagination .page-dot{line-height:1.7em}\n"], dependencies: [{ kind: "directive", type: i1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i1.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "directive", type: i2.NgSelectOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i2.ɵNgSelectMultipleOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i2.SelectControlValueAccessor, selector: "select:not([multiple])[formControlName],select:not([multiple])[formControl],select:not([multiple])[ngModel]", inputs: ["compareWith"] }, { kind: "directive", type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "pipe", type: i1.AsyncPipe, name: "async" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); } } export { NubPaginationComponent }; i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.1.5", ngImport: i0, type: NubPaginationComponent, decorators: [{ type: Component, args: [{ selector: 'nub-pagination', changeDetection: ChangeDetectionStrategy.OnPush, template: "<div class=\"pagination-container\">\n\n <button class=\"btn-refresh\" (click)=\"onRefresh()\">Refresh</button>\n\n <!-- Pagination Section -->\n <div class=\"settings\">\n <label>\n {{localConfigs.labelSettingsItemsPerPage || 'Items per page'}}:\n <select [(ngModel)]=\"localConfigs.pageSize\" (change)=\"setPageSize()\">\n <option *ngFor=\"let page of (pagination$ | async)!.pageSizes\">\n <span>{{ page }}</span>\n </option>\n </select>\n </label>\n </div>\n\n <div class=\"pagination\" *ngIf=\"pagination$ | async\">\n <ng-container *ngTemplateOutlet=\"firstTemplate\"></ng-container>\n <ng-container *ngTemplateOutlet=\"previousTemplate\"></ng-container>\n <ng-container *ngFor=\"let page of pageArray$ | async; let i = index\">\n <ng-container *ngIf=\"page === DOTS\">\n <ng-container *ngTemplateOutlet=\"dotTemplate\"></ng-container>\n </ng-container>\n <ng-container *ngIf=\"page !== DOTS\">\n <ng-container *ngTemplateOutlet=\"pageNumberTemplate; context: {$implicit: page}\"></ng-container>\n </ng-container>\n </ng-container>\n <ng-container *ngTemplateOutlet=\"nextTemplate\"></ng-container>\n <ng-container *ngTemplateOutlet=\"lastTemplate\"></ng-container>\n </div>\n</div>\n\n<ng-template #firstTemplate>\n <div (click)=\"goToPage(0)\">\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n fill=\"none\" viewBox=\"0 0 24 24\"\n stroke-width=\"1.5\"\n stroke=\"currentColor\"\n class=\"page-icon\"\n >\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M18.75 19.5l-7.5-7.5 7.5-7.5m-6 15L5.25 12l7.5-7.5\"/>\n </svg>\n </div>\n</ng-template>\n\n<ng-template #lastTemplate>\n <div (click)=\"goToPage(localConfigs.totalItems! / localConfigs.pageSize!)\">\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n fill=\"none\"\n viewBox=\"0 0 24 24\"\n stroke-width=\"1.5\"\n stroke=\"currentColor\"\n class=\"page-icon\"\n >\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M11.25 4.5l7.5 7.5-7.5 7.5m-6-15l7.5 7.5-7.5 7.5\"/>\n </svg>\n </div>\n</ng-template>\n\n<ng-template #previousTemplate>\n <div (click)=\"goToPage(localConfigs.page! > 1 ? localConfigs.page! - 2 : 0)\">\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n fill=\"none\"\n viewBox=\"0 0 24 24\"\n stroke-width=\"1.5\"\n stroke=\"currentColor\"\n class=\"page-icon\"\n >\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M15.75 19.5L8.25 12l7.5-7.5\"/>\n </svg>\n </div>\n</ng-template>\n\n<ng-template #nextTemplate>\n <div (click)=\"goToPage(localConfigs.page!)\">\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n fill=\"none\"\n viewBox=\"0 0 24 24\"\n stroke-width=\"1.5\"\n stroke=\"currentColor\"\n class=\"page-icon\"\n >\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M8.25 4.5l7.5 7.5-7.5 7.5\"/>\n </svg>\n </div>\n</ng-template>\n\n<ng-template #pageNumberTemplate let-page>\n <div\n class=\"page-number\"\n [ngClass]=\"{ 'active': (pagination$ | async)?.page === page }\"\n (click)=\"goToPage(page - 1)\"\n >\n <span>{{page}}</span>\n </div>\n</ng-template>\n\n<ng-template #dotTemplate>\n <div class=\"page-dot\">\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"18\" height=\"14\" viewBox=\"0 0 18 14\">\n <text id=\"_.\" data-name=\"\u2026.\" transform=\"translate(9 11)\" fill=\"#6badb9\" font-size=\"1em\" font-family=\"Helvetica\">\n <tspan x=\"-8.945\" y=\"0\">\u2026.</tspan>\n </text>\n </svg>\n </div>\n</ng-template>\n", styles: [":host{max-width:100vw;width:100%}.btn-refresh{margin-right:5px}.page-icon{aspect-ratio:1 / 1;width:24px;cursor:pointer}.active{font-weight:700}.pagination-container{display:flex}.pagination{display:flex;align-items:center}.pagination .page-number{aspect-ratio:1 / 1;flex:0 0 24px;border:1px solid gray;text-align:center;line-height:1.7em}.pagination .page-number:not(.active){cursor:pointer}.pagination .page-dot{line-height:1.7em}\n"] }] }], ctorParameters: function () { return []; }, propDecorators: { configs: [{ type: Input }] } }); //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicGFnaW5hdGlvbi5jb21wb25lbnQuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi9saWJzL25neC11aS1idWlsZGVyL3BhZ2luYXRpb24vc3JjL3BhZ2luYXRpb24uY29tcG9uZW50LnRzIiwiLi4vLi4vLi4vLi4vbGlicy9uZ3gtdWktYnVpbGRlci9wYWdpbmF0aW9uL3NyYy9wYWdpbmF0aW9uLmNvbXBvbmVudC5odG1sIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sRUFBRSx1QkFBdUIsRUFBRSxTQUFTLEVBQUUsS0FBSyxFQUFxQixNQUFNLGVBQWUsQ0FBQztBQUM3RixPQUFPLEVBQUUsZUFBZSxFQUFFLE1BQU0sRUFBRSxHQUFHLEVBQWMsT0FBTyxFQUFFLFNBQVMsRUFBRSxNQUFNLE1BQU0sQ0FBQzs7OztBQUdwRixNQU1hLHNCQUFzQjtJQUNqQyxJQUFhLE9BQU8sQ0FBQyxPQUF5QjtRQUM1QyxJQUFJLENBQUMsWUFBWSxHQUFHLEVBQUUsR0FBRyxJQUFJLENBQUMsWUFBWSxFQUFFLEdBQUcsT0FBTyxFQUFFLENBQUM7SUFDM0QsQ0FBQztJQUFBLENBQUM7SUFpQkY7UUFoQkEsU0FBSSxHQUFHLEtBQUssQ0FBQztRQUViLGlCQUFZLEdBQXFCO1lBQy9CLFNBQVMsRUFBRSxDQUFDLENBQUMsRUFBRSxFQUFFLEVBQUUsRUFBRSxFQUFFLEVBQUUsRUFBRSxHQUFHLENBQUM7WUFDL0IsUUFBUSxFQUFFLEVBQUU7WUFDWixJQUFJLEVBQUUsQ0FBQztZQUNQLFlBQVksRUFBRSxDQUFDO1lBQ2YsaUJBQWlCLEVBQUUsS0FBSztZQUN4QixtQkFBbUIsRUFBRSxLQUFLO1NBQzNCLENBQUM7UUFFRixnQkFBVyxHQUFzQyxJQUFJLGVBQWUsQ0FBbUIsSUFBSSxDQUFDLFlBQVksQ0FBQyxDQUFDO1FBQzFHLGVBQVUsR0FBMkIsSUFBSSxlQUFlLENBQVEsRUFBRSxDQUFDLENBQUM7UUFFNUQsc0JBQWlCLEdBQWtCLElBQUks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cG9uZW50LCBJbnB1dCwgT25EZXN0cm95LCBPbkluaXQgfSBmcm9tICdAYW5ndWxhci9jb3JlJztcbmltcG9ydCB7IEJlaGF2aW9yU3ViamVjdCwgZmlsdGVyLCBtYXAsIE9ic2VydmFibGUsIFN1YmplY3QsIHRha2VVbnRpbCB9IGZyb20gJ3J4anMnO1xuaW1wb3J0IHsgUGFnaW5hdGlvbkNvbmZpZyB9IGZyb20gJy4vcGFnaW5hdGlvbi50eXBlcyc7XG5cbkBDb21wb25lbnQoe1xuICBzZWxlY3RvcjogJ251Yi1wYWdpbmF0aW9uJyxcbiAgdGVtcGxhdGVVcmw6ICcuL3BhZ2luYXRpb24uY29tcG9uZW50Lmh0bWwnLFxuICBzdHlsZVVybHM6IFsnLi9wYWdpbmF0aW9uLmNvbXBvbmVudC5jc3MnXSxcbiAgY2hhbmdlRGV0ZWN0aW9uOiBDaGFuZ2VEZXRlY3Rpb25TdHJhdGVneS5PblB1c2gsXG59KVxuZXhwb3J0IGNsYXNzIE51YlBhZ2luYXRpb25Db21wb25lbnQgaW1wbGVtZW50cyBPbkluaXQsIE9uRGVzdHJveSB7XG4gIEBJbnB1dCgpIHNldCBjb25maWdzKGNvbmZpZ3M6IFBhZ2luYXRpb25Db25maWcpIHtcbiAgICB0aGlzLmxvY2FsQ29uZmlncyA9IHsgLi4udGhpcy5sb2NhbENvbmZpZ3MsIC4uLmNvbmZpZ3MgfTtcbiAgfTtcbiAgRE9UUyA9ICcuLi4nO1xuXG4gIGxvY2FsQ29uZmlnczogUGFnaW5hdGlvbkNvbmZpZyA9IHtcbiAgICBwYWdlU2l6ZXM6IFs1LCAxMCwgMjAsIDUwLCAxMDBdLFxuICAgIHBhZ2VTaXplOiAxMCxcbiAgICBwYWdlOiAxLFxuICAgIHNpYmxpbmdDb3VudDogMixcbiAgICBzaG93UmVmcmVzaEJ1dHRvbjogZmFsc2UsXG4gICAgc2hvd1BhZ2VTaXplc0NvbmZpZzogZmFsc2UsXG4gIH07XG5cbiAgcGFnaW5hdGlvbiQ6IEJlaGF2aW9yU3ViamVjdDxQYWdpbmF0aW9uQ29uZmlnPiA9IG5ldyBCZWhhdmlvclN1YmplY3Q8UGFnaW5hdGlvbkNvbmZpZz4odGhpcy5sb2NhbENvbmZpZ3MpO1xuICBwYWdlQXJyYXkkOiBCZWhhdmlvclN1YmplY3Q8YW55W10+ID0gbmV3IEJlaGF2aW9yU3ViamVjdDxhbnlbXT4oW10pO1xuXG4gIHByaXZhdGUgX2NvbXBvbmVudERlc3Ryb3k6IFN1YmplY3Q8dm9pZD4gPSBuZXcgU3ViamVjdDx2b2lkPigpO1xuXG4gIGNvbnN0cnVjdG9yKCkge31cblxuICBuZ09uSW5pdCgpOiB2b2lkIHtcbiAgICB0aGlzLnBhZ2luYXRpb24kLm5leHQodGhpcy5sb2NhbENvbmZpZ3MpO1xuXG4gICAgdGhpcy5yZWZyZXNoKCk7XG5cbiAgICB0aGlzLnBhZ2luYXRpb24kLnBpcGUoXG4gICAgICB0YWtlVW50aWwodGhpcy5fY29tcG9uZW50RGVzdHJveSksXG4gICAgKS5zdWJzY3JpYmUoKHBhZ2luYXRpb24gPT4ge1xuICAgICAgT2JqZWN0LmFzc2lnbih0aGlzLmxvY2FsQ29uZmlncywgcGFnaW5hdGlvbik7XG4gICAgfSkpO1xuICB9XG5cbiAgbmdPbkRlc3Ryb3koKSB7XG4gICAgdGhpcy5fY29tcG9uZW50RGVzdHJveS5uZXh0KCk7XG4gICAgdGhpcy5fY29tcG9uZW50RGVzdHJveS5jb21wbGV0ZSgpO1xuICB9XG5cbiAgYnVpbGRQYWdlQXJyYXkoKTogT2JzZXJ2YWJsZTxhbnlbXT4ge1xuICAgIHJldHVybiB0aGlzLnBhZ2luYXRpb24kLnBpcGUoXG4gICAgICB0YWtlVW50aWwodGhpcy5fY29tcG9uZW50RGVzdHJveSksXG4gICAgICBmaWx0ZXIocGFnaW5hdGlvbiA9PiAhIXBhZ2luYXRpb24pLFxuICAgICAgbWFwKHBhZ2luYXRpb24gPT4ge1xuICAgICAgICBjb25zdCB0b3RhbFBhZ2VDb3VudCA9IE1hdGgucm91bmQoKHBhZ2luYXRpb24/LnRvdGFsSXRlbXMgPz8gMCkgLyAocGFnaW5hdGlvbj8ucGFnZVNpemUgPz8gMTApKTtcblxuICAgICAgICAvLyBzaWJsaW5nQ291bnQgKyBmaXJzdFBhZ2UgKyBsYXN0UGFnZSArIGN1cnJlbnRQYWdlICsgMipET1RTXG4gICAgICAgIGNvbnN0IHRvdGFsUGFnZU51bWJlcnMgPSAocGFnaW5hdGlvbj8uc2libGluZ0NvdW50ID8/IDEpICsgNTtcblxuICAgICAgICAvLyBbMS4udG90YWxQYWdlQ291bnRdXG4gICAgICAgIGlmICh0b3RhbFBhZ2VOdW1iZXJzID49IHRvdGFsUGFnZUNvdW50KSB7XG4gICAgICAgICAgcmV0dXJuIHRoaXMucmFuZ2UoMSwgdG90YWxQYWdlQ291bnQpO1xuICAgICAgICB9XG5cbiAgICAgICAgY29uc3QgbGVmdFNpYmxpbmdJbmRleCA9IE1hdGgubWF4KChwYWdpbmF0aW9uPy5wYWdlID8/IDEpIC0gKHBhZ2luYXRpb24/LnNpYmxpbmdDb3VudCA/PyAxKSwgMSk7XG4gICAgICAgIGNvbnN0IHJpZ2h0U2libGluZ0luZGV4ID0gTWF0aC5taW4oXG4gICAgICAgICAgKHBhZ2luYXRpb24/LnBhZ2UgPz8gMSkgKyAocGFnaW5hdGlvbj8uc2libGluZ0NvdW50ID8/IDEpLFxuICAgICAgICAgIHRvdGFsUGFnZUNvdW50XG4gICAgICAgICk7XG5cbiAgICAgICAgY29uc3Qgc2hvdWxkU2hvd0xlZnREb3RzID0gbGVmdFNpYmxpbmdJbmRleCA+IDI7XG4gICAgICAgIGNvbnN0IHNob3VsZFNob3dSaWdodERvdHMgPSByaWdodFNpYmxpbmdJbmRleCA8IHRvdGFsUGFnZUNvdW50IC0gMjtcblxuICAgICAgICBjb25zdCBmaXJzdFBhZ2VJbmRleCA9IDE7XG4gICAgICAgIGNvbnN0IGxhc3RQYWdlSW5kZXggPSB0b3RhbFBhZ2VDb3VudDtcblxuICAgICAgICBpZiAoIXNob3VsZFNob3dMZWZ0RG90cyAmJiBzaG91bGRTaG93UmlnaHREb3RzKSB7XG4gICAgICAgICAgY29uc3QgbGVmdEl0ZW1Db3VudCA9IDMgKyAyICogKHBhZ2luYXRpb24/LnNpYmxpbmdDb3VudCA/PyAxKTtcbiAgICAgICAgICBjb25zdCBsZWZ0UmFuZ2UgPSB0aGlzLnJhbmdlKDEsIGxlZnRJdGVtQ291bnQpO1xuXG4gICAgICAgICAgcmV0dXJuIFsuLi5sZWZ0UmFuZ2UsIHRoaXMuRE9UUywgdG90YWxQYWdlQ291bnRdO1xuICAgICAgICB9XG5cbiAgICAgICAgaWYgKHNob3VsZFNob3dMZWZ0RG90cyAmJiAhc2hvdWxkU2hvd1JpZ2h0RG90cykge1xuICAgICAgICAgIGNvbnN0IHJpZ2h0SXRlbUNvdW50ID0gMyArIDIgKiAocGFnaW5hdGlvbj8uc2libGluZ0NvdW50ID8/IDEpO1xuICAgICAgICAgIGNvbnN0IHJpZ2h0UmFuZ2UgPSB0aGlzLnJhbmdlKFxuICAgICAgICAgICAgdG90YWxQYWdlQ291bnQgLSByaWdodEl0ZW1Db3VudCArIDEsXG4gICAgICAgICAgICB0b3RhbFBhZ2VDb3VudFxuICAgICAgICAgICk7XG4gICAgICAgICAgcmV0dXJuIFtmaXJzdFBhZ2VJbmRleCwgdGhpcy5ET1RTLCAuLi5yaWdodFJhbmdlXTtcbiAgICAgICAgfVxuXG4gICAgICAgIGlmIChzaG91bGRTaG93TGVmdERvdHMgJiYgc2hvdWxkU2hvd1JpZ2h0RG90cykge1xuICAgICAgICAgIGNvbnN0IG1pZGRsZVJhbmdlID0gdGhpcy5yYW5nZShsZWZ0U2libGluZ0luZGV4LCByaWdodFNpYmxpbmdJbmRleCk7XG4gICAgICAgICAgcmV0dXJuIFtmaXJzdFBhZ2VJbmRleCwgdGhpcy5ET1RTLCAuLi5taWRkbGVSYW5nZSwgdGhpcy5ET1RTLCBsYXN0UGFnZUluZGV4XTtcbiAgICAgICAgfVxuXG4gICAgICAgIHJldHVybiBuZXcgQXJyYXkodG90YWxQYWdlQ291bnQpO1xuICAgICAgfSksXG4gICAgKTtcbiAgfVxuXG4gIGFzeW5jIHNldFBhZ2VTaXplKCk6IFByb21pc2U8dm9pZD4ge1xuICAgIGF3YWl0IHRoaXMucmVmcmVzaCgpO1xuICAgIGNvbnN0IHBhZ2luYXRpb24gPSB0aGlzLmJ1aWxkT3B0aW9ucygpO1xuICAgIGlmICh0aGlzLmxvY2FsQ29uZmlncy5hZnRlckNoYW5nZVBhZ2VTaXplKSB7XG4gICAgICB0aGlzLmxvY2FsQ29uZmlncy5hZnRlckNoYW5nZVBhZ2VTaXplKHBhZ2luYXRpb24pO1xuICAgIH0gZWxzZSB7XG4gICAgICB0aGlzLmdvVG9QYWdlKDApO1xuICAgIH1cbiAgfVxuXG4gIGdvVG9QYWdlKHBhZ2VJbmRleDogbnVtYmVyKTogdm9pZCB7XG4gICAgY29uc3QgcGFnaW5hdGlvbiA9IHRoaXMuYnVpbGRPcHRpb25zKHBhZ2VJbmRleCk7XG5cbiAgICB0aGlzLnBhZ2luYXRpb24kLm5leHQoe1xuICAgICAgLi4ucGFnaW5hdGlvbixcbiAgICB9IGFzIFBhZ2luYXRpb25Db25maWcpO1xuXG4gICAgaWYgKHRoaXMubG9jYWxDb25maWdzLmFmdGVyQ2hhbmdlUGFnZSkge1xuICAgICAgdGhpcy5sb2NhbENvbmZpZ3MuYWZ0ZXJDaGFuZ2VQYWdlKHBhZ2luYXRpb24pO1xuICAgIH1cbiAgICB0aGlzLnJlZnJlc2goKTtcbiAgfVxuXG4gIHJlZnJlc2goKTogdm9pZCB7XG4gICAgdGhpcy5idWlsZFBhZ2VBcnJheSgpLnN1YnNjcmliZShkYXRhID0+IHtcbiAgICAgIHRoaXMucGFnZUFycmF5JC5uZXh0KGRhdGEpO1xuICAgIH0pO1xuICB9XG5cbiAgb25SZWZyZXNoKCk6IHZvaWQge1xuICAgIHRoaXMucmVmcmVzaCgpO1xuICB9XG5cbiAgcHJpdmF0ZSBidWlsZE9wdGlvbnMocGFnZUluZGV4ID0gMCkge1xuICAgIHJldHVybiB7XG4gICAgICBwYWdlU2l6ZXM6IHRoaXMubG9jYWxDb25maWdzLnBhZ2VTaXplcyxcbiAgICAgIHBhZ2VTaXplOiB0aGlzLmxvY2FsQ29uZmlncy5wYWdlU2l6ZSxcbiAgICAgIHBhZ2U6IHBhZ2VJbmRleCArIDEsXG4gICAgICBzaWJsaW5nQ291bnQ6IHRoaXMubG9jYWxDb25maWdzLnNpYmxpbmdDb3VudCxcbiAgICAgIHRvdGFsSXRlbXM6IHRoaXMubG9jYWxDb25maWdzLnRvdGFsSXRlbXMsXG4gICAgfTtcbiAgfVxuXG4gIHByaXZhdGUgcmFuZ2Uoc3RhcnQ6IG51bWJlciwgZW5kOiBudW1iZXIpIHtcbiAgICBjb25zdCBsZW5ndGggPSBlbmQgLSBzdGFydCArIDE7XG4gICAgcmV0dXJuIEFycmF5LmZyb20oeyBsZW5ndGggfSwgKF8sIGlkeCkgPT4gaWR4ICsgc3RhcnQpO1xuICB9XG59XG4iLCI8ZGl2IGNsYXNzPVwicGFnaW5hdGlvbi1jb250YWluZXJcIj5cblxuICA8YnV0dG9uIGNsYXNzPVwiYnRuLXJlZnJlc2hcIiAoY2xpY2spPVwib25SZWZyZXNoKClcIj5SZWZyZXNoPC9idXR0b24+XG5cbiAgPCEtLSBQYWdpbmF0aW9uIFNlY3Rpb24gLS0+XG4gIDxkaXYgY2xhc3M9XCJzZXR0aW5nc1wiPlxuICAgIDxsYWJlbD5cbiAgICAgIHt7bG9jYWxDb25maWdzLmxhYmVsU2V0dGluZ3NJdGVtc1BlclBhZ2UgfHwgJ0l0ZW1zIHBlciBwYWdlJ319OlxuICAgICAgPHNlbGVjdCBbKG5nTW9kZWwpXT1cImxvY2FsQ29uZmlncy5wYWdlU2l6ZVwiIChjaGFuZ2UpPVwic2V0UGFnZVNpemUoKVwiPlxuICAgICAgICA8b3B0aW9uICpuZ0Zvcj1cImxldCBwYWdlIG9mIChwYWdpbmF0aW9uJCB8IGFzeW5jKSEucGFnZVNpemVzXCI+XG4gICAgICAgICAgPHNwYW4+e3sgcGFnZSB9fTwvc3Bhbj5cbiAgICAgICAgPC9vcHRpb24+XG4gICAgICA8L3NlbGVjdD5cbiAgICA8L2xhYmVsPlxuICA8L2Rpdj5cblxuICA8ZGl2IGNsYXNzPVwicGFnaW5hdGlvblwiICpuZ0lmPVwicGFnaW5hdGlvbiQgfCBhc3luY1wiPlxuICAgIDxuZy1jb250YWluZXIgKm5nVGVtcGxhdGVPdXRsZXQ9XCJmaXJzdFRlbXBsYXRlXCI+PC9uZy1jb250YWluZXI+XG4gICAgPG5nLWNvbnRhaW5lciAqbmdUZW1wbGF0ZU91dGxldD1cInByZXZpb3VzVGVtcGxhdGVcIj48L25nLWNvbnRhaW5lcj5cbiAgICA8bmctY29udGFpbmVyICpuZ0Zvcj1cImxldCBwYWdlIG9mIHBhZ2VBcnJheSQgfCBhc3luYzsgbGV0IGkgPSBpbmRleFwiPlxuICAgICAgPG5nLWNvbnRhaW5lciAqbmdJZj1cInBhZ2UgPT09IERPVFNcIj5cbiAgICAgICAgPG5nLWNvbnRhaW5lciAqbmdUZW1wbGF0ZU91dGxldD1cImRvdFRlbXBsYXRlXCI+PC9uZy1jb250YWluZXI+XG4gICAgICA8L25nLWNvbnRhaW5lcj5cbiAgICAgIDxuZy1jb250YWluZXIgKm5nSWY9XCJwYWdlICE9PSBET1RTXCI+XG4gICAgICAgIDxuZy1jb250YWluZXIgKm5nVGVtcGxhdGVPdXRsZXQ9XCJwYWdlTnVtYmVyVGVtcGxhdGU7IGNvbnRleHQ6IHskaW1wbGljaXQ6IHBhZ2V9XCI+PC9uZy1jb250YWluZXI+XG4gICAgICA8L25nLWNvbnRhaW5lcj5cbiAgICA8L25nLWNvbnRhaW5lcj5cbiAgICA8bmctY29udGFpbmVyICpuZ1RlbXBsYXRlT3V0bGV0PVwibmV4dFRlbXBsYXRlXCI+PC9uZy1jb250YWluZXI+XG4gICAgPG5nLWNvbnRhaW5lciAqbmdUZW1wbGF0ZU91dGxldD1cImxhc3RUZW1wbGF0ZVwiPjwvbmctY29udGFpbmVyPlxuICA8L2Rpdj5cbjwvZGl2PlxuXG48bmctdGVtcGxhdGUgI2ZpcnN0VGVtcGxhdGU+XG4gIDxkaXYgKGNsaWNrKT1cImdvVG9QYWdlKDApXCI+XG4gICAgPHN2Z1xuICAgICAgeG1sbnM9XCJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2Z1wiXG4gICAgICBmaWxsPVwibm9uZVwiIHZpZXdCb3g9XCIwIDAgMjQgMjRcIlxuICAgICAgc3Ryb2tlLXdpZHRoPVwiMS41XCJcbiAgICAgIHN0cm9rZT1cImN1cnJlbnRDb2xvclwiXG4gICAgICBjbGFzcz1cInBhZ2UtaWNvblwiXG4gICAgPlxuICAgICAgPHBhdGggc3Ryb2tlLWxpbmVjYXA9XCJyb3VuZFwiIHN0cm9rZS1saW5lam9pbj1cInJvdW5kXCIgZD1cIk0xOC43NSAxOS41bC03LjUtNy41IDcuNS03LjVtLTYgMTVMNS4yNSAxMmw3LjUtNy41XCIvPlxuICAgIDwvc3ZnPlxuICA8L2Rpdj5cbjwvbmctdGVtcGxhdGU+XG5cbjxuZy10ZW1wbGF0ZSAjbGFzdFRlbXBsYXRlPlxuICA8ZGl2IChjbGljayk9XCJnb1RvUGFnZShsb2NhbENvbmZpZ3MudG90YWxJdGVtcyEgLyBsb2NhbENvbmZpZ3MucGFnZVNpemUhKVwiPlxuICAgIDxzdmdcbiAgICAgIHhtbG5zPVwiaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmdcIlxuICAgICAgZmlsbD1cIm5vbmVcIlxuICAgICAgdmlld0JveD1cIjAgMCAyNCAyNFwiXG4gICAgICBzdHJva2Utd2lkdGg9XCIxLjVcIlxuICAgICAgc3Ryb2tlPVwiY3VycmVudENvbG9yXCJcbiAgICAgIGNsYXNzPVwicGFnZS1pY29uXCJcbiAgICA+XG4gICAgICA8cGF0aCBzdHJva2UtbGluZWNhcD1cInJvdW5kXCIgc3Ryb2tlLWxpbmVqb2luPVwicm91bmRcIiBkPVwiTTExLjI1IDQuNWw3LjUgNy41LTcuNSA3LjVtLTYtMTVsNy41IDcuNS03LjUgNy41XCIvPlxuICAgIDwvc3ZnPlxuICA8L2Rpdj5cbjwvbmctdGVtcGxhdGU+XG5cbjxuZy10ZW1wbGF0ZSAjcHJldmlvdXNUZW1wbGF0ZT5cbiAgPGRpdiAoY2xpY2spPVwiZ29Ub1BhZ2UobG9jYWxDb25maWdzLnBhZ2UhID4gMSA/IGxvY2FsQ29uZmlncy5wYWdlISAtIDIgOiAwKVwiPlxuICAgIDxzdmdcbiAgICAgIHhtbG5zPVwiaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmdcIlxuICAgICAgZmlsbD1cIm5vbmVcIlxuICAgICAgdmlld0JveD1cIjAgMCAyNCAyNFwiXG4gICAgICBzdHJva2Utd2lkdGg9XCIxLjVcIlxuICAgICAgc3Ryb2tlPVwiY3VycmVudENvbG9yXCJcbiAgICAgIGNsYXNzPVwicGFnZS1pY29uXCJcbiAgICA+XG4gICAgICA8cGF0aCBzdHJva2UtbGluZWNhcD1cInJvdW5kXCIgc3Ryb2tlLWxpbmVqb2luPVwicm91bmRcIiBkPVwiTTE1Ljc1IDE5LjVMOC4yNSAxMmw3LjUtNy41XCIvPlxuICAgIDwvc3ZnPlxuICA8L2Rpdj5cbjwvbmctdGVtcGxhdGU+XG5cbjxuZy10ZW1wbGF0ZSAjbmV4dFRlbXBsYXRlPlxuICA8ZGl2IChjbGljayk9XCJnb1RvUGFnZShsb2NhbENvbmZpZ3MucGFnZSEpXCI+XG4gICAgPHN2Z1xuICAgICAgeG1sbnM9XCJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2Z1wiXG4gICAgICBmaWxsPVwibm9uZVwiXG4gICAgICB2aWV3Qm94PVwiMCAwIDI0IDI0XCJcbiAgICAgIHN0cm9rZS13aWR0aD1cIjEuNVwiXG4gICAgICBzdHJva2U9XCJjdXJyZW50Q29sb3JcIlxuICAgICAgY2xhc3M9XCJwYWdlLWljb25cIlxuICAgID5cbiAgICAgIDxwYXRoIHN0cm9rZS1saW5lY2FwPVwicm91bmRcIiBzdHJva2UtbGluZWpvaW49XCJyb3VuZFwiIGQ9XCJNOC4yNSA0LjVsNy41IDcuNS03LjUgNy41XCIvPlxuICAgIDwvc3ZnPlxuICA8L2Rpdj5cbjwvbmctdGVtcGxhdGU+XG5cbjxuZy10ZW1wbGF0ZSAjcGFnZU51bWJlclRlbXBsYXRlIGxldC1wYWdlPlxuICA8ZGl2XG4gICAgY2xhc3M9XCJwYWdlLW51bWJlclwiXG4gICAgW25nQ2xhc3NdPVwieyAnYWN0aXZlJzogKHBhZ2luYXRpb24kIHwgYXN5bmMpPy5wYWdlID09PSBwYWdlIH1cIlxuICAgIChjbGljayk9XCJnb1RvUGFnZShwYWdlIC0gMSlcIlxuICA+XG4gICAgPHNwYW4+e3twYWdlfX08L3NwYW4+XG4gIDwvZGl2PlxuPC9uZy10ZW1wbGF0ZT5cblxuPG5nLXRlbXBsYXRlICNkb3RUZW1wbGF0ZT5cbiAgPGRpdiBjbGFzcz1cInBhZ2UtZG90XCI+XG4gICAgPHN2ZyB4bWxucz1cImh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnXCIgd2lkdGg9XCIxOFwiIGhlaWdodD1cIjE0XCIgdmlld0JveD1cIjAgMCAxOCAxNFwiPlxuICAgICAgPHRleHQgaWQ9XCJfLlwiIGRhdGEtbmFtZT1cIuKApi5cIiB0cmFuc2Zvcm09XCJ0cmFuc2xhdGUoOSAxMSlcIiBmaWxsPVwiIzZiYWRiOVwiIGZvbnQtc2l6ZT1cIjFlbVwiIGZvbnQtZmFtaWx5PVwiSGVsdmV0aWNhXCI+XG4gICAgICAgIDx0c3BhbiB4PVwiLTguOTQ1XCIgeT1cIjBcIj7igKYuPC90c3Bhbj5cbiAgICAgIDwvdGV4dD5cbiAgICA8L3N2Zz5cbiAgPC9kaXY+XG48L25nLXRlbXBsYXRlPlxuIl19