dfx-bootstrap-table
Version:
Angular table CDK implementation for Bootstrap with filtering, sorting and pagination.
244 lines • 45 kB
JavaScript
import { _IdGenerator } from '@angular/cdk/a11y';
import { ChangeDetectionStrategy, ChangeDetectorRef, Component, EventEmitter, Inject, InjectionToken, Input, Optional, Output, ViewEncapsulation, booleanAttribute, inject, numberAttribute, } from '@angular/core';
import { FormsModule } from '@angular/forms';
import { ReplaySubject } from 'rxjs';
import { NgbPaginatorIntl } from './paginator-intl.service';
import * as i0 from "@angular/core";
import * as i1 from "./paginator-intl.service";
import * as i2 from "@angular/forms";
/** The default page size if there is no page size and there are no provided page size options. */
const DEFAULT_PAGE_SIZE = 50;
/** Injection token that can be used to provide the default options for the paginator module. */
export const NGB_PAGINATOR_DEFAULT_OPTIONS = new InjectionToken('NGB_PAGINATOR_DEFAULT_OPTIONS');
export class NgbPaginator {
/** The zero-based page index of the displayed list of items. Defaulted to 0. */
get pageIndex() {
return this._pageIndex;
}
set pageIndex(value) {
this._pageIndex = Math.max(value || 0, 0);
this._changeDetectorRef.markForCheck();
}
/** The length of the total number of items that are being paginated. Defaulted to 0. */
get length() {
return this._length;
}
set length(value) {
this._length = value || 0;
this._changeDetectorRef.markForCheck();
}
/** Number of items to display on a page. By default set to 50. */
get pageSize() {
return this._pageSize;
}
set pageSize(value) {
this._pageSize = Math.max(value || 0, 0);
this._updateDisplayedPageSizeOptions();
}
/** The set of provided page size options to display to the user. */
get pageSizeOptions() {
return this._pageSizeOptions;
}
set pageSizeOptions(value) {
this._pageSizeOptions = (value || []).map((p) => numberAttribute(p, 0));
this._updateDisplayedPageSizeOptions();
}
constructor(
// eslint-disable-next-line @angular-eslint/prefer-inject
_intl,
// eslint-disable-next-line @angular-eslint/prefer-inject
_changeDetectorRef,
// eslint-disable-next-line @angular-eslint/prefer-inject
defaults) {
this._intl = _intl;
this._changeDetectorRef = _changeDetectorRef;
/** ID for the DOM node containing the paginator's items per page label. */
this._pageSizeLabelId = inject(_IdGenerator).getId('ngb-paginator-page-size-label-');
this._isInitialized = false;
this._initializedStream = new ReplaySubject(1);
this._pageIndex = 0;
this._length = 0;
this._pageSizeOptions = [];
/** Whether to hide the page size selection UI from the user. */
this.hidePageSize = false;
/** Whether to show the first/last buttons UI to the user. */
this.showFirstLastButtons = false;
/** Whether the paginator is disabled. */
this.disabled = false;
/** Event emitted when the paginator changes the page size or page index. */
this.page = new EventEmitter();
/** Emits when the paginator is initialized. */
this.initialized = this._initializedStream;
this._intlChanges = _intl.changes.subscribe(() => this._changeDetectorRef.markForCheck());
if (defaults) {
const { pageSize, pageSizeOptions, hidePageSize, showFirstLastButtons } = defaults;
if (pageSize != null) {
this.pageSize = pageSize;
}
if (pageSizeOptions != null) {
this.pageSizeOptions = pageSizeOptions;
}
if (hidePageSize != null) {
this.hidePageSize = hidePageSize;
}
if (showFirstLastButtons != null) {
this.showFirstLastButtons = showFirstLastButtons;
}
}
}
ngOnInit() {
this._isInitialized = true;
this._updateDisplayedPageSizeOptions();
this._initializedStream.next();
}
ngOnDestroy() {
this._initializedStream.complete();
this._intlChanges.unsubscribe();
}
/** Advances to the next page if it exists. */
nextPage() {
if (!this.hasNextPage()) {
return;
}
const previousPageIndex = this.pageIndex;
this.pageIndex = this.pageIndex + 1;
this._emitPageEvent(previousPageIndex);
}
/** Move back to the previous page if it exists. */
previousPage() {
if (!this.hasPreviousPage()) {
return;
}
const previousPageIndex = this.pageIndex;
this.pageIndex = this.pageIndex - 1;
this._emitPageEvent(previousPageIndex);
}
/** Move to the first page if not already there. */
firstPage() {
// hasPreviousPage being false implies at the start
if (!this.hasPreviousPage()) {
return;
}
const previousPageIndex = this.pageIndex;
this.pageIndex = 0;
this._emitPageEvent(previousPageIndex);
}
/** Move to the last page if not already there. */
lastPage() {
// hasNextPage being false implies at the end
if (!this.hasNextPage()) {
return;
}
const previousPageIndex = this.pageIndex;
this.pageIndex = this.getNumberOfPages() - 1;
this._emitPageEvent(previousPageIndex);
}
/** Whether there is a previous page. */
hasPreviousPage() {
return this.pageIndex >= 1 && this.pageSize !== 0;
}
/** Whether there is a next page. */
hasNextPage() {
const maxPageIndex = this.getNumberOfPages() - 1;
return this.pageIndex < maxPageIndex && this.pageSize !== 0;
}
/** Calculate the number of pages */
getNumberOfPages() {
if (!this.pageSize) {
return 0;
}
return Math.ceil(this.length / this.pageSize);
}
/**
* Changes the page size so that the first item displayed on the page will still be
* displayed using the new page size.
*
* For example, if the page size is 10 and on the second page (items indexed 10-19) then
* switching so that the page size is 5 will set the third page as the current page so
* that the 10th item will still be displayed.
*/
_changePageSize(pageSize) {
// Current page needs to be updated to reflect the new page size. Navigate to the page
// containing the previous page's first item.
const startIndex = this.pageIndex * this.pageSize;
const previousPageIndex = this.pageIndex;
this.pageIndex = Math.floor(startIndex / pageSize) || 0;
this.pageSize = pageSize;
this._emitPageEvent(previousPageIndex);
}
/** Checks whether the buttons for going forwards should be disabled. */
_nextButtonsDisabled() {
return this.disabled || !this.hasNextPage();
}
/** Checks whether the buttons for going backwards should be disabled. */
_previousButtonsDisabled() {
return this.disabled || !this.hasPreviousPage();
}
/**
* Updates the list of page size options to display to the user. Includes making sure that
* the page size is an option and that the list is sorted.
*/
_updateDisplayedPageSizeOptions() {
if (!this._isInitialized) {
return;
}
// If no page size is provided, use the first page size option or the default page size.
if (!this.pageSize) {
this._pageSize = this.pageSizeOptions.length != 0 ? this.pageSizeOptions[0] : DEFAULT_PAGE_SIZE;
}
this._displayedPageSizeOptions = this.pageSizeOptions.slice();
if (this._displayedPageSizeOptions.indexOf(this.pageSize) === -1) {
this._displayedPageSizeOptions.push(this.pageSize);
}
// Sort the numbers using a number-specific sort function.
this._displayedPageSizeOptions.sort((a, b) => a - b);
this._changeDetectorRef.markForCheck();
}
/** Emits an event notifying that a change of the paginator's properties has been triggered. */
_emitPageEvent(previousPageIndex) {
this.page.emit({
previousPageIndex,
pageIndex: this.pageIndex,
pageSize: this.pageSize,
length: this.length,
});
}
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.2", ngImport: i0, type: NgbPaginator, deps: [{ token: i1.NgbPaginatorIntl }, { token: i0.ChangeDetectorRef }, { token: NGB_PAGINATOR_DEFAULT_OPTIONS, optional: true }], target: i0.ɵɵFactoryTarget.Component }); }
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.2", type: NgbPaginator, isStandalone: true, selector: "ngb-paginator", inputs: { pageIndex: ["pageIndex", "pageIndex", numberAttribute], length: ["length", "length", numberAttribute], pageSize: ["pageSize", "pageSize", numberAttribute], pageSizeOptions: "pageSizeOptions", hidePageSize: ["hidePageSize", "hidePageSize", booleanAttribute], showFirstLastButtons: ["showFirstLastButtons", "showFirstLastButtons", booleanAttribute], disabled: ["disabled", "disabled", booleanAttribute], size: "size" }, outputs: { page: "page" }, host: { attributes: { "role": "group" } }, exportAs: ["ngbPaginator"], ngImport: i0, template: "<div\n class=\"d-flex flex-column-reverse flex-lg-row justify-content-center justify-content-lg-end align-items-end align-items-lg-center gap-lg-5 gap-3\">\n @if (!hidePageSize) {\n <div class=\"d-inline-flex align-items-center gap-2\">\n <small class=\"ws-nowrap\" [attr.id]=\"_pageSizeLabelId\">{{ _intl.itemsPerPageLabel }}</small>\n\n @if (_displayedPageSizeOptions.length > 1) {\n <select\n class=\"form-select form-select-sm\"\n name=\"pageSize\"\n [ngModel]=\"pageSize\"\n [disabled]=\"disabled\"\n [attr.aria-labelledby]=\"_pageSizeLabelId\"\n (ngModelChange)=\"_changePageSize($any($event))\">\n @for (pageSizeOption of _displayedPageSizeOptions; track pageSizeOption) {\n <option [ngValue]=\"pageSizeOption\">{{ pageSizeOption }}</option>\n }\n </select>\n } @if (_displayedPageSizeOptions.length <= 1) {\n <small>{{pageSize}}</small>\n }\n </div>\n }\n\n <div class=\"d-inline-flex align-items-center gap-lg-5 gap-3\">\n <small aria-live=\"polite\">{{ _intl.getRangeLabel(pageIndex, pageSize, length) }}</small>\n\n <ul [class]=\"'my-0 pagination' + (size ? ' pagination-' + size : '')\">\n @if (showFirstLastButtons) {\n <li class=\"page-item\" [class.disabled]=\"_previousButtonsDisabled()\">\n <button\n class=\"page-link\"\n type=\"button\"\n (click)=\"firstPage()\"\n [disabled]=\"_previousButtonsDisabled()\"\n [attr.aria-label]=\"_intl.firstPageLabel\"\n [attr.tabindex]=\"_previousButtonsDisabled() ? '-1' : null\">\n <span aria-hidden=\"true\">««</span>\n </button>\n </li>\n }\n\n <li class=\"page-item\" [class.disabled]=\"_previousButtonsDisabled()\">\n <button\n class=\"page-link\"\n type=\"button\"\n (click)=\"previousPage()\"\n [disabled]=\"_previousButtonsDisabled()\"\n [attr.aria-label]=\"_intl.previousPageLabel\"\n [attr.tabindex]=\"_previousButtonsDisabled() ? '-1' : null\">\n <span aria-hidden=\"true\">«</span>\n </button>\n </li>\n <li class=\"page-item\" [class.disabled]=\"_nextButtonsDisabled()\">\n <button\n class=\"page-link\"\n type=\"button\"\n (click)=\"nextPage()\"\n [disabled]=\"_nextButtonsDisabled()\"\n [attr.aria-label]=\"_intl.nextPageLabel\"\n [attr.tabindex]=\"_nextButtonsDisabled() ? '-1' : null\">\n <span aria-hidden=\"true\">»</span>\n </button>\n </li>\n\n @if(showFirstLastButtons) {\n <li class=\"page-item\" [class.disabled]=\"_nextButtonsDisabled()\">\n <button\n class=\"page-link\"\n type=\"button\"\n (click)=\"lastPage()\"\n [disabled]=\"_nextButtonsDisabled()\"\n [attr.aria-label]=\"_intl.lastPageLabel\"\n [attr.tabindex]=\"_nextButtonsDisabled() ? '-1' : null\">\n <span aria-hidden=\"true\">»»</span>\n </button>\n </li>\n }\n </ul>\n </div>\n</div>\n", styles: [".ws-nowrap{white-space:nowrap}\n"], dependencies: [{ kind: "ngmodule", type: FormsModule }, { 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"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.2", ngImport: i0, type: NgbPaginator, decorators: [{
type: Component,
args: [{ selector: 'ngb-paginator', exportAs: 'ngbPaginator', host: {
role: 'group',
}, changeDetection: ChangeDetectionStrategy.OnPush, encapsulation: ViewEncapsulation.None, imports: [FormsModule], template: "<div\n class=\"d-flex flex-column-reverse flex-lg-row justify-content-center justify-content-lg-end align-items-end align-items-lg-center gap-lg-5 gap-3\">\n @if (!hidePageSize) {\n <div class=\"d-inline-flex align-items-center gap-2\">\n <small class=\"ws-nowrap\" [attr.id]=\"_pageSizeLabelId\">{{ _intl.itemsPerPageLabel }}</small>\n\n @if (_displayedPageSizeOptions.length > 1) {\n <select\n class=\"form-select form-select-sm\"\n name=\"pageSize\"\n [ngModel]=\"pageSize\"\n [disabled]=\"disabled\"\n [attr.aria-labelledby]=\"_pageSizeLabelId\"\n (ngModelChange)=\"_changePageSize($any($event))\">\n @for (pageSizeOption of _displayedPageSizeOptions; track pageSizeOption) {\n <option [ngValue]=\"pageSizeOption\">{{ pageSizeOption }}</option>\n }\n </select>\n } @if (_displayedPageSizeOptions.length <= 1) {\n <small>{{pageSize}}</small>\n }\n </div>\n }\n\n <div class=\"d-inline-flex align-items-center gap-lg-5 gap-3\">\n <small aria-live=\"polite\">{{ _intl.getRangeLabel(pageIndex, pageSize, length) }}</small>\n\n <ul [class]=\"'my-0 pagination' + (size ? ' pagination-' + size : '')\">\n @if (showFirstLastButtons) {\n <li class=\"page-item\" [class.disabled]=\"_previousButtonsDisabled()\">\n <button\n class=\"page-link\"\n type=\"button\"\n (click)=\"firstPage()\"\n [disabled]=\"_previousButtonsDisabled()\"\n [attr.aria-label]=\"_intl.firstPageLabel\"\n [attr.tabindex]=\"_previousButtonsDisabled() ? '-1' : null\">\n <span aria-hidden=\"true\">««</span>\n </button>\n </li>\n }\n\n <li class=\"page-item\" [class.disabled]=\"_previousButtonsDisabled()\">\n <button\n class=\"page-link\"\n type=\"button\"\n (click)=\"previousPage()\"\n [disabled]=\"_previousButtonsDisabled()\"\n [attr.aria-label]=\"_intl.previousPageLabel\"\n [attr.tabindex]=\"_previousButtonsDisabled() ? '-1' : null\">\n <span aria-hidden=\"true\">«</span>\n </button>\n </li>\n <li class=\"page-item\" [class.disabled]=\"_nextButtonsDisabled()\">\n <button\n class=\"page-link\"\n type=\"button\"\n (click)=\"nextPage()\"\n [disabled]=\"_nextButtonsDisabled()\"\n [attr.aria-label]=\"_intl.nextPageLabel\"\n [attr.tabindex]=\"_nextButtonsDisabled() ? '-1' : null\">\n <span aria-hidden=\"true\">»</span>\n </button>\n </li>\n\n @if(showFirstLastButtons) {\n <li class=\"page-item\" [class.disabled]=\"_nextButtonsDisabled()\">\n <button\n class=\"page-link\"\n type=\"button\"\n (click)=\"lastPage()\"\n [disabled]=\"_nextButtonsDisabled()\"\n [attr.aria-label]=\"_intl.lastPageLabel\"\n [attr.tabindex]=\"_nextButtonsDisabled() ? '-1' : null\">\n <span aria-hidden=\"true\">»»</span>\n </button>\n </li>\n }\n </ul>\n </div>\n</div>\n", styles: [".ws-nowrap{white-space:nowrap}\n"] }]
}], ctorParameters: () => [{ type: i1.NgbPaginatorIntl }, { type: i0.ChangeDetectorRef }, { type: undefined, decorators: [{
type: Optional
}, {
type: Inject,
args: [NGB_PAGINATOR_DEFAULT_OPTIONS]
}] }], propDecorators: { pageIndex: [{
type: Input,
args: [{ transform: numberAttribute }]
}], length: [{
type: Input,
args: [{ transform: numberAttribute }]
}], pageSize: [{
type: Input,
args: [{ transform: numberAttribute }]
}], pageSizeOptions: [{
type: Input
}], hidePageSize: [{
type: Input,
args: [{ transform: booleanAttribute }]
}], showFirstLastButtons: [{
type: Input,
args: [{ transform: booleanAttribute }]
}], disabled: [{
type: Input,
args: [{ transform: booleanAttribute }]
}], size: [{
type: Input
}], page: [{
type: Output
}] } });
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicGFnaW5hdG9yLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vLi4vLi4vbGlicy9kZngtYm9vdHN0cmFwLXRhYmxlL3NyYy9saWIvcGFnaW5hdG9yL3BhZ2luYXRvci50cyIsIi4uLy4uLy4uLy4uLy4uLy4uL2xpYnMvZGZ4LWJvb3RzdHJhcC10YWJsZS9zcmMvbGliL3BhZ2luYXRvci9wYWdpbmF0b3IuaHRtbCJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQUUsWUFBWSxFQUFFLE1BQU0sbUJBQW1CLENBQUM7QUFDakQsT0FBTyxFQUNMLHVCQUF1QixFQUN2QixpQkFBaUIsRUFDakIsU0FBUyxFQUNULFlBQVksRUFDWixNQUFNLEVBQ04sY0FBYyxFQUNkLEtBQUssRUFHTCxRQUFRLEVBQ1IsTUFBTSxFQUNOLGlCQUFpQixFQUNqQixnQkFBZ0IsRUFDaEIsTUFBTSxFQUNOLGVBQWUsR0FDaEIsTUFBTSxlQUFlLENBQUM7QUFDdkIsT0FBTyxFQUFFLFdBQVcsRUFBRSxNQUFNLGdCQUFnQixDQUFDO0FBRTdDLE9BQU8sRUFBYyxhQUFhLEVBQWdCLE1BQU0sTUFBTSxDQUFDO0FBRS9ELE9BQU8sRUFBRSxnQkFBZ0IsRUFBRSxNQUFNLDBCQUEwQixDQUFDOzs7O0FBRTVELGtHQUFrRztBQUNsRyxNQUFNLGlCQUFpQixHQUFHLEVBQUUsQ0FBQztBQW1DN0IsZ0dBQWdHO0FBQ2hHLE1BQU0sQ0FBQyxNQUFNLDZCQUE2QixHQUFHLElBQUksY0FBYyxDQUE2QiwrQkFBK0IsQ0FBQyxDQUFDO0FBa0I3SCxNQUFNLE9BQU8sWUFBWTtJQVF2QixnRkFBZ0Y7SUFDaEYsSUFDSSxTQUFTO1FBQ1gsT0FBTyxJQUFJLENBQUMsVUFBVSxDQUFDO0lBQ3pCLENBQUM7SUFDRCxJQUFJLFNBQVMsQ0FBQyxLQUFhO1FBQ3pCLElBQUksQ0FBQyxVQUFVLEdBQUcsSUFBSSxDQUFDLEdBQUcsQ0FBQyxLQUFLLElBQUksQ0FBQyxFQUFFLENB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QyxFQUFFLFNBQVMsRUFBRSxlQUFlLEVBQUU7Z0JBWWpDLFFBQVE7c0JBRFgsS0FBSzt1QkFBQyxFQUFFLFNBQVMsRUFBRSxlQUFlLEVBQUU7Z0JBWWpDLGVBQWU7c0JBRGxCLEtBQUs7Z0JBV2tDLFlBQVk7c0JBQW5ELEtBQUs7dUJBQUMsRUFBRSxTQUFTLEVBQUUsZ0JBQWdCLEVBQUU7Z0JBR0Usb0JBQW9CO3NCQUEzRCxLQUFLO3VCQUFDLEVBQUUsU0FBUyxFQUFFLGdCQUFnQixFQUFFO2dCQUdFLFFBQVE7c0JBQS9DLEtBQUs7dUJBQUMsRUFBRSxTQUFTLEVBQUUsZ0JBQWdCLEVBQUU7Z0JBTzdCLElBQUk7c0JBQVosS0FBSztnQkFHYSxJQUFJO3NCQUF0QixNQUFNIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgX0lkR2VuZXJhdG9yIH0gZnJvbSAnQGFuZ3VsYXIvY2RrL2ExMXknO1xuaW1wb3J0IHtcbiAgQ2hhbmdlRGV0ZWN0aW9uU3RyYXRlZ3ksXG4gIENoYW5nZURldGVjdG9yUmVmLFxuICBDb21wb25lbnQsXG4gIEV2ZW50RW1pdHRlcixcbiAgSW5qZWN0LFxuICBJbmplY3Rpb25Ub2tlbixcbiAgSW5wdXQsXG4gIE9uRGVzdHJveSxcbiAgT25Jbml0LFxuICBPcHRpb25hbCxcbiAgT3V0cHV0LFxuICBWaWV3RW5jYXBzdWxhdGlvbixcbiAgYm9vbGVhbkF0dHJpYnV0ZSxcbiAgaW5qZWN0LFxuICBudW1iZXJBdHRyaWJ1dGUsXG59IGZyb20gJ0Bhbmd1bGFyL2NvcmUnO1xuaW1wb3J0IHsgRm9ybXNNb2R1bGUgfSBmcm9tICdAYW5ndWxhci9mb3Jtcyc7XG5cbmltcG9ydCB7IE9ic2VydmFibGUsIFJlcGxheVN1YmplY3QsIFN1YnNjcmlwdGlvbiB9IGZyb20gJ3J4anMnO1xuXG5pbXBvcnQgeyBOZ2JQYWdpbmF0b3JJbnRsIH0gZnJvbSAnLi9wYWdpbmF0b3ItaW50bC5zZXJ2aWNlJztcblxuLyoqIFRoZSBkZWZhdWx0IHBhZ2Ugc2l6ZSBpZiB0aGVyZSBpcyBubyBwYWdlIHNpemUgYW5kIHRoZXJlIGFyZSBubyBwcm92aWRlZCBwYWdlIHNpemUgb3B0aW9ucy4gKi9cbmNvbnN0IERFRkFVTFRfUEFHRV9TSVpFID0gNTA7XG5cbi8qKlxuICogQ2hhbmdlIGV2ZW50IG9iamVjdCB0aGF0IGlzIGVtaXR0ZWQgd2hlbiB0aGUgdXNlciBzZWxlY3RzIGFcbiAqIGRpZmZlcmVudCBwYWdlIHNpemUgb3IgbmF2aWdhdGVzIHRvIGFub3RoZXIgcGFnZS5cbiAqL1xuZXhwb3J0IHR5cGUgUGFnZUV2ZW50ID0ge1xuICAvKiogVGhlIGN1cnJlbnQgcGFnZSBpbmRleC4gKi9cbiAgcGFnZUluZGV4OiBudW1iZXI7XG5cbiAgLyoqIEluZGV4IG9mIHRoZSBwYWdlIHRoYXQgd2FzIHNlbGVjdGVkIHByZXZpb3VzbHkuICovXG4gIHByZXZpb3VzUGFnZUluZGV4OiBudW1iZXI7XG5cbiAgLyoqIFRoZSBjdXJyZW50IHBhZ2Ugc2l6ZS4gKi9cbiAgcGFnZVNpemU6IG51bWJlcjtcblxuICAvKiogVGhlIGN1cnJlbnQgdG90YWwgbnVtYmVyIG9mIGl0ZW1zIGJlaW5nIHBhZ2VkLiAqL1xuICBsZW5ndGg6IG51bWJlcjtcbn07XG5cbi8qKiBPYmplY3QgdGhhdCBjYW4gYmUgdXNlZCB0byBjb25maWd1cmUgdGhlIGRlZmF1bHQgb3B0aW9ucyBmb3IgdGhlIHBhZ2luYXRvciBtb2R1bGUuICovXG5leHBvcnQgaW50ZXJmYWNlIE5nYlBhZ2luYXRvckRlZmF1bHRPcHRpb25zIHtcbiAgLyoqIE51bWJlciBvZiBpdGVtcyB0byBkaXNwbGF5IG9uIGEgcGFnZS4gQnkgZGVmYXVsdCBzZXQgdG8gNTAuICovXG4gIHBhZ2VTaXplPzogbnVtYmVyO1xuXG4gIC8qKiBUaGUgc2V0IG9mIHByb3ZpZGVkIHBhZ2Ugc2l6ZSBvcHRpb25zIHRvIGRpc3BsYXkgdG8gdGhlIHVzZXIuICovXG4gIHBhZ2VTaXplT3B0aW9ucz86IG51bWJlcltdO1xuXG4gIC8qKiBXaGV0aGVyIHRvIGhpZGUgdGhlIHBhZ2Ugc2l6ZSBzZWxlY3Rpb24gVUkgZnJvbSB0aGUgdXNlci4gKi9cbiAgaGlkZVBhZ2VTaXplPzogYm9vbGVhbjtcblxuICAvKiogV2hldGhlciB0byBzaG93IHRoZSBmaXJzdC9sYXN0IGJ1dHRvbnMgVUkgdG8gdGhlIHVzZXIuICovXG4gIHNob3dGaXJzdExhc3RCdXR0b25zPzogYm9vbGVhbjtcbn1cblxuLyoqIEluamVjdGlvbiB0b2tlbiB0aGF0IGNhbiBiZSB1c2VkIHRvIHByb3ZpZGUgdGhlIGRlZmF1bHQgb3B0aW9ucyBmb3IgdGhlIHBhZ2luYXRvciBtb2R1bGUuICovXG5leHBvcnQgY29uc3QgTkdCX1BBR0lOQVRPUl9ERUZBVUxUX09QVElPTlMgPSBuZXcgSW5qZWN0aW9uVG9rZW48TmdiUGFnaW5hdG9yRGVmYXVsdE9wdGlvbnM+KCdOR0JfUEFHSU5BVE9SX0RFRkFVTFRfT1BUSU9OUycpO1xuXG5AQ29tcG9uZW50KHtcbiAgc2VsZWN0b3I6ICduZ2ItcGFnaW5hdG9yJyxcbiAgZXhwb3J0QXM6ICduZ2JQYWdpbmF0b3InLFxuICB0ZW1wbGF0ZVVybDogJy4vcGFnaW5hdG9yLmh0bWwnLFxuICBzdHlsZXM6IGBcbiAgICAud3Mtbm93cmFwIHtcbiAgICAgIHdoaXRlLXNwYWNlOiBub3dyYXA7XG4gICAgfVxuICBgLFxuICBob3N0OiB7XG4gICAgcm9sZTogJ2dyb3VwJyxcbiAgfSxcbiAgY2hhbmdlRGV0ZWN0aW9uOiBDaGFuZ2VEZXRlY3Rpb25TdHJhdGVneS5PblB1c2gsXG4gIGVuY2Fwc3VsYXRpb246IFZpZXdFbmNhcHN1bGF0aW9uLk5vbmUsXG4gIGltcG9ydHM6IFtGb3Jtc01vZHVsZV0sXG59KVxuZXhwb3J0IGNsYXNzIE5nYlBhZ2luYXRvciBpbXBsZW1lbnRzIE9uSW5pdCwgT25EZXN0cm95IHtcbiAgLyoqIElEIGZvciB0aGUgRE9NIG5vZGUgY29udGFpbmluZyB0aGUgcGFnaW5hdG9yJ3MgaXRlbXMgcGVyIHBhZ2UgbGFiZWwuICovXG4gIHJlYWRvbmx5IF9wYWdlU2l6ZUxhYmVsSWQgPSBpbmplY3QoX0lkR2VuZXJhdG9yKS5nZXRJZCgnbmdiLXBhZ2luYXRvci1wYWdlLXNpemUtbGFiZWwtJyk7XG5cbiAgcHJpdmF0ZSBfaW50bENoYW5nZXM6IFN1YnNjcmlwdGlvbjtcbiAgcHJpdmF0ZSBfaXNJbml0aWFsaXplZCA9IGZhbHNlO1xuICBwcml2YXRlIF9pbml0aWFsaXplZFN0cmVhbSA9IG5ldyBSZXBsYXlTdWJqZWN0PHZvaWQ+KDEpO1xuXG4gIC8qKiBUaGUgemVyby1iYXNlZCBwYWdlIGluZGV4IG9mIHRoZSBkaXNwbGF5ZWQgbGlzdCBvZiBpdGVtcy4gRGVmYXVsdGVkIHRvIDAuICovXG4gIEBJbnB1dCh7IHRyYW5zZm9ybTogbnVtYmVyQXR0cmlidXRlIH0pXG4gIGdldCBwYWdlSW5kZXgoKTogbnVtYmVyIHtcbiAgICByZXR1cm4gdGhpcy5fcGFnZUluZGV4O1xuICB9XG4gIHNldCBwYWdlSW5kZXgodmFsdWU6IG51bWJlcikge1xuICAgIHRoaXMuX3BhZ2VJbmRleCA9IE1hdGgubWF4KHZhbHVlIHx8IDAsIDApO1xuICAgIHRoaXMuX2NoYW5nZURldGVjdG9yUmVmLm1hcmtGb3JDaGVjaygpO1xuICB9XG4gIHByaXZhdGUgX3BhZ2VJbmRleCA9IDA7XG5cbiAgLyoqIFRoZSBsZW5ndGggb2YgdGhlIHRvdGFsIG51bWJlciBvZiBpdGVtcyB0aGF0IGFyZSBiZWluZyBwYWdpbmF0ZWQuIERlZmF1bHRlZCB0byAwLiAqL1xuICBASW5wdXQoeyB0cmFuc2Zvcm06IG51bWJlckF0dHJpYnV0ZSB9KVxuICBnZXQgbGVuZ3RoKCk6IG51bWJlciB7XG4gICAgcmV0dXJuIHRoaXMuX2xlbmd0aDtcbiAgfVxuICBzZXQgbGVuZ3RoKHZhbHVlOiBudW1iZXIpIHtcbiAgICB0aGlzLl9sZW5ndGggPSB2YWx1ZSB8fCAwO1xuICAgIHRoaXMuX2NoYW5nZURldGVjdG9yUmVmLm1hcmtGb3JDaGVjaygpO1xuICB9XG4gIHByaXZhdGUgX2xlbmd0aCA9IDA7XG5cbiAgLyoqIE51bWJlciBvZiBpdGVtcyB0byBkaXNwbGF5IG9uIGEgcGFnZS4gQnkgZGVmYXVsdCBzZXQgdG8gNTAuICovXG4gIEBJbnB1dCh7IHRyYW5zZm9ybTogbnVtYmVyQXR0cmlidXRlIH0pXG4gIGdldCBwYWdlU2l6ZSgpOiBudW1iZXIge1xuICAgIHJldHVybiB0aGlzLl9wYWdlU2l6ZTtcbiAgfVxuICBzZXQgcGFnZVNpemUodmFsdWU6IG51bWJlcikge1xuICAgIHRoaXMuX3BhZ2VTaXplID0gTWF0aC5tYXgodmFsdWUgfHwgMCwgMCk7XG4gICAgdGhpcy5fdXBkYXRlRGlzcGxheWVkUGFnZVNpemVPcHRpb25zKCk7XG4gIH1cbiAgcHJpdmF0ZSBfcGFnZVNpemUhOiBudW1iZXI7XG5cbiAgLyoqIFRoZSBzZXQgb2YgcHJvdmlkZWQgcGFnZSBzaXplIG9wdGlvbnMgdG8gZGlzcGxheSB0byB0aGUgdXNlci4gKi9cbiAgQElucHV0KClcbiAgZ2V0IHBhZ2VTaXplT3B0aW9ucygpOiBudW1iZXJbXSB7XG4gICAgcmV0dXJuIHRoaXMuX3BhZ2VTaXplT3B0aW9ucztcbiAgfVxuICBzZXQgcGFnZVNpemVPcHRpb25zKHZhbHVlOiBudW1iZXJbXSB8IHJlYWRvbmx5IG51bWJlcltdKSB7XG4gICAgdGhpcy5fcGFnZVNpemVPcHRpb25zID0gKHZhbHVlIHx8IChbXSBhcyBudW1iZXJbXSkpLm1hcCgocCkgPT4gbnVtYmVyQXR0cmlidXRlKHAsIDApKTtcbiAgICB0aGlzLl91cGRhdGVEaXNwbGF5ZWRQYWdlU2l6ZU9wdGlvbnMoKTtcbiAgfVxuICBwcml2YXRlIF9wYWdlU2l6ZU9wdGlvbnM6IG51bWJlcltdID0gW107XG5cbiAgLyoqIFdoZXRoZXIgdG8gaGlkZSB0aGUgcGFnZSBzaXplIHNlbGVjdGlvbiBVSSBmcm9tIHRoZSB1c2VyLiAqL1xuICBASW5wdXQoeyB0cmFuc2Zvcm06IGJvb2xlYW5BdHRyaWJ1dGUgfSkgaGlkZVBhZ2VTaXplID0gZmFsc2U7XG5cbiAgLyoqIFdoZXRoZXIgdG8gc2hvdyB0aGUgZmlyc3QvbGFzdCBidXR0b25zIFVJIHRvIHRoZSB1c2VyLiAqL1xuICBASW5wdXQoeyB0cmFuc2Zvcm06IGJvb2xlYW5BdHRyaWJ1dGUgfSkgc2hvd0ZpcnN0TGFzdEJ1dHRvbnMgPSBmYWxzZTtcblxuICAvKiogV2hldGhlciB0aGUgcGFnaW5hdG9yIGlzIGRpc2FibGVkLiAqL1xuICBASW5wdXQoeyB0cmFuc2Zvcm06IGJvb2xlYW5BdHRyaWJ1dGUgfSkgZGlzYWJsZWQgPSBmYWxzZTtcblxuICAvKipcbiAgICogVGhlIHBhZ2luYXRvciBkaXNwbGF5IHNpemUuXG4gICAqXG4gICAqIEJvb3RzdHJhcCBjdXJyZW50bHkgc3VwcG9ydHMgc21hbGwgYW5kIGxhcmdlIHNpemVzLlxuICAgKi9cbiAgQElucHV0KCkgc2l6ZT86ICdzbScgfCAnbGcnIHwgbnVsbDtcblxuICAvKiogRXZlbnQgZW1pdHRlZCB3aGVuIHRoZSBwYWdpbmF0b3IgY2hhbmdlcyB0aGUgcGFnZSBzaXplIG9yIHBhZ2UgaW5kZXguICovXG4gIEBPdXRwdXQoKSByZWFkb25seSBwYWdlOiBFdmVudEVtaXR0ZXI8UGFnZUV2ZW50PiA9IG5ldyBFdmVudEVtaXR0ZXI8UGFnZUV2ZW50PigpO1xuXG4gIC8qKiBEaXNwbGF5ZWQgc2V0IG9mIHBhZ2Ugc2l6ZSBvcHRpb25zLiBXaWxsIGJlIHNvcnRlZCBhbmQgaW5jbHVkZSBjdXJyZW50IHBhZ2Ugc2l6ZS4gKi9cbiAgX2Rpc3BsYXllZFBhZ2VTaXplT3B0aW9ucyE6IG51bWJlcltdO1xuXG4gIC8qKiBFbWl0cyB3aGVuIHRoZSBwYWdpbmF0b3IgaXMgaW5pdGlhbGl6ZWQuICovXG4gIGluaXRpYWxpemVkOiBPYnNlcnZhYmxlPHZvaWQ+ID0gdGhpcy5faW5pdGlhbGl6ZWRTdHJlYW07XG5cbiAgY29uc3RydWN0b3IoXG4gICAgLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIEBhbmd1bGFyLWVzbGludC9wcmVmZXItaW5qZWN0XG4gICAgcHVibGljIF9pbnRsOiBOZ2JQYWdpbmF0b3JJbnRsLFxuICAgIC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBAYW5ndWxhci1lc2xpbnQvcHJlZmVyLWluamVjdFxuICAgIHByaXZhdGUgX2NoYW5nZURldGVjdG9yUmVmOiBDaGFuZ2VEZXRlY3RvclJlZixcbiAgICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgQGFuZ3VsYXItZXNsaW50L3ByZWZlci1pbmplY3RcbiAgICBAT3B0aW9uYWwoKSBASW5qZWN0KE5HQl9QQUdJTkFUT1JfREVGQVVMVF9PUFRJT05TKSBkZWZhdWx0cz86IE5nYlBhZ2luYXRvckRlZmF1bHRPcHRpb25zLFxuICApIHtcbiAgICB0aGlzLl9pbnRsQ2hhbmdlcyA9IF9pbnRsLmNoYW5nZXMuc3Vic2NyaWJlKCgpID0+IHRoaXMuX2NoYW5nZURldGVjdG9yUmVmLm1hcmtGb3JDaGVjaygpKTtcblxuICAgIGlmIChkZWZhdWx0cykge1xuICAgICAgY29uc3QgeyBwYWdlU2l6ZSwgcGFnZVNpemVPcHRpb25zLCBoaWRlUGFnZVNpemUsIHNob3dGaXJzdExhc3RCdXR0b25zIH0gPSBkZWZhdWx0cztcblxuICAgICAgaWYgKHBhZ2VTaXplICE9IG51bGwpIHtcbiAgICAgICAgdGhpcy5wYWdlU2l6ZSA9IHBhZ2VTaXplO1xuICAgICAgfVxuXG4gICAgICBpZiAocGFnZVNpemVPcHRpb25zICE9IG51bGwpIHtcbiAgICAgICAgdGhpcy5wYWdlU2l6ZU9wdGlvbnMgPSBwYWdlU2l6ZU9wdGlvbnM7XG4gICAgICB9XG5cbiAgICAgIGlmIChoaWRlUGFnZVNpemUgIT0gbnVsbCkge1xuICAgICAgICB0aGlzLmhpZGVQYWdlU2l6ZSA9IGhpZGVQYWdlU2l6ZTtcbiAgICAgIH1cblxuICAgICAgaWYgKHNob3dGaXJzdExhc3RCdXR0b25zICE9IG51bGwpIHtcbiAgICAgICAgdGhpcy5zaG93Rmlyc3RMYXN0QnV0dG9ucyA9IHNob3dGaXJzdExhc3RCdXR0b25zO1xuICAgICAgfVxuICAgIH1cbiAgfVxuXG4gIG5nT25Jbml0KCk6IHZvaWQge1xuICAgIHRoaXMuX2lzSW5pdGlhbGl6ZWQgPSB0cnVlO1xuICAgIHRoaXMuX3VwZGF0ZURpc3BsYXllZFBhZ2VTaXplT3B0aW9ucygpO1xuICAgIHRoaXMuX2luaXRpYWxpemVkU3RyZWFtLm5leHQoKTtcbiAgfVxuXG4gIG5nT25EZXN0cm95KCk6IHZvaWQge1xuICAgIHRoaXMuX2luaXRpYWxpemVkU3RyZWFtLmNvbXBsZXRlKCk7XG4gICAgdGhpcy5faW50bENoYW5nZXMudW5zdWJzY3JpYmUoKTtcbiAgfVxuXG4gIC8qKiBBZHZhbmNlcyB0byB0aGUgbmV4dCBwYWdlIGlmIGl0IGV4aXN0cy4gKi9cbiAgbmV4dFBhZ2UoKTogdm9pZCB7XG4gICAgaWYgKCF0aGlzLmhhc05leHRQYWdlKCkpIHtcbiAgICAgIHJldHVybjtcbiAgICB9XG5cbiAgICBjb25zdCBwcmV2aW91c1BhZ2VJbmRleCA9IHRoaXMucGFnZUluZGV4O1xuICAgIHRoaXMucGFnZUluZGV4ID0gdGhpcy5wYWdlSW5kZXggKyAxO1xuICAgIHRoaXMuX2VtaXRQYWdlRXZlbnQocHJldmlvdXNQYWdlSW5kZXgpO1xuICB9XG5cbiAgLyoqIE1vdmUgYmFjayB0byB0aGUgcHJldmlvdXMgcGFnZSBpZiBpdCBleGlzdHMuICovXG4gIHByZXZpb3VzUGFnZSgpOiB2b2lkIHtcbiAgICBpZiAoIXRoaXMuaGFzUHJldmlvdXNQYWdlKCkpIHtcbiAgICAgIHJldHVybjtcbiAgICB9XG5cbiAgICBjb25zdCBwcmV2aW91c1BhZ2VJbmRleCA9IHRoaXMucGFnZUluZGV4O1xuICAgIHRoaXMucGFnZUluZGV4ID0gdGhpcy5wYWdlSW5kZXggLSAxO1xuICAgIHRoaXMuX2VtaXRQYWdlRXZlbnQocHJldmlvdXNQYWdlSW5kZXgpO1xuICB9XG5cbiAgLyoqIE1vdmUgdG8gdGhlIGZpcnN0IHBhZ2UgaWYgbm90IGFscmVhZHkgdGhlcmUuICovXG4gIGZpcnN0UGFnZSgpOiB2b2lkIHtcbiAgICAvLyBoYXNQcmV2aW91c1BhZ2UgYmVpbmcgZmFsc2UgaW1wbGllcyBhdCB0aGUgc3RhcnRcbiAgICBpZiAoIXRoaXMuaGFzUHJldmlvdXNQYWdlKCkpIHtcbiAgICAgIHJldHVybjtcbiAgICB9XG5cbiAgICBjb25zdCBwcmV2aW91c1BhZ2VJbmRleCA9IHRoaXMucGFnZUluZGV4O1xuICAgIHRoaXMucGFnZUluZGV4ID0gMDtcbiAgICB0aGlzLl9lbWl0UGFnZUV2ZW50KHByZXZpb3VzUGFnZUluZGV4KTtcbiAgfVxuXG4gIC8qKiBNb3ZlIHRvIHRoZSBsYXN0IHBhZ2UgaWYgbm90IGFscmVhZHkgdGhlcmUuICovXG4gIGxhc3RQYWdlKCk6IHZvaWQge1xuICAgIC8vIGhhc05leHRQYWdlIGJlaW5nIGZhbHNlIGltcGxpZXMgYXQgdGhlIGVuZFxuICAgIGlmICghdGhpcy5oYXNOZXh0UGFnZSgpKSB7XG4gICAgICByZXR1cm47XG4gICAgfVxuXG4gICAgY29uc3QgcHJldmlvdXNQYWdlSW5kZXggPSB0aGlzLnBhZ2VJbmRleDtcbiAgICB0aGlzLnBhZ2VJbmRleCA9IHRoaXMuZ2V0TnVtYmVyT2ZQYWdlcygpIC0gMTtcbiAgICB0aGlzLl9lbWl0UGFnZUV2ZW50KHByZXZpb3VzUGFnZUluZGV4KTtcbiAgfVxuXG4gIC8qKiBXaGV0aGVyIHRoZXJlIGlzIGEgcHJldmlvdXMgcGFnZS4gKi9cbiAgaGFzUHJldmlvdXNQYWdlKCk6IGJvb2xlYW4ge1xuICAgIHJldHVybiB0aGlzLnBhZ2VJbmRleCA+PSAxICYmIHRoaXMucGFnZVNpemUgIT09IDA7XG4gIH1cblxuICAvKiogV2hldGhlciB0aGVyZSBpcyBhIG5leHQgcGFnZS4gKi9cbiAgaGFzTmV4dFBhZ2UoKTogYm9vbGVhbiB7XG4gICAgY29uc3QgbWF4UGFnZUluZGV4ID0gdGhpcy5nZXROdW1iZXJPZlBhZ2VzKCkgLSAxO1xuICAgIHJldHVybiB0aGlzLnBhZ2VJbmRleCA8IG1heFBhZ2VJbmRleCAmJiB0aGlzLnBhZ2VTaXplICE9PSAwO1xuICB9XG5cbiAgLyoqIENhbGN1bGF0ZSB0aGUgbnVtYmVyIG9mIHBhZ2VzICovXG4gIGdldE51bWJlck9mUGFnZXMoKTogbnVtYmVyIHtcbiAgICBpZiAoIXRoaXMucGFnZVNpemUpIHtcbiAgICAgIHJldHVybiAwO1xuICAgIH1cblxuICAgIHJldHVybiBNYXRoLmNlaWwodGhpcy5sZW5ndGggLyB0aGlzLnBhZ2VTaXplKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBDaGFuZ2VzIHRoZSBwYWdlIHNpemUgc28gdGhhdCB0aGUgZmlyc3QgaXRlbSBkaXNwbGF5ZWQgb24gdGhlIHBhZ2Ugd2lsbCBzdGlsbCBiZVxuICAgKiBkaXNwbGF5ZWQgdXNpbmcgdGhlIG5ldyBwYWdlIHNpemUuXG4gICAqXG4gICAqIEZvciBleGFtcGxlLCBpZiB0aGUgcGFnZSBzaXplIGlzIDEwIGFuZCBvbiB0aGUgc2Vjb25kIHBhZ2UgKGl0ZW1zIGluZGV4ZWQgMTAtMTkpIHRoZW5cbiAgICogc3dpdGNoaW5nIHNvIHRoYXQgdGhlIHBhZ2Ugc2l6ZSBpcyA1IHdpbGwgc2V0IHRoZSB0aGlyZCBwYWdlIGFzIHRoZSBjdXJyZW50IHBhZ2Ugc29cbiAgICogdGhhdCB0aGUgMTB0aCBpdGVtIHdpbGwgc3RpbGwgYmUgZGlzcGxheWVkLlxuICAgKi9cbiAgX2NoYW5nZVBhZ2VTaXplKHBhZ2VTaXplOiBudW1iZXIpOiB2b2lkIHtcbiAgICAvLyBDdXJyZW50IHBhZ2UgbmVlZHMgdG8gYmUgdXBkYXRlZCB0byByZWZsZWN0IHRoZSBuZXcgcGFnZSBzaXplLiBOYXZpZ2F0ZSB0byB0aGUgcGFnZVxuICAgIC8vIGNvbnRhaW5pbmcgdGhlIHByZXZpb3VzIHBhZ2UncyBmaXJzdCBpdGVtLlxuICAgIGNvbnN0IHN0YXJ0SW5kZXggPSB0aGlzLnBhZ2VJbmRleCAqIHRoaXMucGFnZVNpemU7XG4gICAgY29uc3QgcHJldmlvdXNQYWdlSW5kZXggPSB0aGlzLnBhZ2VJbmRleDtcblxuICAgIHRoaXMucGFnZUluZGV4ID0gTWF0aC5mbG9vcihzdGFydEluZGV4IC8gcGFnZVNpemUpIHx8IDA7XG4gICAgdGhpcy5wYWdlU2l6ZSA9IHBhZ2VTaXplO1xuICAgIHRoaXMuX2VtaXRQYWdlRXZlbnQocHJldmlvdXNQYWdlSW5kZXgpO1xuICB9XG5cbiAgLyoqIENoZWNrcyB3aGV0aGVyIHRoZSBidXR0b25zIGZvciBnb2luZyBmb3J3YXJkcyBzaG91bGQgYmUgZGlzYWJsZWQuICovXG4gIF9uZXh0QnV0dG9uc0Rpc2FibGVkKCk6IGJvb2xlYW4ge1xuICAgIHJldHVybiB0aGlzLmRpc2FibGVkIHx8ICF0aGlzLmhhc05leHRQYWdlKCk7XG4gIH1cblxuICAvKiogQ2hlY2tzIHdoZXRoZXIgdGhlIGJ1dHRvbnMgZm9yIGdvaW5nIGJhY2t3YXJkcyBzaG91bGQgYmUgZGlzYWJsZWQuICovXG4gIF9wcmV2aW91c0J1dHRvbnNEaXNhYmxlZCgpOiBib29sZWFuIHtcbiAgICByZXR1cm4gdGhpcy5kaXNhYmxlZCB8fCAhdGhpcy5oYXNQcmV2aW91c1BhZ2UoKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBVcGRhdGVzIHRoZSBsaXN0IG9mIHBhZ2Ugc2l6ZSBvcHRpb25zIHRvIGRpc3BsYXkgdG8gdGhlIHVzZXIuIEluY2x1ZGVzIG1ha2luZyBzdXJlIHRoYXRcbiAgICogdGhlIHBhZ2Ugc2l6ZSBpcyBhbiBvcHRpb24gYW5kIHRoYXQgdGhlIGxpc3QgaXMgc29ydGVkLlxuICAgKi9cbiAgcHJpdmF0ZSBfdXBkYXRlRGlzcGxheWVkUGFnZVNpemVPcHRpb25zKCkge1xuICAgIGlmICghdGhpcy5faXNJbml0aWFsaXplZCkge1xuICAgICAgcmV0dXJuO1xuICAgIH1cblxuICAgIC8vIElmIG5vIHBhZ2Ugc2l6ZSBpcyBwcm92aWRlZCwgdXNlIHRoZSBmaXJzdCBwYWdlIHNpemUgb3B0aW9uIG9yIHRoZSBkZWZhdWx0IHBhZ2Ugc2l6ZS5cbiAgICBpZiAoIXRoaXMucGFnZVNpemUpIHtcbiAgICAgIHRoaXMuX3BhZ2VTaXplID0gdGhpcy5wYWdlU2l6ZU9wdGlvbnMubGVuZ3RoICE9IDAgPyB0aGlzLnBhZ2VTaXplT3B0aW9uc1swXSA6IERFRkFVTFRfUEFHRV9TSVpFO1xuICAgIH1cblxuICAgIHRoaXMuX2Rpc3BsYXllZFBhZ2VTaXplT3B0aW9ucyA9IHRoaXMucGFnZVNpemVPcHRpb25zLnNsaWNlKCk7XG5cbiAgICBpZiAodGhpcy5fZGlzcGxheWVkUGFnZVNpemVPcHRpb25zLmluZGV4T2YodGhpcy5wYWdlU2l6ZSkgPT09IC0xKSB7XG4gICAgICB0aGlzLl9kaXNwbGF5ZWRQYWdlU2l6ZU9wdGlvbnMucHVzaCh0aGlzLnBhZ2VTaXplKTtcbiAgICB9XG5cbiAgICAvLyBTb3J0IHRoZSBudW1iZXJzIHVzaW5nIGEgbnVtYmVyLXNwZWNpZmljIHNvcnQgZnVuY3Rpb24uXG4gICAgdGhpcy5fZGlzcGxheWVkUGFnZVNpemVPcHRpb25zLnNvcnQoKGEsIGIpID0+IGEgLSBiKTtcbiAgICB0aGlzLl9jaGFuZ2VEZXRlY3RvclJlZi5tYXJrRm9yQ2hlY2soKTtcbiAgfVxuXG4gIC8qKiBFbWl0cyBhbiBldmVudCBub3RpZnlpbmcgdGhhdCBhIGNoYW5nZSBvZiB0aGUgcGFnaW5hdG9yJ3MgcHJvcGVydGllcyBoYXMgYmVlbiB0cmlnZ2VyZWQuICovXG4gIHByaXZhdGUgX2VtaXRQYWdlRXZlbnQocHJldmlvdXNQYWdlSW5kZXg6IG51bWJlcikge1xuICAgIHRoaXMucGFnZS5lbWl0KHtcbiAgICAgIHByZXZpb3VzUGFnZUluZGV4LFxuICAgICAgcGFnZUluZGV4OiB0aGlzLnBhZ2VJbmRleCxcbiAgICAgIHBhZ2VTaXplOiB0aGlzLnBhZ2VTaXplLFxuICAgICAgbGVuZ3RoOiB0aGlzLmxlbmd0aCxcbiAgICB9KTtcbiAgfVxufVxuIiwiPGRpdlxuICBjbGFzcz1cImQtZmxleCBmbGV4LWNvbHVtbi1yZXZlcnNlIGZsZXgtbGctcm93IGp1c3RpZnktY29udGVudC1jZW50ZXIganVzdGlmeS1jb250ZW50LWxnLWVuZCBhbGlnbi1pdGVtcy1lbmQgYWxpZ24taXRlbXMtbGctY2VudGVyIGdhcC1sZy01IGdhcC0zXCI+XG4gIEBpZiAoIWhpZGVQYWdlU2l6ZSkge1xuICA8ZGl2IGNsYXNzPVwiZC1pbmxpbmUtZmxleCBhbGlnbi1pdGVtcy1jZW50ZXIgZ2FwLTJcIj5cbiAgICA8c21hbGwgY2xhc3M9XCJ3cy1ub3dyYXBcIiBbYXR0ci5pZF09XCJfcGFnZVNpemVMYWJlbElkXCI+e3sgX2ludGwuaXRlbXNQZXJQYWdlTGFiZWwgfX08L3NtYWxsPlxuXG4gICAgQGlmIChfZGlzcGxheWVkUGFnZVNpemVPcHRpb25zLmxlbmd0aCA+IDEpIHtcbiAgICA8c2VsZWN0XG4gICAgICBjbGFzcz1cImZvcm0tc2VsZWN0IGZvcm0tc2VsZWN0LXNtXCJcbiAgICAgIG5hbWU9XCJwYWdlU2l6ZVwiXG4gICAgICBbbmdNb2RlbF09XCJwYWdlU2l6ZVwiXG4gICAgICBbZGlzYWJsZWRdPVwiZGlzYWJsZWRcIlxuICAgICAgW2F0dHIuYXJpYS1sYWJlbGxlZGJ5XT1cIl9wYWdlU2l6ZUxhYmVsSWRcIlxuICAgICAgKG5nTW9kZWxDaGFuZ2UpPVwiX2NoYW5nZVBhZ2VTaXplKCRhbnkoJGV2ZW50KSlcIj5cbiAgICAgIEBmb3IgKHBhZ2VTaXplT3B0aW9uIG9mIF9kaXNwbGF5ZWRQYWdlU2l6ZU9wdGlvbnM7IHRyYWNrIHBhZ2VTaXplT3B0aW9uKSB7XG4gICAgICA8b3B0aW9uIFtuZ1ZhbHVlXT1cInBhZ2VTaXplT3B0aW9uXCI+e3sgcGFnZVNpemVPcHRpb24gfX08L29wdGlvbj5cbiAgICAgIH1cbiAgICA8L3NlbGVjdD5cbiAgICB9IEBpZiAoX2Rpc3BsYXllZFBhZ2VTaXplT3B0aW9ucy5sZW5ndGggPD0gMSkge1xuICAgIDxzbWFsbD57e3BhZ2VTaXplfX08L3NtYWxsPlxuICAgIH1cbiAgPC9kaXY+XG4gIH1cblxuICA8ZGl2IGNsYXNzPVwiZC1pbmxpbmUtZmxleCBhbGlnbi1pdGVtcy1jZW50ZXIgZ2FwLWxnLTUgZ2FwLTNcIj5cbiAgICA8c21hbGwgYXJpYS1saXZlPVwicG9saXRlXCI+e3sgX2ludGwuZ2V0UmFuZ2VMYWJlbChwYWdlSW5kZXgsIHBhZ2VTaXplLCBsZW5ndGgpIH19PC9zbWFsbD5cblxuICAgIDx1bCBbY2xhc3NdPVwiJ215LTAgcGFnaW5hdGlvbicgKyAoc2l6ZSA/ICcgcGFnaW5hdGlvbi0nICsgc2l6ZSA6ICcnKVwiPlxuICAgICAgQGlmIChzaG93Rmlyc3RMYXN0QnV0dG9ucykge1xuICAgICAgPGxpIGNsYXNzPVwicGFnZS1pdGVtXCIgW2NsYXNzLmRpc2FibGVkXT1cIl9wcmV2aW91c0J1dHRvbnNEaXNhYmxlZCgpXCI+XG4gICAgICAgIDxidXR0b25cbiAgICAgICAgICBjbGFzcz1cInBhZ2UtbGlua1wiXG4gICAgICAgICAgdHlwZT1cImJ1dHRvblwiXG4gICAgICAgICAgKGNsaWNrKT1cImZpcnN0UGFnZSgpXCJcbiAgICAgICAgICBbZGlzYWJsZWRdPVwiX3ByZXZpb3VzQnV0dG9uc0Rpc2FibGVkKClcIlxuICAgICAgICAgIFthdHRyLmFyaWEtbGFiZWxdPVwiX2ludGwuZmlyc3RQYWdlTGFiZWxcIlxuICAgICAgICAgIFthdHRyLnRhYmluZGV4XT1cIl9wcmV2aW91c0J1dHRvbnNEaXNhYmxlZCgpID8gJy0xJyA6IG51bGxcIj5cbiAgICAgICAgICA8c3BhbiBhcmlhLWhpZGRlbj1cInRydWVcIj4mbGFxdW87JmxhcXVvOzwvc3Bhbj5cbiAgICAgICAgPC9idXR0b24+XG4gICAgICA8L2xpPlxuICAgICAgfVxuXG4gICAgICA8bGkgY2xhc3M9XCJwYWdlLWl0ZW1cIiBbY2xhc3MuZGlzYWJsZWRdPVwiX3ByZXZpb3VzQnV0dG9uc0Rpc2FibGVkKClcIj5cbiAgICAgICAgPGJ1dHRvblxuICAgICAgICAgIGNsYXNzPVwicGFnZS1saW5rXCJcbiAgICAgICAgICB0eXBlPVwiYnV0dG9uXCJcbiAgICAgICAgICAoY2xpY2spPVwicHJldmlvdXNQYWdlKClcIlxuICAgICAgICAgIFtkaXNhYmxlZF09XCJfcHJldmlvdXNCdXR0b25zRGlzYWJsZWQoKVwiXG4gICAgICAgICAgW2F0dHIuYXJpYS1sYWJlbF09XCJfaW50bC5wcmV2aW91c1BhZ2VMYWJlbFwiXG4gICAgICAgICAgW2F0dHIudGFiaW5kZXhdPVwiX3ByZXZpb3VzQnV0dG9uc0Rpc2FibGVkKCkgPyAnLTEnIDogbnVsbFwiPlxuICAgICAgICAgIDxzcGFuIGFyaWEtaGlkZGVuPVwidHJ1ZVwiPiZsYXF1bzs8L3NwYW4+XG4gICAgICAgIDwvYnV0dG9uPlxuICAgICAgPC9saT5cbiAgICAgIDxsaSBjbGFzcz1cInBhZ2UtaXRlbVwiIFtjbGFzcy5kaXNhYmxlZF09XCJfbmV4dEJ1dHRvbnNEaXNhYmxlZCgpXCI+XG4gICAgICAgIDxidXR0b25cbiAgICAgICAgICBjbGFzcz1cInBhZ2UtbGlua1wiXG4gICAgICAgICAgdHlwZT1cImJ1dHRvblwiXG4gICAgICAgICAgKGNsaWNrKT1cIm5leHRQYWdlKClcIlxuICAgICAgICAgIFtkaXNhYmxlZF09XCJfbmV4dEJ1dHRvbnNEaXNhYmxlZCgpXCJcbiAgICAgICAgICBbYXR0ci5hcmlhLWxhYmVsXT1cIl9pbnRsLm5leHRQYWdlTGFiZWxcIlxuICAgICAgICAgIFthdHRyLnRhYmluZGV4XT1cIl9uZXh0QnV0dG9uc0Rpc2FibGVkKCkgPyAnLTEnIDogbnVsbFwiPlxuICAgICAgICAgIDxzcGFuIGFyaWEtaGlkZGVuPVwidHJ1ZVwiPiZyYXF1bzs8L3NwYW4+XG4gICAgICAgIDwvYnV0dG9uPlxuICAgICAgPC9saT5cblxuICAgICAgQGlmKHNob3dGaXJzdExhc3RCdXR0b25zKSB7XG4gICAgICA8bGkgY2xhc3M9XCJwYWdlLWl0ZW1cIiBbY2xhc3MuZGlzYWJsZWRdPVwiX25leHRCdXR0b25zRGlzYWJsZWQoKVwiPlxuICAgICAgICA8YnV0dG9uXG4gICAgICAgICAgY2xhc3M9XCJwYWdlLWxpbmtcIlxuICAgICAgICAgIHR5cGU9XCJidXR0b25cIlxuICAgICAgICAgIChjbGljayk9XCJsYXN0UGFnZSgpXCJcbiAgICAgICAgICBbZGlzYWJsZWRdPVwiX25leHRCdXR0b25zRGlzYWJsZWQoKVwiXG4gICAgICAgICAgW2F0dHIuYXJpYS1sYWJlbF09XCJfaW50bC5sYXN0UGFnZUxhYmVsXCJcbiAgICAgICAgICBbYXR0ci50YWJpbmRleF09XCJfbmV4dEJ1dHRvbnNEaXNhYmxlZCgpID8gJy0xJyA6IG51bGxcIj5cbiAgICAgICAgICA8c3BhbiBhcmlhLWhpZGRlbj1cInRydWVcIj4mcmFxdW87JnJhcXVvOzwvc3Bhbj5cbiAgICAgICAgPC9idXR0b24+XG4gICAgICA8L2xpPlxuICAgICAgfVxuICAgIDwvdWw+XG4gIDwvZGl2PlxuPC9kaXY+XG4iXX0=