UNPKG

carbon-components-angular

Version:
504 lines (494 loc) 47.8 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; /** * Set `size` of pagination */ this.size = "md"; /** * 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", size: "size", 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, 'cds--pagination--sm': size === 'sm', 'cds--pagination--md': size === 'md', 'cds--pagination--lg': size === 'lg' }"> <!-- 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, 'cds--pagination--sm': size === 'sm', 'cds--pagination--md': size === 'md', 'cds--pagination--lg': size === 'lg' }"> <!-- 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 }], size: [{ 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,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicGFnaW5hdGlvbi5jb21wb25lbnQuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi9zcmMvcGFnaW5hdGlvbi9wYWdpbmF0aW9uLmNvbXBvbmVudC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFDQSxPQUFPLEVBQ04sU0FBUyxFQUNULEtBQUssRUFDTCxNQUFNLEVBQ04sWUFBWSxFQUNaLE1BQU0sZUFBZSxDQUFDO0FBSXZCLE9BQU8sRUFBRSxLQUFLLEVBQUUsTUFBTSxpQ0FBaUMsQ0FBQzs7Ozs7Ozs7QUFjeEQ7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7R0F5Qkc7QUFrSkgsTUFBTSxPQUFPLFVBQVU7SUF3S3RCLFlBQXNCLElBQVUsRUFBWSxZQUFpQztRQUF2RCxTQUFJLEdBQUosSUFBSSxDQUFNO1FBQVksaUJBQVksR0FBWixZQUFZLENBQXFCO1FBcks3RTs7V0FFRztRQUNNLGFBQVEsR0FBRyxLQUFLLENBQUM7UUFZMUI7O1dBRUc7UUFDTSxzQkFBaUIsR0FBRyxLQUFLLENBQUM7UUFDbkM7O1dBRUc7UUFDTSxTQUFJLEdBQXVCLElBQUksQ0FBQztRQUN6Qzs7V0FFRztRQUNNLGtCQUFhLEdBQUcsSUFBSSxDQUFDO1FBQzlCOztXQUVHO1FBQ00saUJBQVksR0FBRyxLQUFLLENBQUM7UUFDckIsd0JBQW1CLEdBQUcsSUFBSSxDQUFDO1FBRTNCLHFCQUFnQixHQUFHLEtBQUssQ0FBQztRQUN6QixvQkFBZSxHQUFHLEtBQUssQ0FBQztRQWlDakM7Ozs7V0FJRztRQUNNLHdCQUFtQixHQUFhLENBQUMsRUFBRSxFQUFFLEVBQUUsRUFBRSxFQUFFLEVBQUUsRUFBRSxFQUFFLEVBQUUsQ0FBQyxDQUFDO1FBRTlEOzs7OztXQUtHO1FBQ08sZUFBVSxHQUFHLElBQUksWUFBWSxFQUFVLENBQUM7UUFxRWxELHlCQUFvQixHQUFHLG9DQUFvQyxVQUFVLENBQUMsaUJBQWlCLEVBQUUsQ0FBQztRQUMxRix3QkFBbUIsR0FBRyxrQ0FBa0Ms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Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7O0VBNklUO2lCQUNEOzZIQU9TLFFBQVE7c0JBQWhCLEtBQUs7Z0JBSUcsS0FBSztzQkFBYixLQUFLO2dCQUlPLFFBQVE7c0JBQXBCLEtBQUs7Z0JBT0csaUJBQWlCO3NCQUF6QixLQUFLO2dCQUlHLElBQUk7c0JBQVosS0FBSztnQkFJRyxhQUFhO3NCQUFyQixLQUFLO2dCQUlHLFlBQVk7c0JBQXBCLEtBQUs7Z0JBQ0csbUJBQW1CO3NCQUEzQixLQUFLO2dCQUVHLGdCQUFnQjtzQkFBeEIsS0FBSztnQkFDRyxlQUFlO3NCQUF2QixLQUFLO2dCQW1CRixZQUFZO3NCQURmLEtBQUs7Z0JBb0JHLG1CQUFtQjtzQkFBM0IsS0FBSztnQkFRSSxVQUFVO3NCQUFuQixNQUFNIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgUGFnaW5hdGlvbk1vZGVsIH0gZnJvbSBcIi4vcGFnaW5hdGlvbi1tb2RlbC5jbGFzc1wiO1xuaW1wb3J0IHtcblx0Q29tcG9uZW50LFxuXHRJbnB1dCxcblx0T3V0cHV0LFxuXHRFdmVudEVtaXR0ZXJcbn0gZnJvbSBcIkBhbmd1bGFyL2NvcmVcIjtcblxuaW1wb3J0IHsgSTE4biwgT3ZlcnJpZGFibGUgfSBmcm9tIFwiY2FyYm9uLWNvbXBvbmVudHMtYW5ndWxhci9pMThuXCI7XG5pbXBvcnQgeyBFeHBlcmltZW50YWxTZXJ2aWNlIH0gZnJvbSBcImNhcmJvbi1jb21wb25lbnRzLWFuZ3VsYXIvZXhwZXJpbWVudGFsXCI7XG5pbXBvcnQgeyBtZXJnZSB9IGZyb20gXCJjYXJib24tY29tcG9uZW50cy1hbmd1bGFyL3V0aWxzXCI7XG5cbmV4cG9ydCBpbnRlcmZhY2UgUGFnaW5hdGlvblRyYW5zbGF0aW9ucyB7XG5cdElURU1TX1BFUl9QQUdFOiBzdHJpbmc7XG5cdE9QRU5fTElTVF9PRl9PUFRJT05TOiBzdHJpbmc7XG5cdEJBQ0tXQVJEOiBzdHJpbmc7XG5cdEZPUldBUkQ6IHN0cmluZztcblx0VE9UQUxfSVRFTVNfVU5LTk9XTjogc3RyaW5nO1xuXHRUT1RBTF9JVEVNUzogc3RyaW5nO1xuXHRUT1RBTF9JVEVNOiBzdHJpbmc7XG5cdE9GX0xBU1RfUEFHRVM6IHN0cmluZztcblx0T0ZfTEFTVF9QQUdFOiBzdHJpbmc7XG59XG5cbi8qKlxuICogVXNlIHBhZ2luYXRpb24gd2hlbiB5b3UgaGF2ZSBtdWx0aXBsZSBwYWdlcyBvZiBkYXRhIHRvIGhhbmRsZS4gR2V0IHN0YXJ0ZWQgd2l0aCBpbXBvcnRpbmcgdGhlIG1vZHVsZTpcbiAqXG4gKiBgYGB0eXBlc2NyaXB0XG4gKiBpbXBvcnQgeyBQYWdpbmF0aW9uTW9kdWxlIH0gZnJvbSAnY2FyYm9uLWNvbXBvbmVudHMtYW5ndWxhcic7XG4gKiBgYGBcbiAqXG4gKiBgYGBodG1sXG4gKlx0PGNkcy1wYWdpbmF0aW9uIFttb2RlbF09XCJtb2RlbFwiIChzZWxlY3RQYWdlKT1cInNlbGVjdFBhZ2UoJGV2ZW50KVwiPjwvY2RzLXBhZ2luYXRpb24+XG4gKiBgYGBcbiAqXG4gKiBJbiB5b3VyIGBzZWxlY3RQYWdlKClgIG1ldGhvZCBzZXQgdGhlIGBtb2RlbC5jdXJyZW50UGFnZWAgdG8gc2VsZWN0ZWQgcGFnZSwgX2FmdGVyX1xuICogeW91IGxvYWQgdGhlIHBhZ2UuXG4gKlxuICogYGBgdHlwZXNjcmlwdFxuICogc2VsZWN0UGFnZShwYWdlKSB7XG4gKiBcdC8vIC4uLiB5b3VyIGNvZGUgdG8gbG9hZCB0aGUgcGFnZSBnb2VzIGhlcmVcbiAqXG4gKiBcdHRoaXMubW9kZWwuY3VycmVudFBhZ2UgPSBwYWdlO1xuICpcbiAqIFx0Ly8gLi4uIGFueXRoaW5nIHlvdSB3YW50IHRvIGRvIGFmdGVyIHBhZ2Ugc2VsZWN0aW9uIGNoYW5nZXMgZ29lcyBoZXJlXG4gKiB9XG4gKiBgYGBcbiAqXG4gKiBbU2VlIGRlbW9dKC4uLy4uLz9wYXRoPS9zdG9yeS9jb21wb25lbnRzLXBhZ2luYXRpb24tLWJhc2ljKVxuICovXG5AQ29tcG9uZW50KHtcblx0c2VsZWN0b3I6IFwiY2RzLXBhZ2luYXRpb24sIGlibS1wYWdpbmF0aW9uXCIsXG5cdHRlbXBsYXRlOiBgXG5cdDxkaXZcblx0XHRjbGFzcz1cImNkcy0tcGFnaW5hdGlvblwiXG5cdFx0W25nQ2xhc3NdPVwie1xuXHRcdFx0J2Nkcy0tc2tlbGV0b24nOiBza2VsZXRvbixcblx0XHRcdCdjZHMtLXBhZ2luYXRpb24tLXNtJzogc2l6ZSA9PT0gJ3NtJyxcblx0XHRcdCdjZHMtLXBhZ2luYXRpb24tLW1kJzogc2l6ZSA9PT0gJ21kJyxcblx0XHRcdCdjZHMtLXBhZ2luYXRpb24tLWxnJzogc2l6ZSA9PT0gJ2xnJ1xuXHRcdH1cIj5cblx0XHQ8IS0tIGxlZnQgc2tlbGV0b24gZGl2IC0tPlxuXHRcdDxkaXYgKm5nSWY9XCJza2VsZXRvblwiIGNsYXNzPVwiY2RzLS1wYWdpbmF0aW9uX19sZWZ0XCI+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+XG5cdFx0XHRcdFx0PHN2ZyBjZHNJY29uPVwiY2FyZXQtLXJpZ2h0XCIgc2l6ZT1cIjE2XCIgY2xhc3M9XCJjZHMtLWJ0bl9faWNvblwiPjwvc3ZnPlxuXHRcdFx0XHQ8L2J1dHRvbj5cblx0XHRcdDwvZGl2PlxuXHRcdDwvZGl2PlxuXHQ8L2Rpdj5cblx0YFxufSlcbmV4cG9ydCBjbGFzcyBQYWdpbmF0aW9uIHtcblx0c3RhdGljIHBhZ2luYXRpb25Db3VudGVyID0gMDtcblxuXHQvKipcblx0ICogU2V0IHRvIGB0cnVlYCBmb3IgYSBsb2FkaW5nIHBhZ2luYXRpb24gY29tcG9uZW50LlxuXHQgKi9cblx0QElucHV0KCkgc2tlbGV0b24gPSBmYWxzZTtcblx0LyoqXG5cdCAqIGBQYWdpbmF0aW9uTW9kZWxgIHdpdGggdGhlIGluZm9ybWF0aW9uIGFib3V0IHBhZ2VzIHlvdSdyZSBjb250cm9sbGluZy5cblx0ICovXG5cdEBJbnB1dCgpIG1vZGVsOiBQYWdpbmF0aW9uTW9kZWw7XG5cdC8qKlxuIFx0ICogU2V0IHRvIGB0cnVlYCB0byBkaXNhYmxlIHRoZSBiYWNrd2FyZC9mb3J3YXJkIGJ1dHRvbnMuXG5cdCAqL1xuXHRASW5wdXQoKSBzZXQgZGlzYWJsZWQodmFsdWU6IGJvb2xlYW4pIHtcblx0XHR0aGlzLmJhY2t3YXJkRGlzYWJsZWQgPSB2YWx1ZTtcblx0XHR0aGlzLmZvcndhcmREaXNhYmxlZCA9IHZhbHVlO1xuXHR9XG5cdC8qKlxuXHQgKiBTZXQgdG8gYHRydWVgIHRvIGRpc2FibGUgdGhlIHNlbGVjdCBib3ggdGhhdCBjaGFuZ2VzIHRoZSBwYWdlLlxuXHQgKi9cblx0QElucHV0KCkgcGFnZUlucHV0RGlzYWJsZWQgPSBmYWxzZTtcblx0LyoqXG5cdCAqIFNldCBgc2l6ZWAgb2YgcGFnaW5hdGlvblxuXHQgKi9cblx0QElucHV0KCkgc2l6ZTogXCJzbVwiIHwgXCJtZFwiIHwgXCJsZ1wiID0gXCJtZFwiO1xuXHQvKipcblx0ICogQ29udHJvbHMgd2V0aGVyIG9yIG5vdCB0byBzaG93IHRoZSBwYWdlIHNlbGVjdHNcblx0ICovXG5cdEBJbnB1dCgpIHNob3dQYWdlSW5wdXQgPSB0cnVlO1xuXHQvKipcblx0ICogU2V0IHRvIGB0cnVlYCBpZiB0aGUgdG90YWwgbnVtYmVyIG9mIGl0ZW1zIGlzIHVua25vd24uXG5cdCAqL1xuXHRASW5wdXQoKSBwYWdlc1Vua25vd24gPSBmYWxzZTtcblx0QElucHV0KCkgcGFnZVNlbGVjdFRocmVzaG9sZCA9IDEwMDA7XG5cblx0QElucHV0KCkgYmFja3dhcmREaXNhYmxlZCA9IGZhbHNlO1xuXHRASW5wdXQoKSBmb3J3YXJkRGlzYWJsZWQgPSBmYWxzZTtcblxuXHQvKipcblx0ICogRXhwZWN0cyBhbiBvYmplY3QgdGhhdCBjb250YWlucyBzb21lIG9yIGFsbCBvZjpcblx0ICogYGBgXG5cdCAqIHtcblx0ICpcdFx0XCJJVEVNU19QRVJfUEFHRVwiOiBcIkl0ZW1zIHBlciBwYWdlOlwiLFxuXHQgKlx0XHRcIk9QRU5fTElTVF9PRl9PUFRJT05TXCI6IFwiT3BlbiBsaXN0IG9mIG9wdGlvbnNcIixcblx0ICpcdFx0XCJCQUNLV0FSRFwiOiBcIkJhY2t3YXJkXCIsXG5cdCAqXHRcdFwiRk9SV0FSRFwiOiBcIkZvcndhcmRcIixcblx0ICpcdFx0XCJUT1RBTF9JVEVNU19VTktOT1dOXCI6IFwie3tzdGFydH19LXt7ZW5kfX0gaXRlbXNcIixcblx0ICpcdFx0XCJUT1RBTF9JVEVNU1wiOiBcInt7c3RhcnR9fS17e2VuZH19IG9mIHt7dG90YWx9fSBpdGVtc1wiLFxuXHQgKlx0XHRcIlRPVEFMX0lURU1cIjogXCJ7e3N0YXJ0fX0te3tlbmR9fSBvZiB7e3RvdGFsfX0gaXRlbVwiLFxuXHQgKlx0XHRcIk9GX0xBU1RfUEFHRVNcIjogXCJvZiB7e2xhc3R9fSBwYWdlc1wiLFxuXHQgKlx0XHRcIk9GX0xBU1RfUEFHRVwiOiBcIm9mIHt7bGFzdH19IHBhZ2VcIlxuXHQgKiB9XG5cdCAqIGBgYFxuXHQgKi9cblx0QElucHV0KClcblx0c2V0IHRyYW5zbGF0aW9ucyAodmFsdWU6IFBhZ2luYXRpb25UcmFuc2xhdGlvbnMpIHtcblx0XHRjb25zdCB2YWx1ZVdpdGhEZWZhdWx0cyA9IG1lcmdlKHRoaXMuaTE4bi5nZXRNdWx0aXBsZShcIlBBR0lOQVRJT05cIiksIHZhbHVlKTtcblx0XHR0aGlzLml0ZW1zUGVyUGFnZVRleHQub3ZlcnJpZGUodmFsdWVXaXRoRGVmYXVsdHMuSVRFTVNfUEVSX1BBR0UpO1xuXHRcdHRoaXMub3B0aW9uc0xpc3RUZXh0Lm92ZXJyaWRlKHZhbHVlV2l0aERlZmF1bHRzLk9QRU5fTElTVF9PRl9PUFRJT05TKTtcblx0XHR0aGlzLmJhY2t3YXJkVGV4dC5vdmVycmlkZSh2YWx1ZVdpdGhEZWZhdWx0cy5CQUNLV0FSRCk7XG5cdFx0dGhpcy5mb3J3YXJkVGV4dC5vdmVycmlkZSh2YWx1ZVdpdGhEZWZhdWx0cy5GT1JXQVJEKTtcblx0XHR0aGlzLnRvdGFsSXRlbXNUZXh0Lm92ZXJyaWRlKHZhbHVlV2l0aERlZmF1bHRzLlRPVEFMX0lURU1TKTtcblx0XHR0aGlzLnRvdGFsSXRlbVRleHQub3ZlcnJpZGUodmFsdWVXaXRoRGVmYXVsdHMuVE9UQUxfSVRFTSk7XG5cdFx0dGhpcy50b3RhbEl0ZW1zVW5rbm93blRleHQub3ZlcnJpZGUodmFsdWVXaXRoRGVmYXVsdHMuVE9UQUxfSVRFTVNfVU5LTk9XTik7XG5cdFx0dGhpcy5wYWdlVGV4dC5vdmVycmlkZSh2YWx1ZVdpdGhEZWZhdWx0cy5QQUdFKTtcblx0XHR0aGlzLm9mTGFzdFBhZ2VzVGV4dC5vdmVycmlkZSh2YWx1ZVdpdGhEZWZhdWx0cy5PRl9MQVNUX1BBR0VTKTtcblx0XHR0aGlzLm9mTGFzdFBhZ2VUZXh0Lm92ZXJyaWRlKHZhbHVlV2l0aERlZmF1bHRzLk9GX0xBU1RfUEFHRSk7XG5cdH1cblxuXHQvKipcblx0ICogT3B0aW9ucyBmb3IgaXRlbXMgcGVyIHBhZ2Ugc2VsZWN0XG5cdCAqXG5cdCAqIEEgZGVmYXVsdCBhcnJheSBvZiBvcHRpb25zIHdpbGwgYmUgZGVmaW5lZDogWzEwLCAyMCwgMzAsIDQwLCA1MF1cblx0ICovXG5cdEBJbnB1dCgpIGl0ZW1zUGVyUGFnZU9wdGlvbnM6IG51bWJlcltdID0gWzEwLCAyMCwgMzAsIDQwLCA1MF07XG5cblx0LyoqXG5cdCAqIEVtaXRzIHRoZSBuZXcgcGFnZSBudW1iZXIuXG5cdCAqXG5cdCAqIFlvdSBzaG91bGQgdGllIGludG8gdGhpcyBhbmQgdXBkYXRlIGBtb2RlbC5jdXJyZW50UGFnZWAgb25jZSB0aGUgZnJlc2hcblx0ICogZGF0YSBpcyBmaW5hbGx5IGxvYWRlZC5cblx0ICovXG5cdEBPdXRwdXQoKSBzZWxlY3RQYWdlID0gbmV3IEV2ZW50RW1pdHRlcjxudW1iZXI+KCk7XG5cblx0Z2V0IGl0ZW1zUGVyUGFnZSgpIHtcblx0XHRyZXR1cm4gdGhpcy5tb2RlbC5wYWdlTGVuZ3RoO1xuXHR9XG5cdHNldCBpdGVtc1BlclBhZ2UodmFsdWUpIHtcblx0XHR0aGlzLm1vZGVsLnBhZ2VMZW5ndGggPSBOdW1iZXIodmFsdWUpO1xuXHRcdHRoaXMuY3VycmVudFBhZ2UgPSAxOyAvLyByZXNldCBwYWdlXG5cdH1cblxuXHRnZXQgY3VycmVudFBhZ2UoKSB7XG5cdFx0cmV0dXJuIHRoaXMubW9kZWwuY3VycmVudFBhZ2U7XG5cdH1cblx0c2V0IGN1cnJlbnRQYWdlKHZhbHVlKSB7XG5cdFx0dmFsdWUgPSBOdW1iZXIodmFsdWUpO1xuXHRcdC8vIGVtaXRzIHRoZSB2YWx1ZSB0byBhbGxvdyB0aGUgdXNlciB0byB1cGRhdGUgY3VycmVudCBwYWdlXG5cdFx0Ly8gaW4gdGhlIG1vZGVsIG9uY2UgdGhlIHBhZ2UgaXMgbG9hZGVkXG5cdFx0dGhpcy5zZWxlY3RQYWdlLmVtaXQodmFsdWUpO1xuXHR9XG5cblx0Z2V0IHRvdGFsRGF0YUxlbmd0aCgpIHtcblx0XHRyZXR1cm4gdGhpcy5tb2RlbC50b3RhbERhdGFMZW5ndGg7XG5cdH1cblx0LyoqXG5cdCAqIFRoZSBsYXN0IHBhZ2UgbnVtYmVyIHRvIGRpc3BsYXkgaW4gdGhlIHBhZ2luYXRpb24gdmlldy5cblx0ICovXG5cdGdldCBsYXN0UGFnZSgpOiBudW1iZXIge1xuXHRcdGNvbnN0IGxhc3QgPSBNYXRoLmNlaWwodGhpcy50b3RhbERhdGFMZW5ndGggLyB0aGlzLml0ZW1zUGVyUGFnZSk7XG5cdFx0cmV0dXJuIGxhc3QgPiAwID8gbGFzdCA6IDE7XG5cdH1cblxuXHRnZXQgc3RhcnRJdGVtSW5kZXgoKSB7XG5cdFx0cmV0dXJuIHRoaXMuZW5kSXRlbUluZGV4ID4gMCA/ICh0aGlzLmN1cnJlbnRQYWdlIC0gMSkgKiB0aGlzLml0ZW1zUGVyUGFnZSArIDEgOiAwO1xuXHR9XG5cblx0Z2V0IGVuZEl0ZW1JbmRleCgpIHtcblx0XHRjb25zdCBwcm9qZWN0ZWRFbmRJdGVtSW5kZXggPSB0aGlzLmN1cnJlbnRQYWdlICogdGhpcy5pdGVtc1BlclBhZ2U7XG5cblx0XHRyZXR1cm4gcHJvamVjdGVkRW5kSXRlbUluZGV4IDwgdGhpcy50b3RhbERhdGFMZW5ndGggPyBwcm9qZWN0ZWRFbmRJdGVtSW5kZXggOiB0aGlzLnRvdGFsRGF0YUxlbmd0aDtcblx0fVxuXG5cdC8qKlxuXHQgKiBUaGUgcHJldmlvdXMgcGFnZSBudW1iZXIgdG8gbmF2aWdhdGUgdG8sIGZyb20gdGhlIGN1cnJlbnQgcGFnZS5cblx0ICovXG5cdGdldCBwcmV2aW91c1BhZ2UoKTogbnVtYmVyIHtcblx0XHRyZXR1cm4gdGhpcy5jdXJyZW50UGFnZSA8PSAxID8gMSA6IHRoaXMuY3VycmVudFBhZ2UgLSAxO1xuXHR9XG5cblx0LyoqXG5cdCAqIFRoZSBuZXh0IHBhZ2UgbnVtYmVyIHRvIG5hdmlnYXRlIHRvLCBmcm9tIHRoZSBjdXJyZW50IHBhZ2UuXG5cdCAqL1xuXHRnZXQgbmV4dFBhZ2UoKTogbnVtYmVyIHtcblx0XHRjb25zdCBsYXN0UGFnZSA9IHRoaXMubGFzdFBhZ2U7XG5cdFx0cmV0dXJuIHRoaXMuY3VycmVudFBhZ2UgPj0gbGFzdFBhZ2UgPyBsYXN0UGFnZSA6IHRoaXMuY3VycmVudFBhZ2UgKyAxO1xuXHR9XG5cblx0Z2V0IHBhZ2VPcHRpb25zKCkge1xuXHRcdC8qKlxuXHRcdCAqIENhbGN1bGF0ZSBudW1iZXIgb2YgcGFnZXMgYmFzZWQgb24gdG90YWxEYXRhTGVuZ3RoIGFuZCBpdGVtc1BlclBhZ2UuXG5cdFx0ICogRXZlbiBpZiB0b3RhbERhdGFMZW5ndGggaXMgMCwgbnVtYmVyT2ZQYWdlcyBzaG91bGQgYmUgYWx3YXlzIGF0IGxlYXN0IDEuXG5cdFx0ICogTmV3IGFycmF5IHdpbGwgYmUgY29uc3RydWN0ZWQgb25seSBpZiBudW1iZXIgb2YgcGFnZXMgY2hhbmdlcy5cblx0XHQgKi9cblx0XHRjb25zdCBudW1iZXJPZlBhZ2VzID0gTWF0aC5tYXgoTWF0aC5jZWlsKHRoaXMudG90YWxEYXRhTGVuZ3RoIC8gdGhpcy5pdGVtc1BlclBhZ2UpLCAxKTtcblx0XHRpZiAodGhpcy5fcGFnZU9wdGlvbnMubGVuZ3RoICE9PSBudW1iZXJPZlBhZ2VzKSB7XG5cdFx0XHR0aGlzLl9wYWdlT3B0aW9ucyA9IEFycmF5KG51bWJlck9mUGFnZXMpO1xuXHRcdH1cblx0XHRyZXR1cm4gdGhpcy5fcGFnZU9wdGlvbnM7XG5cdH1cblxuXHRpdGVtc1BlclBhZ2VTZWxlY3RJZCA9IGBwYWdpbmF0aW9uLXNlbGVjdC1pdGVtcy1wZXItcGFnZS0ke1BhZ2luYXRpb24ucGFnaW5hdGlvbkNvdW50ZXJ9YDtcblx0Y3VycmVudFBhZ2VTZWxlY3RJZCA9IGBwYWdpbmF0aW9uLXNlbGVjdC1jdXJyZW50LXBhZ2UtJHtQYWdpbmF0aW9uLnBhZ2luYXRpb25Db3VudGVyfWA7XG5cblx0aXRlbXNQZXJQYWdlVGV4dCA9IHRoaXMuaTE4bi5nZXRPdmVycmlkYWJsZShcIlBBR0lOQVRJT04uSVRFTVNfUEVSX1BBR0VcIik7XG5cdG9wdGlvbnNMaXN0VGV4dCA9IHRoaXMuaTE4bi5nZXRPdmVycmlkYWJsZShcIlBBR0lOQVRJT04uT1BFTl9MSVNUX09GX09QVElPTlNcIik7XG5cdGJhY2t3YXJkVGV4dCA9IHRoaXMuaTE4bi5nZXRPdmVycmlkYWJsZShcIlBBR0lOQVRJT04uQkFDS1dBUkRcIik7XG5cdGZvcndhcmRUZXh0ID0gdGhpcy5pMThuLmdldE92ZXJyaWRhYmxlKFwiUEFHSU5BVElPTi5GT1JXQVJEXCIpO1xuXHR0b3RhbEl0ZW1zVGV4dCA9IHRoaXMuaTE4bi5nZXRPdmVycmlkYWJsZShcIlBBR0lOQVRJT04uVE9UQUxfSVRFTVNcIik7XG5cdHRvdGFsSXRlbVRleHQgPSB0aGlzLmkxOG4uZ2V0T3ZlcnJpZGFibGUoXCJQQUdJTkFUSU9OLlRPVEFMX0lURU1cIik7XG5cdHRvdGFsSXRlbXNVbmtub3duVGV4dCA9IHRoaXMuaTE4bi5nZXRPdmVycmlkYWJsZShcIlBBR0lOQVRJT04uVE9UQUxfSVRFTVNfVU5LTk9XTlwiKTtcblx0cGFnZVRleHQgPSB0aGlzLmkxOG4uZ2V0T3ZlcnJpZGFibGUoXCJQQUdJTkFUSU9OLlBBR0VcIik7XG5cdG9mTGFzdFBhZ2VzVGV4dCA9IHRoaXMuaTE4bi5nZXRPdmVycmlkYWJsZShcIlBBR0lOQVRJT04uT0ZfTEFTVF9QQUdFU1wiKTtcblx0b2ZMYXN0UGFnZVRleHQgPSB0aGlzLmkxOG4uZ2V0T3ZlcnJpZGFibGUoXCJQQUdJTkFUSU9OLk9GX0xBU1RfUEFHRVwiKTtcblxuXHRwcm90ZWN0ZWQgX3BhZ2VPcHRpb25zID0gW107XG5cblx0Y29uc3RydWN0b3IocHJvdGVjdGVkIGkxOG46IEkxOG4sIHByb3RlY3RlZCBleHBlcmltZW50YWw6IEV4cGVyaW1lbnRhbFNlcnZpY2UpIHtcblx0XHRQYWdpbmF0aW9uLnBhZ2luYXRpb25Db3VudGVyKys7XG5cdH1cbn1cbiJdfQ==