carbon-components-angular
Version:
Next generation components
477 lines (467 loc) • 45.3 kB
JavaScript
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 backward/forward buttons.
*/
this.disabled = 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;
/**
* 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++;
}
/**
* 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() {
if (this.totalDataLength && this._pageOptions.length !== this.totalDataLength) {
this._pageOptions = Array(Math.ceil(this.totalDataLength / this.itemsPerPage));
}
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", 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 <= 1000"
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 || disabled
}"
tabindex="0"
[attr.aria-label]="backwardText.subject | async"
(click)="selectPage.emit(previousPage)"
[disabled]="(currentPage <= 1 || disabled ? 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 || disabled
}"
tabindex="0"
[attr.aria-label]="forwardText.subject | async"
(click)="selectPage.emit(nextPage)"
[disabled]="(currentPage >= lastPage || disabled ? 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 <= 1000"
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 || disabled
}"
tabindex="0"
[attr.aria-label]="backwardText.subject | async"
(click)="selectPage.emit(previousPage)"
[disabled]="(currentPage <= 1 || disabled ? 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 || disabled
}"
tabindex="0"
[attr.aria-label]="forwardText.subject | async"
(click)="selectPage.emit(nextPage)"
[disabled]="(currentPage >= lastPage || disabled ? 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
}], translations: [{
type: Input
}], itemsPerPageOptions: [{
type: Input
}], selectPage: [{
type: Output
}] } });
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicGFnaW5hdGlvbi5jb21wb25lbnQuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi9zcmMvcGFnaW5hdGlvbi9wYWdpbmF0aW9uLmNvbXBvbmVudC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFDQSxPQUFPLEVBQ04sU0FBUyxFQUNULEtBQUssRUFDTCxNQUFNLEVBQ04sWUFBWSxFQUNaLE1BQU0sZUFBZSxDQUFDO0FBSXZCLE9BQU8sRUFBRSxLQUFLLEVBQUUsTUFBTSxpQ0FBaUMsQ0FBQzs7Ozs7Ozs7QUFjeEQ7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7R0F5Qkc7QUErSUgsTUFBTSxPQUFPLFVBQVU7SUF3SnRCLFlBQXNCLElBQVUsRUFBWSxZQUFpQztRQUF2RCxTQUFJLEdBQUosSUFBSSxDQUFNO1FBQVksaUJBQVksR0FBWixZQUFZLENBQXFCO1FBcko3RTs7V0FFRztRQUNNLGFBQVEsR0FBRyxLQUFLLENBQUM7UUFLMUI7O1dBRUc7UUFDTSxhQUFRLEdBQUcsS0FBSyxDQUFDO1FBQzFCOztXQUVHO1FBQ00sc0JBQWlCLEdBQUcsS0FBSyxDQUFDO1FBQ25DOztXQUVHO1FBQ00sa0JBQWEsR0FBRyxJQUFJLENBQUM7UUFDOUI7O1dBRUc7UUFDTSxpQkFBWSxHQUFHLEtBQUssQ0FBQztRQUNyQix3QkFBbUIsR0FBRyxJQUFJLENBQUM7UUFpQ3BDOzs7O1dBSUc7UUFDTSx3QkFBbUIsR0FBYSxDQUFDLEVBQUUsRUFBRSxFQUFFLEVBQUUsRUFBRSxFQUFFLEVBQUUsRUFBRSxFQUFFLENBQUMsQ0FBQztRQUU5RDs7Ozs7V0FLRztRQUNPLGVBQVUsR0FBRyxJQUFJLFlBQVksRUFBVSxDQUFDO1FBK0RsRCx5QkFBb0IsR0FBRyxvQ0FBb0MsVUFBVSxDQUFDLGlCQUFpQixFQUFFLENBQUM7UUFDMUYsd0JBQW1CLEdBQUcsa0NBQWtDLFVBQVUsQ0FBQyxpQkFBaUIsRUFBRSxDQUFDO1FBRXZGLHFCQUFnQixHQUFHLElBQUksQ0FBQyxJ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QUFhO3NCQUFyQixLQUFLO2dCQUlHLFlBQVk7c0JBQXBCLEtBQUs7Z0JBQ0csbUJBQW1CO3NCQUEzQixLQUFLO2dCQW1CRixZQUFZO3NCQURmLEtBQUs7Z0JBb0JHLG1CQUFtQjtzQkFBM0IsS0FBSztnQkFRSSxVQUFVO3NCQUFuQixNQUFNIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgUGFnaW5hdGlvbk1vZGVsIH0gZnJvbSBcIi4vcGFnaW5hdGlvbi1tb2RlbC5jbGFzc1wiO1xuaW1wb3J0IHtcblx0Q29tcG9uZW50LFxuXHRJbnB1dCxcblx0T3V0cHV0LFxuXHRFdmVudEVtaXR0ZXJcbn0gZnJvbSBcIkBhbmd1bGFyL2NvcmVcIjtcblxuaW1wb3J0IHsgSTE4biwgT3ZlcnJpZGFibGUgfSBmcm9tIFwiY2FyYm9uLWNvbXBvbmVudHMtYW5ndWxhci9pMThuXCI7XG5pbXBvcnQgeyBFeHBlcmltZW50YWxTZXJ2aWNlIH0gZnJvbSBcImNhcmJvbi1jb21wb25lbnRzLWFuZ3VsYXIvZXhwZXJpbWVudGFsXCI7XG5pbXBvcnQgeyBtZXJnZSB9IGZyb20gXCJjYXJib24tY29tcG9uZW50cy1hbmd1bGFyL3V0aWxzXCI7XG5cbmV4cG9ydCBpbnRlcmZhY2UgUGFnaW5hdGlvblRyYW5zbGF0aW9ucyB7XG5cdElURU1TX1BFUl9QQUdFOiBzdHJpbmc7XG5cdE9QRU5fTElTVF9PRl9PUFRJT05TOiBzdHJpbmc7XG5cdEJBQ0tXQVJEOiBzdHJpbmc7XG5cdEZPUldBUkQ6IHN0cmluZztcblx0VE9UQUxfSVRFTVNfVU5LTk9XTjogc3RyaW5nO1xuXHRUT1RBTF9JVEVNUzogc3RyaW5nO1xuXHRUT1RBTF9JVEVNOiBzdHJpbmc7XG5cdE9GX0xBU1RfUEFHRVM6IHN0cmluZztcblx0T0ZfTEFTVF9QQUdFOiBzdHJpbmc7XG59XG5cbi8qKlxuICogVXNlIHBhZ2luYXRpb24gd2hlbiB5b3UgaGF2ZSBtdWx0aXBsZSBwYWdlcyBvZiBkYXRhIHRvIGhhbmRsZS4gR2V0IHN0YXJ0ZWQgd2l0aCBpbXBvcnRpbmcgdGhlIG1vZHVsZTpcbiAqXG4gKiBgYGB0eXBlc2NyaXB0XG4gKiBpbXBvcnQgeyBQYWdpbmF0aW9uTW9kdWxlIH0gZnJvbSAnY2FyYm9uLWNvbXBvbmVudHMtYW5ndWxhcic7XG4gKiBgYGBcbiAqXG4gKiBgYGBodG1sXG4gKlx0PGNkcy1wYWdpbmF0aW9uIFttb2RlbF09XCJtb2RlbFwiIChzZWxlY3RQYWdlKT1cInNlbGVjdFBhZ2UoJGV2ZW50KVwiPjwvY2RzLXBhZ2luYXRpb24+XG4gKiBgYGBcbiAqXG4gKiBJbiB5b3VyIGBzZWxlY3RQYWdlKClgIG1ldGhvZCBzZXQgdGhlIGBtb2RlbC5jdXJyZW50UGFnZWAgdG8gc2VsZWN0ZWQgcGFnZSwgX2FmdGVyX1xuICogeW91IGxvYWQgdGhlIHBhZ2UuXG4gKlxuICogYGBgdHlwZXNjcmlwdFxuICogc2VsZWN0UGFnZShwYWdlKSB7XG4gKiBcdC8vIC4uLiB5b3VyIGNvZGUgdG8gbG9hZCB0aGUgcGFnZSBnb2VzIGhlcmVcbiAqXG4gKiBcdHRoaXMubW9kZWwuY3VycmVudFBhZ2UgPSBwYWdlO1xuICpcbiAqIFx0Ly8gLi4uIGFueXRoaW5nIHlvdSB3YW50IHRvIGRvIGFmdGVyIHBhZ2Ugc2VsZWN0aW9uIGNoYW5nZXMgZ29lcyBoZXJlXG4gKiB9XG4gKiBgYGBcbiAqXG4gKiBbU2VlIGRlbW9dKC4uLy4uLz9wYXRoPS9zdG9yeS9jb21wb25lbnRzLXBhZ2luYXRpb24tLWJhc2ljKVxuICovXG5AQ29tcG9uZW50KHtcblx0c2VsZWN0b3I6IFwiY2RzLXBhZ2luYXRpb24sIGlibS1wYWdpbmF0aW9uXCIsXG5cdHRlbXBsYXRlOiBgXG5cdDxkaXZcblx0XHRjbGFzcz1cImNkcy0tcGFnaW5hdGlvblwiXG5cdFx0W25nQ2xhc3NdPVwie1xuXHRcdFx0J2Nkcy0tc2tlbGV0b24nOiBza2VsZXRvblxuXHRcdH1cIj5cblx0XHQ8IS0tIGxlZnQgc2tlbGV0b24gZGl2IC0tPlxuXHRcdDxkaXYgKm5nSWY9XCJza2VsZXRvblwiIGNsYXNzPVwiY2RzLS1wYWdpbmF0aW9uX19sZWZ0XCI+XG5cdFx0XHQ8cCBjbGFzcz1cImNkcy0tc2tlbGV0b25fX3RleHRcIiBzdHlsZT1cIndpZHRoOiA3MHB4XCI+PC9wPlxuXHRcdFx0PHAgY2xhc3M9XCJjZHMtLXNrZWxldG9uX190ZXh0XCIgc3R5bGU9XCJ3aWR0aDogMzVweFwiPjwvcD5cblx0XHRcdDxwIGNsYXNzPVwiY2RzLS1za2VsZXRvbl9fdGV4dFwiIHN0eWxlPVwid2lkdGg6IDEwNXB4XCI+PC9wPlxuXHRcdDwvZGl2PlxuXG5cdFx0PGRpdiAqbmdJZj1cIiFza2VsZXRvblwiIGNsYXNzPVwiY2RzLS1wYWdpbmF0aW9uX19sZWZ0XCI+XG5cdFx0XHQ8bmctY29udGFpbmVyICpuZ0lmPVwic2hvd1BhZ2VJbnB1dFwiPlxuXHRcdFx0XHQ8bGFiZWwgY2xhc3M9XCJjZHMtLXBhZ2luYXRpb25fX3RleHRcIiBbZm9yXT1cIml0ZW1zUGVyUGFnZVNlbGVjdElkXCI+XG5cdFx0XHRcdFx0e3tpdGVtc1BlclBhZ2VUZXh0LnN1YmplY3QgfCBhc3luY319XG5cdFx0XHRcdDwvbGFiZWw+XG5cdFx0XHRcdDxkaXZcblx0XHRcdFx0XHRjbGFzcz1cImNkcy0tc2VsZWN0IGNkcy0tc2VsZWN0LS1pbmxpbmUgY2RzLS1zZWxlY3RfX2l0ZW0tY291bnRcIlxuXHRcdFx0XHRcdFtjbGFzcy5jZHMtLXNlbGVjdC0tZGlzYWJsZWRdPVwicGFnZUlucHV0RGlzYWJsZWRcIj5cblx0XHRcdFx0XHQ8c2VsZWN0XG5cdFx0XHRcdFx0XHRbaWRdPVwiaXRlbXNQZXJQYWdlU2VsZWN0SWRcIlxuXHRcdFx0XHRcdFx0WyhuZ01vZGVsKV09XCJpdGVtc1BlclBhZ2VcIlxuXHRcdFx0XHRcdFx0W2Rpc2FibGVkXT1cInBhZ2VJbnB1dERpc2FibGVkXCJcblx0XHRcdFx0XHRcdGNsYXNzPVwiY2RzLS1zZWxlY3QtaW5wdXRcIj5cblx0XHRcdFx0XHRcdDxvcHRpb25cblx0XHRcdFx0XHRcdFx0Y2xhc3M9XCJjZHMtLXNlbGVjdC1vcHRpb25cIlxuXHRcdFx0XHRcdFx0XHQqbmdGb3I9XCJsZXQgb3B0aW9uIG9mIGl0ZW1zUGVyUGFnZU9wdGlvbnNcIlxuXHRcdFx0XHRcdFx0XHRbdmFsdWVdPVwib3B0aW9uXCI+XG5cdFx0XHRcdFx0XHRcdFx0e3sgb3B0aW9uIH19XG5cdFx0XHRcdFx0XHQ8L29wdGlvbj5cblx0XHRcdFx0XHQ8L3NlbGVjdD5cblx0XHRcdFx0XHQ8c3ZnXG5cdFx0XHRcdFx0XHRjZHNJY29uPVwiY2hldnJvbi0tZG93blwiXG5cdFx0XHRcdFx0XHRzaXplPVwiMTZcIlxuXHRcdFx0XHRcdFx0c3R5bGU9XCJkaXNwbGF5OiBpbmhlcml0XCJcblx0XHRcdFx0XHRcdGNsYXNzPVwiY2RzLS1zZWxlY3RfX2Fycm93XCJcblx0XHRcdFx0XHRcdGFyaWEtaGlkZGVuPVwidHJ1ZVwiXG5cdFx0XHRcdFx0XHRbYXR0ci5hcmlhTGFiZWxdPVwib3B0aW9uc0xpc3RUZXh0LnN1YmplY3QgfCBhc3luY1wiPlxuXHRcdFx0XHRcdDwvc3ZnPlxuXHRcdFx0XHQ8L2Rpdj5cblx0XHRcdDwvbmctY29udGFpbmVyPlxuXHRcdFx0PHNwYW4gKm5nSWY9XCIhcGFnZXNVbmtub3duICYmIHRvdGFsRGF0YUxlbmd0aCA8PSAxXCIgY2xhc3M9XCJjZHMtLXBhZ2luYXRpb25fX3RleHQgY2RzLS1wYWdpbmF0aW9uX19pdGVtcy1jb3VudFwiIFtuZ1N0eWxlXT1cInsnbWFyZ2luLWxlZnQnOiBzaG93UGFnZUlucHV0ID8gbnVsbCA6IDB9XCI+XG5cdFx0XHRcdHt7dG90YWxJdGVtVGV4dC5zdWJqZWN0IHwgaTE4blJlcGxhY2U6e3N0YXJ0OiBzdGFydEl0ZW1JbmRleCwgZW5kOiBlbmRJdGVtSW5kZXgsIHRvdGFsOiB0b3RhbERhdGFMZW5ndGggfSB8IGFzeW5jfX1cblx0XHRcdDwvc3Bhbj5cblx0XHRcdDxzcGFuICpuZ0lmPVwiIXBhZ2VzVW5rbm93biAmJiB0b3RhbERhdGFMZW5ndGggPiAxXCIgY2xhc3M9XCJjZHMtLXBhZ2luYXRpb25fX3RleHQgY2RzLS1wYWdpbmF0aW9uX19pdGVtcy1jb3VudFwiIFtuZ1N0eWxlXT1cInsnbWFyZ2luLWxlZnQnOiBzaG93UGFnZUlucHV0ID8gbnVsbCA6IDB9XCI+XG5cdFx0XHRcdHt7dG90YWxJdGVtc1RleHQuc3ViamVjdCB8IGkxOG5SZXBsYWNlOntzdGFydDogc3RhcnRJdGVtSW5kZXgsIGVuZDogZW5kSXRlbUluZGV4LCB0b3RhbDogdG90YWxEYXRhTGVuZ3RoIH0gfCBhc3luY319XG5cdFx0XHQ8L3NwYW4+XG5cdFx0XHQ8c3BhbiAqbmdJZj1cInBhZ2VzVW5rbm93blwiIGNsYXNzPVwiY2RzLS1wYWdpbmF0aW9uX190ZXh0IGNkcy0tcGFnaW5hdGlvbl9faXRlbXMtY291bnRcIiBbbmdTdHlsZV09XCJ7J21hcmdpbi1sZWZ0Jzogc2hvd1BhZ2VJbnB1dCA/IG51bGwgOiAwfVwiPlxuXHRcdFx0XHR7e3RvdGFsSXRlbXNVbmtub3duVGV4dC5zdWJqZWN0IHwgaTE4blJlcGxhY2U6e3N0YXJ0OiBzdGFydEl0ZW1JbmRleCwgZW5kOiBlbmRJdGVtSW5kZXggfSB8IGFzeW5jfX1cblx0XHRcdDwvc3Bhbj5cblx0XHQ8L2Rpdj5cblxuXHRcdDwhLS0gcmlnaHQgc2tlbGV0b24gZGl2IC0tPlxuXHRcdDxkaXYgKm5nSWY9XCJza2VsZXRvblwiIGNsYXNzPVwiY2RzLS1wYWdpbmF0aW9uX19yaWdodFwiPlxuXHRcdFx0PHAgY2xhc3M9XCJjZHMtLXNrZWxldG9uX190ZXh0XCIgc3R5bGU9XCJ3aWR0aDogNzBweFwiPjwvcD5cblx0XHQ8L2Rpdj5cblxuXHRcdDxkaXYgKm5nSWY9XCIhc2tlbGV0b25cIiBjbGFzcz1cImNkcy0tcGFnaW5hdGlvbl9fcmlnaHRcIj5cblx0XHRcdDxzcGFuICpuZ0lmPVwicGFnZXNVbmtub3duXCIgY2xhc3M9XCJjZHMtLXBhZ2luYXRpb25fX3RleHQgY2RzLS1wYWdpbmF0aW9uX19wYWdlLXRleHRcIj5cblx0XHRcdFx0PG5nLWNvbnRhaW5lciAqbmdJZj1cIiFzaG93UGFnZUlucHV0XCI+e3tjdXJyZW50UGFnZX19PC9uZy1jb250YWluZXI+XG5cdFx0XHRcdHt7cGFnZVRleHQuc3ViamVjdCB8IGFzeW5jfX1cblx0XHRcdDwvc3Bhbj5cblx0XHRcdDxuZy1jb250YWluZXIgKm5nSWY9XCJzaG93UGFnZUlucHV0XCI+XG5cdFx0XHRcdDxkaXZcblx0XHRcdFx0XHRjbGFzcz1cImNkcy0tc2VsZWN0IGNkcy0tc2VsZWN0LS1pbmxpbmUgY2RzLS1zZWxlY3RfX3BhZ2UtbnVtYmVyXCJcblx0XHRcdFx0XHRbY2xhc3MuY2RzLS1zZWxlY3QtLWRpc2FibGVkXT1cInBhZ2VJbnB1dERpc2FibGVkXCI+XG5cdFx0XHRcdFx0PGxhYmVsIFtmb3JdPVwiY3VycmVudFBhZ2VTZWxlY3RJZFwiIGNsYXNzPVwiY2RzLS1sYWJlbCBjZHMtLXZpc3VhbGx5LWhpZGRlblwiPnt7cGFnZVRleHQuc3ViamVjdCB8IGFzeW5jfX08L2xhYmVsPlxuXHRcdFx0XHRcdDxpbnB1dFxuXHRcdFx0XHRcdFx0Km5nSWY9XCJwYWdlT3B0aW9ucy5sZW5ndGggPiBwYWdlU2VsZWN0VGhyZXNob2xkXCJcblx0XHRcdFx0XHRcdHN0eWxlPVwicGFkZGluZy1yaWdodDogMXJlbTsgbWFyZ2luLXJpZ2h0OiAxcmVtO1wiXG5cdFx0XHRcdFx0XHRbaWRdPVwiY3VycmVudFBhZ2VTZWxlY3RJZFwiXG5cdFx0XHRcdFx0XHR0eXBlPVwibnVtYmVyXCJcblx0XHRcdFx0XHRcdG1pbj1cIjFcIlxuXHRcdFx0XHRcdFx0W21heF09XCJwYWdlT3B0aW9ucy5sZW5ndGhcIlxuXHRcdFx0XHRcdFx0Y2xhc3M9XCJjZHMtLXNlbGVjdC1pbnB1dFwiXG5cdFx0XHRcdFx0XHRbKG5nTW9kZWwpXT1cImN1cnJlbnRQYWdlXCI+XG5cdFx0XHRcdFx0PHNlbGVjdFxuXHRcdFx0XHRcdFx0Km5nSWY9XCJwYWdlT3B0aW9ucy5sZW5ndGggPD0gcGFnZVNlbGVjdFRocmVzaG9sZFwiXG5cdFx0XHRcdFx0XHRbaWRdPVwiY3VycmVudFBhZ2VTZWxlY3RJZFwiXG5cdFx0XHRcdFx0XHRjbGFzcz1cImNkcy0tc2VsZWN0LWlucHV0XCJcblx0XHRcdFx0XHRcdFtkaXNhYmxlZF09XCJwYWdlSW5wdXREaXNhYmxlZFwiXG5cdFx0XHRcdFx0XHRbKG5nTW9kZWwpXT1cImN1cnJlbnRQYWdlXCI+XG5cdFx0XHRcdFx0XHQ8b3B0aW9uICpuZ0Zvcj1cImxldCBwYWdlIG9mIHBhZ2VPcHRpb25zOyBsZXQgaSA9IGluZGV4O1wiIGNsYXNzPVwiY2RzLS1zZWxlY3Qtb3B0aW9uXCIgW3ZhbHVlXT1cImkgKyAxXCI+e3tpICsgMX19PC9vcHRpb24+XG5cdFx0XHRcdFx0PC9zZWxlY3Q+XG5cdFx0XHRcdFx0PHN2Z1xuXHRcdFx0XHRcdFx0Km5nSWY9XCJwYWdlT3B0aW9ucy5sZW5ndGggPD0gMTAwMFwiXG5cdFx0XHRcdFx0XHRjZHNJY29uPVwiY2hldnJvbi0tZG93blwiXG5cdFx0XHRcdFx0XHRzaXplPVwiMTZcIlxuXHRcdFx0XHRcdFx0c3R5bGU9XCJkaXNwbGF5OiBpbmhlcml0O1wiXG5cdFx0XHRcdFx0XHRjbGFzcz1cImNkcy0tc2VsZWN0X19hcnJvd1wiXG5cdFx0XHRcdFx0XHRbYXR0ci5hcmlhTGFiZWxdPVwib3B0aW9uc0xpc3RUZXh0LnN1YmplY3QgfCBhc3luY1wiPlxuXHRcdFx0XHRcdDwvc3ZnPlxuXHRcdFx0XHQ8L2Rpdj5cblx0XHRcdDwvbmctY29udGFpbmVyPlxuXG5cdFx0XHQ8c3BhbiAqbmdJZj1cIiFwYWdlc1Vua25vd24gJiYgbGFzdFBhZ2UgPD0gMVwiIGNsYXNzPVwiY2RzLS1wYWdpbmF0aW9uX190ZXh0XCI+XG5cdFx0XHRcdDxuZy1jb250YWluZXIgKm5nSWY9XCIhc2hvd1BhZ2VJbnB1dFwiPnt7Y3VycmVudFBhZ2V9fTwvbmctY29udGFpbmVyPlxuXHRcdFx0XHR7e29mTGFzdFBhZ2VUZXh0LnN1YmplY3QgfCBpMThuUmVwbGFjZToge2xhc3Q6IGxhc3RQYWdlfSB8IGFzeW5jfX1cblx0XHRcdDwvc3Bhbj5cblx0XHRcdDxzcGFuICpuZ0lmPVwiIXBhZ2VzVW5rbm93biAmJiBsYXN0UGFnZSA+IDFcIiBjbGFzcz1cImNkcy0tcGFnaW5hdGlvbl9fdGV4dFwiPlxuXHRcdFx0XHQ8bmctY29udGFpbmVyICpuZ0lmPVwiIXNob3dQYWdlSW5wdXRcIj57e2N1cnJlbnRQYWdlfX08L25nLWNvbnRhaW5lcj5cblx0XHRcdFx0e3tvZkxhc3RQYWdlc1RleHQuc3ViamVjdCB8IGkxOG5SZXBsYWNlOiB7bGFzdDogbGFzdFBhZ2V9IHwgYXN5bmN9fVxuXHRcdFx0PC9zcGFuPlxuXHRcdFx0PGRpdiBjbGFzcz1cImNkcy0tcGFnaW5hdGlvbl9fY29udHJvbC1idXR0b25zXCI+XG5cdFx0XHRcdDxidXR0b25cblx0XHRcdFx0XHRjZHNCdXR0b249XCJnaG9zdFwiXG5cdFx0XHRcdFx0aWNvbk9ubHk9XCJ0cnVlXCJcblx0XHRcdFx0XHRjbGFzcz1cImNkcy0tcGFnaW5hdGlvbl9fYnV0dG9uIGNkcy0tcGFnaW5hdGlvbl9fYnV0dG9uLS1iYWNrd2FyZFwiXG5cdFx0XHRcdFx0W25nQ2xhc3NdPVwie1xuXHRcdFx0XHRcdFx0J2Nkcy0tcGFnaW5hdGlvbl9fYnV0dG9uLS1uby1pbmRleCc6IGN1cnJlbnRQYWdlIDw9IDEgfHwgZGlzYWJsZWRcblx0XHRcdFx0XHR9XCJcblx0XHRcdFx0XHR0YWJpbmRleD1cIjBcIlxuXHRcdFx0XHRcdFthdHRyLmFyaWEtbGFiZWxdPVwiYmFja3dhcmRUZXh0LnN1YmplY3QgfCBhc3luY1wiXG5cdFx0XHRcdFx0KGNsaWNrKT1cInNlbGVjdFBhZ2UuZW1pdChwcmV2aW91c1BhZ2UpXCJcblx0XHRcdFx0XHRbZGlzYWJsZWRdPVwiKGN1cnJlbnRQYWdlIDw9IDEgfHwgZGlzYWJsZWQgPyB0cnVlIDogbnVsbClcIj5cblx0XHRcdFx0XHQ8c3ZnIGNkc0ljb249XCJjYXJldC0tbGVmdFwiIHNpemU9XCIxNlwiIGNsYXNzPVwiY2RzLS1idG5fX2ljb25cIj48L3N2Zz5cblx0XHRcdFx0PC9idXR0b24+XG5cblx0XHRcdFx0PGJ1dHRvblxuXHRcdFx0XHRcdGNkc0J1dHRvbj1cImdob3N0XCJcblx0XHRcdFx0XHRpY29uT25seT1cInRydWVcIlxuXHRcdFx0XHRcdGNsYXNzPVwiXG5cdFx0XHRcdFx0XHRjZHMtLXBhZ2luYXRpb25fX2J1dHRvblxuXHRcdFx0XHRcdFx0Y2RzLS1wYWdpbmF0aW9uX19idXR0b24tLWZvcndhcmRcIlxuXHRcdFx0XHRcdFtuZ0NsYXNzXT1cIntcblx0XHRcdFx0XHRcdCdjZHMtLXBhZ2luYXRpb25fX2J1dHRvbi0tbm8taW5kZXgnOiBjdXJyZW50UGFnZSA+PSBsYXN0UGFnZSB8fCBkaXNhYmxlZFxuXHRcdFx0XHRcdH1cIlxuXHRcdFx0XHRcdHRhYmluZGV4PVwiMFwiXG5cdFx0XHRcdFx0W2F0dHIuYXJpYS1sYWJlbF09XCJmb3J3YXJkVGV4dC5zdWJqZWN0IHwgYXN5bmNcIlxuXHRcdFx0XHRcdChjbGljayk9XCJzZWxlY3RQYWdlLmVtaXQobmV4dFBhZ2UpXCJcblx0XHRcdFx0XHRbZGlzYWJsZWRdPVwiKGN1cnJlbnRQYWdlID49IGxhc3RQYWdlIHx8IGRpc2FibGVkID8gdHJ1ZSA6IG51bGwpXCI+XG5cdFx0XHRcdFx0PHN2ZyBjZHNJY29uPVwiY2FyZXQtLXJpZ2h0XCIgc2l6ZT1cIjE2XCIgY2xhc3M9XCJjZHMtLWJ0bl9faWNvblwiPjwvc3ZnPlxuXHRcdFx0XHQ8L2J1dHRvbj5cblx0XHRcdDwvZGl2PlxuXHRcdDwvZGl2PlxuXHQ8L2Rpdj5cblx0YFxufSlcbmV4cG9ydCBjbGFzcyBQYWdpbmF0aW9uIHtcblx0c3RhdGljIHBhZ2luYXRpb25Db3VudGVyID0gMDtcblxuXHQvKipcblx0ICogU2V0IHRvIGB0cnVlYCBmb3IgYSBsb2FkaW5nIHBhZ2luYXRpb24gY29tcG9uZW50LlxuXHQgKi9cblx0QElucHV0KCkgc2tlbGV0b24gPSBmYWxzZTtcblx0LyoqXG5cdCAqIGBQYWdpbmF0aW9uTW9kZWxgIHdpdGggdGhlIGluZm9ybWF0aW9uIGFib3V0IHBhZ2VzIHlvdSdyZSBjb250cm9sbGluZy5cblx0ICovXG5cdEBJbnB1dCgpIG1vZGVsOiBQYWdpbmF0aW9uTW9kZWw7XG5cdC8qKlxuIFx0ICogU2V0IHRvIGB0cnVlYCB0byBkaXNhYmxlIHRoZSBiYWNrd2FyZC9mb3J3YXJkIGJ1dHRvbnMuXG5cdCAqL1xuXHRASW5wdXQoKSBkaXNhYmxlZCA9IGZhbHNlO1xuXHQvKipcblx0ICogU2V0IHRvIGB0cnVlYCB0byBkaXNhYmxlIHRoZSBzZWxlY3QgYm94IHRoYXQgY2hhbmdlcyB0aGUgcGFnZS5cblx0ICovXG5cdEBJbnB1dCgpIHBhZ2VJbnB1dERpc2FibGVkID0gZmFsc2U7XG5cdC8qKlxuXHQgKiBDb250cm9scyB3ZXRoZXIgb3Igbm90IHRvIHNob3cgdGhlIHBhZ2Ugc2VsZWN0c1xuXHQgKi9cblx0QElucHV0KCkgc2hvd1BhZ2VJbnB1dCA9IHRydWU7XG5cdC8qKlxuXHQgKiBTZXQgdG8gYHRydWVgIGlmIHRoZSB0b3RhbCBudW1iZXIgb2YgaXRlbXMgaXMgdW5rbm93bi5cblx0ICovXG5cdEBJbnB1dCgpIHBhZ2VzVW5rbm93biA9IGZhbHNlO1xuXHRASW5wdXQoKSBwYWdlU2VsZWN0VGhyZXNob2xkID0gMTAwMDtcblxuXHQvKipcblx0ICogRXhwZWN0cyBhbiBvYmplY3QgdGhhdCBjb250YWlucyBzb21lIG9yIGFsbCBvZjpcblx0ICogYGBgXG5cdCAqIHtcblx0ICpcdFx0XCJJVEVNU19QRVJfUEFHRVwiOiBcIkl0ZW1zIHBlciBwYWdlOlwiLFxuXHQgKlx0XHRcIk9QRU5fTElTVF9PRl9PUFRJT05TXCI6IFwiT3BlbiBsaXN0IG9mIG9wdGlvbnNcIixcblx0ICpcdFx0XCJCQUNLV0FSRFwiOiBcIkJhY2t3YXJkXCIsXG5cdCAqXHRcdFwiRk9SV0FSRFwiOiBcIkZvcndhcmRcIixcblx0ICpcdFx0XCJUT1RBTF9JVEVNU19VTktOT1dOXCI6IFwie3tzdGFydH19LXt7ZW5kfX0gaXRlbXNcIixcblx0ICpcdFx0XCJUT1RBTF9JVEVNU1wiOiBcInt7c3RhcnR9fS17e2VuZH19IG9mIHt7dG90YWx9fSBpdGVtc1wiLFxuXHQgKlx0XHRcIlRPVEFMX0lURU1cIjogXCJ7e3N0YXJ0fX0te3tlbmR9fSBvZiB7e3RvdGFsfX0gaXRlbVwiLFxuXHQgKlx0XHRcIk9GX0xBU1RfUEFHRVNcIjogXCJvZiB7e2xhc3R9fSBwYWdlc1wiLFxuXHQgKlx0XHRcIk9GX0xBU1RfUEFHRVwiOiBcIm9mIHt7bGFzdH19IHBhZ2VcIlxuXHQgKiB9XG5cdCAqIGBgYFxuXHQgKi9cblx0QElucHV0KClcblx0c2V0IHRyYW5zbGF0aW9ucyAodmFsdWU6IFBhZ2luYXRpb25UcmFuc2xhdGlvbnMpIHtcblx0XHRjb25zdCB2YWx1ZVdpdGhEZWZhdWx0cyA9IG1lcmdlKHRoaXMuaTE4bi5nZXRNdWx0aXBsZShcIlBBR0lOQVRJT05cIiksIHZhbHVlKTtcblx0XHR0aGlzLml0ZW1zUGVyUGFnZVRleHQub3ZlcnJpZGUodmFsdWVXaXRoRGVmYXVsdHMuSVRFTVNfUEVSX1BBR0UpO1xuXHRcdHRoaXMub3B0aW9uc0xpc3RUZXh0Lm92ZXJyaWRlKHZhbHVlV2l0aERlZmF1bHRzLk9QRU5fTElTVF9PRl9PUFRJT05TKTtcblx0XHR0aGlzLmJhY2t3YXJkVGV4dC5vdmVycmlkZSh2YWx1ZVdpdGhEZWZhdWx0cy5CQUNLV0FSRCk7XG5cdFx0dGhpcy5mb3J3YXJkVGV4dC5vdmVycmlkZSh2YWx1ZVdpdGhEZWZhdWx0cy5GT1JXQVJEKTtcblx0XHR0aGlzLnRvdGFsSXRlbXNUZXh0Lm92ZXJyaWRlKHZhbHVlV2l0aERlZmF1bHRzLlRPVEFMX0lURU1TKTtcblx0XHR0aGlzLnRvdGFsSXRlbVRleHQub3ZlcnJpZGUodmFsdWVXaXRoRGVmYXVsdHMuVE9UQUxfSVRFTSk7XG5cdFx0dGhpcy50b3RhbEl0ZW1zVW5rbm93blRleHQub3ZlcnJpZGUodmFsdWVXaXRoRGVmYXVsdHMuVE9UQUxfSVRFTVNfVU5LTk9XTik7XG5cdFx0dGhpcy5wYWdlVGV4dC5vdmVycmlkZSh2YWx1ZVdpdGhEZWZhdWx0cy5QQUdFKTtcblx0XHR0aGlzLm9mTGFzdFBhZ2VzVGV4dC5vdmVycmlkZSh2YWx1ZVdpdGhEZWZhdWx0cy5PRl9MQVNUX1BBR0VTKTtcblx0XHR0aGlzLm9mTGFzdFBhZ2VUZXh0Lm92ZXJyaWRlKHZhbHVlV2l0aERlZmF1bHRzLk9GX0xBU1RfUEFHRSk7XG5cdH1cblxuXHQvKipcblx0ICogT3B0aW9ucyBmb3IgaXRlbXMgcGVyIHBhZ2Ugc2VsZWN0XG5cdCAqXG5cdCAqIEEgZGVmYXVsdCBhcnJheSBvZiBvcHRpb25zIHdpbGwgYmUgZGVmaW5lZDogWzEwLCAyMCwgMzAsIDQwLCA1MF1cblx0ICovXG5cdEBJbnB1dCgpIGl0ZW1zUGVyUGFnZU9wdGlvbnM6IG51bWJlcltdID0gWzEwLCAyMCwgMzAsIDQwLCA1MF07XG5cblx0LyoqXG5cdCAqIEVtaXRzIHRoZSBuZXcgcGFnZSBudW1iZXIuXG5cdCAqXG5cdCAqIFlvdSBzaG91bGQgdGllIGludG8gdGhpcyBhbmQgdXBkYXRlIGBtb2RlbC5jdXJyZW50UGFnZWAgb25jZSB0aGUgZnJlc2hcblx0ICogZGF0YSBpcyBmaW5hbGx5IGxvYWRlZC5cblx0ICovXG5cdEBPdXRwdXQoKSBzZWxlY3RQYWdlID0gbmV3IEV2ZW50RW1pdHRlcjxudW1iZXI+KCk7XG5cblx0Z2V0IGl0ZW1zUGVyUGFnZSgpIHtcblx0XHRyZXR1cm4gdGhpcy5tb2RlbC5wYWdlTGVuZ3RoO1xuXHR9XG5cdHNldCBpdGVtc1BlclBhZ2UodmFsdWUpIHtcblx0XHR0aGlzLm1vZGVsLnBhZ2VMZW5ndGggPSBOdW1iZXIodmFsdWUpO1xuXHRcdHRoaXMuY3VycmVudFBhZ2UgPSAxOyAvLyByZXNldCBwYWdlXG5cdH1cblxuXHRnZXQgY3VycmVudFBhZ2UoKSB7XG5cdFx0cmV0dXJuIHRoaXMubW9kZWwuY3VycmVudFBhZ2U7XG5cdH1cblx0c2V0IGN1cnJlbnRQYWdlKHZhbHVlKSB7XG5cdFx0dmFsdWUgPSBOdW1iZXIodmFsdWUpO1xuXHRcdC8vIGVtaXRzIHRoZSB2YWx1ZSB0byBhbGxvdyB0aGUgdXNlciB0byB1cGRhdGUgY3VycmVudCBwYWdlXG5cdFx0Ly8gaW4gdGhlIG1vZGVsIG9uY2UgdGhlIHBhZ2UgaXMgbG9hZGVkXG5cdFx0dGhpcy5zZWxlY3RQYWdlLmVtaXQodmFsdWUpO1xuXHR9XG5cblx0Z2V0IHRvdGFsRGF0YUxlbmd0aCgpIHtcblx0XHRyZXR1cm4gdGhpcy5tb2RlbC50b3RhbERhdGFMZW5ndGg7XG5cdH1cblx0LyoqXG5cdCAqIFRoZSBsYXN0IHBhZ2UgbnVtYmVyIHRvIGRpc3BsYXkgaW4gdGhlIHBhZ2luYXRpb24gdmlldy5cblx0ICovXG5cdGdldCBsYXN0UGFnZSgpOiBudW1iZXIge1xuXHRcdGNvbnN0IGxhc3QgPSBNYXRoLmNlaWwodGhpcy50b3RhbERhdGFMZW5ndGggLyB0aGlzLml0ZW1zUGVyUGFnZSk7XG5cdFx0cmV0dXJuIGxhc3QgPiAwID8gbGFzdCA6IDE7XG5cdH1cblxuXHRnZXQgc3RhcnRJdGVtSW5kZXgoKSB7XG5cdFx0cmV0dXJuIHRoaXMuZW5kSXRlbUluZGV4ID4gMCA/ICh0aGlzLmN1cnJlbnRQYWdlIC0gMSkgKiB0aGlzLml0ZW1zUGVyUGFnZSArIDEgOiAwO1xuXHR9XG5cblx0Z2V0IGVuZEl0ZW1JbmRleCgpIHtcblx0XHRjb25zdCBwcm9qZWN0ZWRFbmRJdGVtSW5kZXggPSB0aGlzLmN1cnJlbnRQYWdlICogdGhpcy5pdGVtc1BlclBhZ2U7XG5cblx0XHRyZXR1cm4gcHJvamVjdGVkRW5kSXRlbUluZGV4IDwgdGhpcy50b3RhbERhdGFMZW5ndGggPyBwcm9qZWN0ZWRFbmRJdGVtSW5kZXggOiB0aGlzLnRvdGFsRGF0YUxlbmd0aDtcblx0fVxuXG5cdC8qKlxuXHQgKiBUaGUgcHJldmlvdXMgcGFnZSBudW1iZXIgdG8gbmF2aWdhdGUgdG8sIGZyb20gdGhlIGN1cnJlbnQgcGFnZS5cblx0ICovXG5cdGdldCBwcmV2aW91c1BhZ2UoKTogbnVtYmVyIHtcblx0XHRyZXR1cm4gdGhpcy5jdXJyZW50UGFnZSA8PSAxID8gMSA6IHRoaXMuY3VycmVudFBhZ2UgLSAxO1xuXHR9XG5cblx0LyoqXG5cdCAqIFRoZSBuZXh0IHBhZ2UgbnVtYmVyIHRvIG5hdmlnYXRlIHRvLCBmcm9tIHRoZSBjdXJyZW50IHBhZ2UuXG5cdCAqL1xuXHRnZXQgbmV4dFBhZ2UoKTogbnVtYmVyIHtcblx0XHRjb25zdCBsYXN0UGFnZSA9IHRoaXMubGFzdFBhZ2U7XG5cdFx0cmV0dXJuIHRoaXMuY3VycmVudFBhZ2UgPj0gbGFzdFBhZ2UgPyBsYXN0UGFnZSA6IHRoaXMuY3VycmVudFBhZ2UgKyAxO1xuXHR9XG5cblx0Z2V0IHBhZ2VPcHRpb25zKCkge1xuXHRcdGlmICh0aGlzLnRvdGFsRGF0YUxlbmd0aCAmJiB0aGlzLl9wYWdlT3B0aW9ucy5sZW5ndGggIT09IHRoaXMudG90YWxEYXRhTGVuZ3RoKSB7XG5cdFx0XHR0aGlzLl9wYWdlT3B0aW9ucyA9IEFycmF5KE1hdGguY2VpbCh0aGlzLnRvdGFsRGF0YUxlbmd0aCAvIHRoaXMuaXRlbXNQZXJQYWdlKSk7XG5cdFx0fVxuXHRcdHJldHVybiB0aGlzLl9wYWdlT3B0aW9ucztcblx0fVxuXG5cdGl0ZW1zUGVyUGFnZVNlbGVjdElkID0gYHBhZ2luYXRpb24tc2VsZWN0LWl0ZW1zLXBlci1wYWdlLSR7UGFnaW5hdGlvbi5wYWdpbmF0aW9uQ291bnRlcn1gO1xuXHRjdXJyZW50UGFnZVNlbGVjdElkID0gYHBhZ2luYXRpb24tc2VsZWN0LWN1cnJlbnQtcGFnZS0ke1BhZ2luYXRpb24ucGFnaW5hdGlvbkNvdW50ZXJ9YDtcblxuXHRpdGVtc1BlclBhZ2VUZXh0ID0gdGhpcy5pMThuLmdldE92ZXJyaWRhYmxlKFwiUEFHSU5BVElPTi5JVEVNU19QRVJfUEFHRVwiKTtcblx0b3B0aW9uc0xpc3RUZXh0ID0gdGhpcy5pMThuLmdldE92ZXJyaWRhYmxlKFwiUEFHSU5BVElPTi5PUEVOX0xJU1RfT0ZfT1BUSU9OU1wiKTtcblx0YmFja3dhcmRUZXh0ID0gdGhpcy5pMThuLmdldE92ZXJyaWRhYmxlKFwiUEFHSU5BVElPTi5CQUNLV0FSRFwiKTtcblx0Zm9yd2FyZFRleHQgPSB0aGlzLmkxOG4uZ2V0T3ZlcnJpZGFibGUoXCJQQUdJTkFUSU9OLkZPUldBUkRcIik7XG5cdHRvdGFsSXRlbXNUZXh0ID0gdGhpcy5pMThuLmdldE92ZXJyaWRhYmxlKFwiUEFHSU5BVElPTi5UT1RBTF9JVEVNU1wiKTtcblx0dG90YWxJdGVtVGV4dCA9IHRoaXMuaTE4bi5nZXRPdmVycmlkYWJsZShcIlBBR0lOQVRJT04uVE9UQUxfSVRFTVwiKTtcblx0dG90YWxJdGVtc1Vua25vd25UZXh0ID0gdGhpcy5pMThuLmdldE92ZXJyaWRhYmxlKFwiUEFHSU5BVElPTi5UT1RBTF9JVEVNU19VTktOT1dOXCIpO1xuXHRwYWdlVGV4dCA9IHRoaXMuaTE4bi5nZXRPdmVycmlkYWJsZShcIlBBR0lOQVRJT04uUEFHRVwiKTtcblx0b2ZMYXN0UGFnZXNUZXh0ID0gdGhpcy5pMThuLmdldE92ZXJyaWRhYmxlKFwiUEFHSU5BVElPTi5PRl9MQVNUX1BBR0VTXCIpO1xuXHRvZkxhc3RQYWdlVGV4dCA9IHRoaXMuaTE4bi5nZXRPdmVycmlkYWJsZShcIlBBR0lOQVRJT04uT0ZfTEFTVF9QQUdFXCIpO1xuXG5cdHByb3RlY3RlZCBfcGFnZU9wdGlvbnMgPSBbXTtcblxuXHRjb25zdHJ1Y3Rvcihwcm90ZWN0ZWQgaTE4bjogSTE4biwgcHJvdGVjdGVkIGV4cGVyaW1lbnRhbDogRXhwZXJpbWVudGFsU2VydmljZSkge1xuXHRcdFBhZ2luYXRpb24ucGFnaW5hdGlvbkNvdW50ZXIrKztcblx0fVxufVxuIl19