UNPKG

carbon-components-angular

Version:
492 lines (482 loc) 47 kB
import { Component, Input, Output, EventEmitter } from "@angular/core"; import { merge } from "carbon-components-angular/utils"; import * as i0 from "@angular/core"; import * as i1 from "carbon-components-angular/i18n"; import * as i2 from "carbon-components-angular/experimental"; import * as i3 from "@angular/common"; import * as i4 from "@angular/forms"; import * as i5 from "carbon-components-angular/icon"; import * as i6 from "carbon-components-angular/forms"; /** * Use pagination when you have multiple pages of data to handle. Get started with importing the module: * * ```typescript * import { PaginationModule } from 'carbon-components-angular'; * ``` * * ```html * <cds-pagination [model]="model" (selectPage)="selectPage($event)"></cds-pagination> * ``` * * In your `selectPage()` method set the `model.currentPage` to selected page, _after_ * you load the page. * * ```typescript * selectPage(page) { * // ... your code to load the page goes here * * this.model.currentPage = page; * * // ... anything you want to do after page selection changes goes here * } * ``` * * [See demo](../../?path=/story/components-pagination--basic) */ export class Pagination { constructor(i18n, experimental) { this.i18n = i18n; this.experimental = experimental; /** * Set to `true` for a loading pagination component. */ this.skeleton = false; /** * Set to `true` to disable the select box that changes the page. */ this.pageInputDisabled = false; /** * Controls wether or not to show the page selects */ this.showPageInput = true; /** * Set to `true` if the total number of items is unknown. */ this.pagesUnknown = false; this.pageSelectThreshold = 1000; this.backwardDisabled = false; this.forwardDisabled = false; /** * Options for items per page select * * A default array of options will be defined: [10, 20, 30, 40, 50] */ this.itemsPerPageOptions = [10, 20, 30, 40, 50]; /** * Emits the new page number. * * You should tie into this and update `model.currentPage` once the fresh * data is finally loaded. */ this.selectPage = new EventEmitter(); this.itemsPerPageSelectId = `pagination-select-items-per-page-${Pagination.paginationCounter}`; this.currentPageSelectId = `pagination-select-current-page-${Pagination.paginationCounter}`; this.itemsPerPageText = this.i18n.getOverridable("PAGINATION.ITEMS_PER_PAGE"); this.optionsListText = this.i18n.getOverridable("PAGINATION.OPEN_LIST_OF_OPTIONS"); this.backwardText = this.i18n.getOverridable("PAGINATION.BACKWARD"); this.forwardText = this.i18n.getOverridable("PAGINATION.FORWARD"); this.totalItemsText = this.i18n.getOverridable("PAGINATION.TOTAL_ITEMS"); this.totalItemText = this.i18n.getOverridable("PAGINATION.TOTAL_ITEM"); this.totalItemsUnknownText = this.i18n.getOverridable("PAGINATION.TOTAL_ITEMS_UNKNOWN"); this.pageText = this.i18n.getOverridable("PAGINATION.PAGE"); this.ofLastPagesText = this.i18n.getOverridable("PAGINATION.OF_LAST_PAGES"); this.ofLastPageText = this.i18n.getOverridable("PAGINATION.OF_LAST_PAGE"); this._pageOptions = []; Pagination.paginationCounter++; } /** * Set to `true` to disable the backward/forward buttons. */ set disabled(value) { this.backwardDisabled = value; this.forwardDisabled = value; } /** * Expects an object that contains some or all of: * ``` * { * "ITEMS_PER_PAGE": "Items per page:", * "OPEN_LIST_OF_OPTIONS": "Open list of options", * "BACKWARD": "Backward", * "FORWARD": "Forward", * "TOTAL_ITEMS_UNKNOWN": "{{start}}-{{end}} items", * "TOTAL_ITEMS": "{{start}}-{{end}} of {{total}} items", * "TOTAL_ITEM": "{{start}}-{{end}} of {{total}} item", * "OF_LAST_PAGES": "of {{last}} pages", * "OF_LAST_PAGE": "of {{last}} page" * } * ``` */ set translations(value) { const valueWithDefaults = merge(this.i18n.getMultiple("PAGINATION"), value); this.itemsPerPageText.override(valueWithDefaults.ITEMS_PER_PAGE); this.optionsListText.override(valueWithDefaults.OPEN_LIST_OF_OPTIONS); this.backwardText.override(valueWithDefaults.BACKWARD); this.forwardText.override(valueWithDefaults.FORWARD); this.totalItemsText.override(valueWithDefaults.TOTAL_ITEMS); this.totalItemText.override(valueWithDefaults.TOTAL_ITEM); this.totalItemsUnknownText.override(valueWithDefaults.TOTAL_ITEMS_UNKNOWN); this.pageText.override(valueWithDefaults.PAGE); this.ofLastPagesText.override(valueWithDefaults.OF_LAST_PAGES); this.ofLastPageText.override(valueWithDefaults.OF_LAST_PAGE); } get itemsPerPage() { return this.model.pageLength; } set itemsPerPage(value) { this.model.pageLength = Number(value); this.currentPage = 1; // reset page } get currentPage() { return this.model.currentPage; } set currentPage(value) { value = Number(value); // emits the value to allow the user to update current page // in the model once the page is loaded this.selectPage.emit(value); } get totalDataLength() { return this.model.totalDataLength; } /** * The last page number to display in the pagination view. */ get lastPage() { const last = Math.ceil(this.totalDataLength / this.itemsPerPage); return last > 0 ? last : 1; } get startItemIndex() { return this.endItemIndex > 0 ? (this.currentPage - 1) * this.itemsPerPage + 1 : 0; } get endItemIndex() { const projectedEndItemIndex = this.currentPage * this.itemsPerPage; return projectedEndItemIndex < this.totalDataLength ? projectedEndItemIndex : this.totalDataLength; } /** * The previous page number to navigate to, from the current page. */ get previousPage() { return this.currentPage <= 1 ? 1 : this.currentPage - 1; } /** * The next page number to navigate to, from the current page. */ get nextPage() { const lastPage = this.lastPage; return this.currentPage >= lastPage ? lastPage : this.currentPage + 1; } get pageOptions() { /** * Calculate number of pages based on totalDataLength and itemsPerPage. * Even if totalDataLength is 0, numberOfPages should be always at least 1. * New array will be constructed only if number of pages changes. */ const numberOfPages = Math.max(Math.ceil(this.totalDataLength / this.itemsPerPage), 1); if (this._pageOptions.length !== numberOfPages) { this._pageOptions = Array(numberOfPages); } return this._pageOptions; } } Pagination.paginationCounter = 0; Pagination.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.3.0", ngImport: i0, type: Pagination, deps: [{ token: i1.I18n }, { token: i2.ExperimentalService }], target: i0.ɵɵFactoryTarget.Component }); Pagination.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "14.3.0", type: Pagination, selector: "cds-pagination, ibm-pagination", inputs: { skeleton: "skeleton", model: "model", disabled: "disabled", pageInputDisabled: "pageInputDisabled", showPageInput: "showPageInput", pagesUnknown: "pagesUnknown", pageSelectThreshold: "pageSelectThreshold", backwardDisabled: "backwardDisabled", forwardDisabled: "forwardDisabled", translations: "translations", itemsPerPageOptions: "itemsPerPageOptions" }, outputs: { selectPage: "selectPage" }, ngImport: i0, template: ` <div class="cds--pagination" [ngClass]="{ 'cds--skeleton': skeleton }"> <!-- left skeleton div --> <div *ngIf="skeleton" class="cds--pagination__left"> <p class="cds--skeleton__text" style="width: 70px"></p> <p class="cds--skeleton__text" style="width: 35px"></p> <p class="cds--skeleton__text" style="width: 105px"></p> </div> <div *ngIf="!skeleton" class="cds--pagination__left"> <ng-container *ngIf="showPageInput"> <label class="cds--pagination__text" [for]="itemsPerPageSelectId"> {{itemsPerPageText.subject | async}} </label> <div class="cds--select cds--select--inline cds--select__item-count" [class.cds--select--disabled]="pageInputDisabled"> <select [id]="itemsPerPageSelectId" [(ngModel)]="itemsPerPage" [disabled]="pageInputDisabled" class="cds--select-input"> <option class="cds--select-option" *ngFor="let option of itemsPerPageOptions" [value]="option"> {{ option }} </option> </select> <svg cdsIcon="chevron--down" size="16" style="display: inherit" class="cds--select__arrow" aria-hidden="true" [attr.ariaLabel]="optionsListText.subject | async"> </svg> </div> </ng-container> <span *ngIf="!pagesUnknown && totalDataLength <= 1" class="cds--pagination__text cds--pagination__items-count" [ngStyle]="{'margin-left': showPageInput ? null : 0}"> {{totalItemText.subject | i18nReplace:{start: startItemIndex, end: endItemIndex, total: totalDataLength } | async}} </span> <span *ngIf="!pagesUnknown && totalDataLength > 1" class="cds--pagination__text cds--pagination__items-count" [ngStyle]="{'margin-left': showPageInput ? null : 0}"> {{totalItemsText.subject | i18nReplace:{start: startItemIndex, end: endItemIndex, total: totalDataLength } | async}} </span> <span *ngIf="pagesUnknown" class="cds--pagination__text cds--pagination__items-count" [ngStyle]="{'margin-left': showPageInput ? null : 0}"> {{totalItemsUnknownText.subject | i18nReplace:{start: startItemIndex, end: endItemIndex } | async}} </span> </div> <!-- right skeleton div --> <div *ngIf="skeleton" class="cds--pagination__right"> <p class="cds--skeleton__text" style="width: 70px"></p> </div> <div *ngIf="!skeleton" class="cds--pagination__right"> <span *ngIf="pagesUnknown" class="cds--pagination__text cds--pagination__page-text"> <ng-container *ngIf="!showPageInput">{{currentPage}}</ng-container> {{pageText.subject | async}} </span> <ng-container *ngIf="showPageInput"> <div class="cds--select cds--select--inline cds--select__page-number" [class.cds--select--disabled]="pageInputDisabled"> <label [for]="currentPageSelectId" class="cds--label cds--visually-hidden">{{pageText.subject | async}}</label> <input *ngIf="pageOptions.length > pageSelectThreshold" style="padding-right: 1rem; margin-right: 1rem;" [id]="currentPageSelectId" type="number" min="1" [max]="pageOptions.length" class="cds--select-input" [(ngModel)]="currentPage"> <select *ngIf="pageOptions.length <= pageSelectThreshold" [id]="currentPageSelectId" class="cds--select-input" [disabled]="pageInputDisabled" [(ngModel)]="currentPage"> <option *ngFor="let page of pageOptions; let i = index;" class="cds--select-option" [value]="i + 1">{{i + 1}}</option> </select> <svg *ngIf="pageOptions.length <= pageSelectThreshold" cdsIcon="chevron--down" size="16" style="display: inherit;" class="cds--select__arrow" [attr.ariaLabel]="optionsListText.subject | async"> </svg> </div> </ng-container> <span *ngIf="!pagesUnknown && lastPage <= 1" class="cds--pagination__text"> <ng-container *ngIf="!showPageInput">{{currentPage}}</ng-container> {{ofLastPageText.subject | i18nReplace: {last: lastPage} | async}} </span> <span *ngIf="!pagesUnknown && lastPage > 1" class="cds--pagination__text"> <ng-container *ngIf="!showPageInput">{{currentPage}}</ng-container> {{ofLastPagesText.subject | i18nReplace: {last: lastPage} | async}} </span> <div class="cds--pagination__control-buttons"> <button cdsButton="ghost" iconOnly="true" class="cds--pagination__button cds--pagination__button--backward" [ngClass]="{ 'cds--pagination__button--no-index': currentPage <= 1 || backwardDisabled }" tabindex="0" [attr.aria-label]="backwardText.subject | async" (click)="selectPage.emit(previousPage)" [disabled]="(currentPage <= 1 || backwardDisabled ? true : null)"> <svg cdsIcon="caret--left" size="16" class="cds--btn__icon"></svg> </button> <button cdsButton="ghost" iconOnly="true" class=" cds--pagination__button cds--pagination__button--forward" [ngClass]="{ 'cds--pagination__button--no-index': currentPage >= lastPage || forwardDisabled }" tabindex="0" [attr.aria-label]="forwardText.subject | async" (click)="selectPage.emit(nextPage)" [disabled]="(currentPage >= lastPage || forwardDisabled ? true : null)"> <svg cdsIcon="caret--right" size="16" class="cds--btn__icon"></svg> </button> </div> </div> </div> `, isInline: true, dependencies: [{ kind: "directive", type: i3.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i3.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i3.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i3.NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }, { kind: "directive", type: i4.NgSelectOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i4.ɵNgSelectMultipleOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i4.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i4.NumberValueAccessor, selector: "input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]" }, { kind: "directive", type: i4.SelectControlValueAccessor, selector: "select:not([multiple])[formControlName],select:not([multiple])[formControl],select:not([multiple])[ngModel]", inputs: ["compareWith"] }, { kind: "directive", type: i4.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i4.MinValidator, selector: "input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]", inputs: ["min"] }, { kind: "directive", type: i4.MaxValidator, selector: "input[type=number][max][formControlName],input[type=number][max][formControl],input[type=number][max][ngModel]", inputs: ["max"] }, { kind: "directive", type: i4.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "directive", type: i5.IconDirective, selector: "[cdsIcon], [ibmIcon]", inputs: ["ibmIcon", "cdsIcon", "size", "title", "ariaLabel", "ariaLabelledBy", "ariaHidden", "isFocusable"] }, { kind: "directive", type: i6.Button, selector: "[cdsButton], [ibmButton]", inputs: ["ibmButton", "cdsButton", "size", "skeleton", "iconOnly", "isExpressive"] }, { kind: "pipe", type: i3.AsyncPipe, name: "async" }, { kind: "pipe", type: i1.ReplacePipe, name: "i18nReplace" }] }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.3.0", ngImport: i0, type: Pagination, decorators: [{ type: Component, args: [{ selector: "cds-pagination, ibm-pagination", template: ` <div class="cds--pagination" [ngClass]="{ 'cds--skeleton': skeleton }"> <!-- left skeleton div --> <div *ngIf="skeleton" class="cds--pagination__left"> <p class="cds--skeleton__text" style="width: 70px"></p> <p class="cds--skeleton__text" style="width: 35px"></p> <p class="cds--skeleton__text" style="width: 105px"></p> </div> <div *ngIf="!skeleton" class="cds--pagination__left"> <ng-container *ngIf="showPageInput"> <label class="cds--pagination__text" [for]="itemsPerPageSelectId"> {{itemsPerPageText.subject | async}} </label> <div class="cds--select cds--select--inline cds--select__item-count" [class.cds--select--disabled]="pageInputDisabled"> <select [id]="itemsPerPageSelectId" [(ngModel)]="itemsPerPage" [disabled]="pageInputDisabled" class="cds--select-input"> <option class="cds--select-option" *ngFor="let option of itemsPerPageOptions" [value]="option"> {{ option }} </option> </select> <svg cdsIcon="chevron--down" size="16" style="display: inherit" class="cds--select__arrow" aria-hidden="true" [attr.ariaLabel]="optionsListText.subject | async"> </svg> </div> </ng-container> <span *ngIf="!pagesUnknown && totalDataLength <= 1" class="cds--pagination__text cds--pagination__items-count" [ngStyle]="{'margin-left': showPageInput ? null : 0}"> {{totalItemText.subject | i18nReplace:{start: startItemIndex, end: endItemIndex, total: totalDataLength } | async}} </span> <span *ngIf="!pagesUnknown && totalDataLength > 1" class="cds--pagination__text cds--pagination__items-count" [ngStyle]="{'margin-left': showPageInput ? null : 0}"> {{totalItemsText.subject | i18nReplace:{start: startItemIndex, end: endItemIndex, total: totalDataLength } | async}} </span> <span *ngIf="pagesUnknown" class="cds--pagination__text cds--pagination__items-count" [ngStyle]="{'margin-left': showPageInput ? null : 0}"> {{totalItemsUnknownText.subject | i18nReplace:{start: startItemIndex, end: endItemIndex } | async}} </span> </div> <!-- right skeleton div --> <div *ngIf="skeleton" class="cds--pagination__right"> <p class="cds--skeleton__text" style="width: 70px"></p> </div> <div *ngIf="!skeleton" class="cds--pagination__right"> <span *ngIf="pagesUnknown" class="cds--pagination__text cds--pagination__page-text"> <ng-container *ngIf="!showPageInput">{{currentPage}}</ng-container> {{pageText.subject | async}} </span> <ng-container *ngIf="showPageInput"> <div class="cds--select cds--select--inline cds--select__page-number" [class.cds--select--disabled]="pageInputDisabled"> <label [for]="currentPageSelectId" class="cds--label cds--visually-hidden">{{pageText.subject | async}}</label> <input *ngIf="pageOptions.length > pageSelectThreshold" style="padding-right: 1rem; margin-right: 1rem;" [id]="currentPageSelectId" type="number" min="1" [max]="pageOptions.length" class="cds--select-input" [(ngModel)]="currentPage"> <select *ngIf="pageOptions.length <= pageSelectThreshold" [id]="currentPageSelectId" class="cds--select-input" [disabled]="pageInputDisabled" [(ngModel)]="currentPage"> <option *ngFor="let page of pageOptions; let i = index;" class="cds--select-option" [value]="i + 1">{{i + 1}}</option> </select> <svg *ngIf="pageOptions.length <= pageSelectThreshold" cdsIcon="chevron--down" size="16" style="display: inherit;" class="cds--select__arrow" [attr.ariaLabel]="optionsListText.subject | async"> </svg> </div> </ng-container> <span *ngIf="!pagesUnknown && lastPage <= 1" class="cds--pagination__text"> <ng-container *ngIf="!showPageInput">{{currentPage}}</ng-container> {{ofLastPageText.subject | i18nReplace: {last: lastPage} | async}} </span> <span *ngIf="!pagesUnknown && lastPage > 1" class="cds--pagination__text"> <ng-container *ngIf="!showPageInput">{{currentPage}}</ng-container> {{ofLastPagesText.subject | i18nReplace: {last: lastPage} | async}} </span> <div class="cds--pagination__control-buttons"> <button cdsButton="ghost" iconOnly="true" class="cds--pagination__button cds--pagination__button--backward" [ngClass]="{ 'cds--pagination__button--no-index': currentPage <= 1 || backwardDisabled }" tabindex="0" [attr.aria-label]="backwardText.subject | async" (click)="selectPage.emit(previousPage)" [disabled]="(currentPage <= 1 || backwardDisabled ? true : null)"> <svg cdsIcon="caret--left" size="16" class="cds--btn__icon"></svg> </button> <button cdsButton="ghost" iconOnly="true" class=" cds--pagination__button cds--pagination__button--forward" [ngClass]="{ 'cds--pagination__button--no-index': currentPage >= lastPage || forwardDisabled }" tabindex="0" [attr.aria-label]="forwardText.subject | async" (click)="selectPage.emit(nextPage)" [disabled]="(currentPage >= lastPage || forwardDisabled ? true : null)"> <svg cdsIcon="caret--right" size="16" class="cds--btn__icon"></svg> </button> </div> </div> </div> ` }] }], ctorParameters: function () { return [{ type: i1.I18n }, { type: i2.ExperimentalService }]; }, propDecorators: { skeleton: [{ type: Input }], model: [{ type: Input }], disabled: [{ type: Input }], pageInputDisabled: [{ type: Input }], showPageInput: [{ type: Input }], pagesUnknown: [{ type: Input }], pageSelectThreshold: [{ type: Input }], backwardDisabled: [{ type: Input }], forwardDisabled: [{ type: Input }], translations: [{ type: Input }], itemsPerPageOptions: [{ type: Input }], selectPage: [{ type: Output }] } }); //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicGFnaW5hdGlvbi5jb21wb25lbnQuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi9zcmMvcGFnaW5hdGlvbi9wYWdpbmF0aW9uLmNvbXBvbmVudC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFDQSxPQUFPLEVBQ04sU0FBUyxFQUNULEtBQUssRUFDTCxNQUFNLEVBQ04sWUFBWSxFQUNaLE1BQU0sZUFBZSxDQUFDO0FBSXZCLE9BQU8sRUFBRSxLQUFLLEVBQUUsTUFBTSxpQ0FBaUMsQ0FBQzs7Ozs7Ozs7QUFjeEQ7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7R0F5Qkc7QUErSUgsTUFBTSxPQUFPLFVBQVU7SUFvS3RCLFlBQXNCLElBQVUsRUFBWSxZQUFpQztRQUF2RCxTQUFJLEdBQUosSUFBSSxDQUFNO1FBQVksaUJBQVksR0FBWixZQUFZLENBQXFCO1FBaks3RTs7V0FFRztRQUNNLGFBQVEsR0FBRyxLQUFLLENBQUM7UUFZMUI7O1dBRUc7UUFDTSxzQkFBaUIsR0FBRyxLQUFLLENBQUM7UUFDbkM7O1dBRUc7UUFDTSxrQkFBYSxHQUFHLElBQUksQ0FBQztRQUM5Qjs7V0FFRztRQUNNLGlCQUFZLEdBQUcsS0FBSyxDQUFDO1FBQ3JCLHdCQUFtQixHQUFHLElBQUksQ0FBQztRQUUzQixxQkFBZ0IsR0FBRyxLQUFLLENBQUM7UUFDekIsb0JBQWUsR0FBRyxLQUFLLENBQUM7UUFpQ2pDOzs7O1dBSUc7UUFDTSx3QkFBbUIsR0FBYSxDQUFDLEVBQUUsRUFBRSxFQUFFLEVBQUUsRUFBRSxFQUFFLEVBQUUsRUFBRSxFQUFFLENBQUMsQ0FBQztRQUU5RDs7Ozs7V0FLRztRQUNPLGVBQVUsR0FBRyxJQUFJLFlBQVksRUFBVSxDQUFDO1FBcUVsRCx5QkFBb0IsR0FBRyxvQ0FBb0MsVUFBVSxDQUFDLGlCQUFpQixFQUFFLENBQUM7UUFDMUYsd0JBQW1CLEdBQUcsa0NBQWtDLFVBQVUsQ0FBQyxpQkFBaUIsRUFBRSxDQUFDO1FBRXZGLHFCQUFn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Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7OztFQTBJVDtpQkFDRDs2SEFPUyxRQUFRO3NCQUFoQixLQUFLO2dCQUlHLEtBQUs7c0JBQWIsS0FBSztnQkFJTyxRQUFRO3NCQUFwQixLQUFLO2dCQU9HLGlCQUFpQjtzQkFBekIsS0FBSztnQkFJRyxhQUFhO3NCQUFyQixLQUFLO2dCQUlHLFlBQVk7c0JBQXBCLEtBQUs7Z0JBQ0csbUJBQW1CO3NCQUEzQixLQUFLO2dCQUVHLGdCQUFnQjtzQkFBeEIsS0FBSztnQkFDRyxlQUFlO3NCQUF2QixLQUFLO2dCQW1CRixZQUFZO3NCQURmLEtBQUs7Z0JBb0JHLG1CQUFtQjtzQkFBM0IsS0FBSztnQkFRSSxVQUFVO3NCQUFuQixNQUFNIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgUGFnaW5hdGlvbk1vZGVsIH0gZnJvbSBcIi4vcGFnaW5hdGlvbi1tb2RlbC5jbGFzc1wiO1xuaW1wb3J0IHtcblx0Q29tcG9uZW50LFxuXHRJbnB1dCxcblx0T3V0cHV0LFxuXHRFdmVudEVtaXR0ZXJcbn0gZnJvbSBcIkBhbmd1bGFyL2NvcmVcIjtcblxuaW1wb3J0IHsgSTE4biwgT3ZlcnJpZGFibGUgfSBmcm9tIFwiY2FyYm9uLWNvbXBvbmVudHMtYW5ndWxhci9pMThuXCI7XG5pbXBvcnQgeyBFeHBlcmltZW50YWxTZXJ2aWNlIH0gZnJvbSBcImNhcmJvbi1jb21wb25lbnRzLWFuZ3VsYXIvZXhwZXJpbWVudGFsXCI7XG5pbXBvcnQgeyBtZXJnZSB9IGZyb20gXCJjYXJib24tY29tcG9uZW50cy1hbmd1bGFyL3V0aWxzXCI7XG5cbmV4cG9ydCBpbnRlcmZhY2UgUGFnaW5hdGlvblRyYW5zbGF0aW9ucyB7XG5cdElURU1TX1BFUl9QQUdFOiBzdHJpbmc7XG5cdE9QRU5fTElTVF9PRl9PUFRJT05TOiBzdHJpbmc7XG5cdEJBQ0tXQVJEOiBzdHJpbmc7XG5cdEZPUldBUkQ6IHN0cmluZztcblx0VE9UQUxfSVRFTVNfVU5LTk9XTjogc3RyaW5nO1xuXHRUT1RBTF9JVEVNUzogc3RyaW5nO1xuXHRUT1RBTF9JVEVNOiBzdHJpbmc7XG5cdE9GX0xBU1RfUEFHRVM6IHN0cmluZztcblx0T0ZfTEFTVF9QQUdFOiBzdHJpbmc7XG59XG5cbi8qKlxuICogVXNlIHBhZ2luYXRpb24gd2hlbiB5b3UgaGF2ZSBtdWx0aXBsZSBwYWdlcyBvZiBkYXRhIHRvIGhhbmRsZS4gR2V0IHN0YXJ0ZWQgd2l0aCBpbXBvcnRpbmcgdGhlIG1vZHVsZTpcbiAqXG4gKiBgYGB0eXBlc2NyaXB0XG4gKiBpbXBvcnQgeyBQYWdpbmF0aW9uTW9kdWxlIH0gZnJvbSAnY2FyYm9uLWNvbXBvbmVudHMtYW5ndWxhcic7XG4gKiBgYGBcbiAqXG4gKiBgYGBodG1sXG4gKlx0PGNkcy1wYWdpbmF0aW9uIFttb2RlbF09XCJtb2RlbFwiIChzZWxlY3RQYWdlKT1cInNlbGVjdFBhZ2UoJGV2ZW50KVwiPjwvY2RzLXBhZ2luYXRpb24+XG4gKiBgYGBcbiAqXG4gKiBJbiB5b3VyIGBzZWxlY3RQYWdlKClgIG1ldGhvZCBzZXQgdGhlIGBtb2RlbC5jdXJyZW50UGFnZWAgdG8gc2VsZWN0ZWQgcGFnZSwgX2FmdGVyX1xuICogeW91IGxvYWQgdGhlIHBhZ2UuXG4gKlxuICogYGBgdHlwZXNjcmlwdFxuICogc2VsZWN0UGFnZShwYWdlKSB7XG4gKiBcdC8vIC4uLiB5b3VyIGNvZGUgdG8gbG9hZCB0aGUgcGFnZSBnb2VzIGhlcmVcbiAqXG4gKiBcdHRoaXMubW9kZWwuY3VycmVudFBhZ2UgPSBwYWdlO1xuICpcbiAqIFx0Ly8gLi4uIGFueXRoaW5nIHlvdSB3YW50IHRvIGRvIGFmdGVyIHBhZ2Ugc2VsZWN0aW9uIGNoYW5nZXMgZ29lcyBoZXJlXG4gKiB9XG4gKiBgYGBcbiAqXG4gKiBbU2VlIGRlbW9dKC4uLy4uLz9wYXRoPS9zdG9yeS9jb21wb25lbnRzLXBhZ2luYXRpb24tLWJhc2ljKVxuICovXG5AQ29tcG9uZW50KHtcblx0c2VsZWN0b3I6IFwiY2RzLXBhZ2luYXRpb24sIGlibS1wYWdpbmF0aW9uXCIsXG5cdHRlbXBsYXRlOiBgXG5cdDxkaXZcblx0XHRjbGFzcz1cImNkcy0tcGFnaW5hdGlvblwiXG5cdFx0W25nQ2xhc3NdPVwie1xuXHRcdFx0J2Nkcy0tc2tlbGV0b24nOiBza2VsZXRvblxuXHRcdH1cIj5cblx0XHQ8IS0tIGxlZnQgc2tlbGV0b24gZGl2IC0tPlxuXHRcdDxkaXYgKm5nSWY9XCJza2VsZXRvblwiIGNsYXNzPVwiY2RzLS1wYWdpbmF0aW9uX19sZWZ0XCI+XG5cdFx0XHQ8cCBjbGFzcz1cImNkcy0tc2tlbGV0b25fX3RleHRcIiBzdHlsZT1cIndpZHRoOiA3MHB4XCI+PC9wPlxuXHRcdFx0PHAgY2xhc3M9XCJjZHMtLXNrZWxldG9uX190ZXh0XCIgc3R5bGU9XCJ3aWR0aDogMzVweFwiPjwvcD5cblx0XHRcdDxwIGNsYXNzPVwiY2RzLS1za2VsZXRvbl9fdGV4dFwiIHN0eWxlPVwid2lkdGg6IDEwNXB4XCI+PC9wPlxuXHRcdDwvZGl2PlxuXG5cdFx0PGRpdiAqbmdJZj1cIiFza2VsZXRvblwiIGNsYXNzPVwiY2RzLS1wYWdpbmF0aW9uX19sZWZ0XCI+XG5cdFx0XHQ8bmctY29udGFpbmVyICpuZ0lmPVwic2hvd1BhZ2VJbnB1dFwiPlxuXHRcdFx0XHQ8bGFiZWwgY2xhc3M9XCJjZHMtLXBhZ2luYXRpb25fX3RleHRcIiBbZm9yXT1cIml0ZW1zUGVyUGFnZVNlbGVjdElkXCI+XG5cdFx0XHRcdFx0e3tpdGVtc1BlclBhZ2VUZXh0LnN1YmplY3QgfCBhc3luY319XG5cdFx0XHRcdDwvbGFiZWw+XG5cdFx0XHRcdDxkaXZcblx0XHRcdFx0XHRjbGFzcz1cImNkcy0tc2VsZWN0IGNkcy0tc2VsZWN0LS1pbmxpbmUgY2RzLS1zZWxlY3RfX2l0ZW0tY291bnRcIlxuXHRcdFx0XHRcdFtjbGFzcy5jZHMtLXNlbGVjdC0tZGlzYWJsZWRdPVwicGFnZUlucHV0RGlzYWJsZWRcIj5cblx0XHRcdFx0XHQ8c2VsZWN0XG5cdFx0XHRcdFx0XHRbaWRdPVwiaXRlbXNQZXJQYWdlU2VsZWN0SWRcIlxuXHRcdFx0XHRcdFx0WyhuZ01vZGVsKV09XCJpdGVtc1BlclBhZ2VcIlxuXHRcdFx0XHRcdFx0W2Rpc2FibGVkXT1cInBhZ2VJbnB1dERpc2FibGVkXCJcblx0XHRcdFx0XHRcdGNsYXNzPVwiY2RzLS1zZWxlY3QtaW5wdXRcIj5cblx0XHRcdFx0XHRcdDxvcHRpb25cblx0XHRcdFx0XHRcdFx0Y2xhc3M9XCJjZHMtLXNlbGVjdC1vcHRpb25cIlxuXHRcdFx0XHRcdFx0XHQqbmdGb3I9XCJsZXQgb3B0aW9uIG9mIGl0ZW1zUGVyUGFnZU9wdGlvbnNcIlxuXHRcdFx0XHRcdFx0XHRbdmFsdWVdPVwib3B0aW9uXCI+XG5cdFx0XHRcdFx0XHRcdFx0e3sgb3B0aW9uIH19XG5cdFx0XHRcdFx0XHQ8L29wdGlvbj5cblx0XHRcdFx0XHQ8L3NlbGVjdD5cblx0XHRcdFx0XHQ8c3ZnXG5cdFx0XHRcdFx0XHRjZHNJY29uPVwiY2hldnJvbi0tZG93blwiXG5cdFx0XHRcdFx0XHRzaXplPVwiMTZcIlxuXHRcdFx0XHRcdFx0c3R5bGU9XCJkaXNwbGF5OiBpbmhlcml0XCJcblx0XHRcdFx0XHRcdGNsYXNzPVwiY2RzLS1zZWxlY3RfX2Fycm93XCJcblx0XHRcdFx0XHRcdGFyaWEtaGlkZGVuPVwidHJ1ZVwiXG5cdFx0XHRcdFx0XHRbYXR0ci5hcmlhTGFiZWxdPVwib3B0aW9uc0xpc3RUZXh0LnN1YmplY3QgfCBhc3luY1wiPlxuXHRcdFx0XHRcdDwvc3ZnPlxuXHRcdFx0XHQ8L2Rpdj5cblx0XHRcdDwvbmctY29udGFpbmVyPlxuXHRcdFx0PHNwYW4gKm5nSWY9XCIhcGFnZXNVbmtub3duICYmIHRvdGFsRGF0YUxlbmd0aCA8PSAxXCIgY2xhc3M9XCJjZHMtLXBhZ2luYXRpb25fX3RleHQgY2RzLS1wYWdpbmF0aW9uX19pdGVtcy1jb3VudFwiIFtuZ1N0eWxlXT1cInsnbWFyZ2luLWxlZnQnOiBzaG93UGFnZUlucHV0ID8gbnVsbCA6IDB9XCI+XG5cdFx0XHRcdHt7dG90YWxJdGVtVGV4dC5zdWJqZWN0IHwgaTE4blJlcGxhY2U6e3N0YXJ0OiBzdGFydEl0ZW1JbmRleCwgZW5kOiBlbmRJdGVtSW5kZXgsIHRvdGFsOiB0b3RhbERhdGFMZW5ndGggfSB8IGFzeW5jfX1cblx0XHRcdDwvc3Bhbj5cblx0XHRcdDxzcGFuICpuZ0lmPVwiIXBhZ2VzVW5rbm93biAmJiB0b3RhbERhdGFMZW5ndGggPiAxXCIgY2xhc3M9XCJjZHMtLXBhZ2luYXRpb25fX3RleHQgY2RzLS1wYWdpbmF0aW9uX19pdGVtcy1jb3VudFwiIFtuZ1N0eWxlXT1cInsnbWFyZ2luLWxlZnQnOiBzaG93UGFnZUlucHV0ID8gbnVsbCA6IDB9XCI+XG5cdFx0XHRcdHt7dG90YWxJdGVtc1RleHQuc3ViamVjdCB8IGkxOG5SZXBsYWNlOntzdGFydDogc3RhcnRJdGVtSW5kZXgsIGVuZDogZW5kSXRlbUluZGV4LCB0b3RhbDogdG90YWxEYXRhTGVuZ3RoIH0gfCBhc3luY319XG5cdFx0XHQ8L3NwYW4+XG5cdFx0XHQ8c3BhbiAqbmdJZj1cInBhZ2VzVW5rbm93blwiIGNsYXNzPVwiY2RzLS1wYWdpbmF0aW9uX190ZXh0IGNkcy0tcGFnaW5hdGlvbl9faXRlbXMtY291bnRcIiBbbmdTdHlsZV09XCJ7J21hcmdpbi1sZWZ0Jzogc2hvd1BhZ2VJbnB1dCA/IG51bGwgOiAwfVwiPlxuXHRcdFx0XHR7e3RvdGFsSXRlbXNVbmtub3duVGV4dC5zdWJqZWN0IHwgaTE4blJlcGxhY2U6e3N0YXJ0OiBzdGFydEl0ZW1JbmRleCwgZW5kOiBlbmRJdGVtSW5kZXggfSB8IGFzeW5jfX1cblx0XHRcdDwvc3Bhbj5cblx0XHQ8L2Rpdj5cblxuXHRcdDwhLS0gcmlnaHQgc2tlbGV0b24gZGl2IC0tPlxuXHRcdDxkaXYgKm5nSWY9XCJza2VsZXRvblwiIGNsYXNzPVwiY2RzLS1wYWdpbmF0aW9uX19yaWdodFwiPlxuXHRcdFx0PHAgY2xhc3M9XCJjZHMtLXNrZWxldG9uX190ZXh0XCIgc3R5bGU9XCJ3aWR0aDogNzBweFwiPjwvcD5cblx0XHQ8L2Rpdj5cblxuXHRcdDxkaXYgKm5nSWY9XCIhc2tlbGV0b25cIiBjbGFzcz1cImNkcy0tcGFnaW5hdGlvbl9fcmlnaHRcIj5cblx0XHRcdDxzcGFuICpuZ0lmPVwicGFnZXNVbmtub3duXCIgY2xhc3M9XCJjZHMtLXBhZ2luYXRpb25fX3RleHQgY2RzLS1wYWdpbmF0aW9uX19wYWdlLXRleHRcIj5cblx0XHRcdFx0PG5nLWNvbnRhaW5lciAqbmdJZj1cIiFzaG93UGFnZUlucHV0XCI+e3tjdXJyZW50UGFnZX19PC9uZy1jb250YWluZXI+XG5cdFx0XHRcdHt7cGFnZVRleHQuc3ViamVjdCB8IGFzeW5jfX1cblx0XHRcdDwvc3Bhbj5cblx0XHRcdDxuZy1jb250YWluZXIgKm5nSWY9XCJzaG93UGFnZUlucHV0XCI+XG5cdFx0XHRcdDxkaXZcblx0XHRcdFx0XHRjbGFzcz1cImNkcy0tc2VsZWN0IGNkcy0tc2VsZWN0LS1pbmxpbmUgY2RzLS1zZWxlY3RfX3BhZ2UtbnVtYmVyXCJcblx0XHRcdFx0XHRbY2xhc3MuY2RzLS1zZWxlY3QtLWRpc2FibGVkXT1cInBhZ2VJbnB1dERpc2FibGVkXCI+XG5cdFx0XHRcdFx0PGxhYmVsIFtmb3JdPVwiY3VycmVudFBhZ2VTZWxlY3RJZFwiIGNsYXNzPVwiY2RzLS1sYWJlbCBjZHMtLXZpc3VhbGx5LWhpZGRlblwiPnt7cGFnZVRleHQuc3ViamVjdCB8IGFzeW5jfX08L2xhYmVsPlxuXHRcdFx0XHRcdDxpbnB1dFxuXHRcdFx0XHRcdFx0Km5nSWY9XCJwYWdlT3B0aW9ucy5sZW5ndGggPiBwYWdlU2VsZWN0VGhyZXNob2xkXCJcblx0XHRcdFx0XHRcdHN0eWxlPVwicGFkZGluZy1yaWdodDogMXJlbTsgbWFyZ2luLXJpZ2h0OiAxcmVtO1wiXG5cdFx0XHRcdFx0XHRbaWRdPVwiY3VycmVudFBhZ2VTZWxlY3RJZFwiXG5cdFx0XHRcdFx0XHR0eXBlPVwibnVtYmVyXCJcblx0XHRcdFx0XHRcdG1pbj1cIjFcIlxuXHRcdFx0XHRcdFx0W21heF09XCJwYWdlT3B0aW9ucy5sZW5ndGhcIlxuXHRcdFx0XHRcdFx0Y2xhc3M9XCJjZHMtLXNlbGVjdC1pbnB1dFwiXG5cdFx0XHRcdFx0XHRbKG5nTW9kZWwpXT1cImN1cnJlbnRQYWdlXCI+XG5cdFx0XHRcdFx0PHNlbGVjdFxuXHRcdFx0XHRcdFx0Km5nSWY9XCJwYWdlT3B0aW9ucy5sZW5ndGggPD0gcGFnZVNlbGVjdFRocmVzaG9sZFwiXG5cdFx0XHRcdFx0XHRbaWRdPVwiY3VycmVudFBhZ2VTZWxlY3RJZFwiXG5cdFx0XHRcdFx0XHRjbGFzcz1cImNkcy0tc2VsZWN0LWlucHV0XCJcblx0XHRcdFx0XHRcdFtkaXNhYmxlZF09XCJwYWdlSW5wdXREaXNhYmxlZFwiXG5cdFx0XHRcdFx0XHRbKG5nTW9kZWwpXT1cImN1cnJlbnRQYWdlXCI+XG5cdFx0XHRcdFx0XHQ8b3B0aW9uICpuZ0Zvcj1cImxldCBwYWdlIG9mIHBhZ2VPcHRpb25zOyBsZXQgaSA9IGluZGV4O1wiIGNsYXNzPVwiY2RzLS1zZWxlY3Qtb3B0aW9uXCIgW3ZhbHVlXT1cImkgKyAxXCI+e3tpICsgMX19PC9vcHRpb24+XG5cdFx0XHRcdFx0PC9zZWxlY3Q+XG5cdFx0XHRcdFx0PHN2Z1xuXHRcdFx0XHRcdFx0Km5nSWY9XCJwYWdlT3B0aW9ucy5sZW5ndGggPD0gcGFnZVNlbGVjdFRocmVzaG9sZFwiXG5cdFx0XHRcdFx0XHRjZHNJY29uPVwiY2hldnJvbi0tZG93blwiXG5cdFx0XHRcdFx0XHRzaXplPVwiMTZcIlxuXHRcdFx0XHRcdFx0c3R5bGU9XCJkaXNwbGF5OiBpbmhlcml0O1wiXG5cdFx0XHRcdFx0XHRjbGFzcz1cImNkcy0tc2VsZWN0X19hcnJvd1wiXG5cdFx0XHRcdFx0XHRbYXR0ci5hcmlhTGFiZWxdPVwib3B0aW9uc0xpc3RUZXh0LnN1YmplY3QgfCBhc3luY1wiPlxuXHRcdFx0XHRcdDwvc3ZnPlxuXHRcdFx0XHQ8L2Rpdj5cblx0XHRcdDwvbmctY29udGFpbmVyPlxuXG5cdFx0XHQ8c3BhbiAqbmdJZj1cIiFwYWdlc1Vua25vd24gJiYgbGFzdFBhZ2UgPD0gMVwiIGNsYXNzPVwiY2RzLS1wYWdpbmF0aW9uX190ZXh0XCI+XG5cdFx0XHRcdDxuZy1jb250YWluZXIgKm5nSWY9XCIhc2hvd1BhZ2VJbnB1dFwiPnt7Y3VycmVudFBhZ2V9fTwvbmctY29udGFpbmVyPlxuXHRcdFx0XHR7e29mTGFzdFBhZ2VUZXh0LnN1YmplY3QgfCBpMThuUmVwbGFjZToge2xhc3Q6IGxhc3RQYWdlfSB8IGFzeW5jfX1cblx0XHRcdDwvc3Bhbj5cblx0XHRcdDxzcGFuICpuZ0lmPVwiIXBhZ2VzVW5rbm93biAmJiBsYXN0UGFnZSA+IDFcIiBjbGFzcz1cImNkcy0tcGFnaW5hdGlvbl9fdGV4dFwiPlxuXHRcdFx0XHQ8bmctY29udGFpbmVyICpuZ0lmPVwiIXNob3dQYWdlSW5wdXRcIj57e2N1cnJlbnRQYWdlfX08L25nLWNvbnRhaW5lcj5cblx0XHRcdFx0e3tvZkxhc3RQYWdlc1RleHQuc3ViamVjdCB8IGkxOG5SZXBsYWNlOiB7bGFzdDogbGFzdFBhZ2V9IHwgYXN5bmN9fVxuXHRcdFx0PC9zcGFuPlxuXHRcdFx0PGRpdiBjbGFzcz1cImNkcy0tcGFnaW5hdGlvbl9fY29udHJvbC1idXR0b25zXCI+XG5cdFx0XHRcdDxidXR0b25cblx0XHRcdFx0XHRjZHNCdXR0b249XCJnaG9zdFwiXG5cdFx0XHRcdFx0aWNvbk9ubHk9XCJ0cnVlXCJcblx0XHRcdFx0XHRjbGFzcz1cImNkcy0tcGFnaW5hdGlvbl9fYnV0dG9uIGNkcy0tcGFnaW5hdGlvbl9fYnV0dG9uLS1iYWNrd2FyZFwiXG5cdFx0XHRcdFx0W25nQ2xhc3NdPVwie1xuXHRcdFx0XHRcdFx0J2Nkcy0tcGFnaW5hdGlvbl9fYnV0dG9uLS1uby1pbmRleCc6IGN1cnJlbnRQYWdlIDw9IDEgfHwgYmFja3dhcmREaXNhYmxlZFxuXHRcdFx0XHRcdH1cIlxuXHRcdFx0XHRcdHRhYmluZGV4PVwiMFwiXG5cdFx0XHRcdFx0W2F0dHIuYXJpYS1sYWJlbF09XCJiYWNrd2FyZFRleHQuc3ViamVjdCB8IGFzeW5jXCJcblx0XHRcdFx0XHQoY2xpY2spPVwic2VsZWN0UGFnZS5lbWl0KHByZXZpb3VzUGFnZSlcIlxuXHRcdFx0XHRcdFtkaXNhYmxlZF09XCIoY3VycmVudFBhZ2UgPD0gMSB8fCBiYWNrd2FyZERpc2FibGVkID8gdHJ1ZSA6IG51bGwpXCI+XG5cdFx0XHRcdFx0PHN2ZyBjZHNJY29uPVwiY2FyZXQtLWxlZnRcIiBzaXplPVwiMTZcIiBjbGFzcz1cImNkcy0tYnRuX19pY29uXCI+PC9zdmc+XG5cdFx0XHRcdDwvYnV0dG9uPlxuXG5cdFx0XHRcdDxidXR0b25cblx0XHRcdFx0XHRjZHNCdXR0b249XCJnaG9zdFwiXG5cdFx0XHRcdFx0aWNvbk9ubHk9XCJ0cnVlXCJcblx0XHRcdFx0XHRjbGFzcz1cIlxuXHRcdFx0XHRcdFx0Y2RzLS1wYWdpbmF0aW9uX19idXR0b25cblx0XHRcdFx0XHRcdGNkcy0tcGFnaW5hdGlvbl9fYnV0dG9uLS1mb3J3YXJkXCJcblx0XHRcdFx0XHRbbmdDbGFzc109XCJ7XG5cdFx0XHRcdFx0XHQnY2RzLS1wYWdpbmF0aW9uX19idXR0b24tLW5vLWluZGV4JzogY3VycmVudFBhZ2UgPj0gbGFzdFBhZ2UgfHwgZm9yd2FyZERpc2FibGVkXG5cdFx0XHRcdFx0fVwiXG5cdFx0XHRcdFx0dGFiaW5kZXg9XCIwXCJcblx0XHRcdFx0XHRbYXR0ci5hcmlhLWxhYmVsXT1cImZvcndhcmRUZXh0LnN1YmplY3QgfCBhc3luY1wiXG5cdFx0XHRcdFx0KGNsaWNrKT1cInNlbGVjdFBhZ2UuZW1pdChuZXh0UGFnZSlcIlxuXHRcdFx0XHRcdFtkaXNhYmxlZF09XCIoY3VycmVudFBhZ2UgPj0gbGFzdFBhZ2UgfHwgZm9yd2FyZERpc2FibGVkID8gdHJ1ZSA6IG51bGwpXCI+XG5cdFx0XHRcdFx0PHN2ZyBjZHNJY29uPVwiY2FyZXQtLXJpZ2h0XCIgc2l6ZT1cIjE2XCIgY2xhc3M9XCJjZHMtLWJ0bl9faWNvblwiPjwvc3ZnPlxuXHRcdFx0XHQ8L2J1dHRvbj5cblx0XHRcdDwvZGl2PlxuXHRcdDwvZGl2PlxuXHQ8L2Rpdj5cblx0YFxufSlcbmV4cG9ydCBjbGFzcyBQYWdpbmF0aW9uIHtcblx0c3RhdGljIHBhZ2luYXRpb25Db3VudGVyID0gMDtcblxuXHQvKipcblx0ICogU2V0IHRvIGB0cnVlYCBmb3IgYSBsb2FkaW5nIHBhZ2luYXRpb24gY29tcG9uZW50LlxuXHQgKi9cblx0QElucHV0KCkgc2tlbGV0b24gPSBmYWxzZTtcblx0LyoqXG5cdCAqIGBQYWdpbmF0aW9uTW9kZWxgIHdpdGggdGhlIGluZm9ybWF0aW9uIGFib3V0IHBhZ2VzIHlvdSdyZSBjb250cm9sbGluZy5cblx0ICovXG5cdEBJbnB1dCgpIG1vZGVsOiBQYWdpbmF0aW9uTW9kZWw7XG5cdC8qKlxuIFx0ICogU2V0IHRvIGB0cnVlYCB0byBkaXNhYmxlIHRoZSBiYWNrd2FyZC9mb3J3YXJkIGJ1dHRvbnMuXG5cdCAqL1xuXHRASW5wdXQoKSBzZXQgZGlzYWJsZWQodmFsdWU6IGJvb2xlYW4pIHtcblx0XHR0aGlzLmJhY2t3YXJkRGlzYWJsZWQgPSB2YWx1ZTtcblx0XHR0aGlzLmZvcndhcmREaXNhYmxlZCA9IHZhbHVlO1xuXHR9XG5cdC8qKlxuXHQgKiBTZXQgdG8gYHRydWVgIHRvIGRpc2FibGUgdGhlIHNlbGVjdCBib3ggdGhhdCBjaGFuZ2VzIHRoZSBwYWdlLlxuXHQgKi9cblx0QElucHV0KCkgcGFnZUlucHV0RGlzYWJsZWQgPSBmYWxzZTtcblx0LyoqXG5cdCAqIENvbnRyb2xzIHdldGhlciBvciBub3QgdG8gc2hvdyB0aGUgcGFnZSBzZWxlY3RzXG5cdCAqL1xuXHRASW5wdXQoKSBzaG93UGFnZUlucHV0ID0gdHJ1ZTtcblx0LyoqXG5cdCAqIFNldCB0byBgdHJ1ZWAgaWYgdGhlIHRvdGFsIG51bWJlciBvZiBpdGVtcyBpcyB1bmtub3duLlxuXHQgKi9cblx0QElucHV0KCkgcGFnZXNVbmtub3duID0gZmFsc2U7XG5cdEBJbnB1dCgpIHBhZ2VTZWxlY3RUaHJlc2hvbGQgPSAxMDAwO1xuXG5cdEBJbnB1dCgpIGJhY2t3YXJkRGlzYWJsZWQgPSBmYWxzZTtcblx0QElucHV0KCkgZm9yd2FyZERpc2FibGVkID0gZmFsc2U7XG5cblx0LyoqXG5cdCAqIEV4cGVjdHMgYW4gb2JqZWN0IHRoYXQgY29udGFpbnMgc29tZSBvciBhbGwgb2Y6XG5cdCAqIGBgYFxuXHQgKiB7XG5cdCAqXHRcdFwiSVRFTVNfUEVSX1BBR0VcIjogXCJJdGVtcyBwZXIgcGFnZTpcIixcblx0ICpcdFx0XCJPUEVOX0xJU1RfT0ZfT1BUSU9OU1wiOiBcIk9wZW4gbGlzdCBvZiBvcHRpb25zXCIsXG5cdCAqXHRcdFwiQkFDS1dBUkRcIjogXCJCYWNrd2FyZFwiLFxuXHQgKlx0XHRcIkZPUldBUkRcIjogXCJGb3J3YXJkXCIsXG5cdCAqXHRcdFwiVE9UQUxfSVRFTVNfVU5LTk9XTlwiOiBcInt7c3RhcnR9fS17e2VuZH19IGl0ZW1zXCIsXG5cdCAqXHRcdFwiVE9UQUxfSVRFTVNcIjogXCJ7e3N0YXJ0fX0te3tlbmR9fSBvZiB7e3RvdGFsfX0gaXRlbXNcIixcblx0ICpcdFx0XCJUT1RBTF9JVEVNXCI6IFwie3tzdGFydH19LXt7ZW5kfX0gb2Yge3t0b3RhbH19IGl0ZW1cIixcblx0ICpcdFx0XCJPRl9MQVNUX1BBR0VTXCI6IFwib2Yge3tsYXN0fX0gcGFnZXNcIixcblx0ICpcdFx0XCJPRl9MQVNUX1BBR0VcIjogXCJvZiB7e2xhc3R9fSBwYWdlXCJcblx0ICogfVxuXHQgKiBgYGBcblx0ICovXG5cdEBJbnB1dCgpXG5cdHNldCB0cmFuc2xhdGlvbnMgKHZhbHVlOiBQYWdpbmF0aW9uVHJhbnNsYXRpb25zKSB7XG5cdFx0Y29uc3QgdmFsdWVXaXRoRGVmYXVsdHMgPSBtZXJnZSh0aGlzLmkxOG4uZ2V0TXVsdGlwbGUoXCJQQUdJTkFUSU9OXCIpLCB2YWx1ZSk7XG5cdFx0dGhpcy5pdGVtc1BlclBhZ2VUZXh0Lm92ZXJyaWRlKHZhbHVlV2l0aERlZmF1bHRzLklURU1TX1BFUl9QQUdFKTtcblx0XHR0aGlzLm9wdGlvbnNMaXN0VGV4dC5vdmVycmlkZSh2YWx1ZVdpdGhEZWZhdWx0cy5PUEVOX0xJU1RfT0ZfT1BUSU9OUyk7XG5cdFx0dGhpcy5iYWNrd2FyZFRleHQub3ZlcnJpZGUodmFsdWVXaXRoRGVmYXVsdHMuQkFDS1dBUkQpO1xuXHRcdHRoaXMuZm9yd2FyZFRleHQub3ZlcnJpZGUodmFsdWVXaXRoRGVmYXVsdHMuRk9SV0FSRCk7XG5cdFx0dGhpcy50b3RhbEl0ZW1zVGV4dC5vdmVycmlkZSh2YWx1ZVdpdGhEZWZhdWx0cy5UT1RBTF9JVEVNUyk7XG5cdFx0dGhpcy50b3RhbEl0ZW1UZXh0Lm92ZXJyaWRlKHZhbHVlV2l0aERlZmF1bHRzLlRPVEFMX0lURU0pO1xuXHRcdHRoaXMudG90YWxJdGVtc1Vua25vd25UZXh0Lm92ZXJyaWRlKHZhbHVlV2l0aERlZmF1bHRzLlRPVEFMX0lURU1TX1VOS05PV04pO1xuXHRcdHRoaXMucGFnZVRleHQub3ZlcnJpZGUodmFsdWVXaXRoRGVmYXVsdHMuUEFHRSk7XG5cdFx0dGhpcy5vZkxhc3RQYWdlc1RleHQub3ZlcnJpZGUodmFsdWVXaXRoRGVmYXVsdHMuT0ZfTEFTVF9QQUdFUyk7XG5cdFx0dGhpcy5vZkxhc3RQYWdlVGV4dC5vdmVycmlkZSh2YWx1ZVdpdGhEZWZhdWx0cy5PRl9MQVNUX1BBR0UpO1xuXHR9XG5cblx0LyoqXG5cdCAqIE9wdGlvbnMgZm9yIGl0ZW1zIHBlciBwYWdlIHNlbGVjdFxuXHQgKlxuXHQgKiBBIGRlZmF1bHQgYXJyYXkgb2Ygb3B0aW9ucyB3aWxsIGJlIGRlZmluZWQ6IFsxMCwgMjAsIDMwLCA0MCwgNTBdXG5cdCAqL1xuXHRASW5wdXQoKSBpdGVtc1BlclBhZ2VPcHRpb25zOiBudW1iZXJbXSA9IFsxMCwgMjAsIDMwLCA0MCwgNTBdO1xuXG5cdC8qKlxuXHQgKiBFbWl0cyB0aGUgbmV3IHBhZ2UgbnVtYmVyLlxuXHQgKlxuXHQgKiBZb3Ugc2hvdWxkIHRpZSBpbnRvIHRoaXMgYW5kIHVwZGF0ZSBgbW9kZWwuY3VycmVudFBhZ2VgIG9uY2UgdGhlIGZyZXNoXG5cdCAqIGRhdGEgaXMgZmluYWxseSBsb2FkZWQuXG5cdCAqL1xuXHRAT3V0cHV0KCkgc2VsZWN0UGFnZSA9IG5ldyBFdmVudEVtaXR0ZXI8bnVtYmVyPigpO1xuXG5cdGdldCBpdGVtc1BlclBhZ2UoKSB7XG5cdFx0cmV0dXJuIHRoaXMubW9kZWwucGFnZUxlbmd0aDtcblx0fVxuXHRzZXQgaXRlbXNQZXJQYWdlKHZhbHVlKSB7XG5cdFx0dGhpcy5tb2RlbC5wYWdlTGVuZ3RoID0gTnVtYmVyKHZhbHVlKTtcblx0XHR0aGlzLmN1cnJlbnRQYWdlID0gMTsgLy8gcmVzZXQgcGFnZVxuXHR9XG5cblx0Z2V0IGN1cnJlbnRQYWdlKCkge1xuXHRcdHJldHVybiB0aGlzLm1vZGVsLmN1cnJlbnRQYWdlO1xuXHR9XG5cdHNldCBjdXJyZW50UGFnZSh2YWx1ZSkge1xuXHRcdHZhbHVlID0gTnVtYmVyKHZhbHVlKTtcblx0XHQvLyBlbWl0cyB0aGUgdmFsdWUgdG8gYWxsb3cgdGhlIHVzZXIgdG8gdXBkYXRlIGN1cnJlbnQgcGFnZVxuXHRcdC8vIGluIHRoZSBtb2RlbCBvbmNlIHRoZSBwYWdlIGlzIGxvYWRlZFxuXHRcdHRoaXMuc2VsZWN0UGFnZS5lbWl0KHZhbHVlKTtcblx0fVxuXG5cdGdldCB0b3RhbERhdGFMZW5ndGgoKSB7XG5cdFx0cmV0dXJuIHRoaXMubW9kZWwudG90YWxEYXRhTGVuZ3RoO1xuXHR9XG5cdC8qKlxuXHQgKiBUaGUgbGFzdCBwYWdlIG51bWJlciB0byBkaXNwbGF5IGluIHRoZSBwYWdpbmF0aW9uIHZpZXcuXG5cdCAqL1xuXHRnZXQgbGFzdFBhZ2UoKTogbnVtYmVyIHtcblx0XHRjb25zdCBsYXN0ID0gTWF0aC5jZWlsKHRoaXMudG90YWxEYXRhTGVuZ3RoIC8gdGhpcy5pdGVtc1BlclBhZ2UpO1xuXHRcdHJldHVybiBsYXN0ID4gMCA/IGxhc3QgOiAxO1xuXHR9XG5cblx0Z2V0IHN0YXJ0SXRlbUluZGV4KCkge1xuXHRcdHJldHVybiB0aGlzLmVuZEl0ZW1JbmRleCA+IDAgPyAodGhpcy5jdXJyZW50UGFnZSAtIDEpICogdGhpcy5pdGVtc1BlclBhZ2UgKyAxIDogMDtcblx0fVxuXG5cdGdldCBlbmRJdGVtSW5kZXgoKSB7XG5cdFx0Y29uc3QgcHJvamVjdGVkRW5kSXRlbUluZGV4ID0gdGhpcy5jdXJyZW50UGFnZSAqIHRoaXMuaXRlbXNQZXJQYWdlO1xuXG5cdFx0cmV0dXJuIHByb2plY3RlZEVuZEl0ZW1JbmRleCA8IHRoaXMudG90YWxEYXRhTGVuZ3RoID8gcHJvamVjdGVkRW5kSXRlbUluZGV4IDogdGhpcy50b3RhbERhdGFMZW5ndGg7XG5cdH1cblxuXHQvKipcblx0ICogVGhlIHByZXZpb3VzIHBhZ2UgbnVtYmVyIHRvIG5hdmlnYXRlIHRvLCBmcm9tIHRoZSBjdXJyZW50IHBhZ2UuXG5cdCAqL1xuXHRnZXQgcHJldmlvdXNQYWdlKCk6IG51bWJlciB7XG5cdFx0cmV0dXJuIHRoaXMuY3VycmVudFBhZ2UgPD0gMSA/IDEgOiB0aGlzLmN1cnJlbnRQYWdlIC0gMTtcblx0fVxuXG5cdC8qKlxuXHQgKiBUaGUgbmV4dCBwYWdlIG51bWJlciB0byBuYXZpZ2F0ZSB0bywgZnJvbSB0aGUgY3VycmVudCBwYWdlLlxuXHQgKi9cblx0Z2V0IG5leHRQYWdlKCk6IG51bWJlciB7XG5cdFx0Y29uc3QgbGFzdFBhZ2UgPSB0aGlzLmxhc3RQYWdlO1xuXHRcdHJldHVybiB0aGlzLmN1cnJlbnRQYWdlID49IGxhc3RQYWdlID8gbGFzdFBhZ2UgOiB0aGlzLmN1cnJlbnRQYWdlICsgMTtcblx0fVxuXG5cdGdldCBwYWdlT3B0aW9ucygpIHtcblx0XHQvKipcblx0XHQgKiBDYWxjdWxhdGUgbnVtYmVyIG9mIHBhZ2VzIGJhc2VkIG9uIHRvdGFsRGF0YUxlbmd0aCBhbmQgaXRlbXNQZXJQYWdlLlxuXHRcdCAqIEV2ZW4gaWYgdG90YWxEYXRhTGVuZ3RoIGlzIDAsIG51bWJlck9mUGFnZXMgc2hvdWxkIGJlIGFsd2F5cyBhdCBsZWFzdCAxLlxuXHRcdCAqIE5ldyBhcnJheSB3aWxsIGJlIGNvbnN0cnVjdGVkIG9ubHkgaWYgbnVtYmVyIG9mIHBhZ2VzIGNoYW5nZXMuXG5cdFx0ICovXG5cdFx0Y29uc3QgbnVtYmVyT2ZQYWdlcyA9IE1hdGgubWF4KE1hdGguY2VpbCh0aGlzLnRvdGFsRGF0YUxlbmd0aCAvIHRoaXMuaXRlbXNQZXJQYWdlKSwgMSk7XG5cdFx0aWYgKHRoaXMuX3BhZ2VPcHRpb25zLmxlbmd0aCAhPT0gbnVtYmVyT2ZQYWdlcykge1xuXHRcdFx0dGhpcy5fcGFnZU9wdGlvbnMgPSBBcnJheShudW1iZXJPZlBhZ2VzKTtcblx0XHR9XG5cdFx0cmV0dXJuIHRoaXMuX3BhZ2VPcHRpb25zO1xuXHR9XG5cblx0aXRlbXNQZXJQYWdlU2VsZWN0SWQgPSBgcGFnaW5hdGlvbi1zZWxlY3QtaXRlbXMtcGVyLXBhZ2UtJHtQYWdpbmF0aW9uLnBhZ2luYXRpb25Db3VudGVyfWA7XG5cdGN1cnJlbnRQYWdlU2VsZWN0SWQgPSBgcGFnaW5hdGlvbi1zZWxlY3QtY3VycmVudC1wYWdlLSR7UGFnaW5hdGlvbi5wYWdpbmF0aW9uQ291bnRlcn1gO1xuXG5cdGl0ZW1zUGVyUGFnZVRleHQgPSB0aGlzLmkxOG4uZ2V0T3ZlcnJpZGFibGUoXCJQQUdJTkFUSU9OLklURU1TX1BFUl9QQUdFXCIpO1xuXHRvcHRpb25zTGlzdFRleHQgPSB0aGlzLmkxOG4uZ2V0T3ZlcnJpZGFibGUoXCJQQUdJTkFUSU9OLk9QRU5fTElTVF9PRl9PUFRJT05TXCIpO1xuXHRiYWNrd2FyZFRleHQgPSB0aGlzLmkxOG4uZ2V0T3ZlcnJpZGFibGUoXCJQQUdJTkFUSU9OLkJBQ0tXQVJEXCIpO1xuXHRmb3J3YXJkVGV4dCA9IHRoaXMuaTE4bi5nZXRPdmVycmlkYWJsZShcIlBBR0lOQVRJT04uRk9SV0FSRFwiKTtcblx0dG90YWxJdGVtc1RleHQgPSB0aGlzLmkxOG4uZ2V0T3ZlcnJpZGFibGUoXCJQQUdJTkFUSU9OLlRPVEFMX0lURU1TXCIpO1xuXHR0b3RhbEl0ZW1UZXh0ID0gdGhpcy5pMThuLmdldE92ZXJyaWRhYmxlKFwiUEFHSU5BVElPTi5UT1RBTF9JVEVNXCIpO1xuXHR0b3RhbEl0ZW1zVW5rbm93blRleHQgPSB0aGlzLmkxOG4uZ2V0T3ZlcnJpZGFibGUoXCJQQUdJTkFUSU9OLlRPVEFMX0lURU1TX1VOS05PV05cIik7XG5cdHBhZ2VUZXh0ID0gdGhpcy5pMThuLmdldE92ZXJyaWRhYmxlKFwiUEFHSU5BVElPTi5QQUdFXCIpO1xuXHRvZkxhc3RQYWdlc1RleHQgPSB0aGlzLmkxOG4uZ2V0T3ZlcnJpZGFibGUoXCJQQUdJTkFUSU9OLk9GX0xBU1RfUEFHRVNcIik7XG5cdG9mTGFzdFBhZ2VUZXh0ID0gdGhpcy5pMThuLmdldE92ZXJyaWRhYmxlKFwiUEFHSU5BVElPTi5PRl9MQVNUX1BBR0VcIik7XG5cblx0cHJvdGVjdGVkIF9wYWdlT3B0aW9ucyA9IFtdO1xuXG5cdGNvbnN0cnVjdG9yKHByb3RlY3RlZCBpMThuOiBJMThuLCBwcm90ZWN0ZWQgZXhwZXJpbWVudGFsOiBFeHBlcmltZW50YWxTZXJ2aWNlKSB7XG5cdFx0UGFnaW5hdGlvbi5wYWdpbmF0aW9uQ291bnRlcisrO1xuXHR9XG59XG4iXX0=