@visa/nova-angular
Version:
Visa Product Design System Nova Angular library
204 lines • 36 kB
JavaScript
/**
* © 2025 Visa
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
**/
/* eslint-disable no-mixed-spaces-and-tabs */
import { computed, signal } from '@angular/core';
/**
* Generates an array from number to from + length
* @param {number} from
* @param {number} length
* @returns {number[]}
*/
export const generateArray = (from, length) => Array.from({ length }, (_, i) => i + from);
const defaultOptions = {
blockMaxLength: 3,
compact: false,
defaultSelected: 1,
defaultTotalPages: 1,
delimiter: -1,
maxPageNumber: null,
startPage: 1
};
/**
* A signals based approach to handling and controlling pagination components. It is very customizable, re-usable, and even allows you to bring your own signal for selected page.
* @docs {@link https://design.visa.com/angular/components/pagination | See docs}
*/
export class PaginationControl {
constructor(options) {
this.totalPages = signal(0);
/// DERIVED STATE:
/** Can paginate or just show all pages */
this.canPaginate = computed(() => this.totalPages() > Math.max(this.options.endBlockMaxLength, this.options.startBlockMaxLength) + 2 && // 1 for end or start number + 1 for single separator show while in start/end blocks
this.totalPages() > this.options.middleBlockMaxLength + 4 // 2 for start and end numbers + 2 for separators shown while in middle block
);
/** Pages to show at the end */
this.endBlock = computed(() => this.isInEndBlock()
? generateArray(this.lastPage() - this.options.endBlockMaxLength + 1, this.options.endBlockMaxLength)
: [this.lastPage()]);
/** Ideal last page without maxPageNumber interfering */
this.idealLastPage = computed(() => this.totalPages() + this.options.startPage - 1);
/** Is first element selected */
this.isFirstPage = computed(() => this.selectedPage() === this.options.startPage);
/** Selected page is in end block */
this.isInEndBlock = computed(() => this.selectedPage() > this.lastPage() - this.options.endBlockMaxLength);
/** Selected page is in middle block */
this.isInMiddleBlock = computed(() => !this.isInStartBlock() && !this.isInEndBlock());
/** Selected page is in start block */
this.isInStartBlock = computed(() => this.selectedPage() < this.options.startPage + this.options.startBlockMaxLength);
/** Is last element selected */
this.isLastPage = computed(() => this.selectedPage() === this.lastPage());
/** Last page */
this.lastPage = computed(() => this.options.maxPageNumber === null
? this.idealLastPage()
: Math.min(this.options.maxPageNumber, this.idealLastPage()));
/** Pages to show in the middle */
this.middleBlock = computed(() => {
if (!this.isInMiddleBlock())
return [];
const middleBlockPadding = Math.floor(this.options.middleBlockMaxLength / 2);
if (this.selectedPage() - middleBlockPadding <= this.options.startPage)
return generateArray(this.selectedPage() - (this.selectedPage() - this.options.startPage) + 1, this.options.middleBlockMaxLength);
if (this.selectedPage() + middleBlockPadding >= this.lastPage())
return generateArray(this.selectedPage() + (this.lastPage() - this.selectedPage()) - this.options.middleBlockMaxLength, this.options.middleBlockMaxLength);
return generateArray(this.selectedPage() - middleBlockPadding, this.options.middleBlockMaxLength);
});
/** Array of pages arrays to loop over */
this.pages = computed(() => {
if (this.options.compact)
return this.compactPages;
return this.canPaginate()
? [this.startBlock(), this.middleBlock(), this.endBlock()]
.map((block) => (block.length ? [...block, this.options.delimiter] : []))
.flat()
.slice(0, -1)
: generateArray(this.options.startPage, this.lastPage() - this.options.startPage + 1);
});
/** Pages to show at the start */
this.startBlock = computed(() => this.isInStartBlock()
? generateArray(this.options.startPage, this.options.startBlockMaxLength)
: [this.options.startPage]);
/** Helper to calculate total pages */
this.getTotalPages = PaginationControl.getTotalPages;
const blockMaxLength = options?.blockMaxLength ?? defaultOptions.blockMaxLength;
// If we have a blockMaxLength, we should set it for all block max lengths, then we override it with all the options provided by the user
this.options = {
...defaultOptions,
endBlockMaxLength: blockMaxLength,
middleBlockMaxLength: blockMaxLength,
startBlockMaxLength: blockMaxLength,
...options
};
this.totalPages.set(this.options.defaultTotalPages);
const defaultStartPage = Math.min(Math.max(this.options.defaultSelected, this.options.startPage), this.options.defaultTotalPages);
this.selectedPage = this.options.selectedPage ?? signal(defaultStartPage);
this.selectedPage.set(defaultStartPage);
}
/// UTILITIES:
/** Getter for selectedPage, we shouldn't directly manipulate the `selectedPage` signal, use `goToPage` to do this safely */
get currentPage() {
return this.selectedPage();
}
get compactPages() {
const { blockMaxLength } = this.options;
// Show all pages if we have less than blockMaxLength
if (blockMaxLength > this.totalPages())
return generateArray(this.options.startPage, this.lastPage() - this.options.startPage + 1);
// Show chunk of blockMaxLength pages
const padding = Math.floor(blockMaxLength / 2);
if (this.selectedPage() - padding <= this.options.startPage)
return generateArray(this.options.startPage, blockMaxLength);
if (this.selectedPage() + padding >= this.lastPage())
return generateArray(this.lastPage() - blockMaxLength + 1, blockMaxLength);
return generateArray(this.selectedPage() - padding, blockMaxLength);
}
/**
* Calculates which range of items that is currently visible from pagination
* @param {number} items - how many items we have
* @param {number} itemsPerPage - how many items there are, per page
* @returns to from object with calculated values
*/
getToFrom(items, itemsPerPage) {
return PaginationControl.getToFrom(items, itemsPerPage, this.selectedPage(), this.options.startPage);
}
/** On first page event */
goToFirstPage() {
this.goToPage(this.options.startPage);
}
/** On last page event */
goToLastPage() {
this.goToPage(this.lastPage());
}
/** On next page event */
goToNextPage() {
this.goToPage(this.selectedPage() + 1);
}
/** On page change event */
goToPage(pageNumber) {
if (Number.isNaN(+pageNumber))
throw new Error("Can't go to page, invalid number");
if (pageNumber > this.lastPage())
this.selectedPage.set(this.lastPage());
else if (pageNumber < this.options.startPage)
this.selectedPage.set(this.options.startPage);
else
this.selectedPage.set(pageNumber);
}
/** On previous page event */
goToPreviousPage() {
this.goToPage(this.selectedPage() - 1);
}
/** Returns if page is current page */
isCurrentPage(page) {
return page === this.selectedPage();
}
/**
* In the context where total pages is calculated using items per page (much like tables use) we can use this utility to easily adjust the pagination control automatically.
* NOTE: by default this resets the pagination to the first page when called.
*/
resetPageCount(totalItems, itemsPerPage, autoResetToFirstPage = true) {
const totalPages = this.getTotalPages(totalItems, itemsPerPage);
this.totalPages.set(totalPages);
if (autoResetToFirstPage)
this.goToFirstPage();
}
/// STATIC UTILITIES:
/**
* Calculates which range of items that is currently visible from pagination
* @param {number} items - how many items we have
* @param {number} itemsPerPage - how many items there are, per page
* @param {number} currentPage - which page is visible
* @param {number} startPage - which page we're starting from, defaults to page 1 (optional)
* @returns to from object with calculated values
*/
static { this.getToFrom = (items, itemsPerPage, currentPage, startPage = 1) => {
if (itemsPerPage < 1 || items < 1)
return { 0: 0, 1: 0, from: 0, to: 0 };
const normalizedPageNumber = currentPage - startPage + 1;
const from = Math.max((normalizedPageNumber - 1) * itemsPerPage + 1, 0);
const to = Math.max(from + itemsPerPage - 1 > items ? items : from + itemsPerPage - 1, 0);
return { 0: from, 1: to, from, to };
}; }
/**
* Calculates how many pages there are
* @param {number} items - how many items we have
* @param {number} itemsPerPage - how many items there are, per page
* @returns {number} how many pages there are in total
*/
static getTotalPages(items, itemsPerPage) {
return Math.ceil(items / itemsPerPage);
}
}
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicGFnaW5hdGlvbi5jb250cm9sLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vLi4vLi4vbGlicy9ub3ZhLWxpYi9zcmMvbGliL3BhZ2luYXRpb24tY29udHJvbC9wYWdpbmF0aW9uLmNvbnRyb2wudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUE7Ozs7Ozs7Ozs7Ozs7OztJQWVJO0FBQ0osNkNBQTZDO0FBQzdDLE9BQU8sRUFBRSxRQUFRLEVBQVUsTUFBTSxFQUFrQixNQUFNLGVBQWUsQ0FBQztBQUV6RTs7Ozs7R0FLRztBQUNILE1BQU0sQ0FBQyxNQUFNLGFBQWEsR0FBRyxDQUFDLElBQVksRUFBRSxNQUFjLEVBQVksRUFBRSxDQUFDLEtBQUssQ0FBQyxJQUFJLENBQUMsRUFBRSxNQUFNLEVBQUUsRUFBRSxDQUFDLENBQUMsRUFBRSxDQUFDLEVBQUUsRUFBRSxDQUFDLENBQUMsR0FBRyxJQUFJLENBQUMsQ0FBQztBQTJCcEgsTUFBTSxjQUFjLEdBQUc7SUFDckIsY0FBYyxFQUFFLENBQUM7SUFDakIsT0FBTyxFQUFFLEtBQUs7SUFDZCxlQUFlLEVBQUUsQ0FBQztJQUNsQixpQkFBaUIsRUFBRSxDQUFDO0lBQ3BCLFNBQVMsRUFBRSxDQUFDLENBQUM7SUFDYixhQUFhLEVBQUUsSUFBSTtJQUNuQixTQUFTLEVBQUUsQ0FBQztDQUMrQixDQUFDO0FBRTlDOzs7R0FHRztBQUNILE1BQU0sT0FBTyxpQkFBaUI7SUFDNUIsWUFBWSxPQUEyQztRQXlCdkMsZUFBVSxHQUEyQixNQUFNLENBQVMsQ0FBQyxDQUFDLENBQUM7UUFFdkUsa0JBQWtCO1FBRWxCLDBDQUEwQztRQUN6QixnQkFBVyxHQUFvQixRQUFRLENBQ3RELEdBQUcsRUFBRSxDQUNILElBQUksQ0FBQyxVQUFVLEVBQUUsR0FBRyxJQUFJLENBQUMsR0FBRyxDQUFDLElBQUksQ0FBQyxPQUFPLENBQUMsaUJBQWlCLEVBQUUsSUFBSSxDQUFDLE9BQU8sQ0FBQyxtQkFBbUIs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QUFFLElBQUksRUFBRSxDQUFDLEVBQUUsRUFBRSxFQUFFLElBQUksRUFBRSxFQUFFLEVBQUUsQ0FBQztJQUN0QyxDQUFDLEFBTnNCLENBTXJCO0lBRUY7Ozs7O09BS0c7SUFDSSxNQUFNLENBQUMsYUFBYSxDQUFDLEtBQWEsRUFBRSxZQUFvQjtRQUM3RCxPQUFPLElBQUksQ0FBQyxJQUFJLENBQUMsS0FBSyxHQUFHLFlBQVksQ0FBQyxDQUFDO0lBQ3pDLENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyIvKipcbiAqICAgICAgICAgICAgICDCqSAyMDI1IFZpc2FcbiAqXG4gKiBMaWNlbnNlZCB1bmRlciB0aGUgQXBhY2hlIExpY2Vuc2UsIFZlcnNpb24gMi4wICh0aGUgXCJMaWNlbnNlXCIpO1xuICogeW91IG1heSBub3QgdXNlIHRoaXMgZmlsZSBleGNlcHQgaW4gY29tcGxpYW5jZSB3aXRoIHRoZSBMaWNlbnNlLlxuICogWW91IG1heSBvYnRhaW4gYSBjb3B5IG9mIHRoZSBMaWNlbnNlIGF0XG4gKlxuICogICAgICAgICBodHRwOi8vd3d3LmFwYWNoZS5vcmcvbGljZW5zZXMvTElDRU5TRS0yLjBcbiAqXG4gKiBVbmxlc3MgcmVxdWlyZWQgYnkgYXBwbGljYWJsZSBsYXcgb3IgYWdyZWVkIHRvIGluIHdyaXRpbmcsIHNvZnR3YXJlXG4gKiBkaXN0cmlidXRlZCB1bmRlciB0aGUgTGljZW5zZSBpcyBkaXN0cmlidXRlZCBvbiBhbiBcIkFTIElTXCIgQkFTSVMsXG4gKiBXSVRIT1VUIFdBUlJBTlRJRVMgT1IgQ09ORElUSU9OUyBPRiBBTlkgS0lORCwgZWl0aGVyIGV4cHJlc3Mgb3IgaW1wbGllZC5cbiAqIFNlZSB0aGUgTGljZW5zZSBmb3IgdGhlIHNwZWNpZmljIGxhbmd1YWdlIGdvdmVybmluZyBwZXJtaXNzaW9ucyBhbmRcbiAqIGxpbWl0YXRpb25zIHVuZGVyIHRoZSBMaWNlbnNlLlxuICpcbiAqKi9cbi8qIGVzbGludC1kaXNhYmxlIG5vLW1peGVkLXNwYWNlcy1hbmQtdGFicyAqL1xuaW1wb3J0IHsgY29tcHV0ZWQsIFNpZ25hbCwgc2lnbmFsLCBXcml0YWJsZVNpZ25hbCB9IGZyb20gJ0Bhbmd1bGFyL2NvcmUnO1xuXG4vKipcbiAqIEdlbmVyYXRlcyBhbiBhcnJheSBmcm9tIG51bWJlciB0byBmcm9tICsgbGVuZ3RoXG4gKiBAcGFyYW0ge251bWJlcn0gZnJvbVxuICogQHBhcmFtIHtudW1iZXJ9IGxlbmd0aFxuICogQHJldHVybnMge251bWJlcltdfVxuICovXG5leHBvcnQgY29uc3QgZ2VuZXJhdGVBcnJheSA9IChmcm9tOiBudW1iZXIsIGxlbmd0aDogbnVtYmVyKTogbnVtYmVyW10gPT4gQXJyYXkuZnJvbSh7IGxlbmd0aCB9LCAoXywgaSkgPT4gaSArIGZyb20pO1xuXG5leHBvcnQgdHlwZSBQYWdpbmF0aW9uQ29udHJvbE9wdGlvbnMgPSB7XG4gIC8qKiBNYXggYmxvY2sgbGVuZ3RoIGZvciBhbGwgYmxvY2tzLCB0aGlzIGdldHMgb3ZlcndyaXR0ZW4gYnkgYHN0YXJ0QmxvY2tNYXhMZW5ndGhgLCBgbWlkZGxlQmxvY2tNYXhMZW5ndGhgLCBgZW5kQmxvY2tNYXhMZW5ndGhgICovXG4gIGJsb2NrTWF4TGVuZ3RoOiBudW1iZXI7XG4gIC8qKiBGb3JjZXMgcGFnZXMgbm90IHRvIHBhZ2luYXRlICovXG4gIGNvbXBhY3Q6IGJvb2xlYW47XG4gIC8qKiBEZWZhdWx0IHNlbGVjdGVkIHBhZ2UgKi9cbiAgZGVmYXVsdFNlbGVjdGVkOiBudW1iZXI7XG4gIC8qKiBEZWZhdWx0IHRvdGFsIGFtb3VudCBvZiBwYWdlICovXG4gIGRlZmF1bHRUb3RhbFBhZ2VzOiBudW1iZXI7XG4gIC8qKiBXaGF0IHRvIHNlcGFyYXRlIHRoZSBwYWdpbmF0aW9uIGFycmF5IHVwIHdpdGgsIHVzdWFsbHkgdGhpcyBkZWxpbWl0ZXIgd2lsbCBiZSByZXBsYWNlZCB3aXRoIGljb24gb3IgZWxsaXBzZXMgd2hlbiBzaG93biBpbiB0aGUgVUkgKi9cbiAgZGVsaW1pdGVyOiBudW1iZXIgfCBzdHJpbmc7XG4gIC8qKiBNYXhpbXVtIGxlbmd0aCBvZiBwYWdlcyB0byBzaG93IG9uIHRoZSBlbmQgcGFnaW5hdGlvbiBibG9jaywgb3ZlcndyaXRlcyBgYmxvY2tNYXhMZW5ndGhgIGZvciBlbmQgYmxvY2sgKi9cbiAgZW5kQmxvY2tNYXhMZW5ndGg6IG51bWJlcjtcbiAgLyoqIE1heGltdW0gcGFnZSBudW1iZXIgdG8gYmUgc2hvd24sIChkZWZhdWx0IG51bGwgZm9yIG5vIG1heGltdW0pICovXG4gIG1heFBhZ2VOdW1iZXI6IG51bWJlciB8IG51bGw7XG4gIC8qKiBNYXhpbXVtIGxlbmd0aCBvZiBwYWdlcyB0byBzaG93IG9uIHRoZSBtaWRkbGUgcGFnaW5hdGlvbiBibG9jaywgb3ZlcndyaXRlcyBgYmxvY2tNYXhMZW5ndGhgIGZvciBtaWRkbGUgYmxvY2sgKi9cbiAgbWlkZGxlQmxvY2tNYXhMZW5ndGg6IG51bWJlcjtcbiAgLyoqIFNpZ25hbCB0byBiZSB1c2VkIGZvciBzZWxlY3RlZCBwYWdlLCBvdGhlcndpc2UgY29udHJvbCB3aWxsIGNyZWF0ZSBvbmUgKi9cbiAgc2VsZWN0ZWRQYWdlPzogV3JpdGFibGVTaWduYWw8bnVtYmVyPiB8IG51bGw7XG4gIC8qKiBNYXhpbXVtIGxlbmd0aCBvZiBwYWdlcyB0byBzaG93IG9uIHRoZSBzdGFydCBwYWdpbmF0aW9uIGJsb2NrLCBvdmVyd3JpdGVzIGBibG9ja01heExlbmd0aGAgZm9yIHN0YXJ0IGJsb2NrICovXG4gIHN0YXJ0QmxvY2tNYXhMZW5ndGg6IG51bWJlcjtcbiAgLyoqIFN0YXJ0IGZyb20gdGhpcyBwYWdlICovXG4gIHN0YXJ0UGFnZTogbnVtYmVyO1xufTtcblxuY29uc3QgZGVmYXVsdE9wdGlvbnMgPSB7XG4gIGJsb2NrTWF4TGVuZ3RoOiAzLFxuICBjb21wYWN0OiBmYWxzZSxcbiAgZGVmYXVsdFNlbGVjdGVkOiAxLFxuICBkZWZhdWx0VG90YWxQYWdlczogMSxcbiAgZGVsaW1pdGVyOiAtMSxcbiAgbWF4UGFnZU51bWJlcjogbnVsbCxcbiAgc3RhcnRQYWdlOiAxXG59IHNhdGlzZmllcyBQYXJ0aWFsPFBhZ2luYXRpb25Db250cm9sT3B0aW9ucz47XG5cbi8qKlxuICogQSBzaWduYWxzIGJhc2VkIGFwcHJvYWNoIHRvIGhhbmRsaW5nIGFuZCBjb250cm9sbGluZyBwYWdpbmF0aW9uIGNvbXBvbmVudHMuIEl0IGlzIHZlcnkgY3VzdG9taXphYmxlLCByZS11c2FibGUsIGFuZCBldmVuIGFsbG93cyB5b3UgdG8gYnJpbmcgeW91ciBvd24gc2lnbmFsIGZvciBzZWxlY3RlZCBwYWdlLlxuICogQGRvY3Mge0BsaW5rIGh0dHBzOi8vZGVzaWduLnZpc2EuY29tL2FuZ3VsYXIvY29tcG9uZW50cy9wYWdpbmF0aW9uIHwgU2VlIGRvY3N9XG4gKi9cbmV4cG9ydCBjbGFzcyBQYWdpbmF0aW9uQ29udHJvbCB7XG4gIGNvbnN0cnVjdG9yKG9wdGlvbnM/OiBQYXJ0aWFsPFBhZ2luYXRpb25Db250cm9sT3B0aW9ucz4pIHtcbiAgICBjb25zdCBibG9ja01heExlbmd0aCA9IG9wdGlvbnM/LmJsb2NrTWF4TGVuZ3RoID8/IGRlZmF1bHRPcHRpb25zLmJsb2NrTWF4TGVuZ3RoO1xuICAgIC8vIElmIHdlIGhhdmUgYSBibG9ja01heExlbmd0aCwgd2Ugc2hvdWxkIHNldCBpdCBmb3IgYWxsIGJsb2NrIG1heCBsZW5ndGhzLCB0aGVuIHdlIG92ZXJyaWRlIGl0IHdpdGggYWxsIHRoZSBvcHRpb25zIHByb3ZpZGVkIGJ5IHRoZSB1c2VyXG4gICAgdGhpcy5vcHRpb25zID0ge1xuICAgICAgLi4uZGVmYXVsdE9wdGlvbnMsXG4gICAgICBlbmRCbG9ja01heExlbmd0aDogYmxvY2tNYXhMZW5ndGgsXG4gICAgICBtaWRkbGVCbG9ja01heExlbmd0aDogYmxvY2tNYXhMZW5ndGgsXG4gICAgICBzdGFydEJsb2NrTWF4TGVuZ3RoOiBibG9ja01heExlbmd0aCxcbiAgICAgIC4uLm9wdGlvbnNcbiAgICB9IGFzIFBhZ2luYXRpb25Db250cm9sT3B0aW9ucztcbiAgICB0aGlzLnRvdGFsUGFnZXMuc2V0KHRoaXMub3B0aW9ucy5kZWZhdWx0VG90YWxQYWdlcyk7XG4gICAgY29uc3QgZGVmYXVsdFN0YXJ0UGFnZSA9IE1hdGgubWluKFxuICAgICAgTWF0aC5tYXgodGhpcy5vcHRpb25zLmRlZmF1bHRTZWxlY3RlZCwgdGhpcy5vcHRpb25zLnN0YXJ0UGFnZSksXG4gICAgICB0aGlzLm9wdGlvbnMuZGVmYXVsdFRvdGFsUGFnZXNcbiAgICApO1xuICAgIHRoaXMuc2VsZWN0ZWRQYWdlID0gdGhpcy5vcHRpb25zLnNlbGVjdGVkUGFnZSA/PyBzaWduYWwoZGVmYXVsdFN0YXJ0UGFnZSk7XG4gICAgdGhpcy5zZWxlY3RlZFBhZ2Uuc2V0KGRlZmF1bHRTdGFydFBhZ2UpO1xuICB9XG5cbiAgLy8vIFNUQVRFOlxuXG4gIHByaXZhdGUgcmVhZG9ubHkgb3B0aW9uczogUGFnaW5hdGlvbkNvbnRyb2xPcHRpb25zO1xuXG4gIHByaXZhdGUgcmVhZG9ubHkgc2VsZWN0ZWRQYWdlOiBXcml0YWJsZVNpZ25hbDxudW1iZXI+O1xuXG4gIHB1YmxpYyByZWFkb25seSB0b3RhbFBhZ2VzOiBXcml0YWJsZVNpZ25hbDxudW1iZXI+ID0gc2lnbmFsPG51bWJlcj4oMCk7XG5cbiAgLy8vIERFUklWRUQgU1RBVEU6XG5cbiAgLyoqIENhbiBwYWdpbmF0ZSBvciBqdXN0IHNob3cgYWxsIHBhZ2VzICovXG4gIHByaXZhdGUgcmVhZG9ubHkgY2FuUGFnaW5hdGU6IFNpZ25hbDxib29sZWFuPiA9IGNvbXB1dGVkKFxuICAgICgpID0+XG4gICAgICB0aGlzLnRvdGFsUGFnZXMoKSA+IE1hdGgubWF4KHRoaXMub3B0aW9ucy5lbmRCbG9ja01heExlbmd0aCwgdGhpcy5vcHRpb25zLnN0YXJ0QmxvY2tNYXhMZW5ndGgpICsgMiAmJiAvLyAxIGZvciBlbmQgb3Igc3RhcnQgbnVtYmVyICsgMSBmb3Igc2luZ2xlIHNlcGFyYXRvciBzaG93IHdoaWxlIGluIHN0YXJ0L2VuZCBibG9ja3NcbiAgICAgIHRoaXMudG90YWxQYWdlcygpID4gdGhpcy5vcHRpb25zLm1pZGRsZUJsb2NrTWF4TGVuZ3RoICsgNCAvLyAyIGZvciBzdGFydCBhbmQgZW5kIG51bWJlcnMgKyAyIGZvciBzZXBhcmF0b3JzIHNob3duIHdoaWxlIGluIG1pZGRsZSBibG9ja1xuICApO1xuXG4gIC8qKiBQYWdlcyB0byBzaG93IGF0IHRoZSBlbmQgKi9cbiAgcHJpdmF0ZSByZWFkb25seSBlbmRCbG9jazogU2lnbmFsPG51bWJlcltdPiA9IGNvbXB1dGVkKCgpID0+XG4gICAgdGhpcy5pc0luRW5kQmxvY2soKVxuICAgICAgPyBnZW5lcmF0ZUFycmF5KHRoaXMubGFzdFBhZ2UoKSAtIHRoaXMub3B0aW9ucy5lbmRCbG9ja01heExlbmd0aCArIDEsIHRoaXMub3B0aW9ucy5lbmRCbG9ja01heExlbmd0aClcbiAgICAgIDogW3RoaXMubGFzdFBhZ2UoKV1cbiAgKTtcblxuICAvKiogSWRlYWwgbGFzdCBwYWdlIHdpdGhvdXQgbWF4UGFnZU51bWJlciBpbnRlcmZlcmluZyAqL1xuICBwcml2YXRlIHJlYWRvbmx5IGlkZWFsTGFzdFBhZ2U6IFNpZ25hbDxudW1iZXI+ID0gY29tcHV0ZWQoKCkgPT4gdGhpcy50b3RhbFBhZ2VzKCkgKyB0aGlzLm9wdGlvbnMuc3RhcnRQYWdlIC0gMSk7XG5cbiAgLyoqIElzIGZpcnN0IGVsZW1lbnQgc2VsZWN0ZWQgKi9cbiAgcHVibGljIHJlYWRvbmx5IGlzRmlyc3RQYWdlOiBTaWduYWw8Ym9vbGVhbj4gPSBjb21wdXRlZCgoKSA9PiB0aGlzLnNlbGVjdGVkUGFnZSgpID09PSB0aGlzLm9wdGlvbnMuc3RhcnRQYWdlKTtcblxuICAvKiogU2VsZWN0ZWQgcGFnZSBpcyBpbiBlbmQgYmxvY2sgKi9cbiAgcHJpdmF0ZSByZWFkb25seSBpc0luRW5kQmxvY2s6IFNpZ25hbDxib29sZWFuPiA9IGNvbXB1dGVkKFxuICAgICgpID0+IHRoaXMuc2VsZWN0ZWRQYWdlKCkgPiB0aGlzLmxhc3RQYWdlKCkgLSB0aGlzLm9wdGlvbnMuZW5kQmxvY2tNYXhMZW5ndGhcbiAgKTtcblxuICAvKiogU2VsZWN0ZWQgcGFnZSBpcyBpbiBtaWRkbGUgYmxvY2sgKi9cbiAgcHJpdmF0ZSByZWFkb25seSBpc0luTWlkZGxlQmxvY2s6IFNpZ25hbDxib29sZWFuPiA9IGNvbXB1dGVkKCgpID0+ICF0aGlzLmlzSW5TdGFydEJsb2NrKCkgJiYgIXRoaXMuaXNJbkVuZEJsb2NrKCkpO1xuXG4gIC8qKiBTZWxlY3RlZCBwYWdlIGlzIGluIHN0YXJ0IGJsb2NrICovXG4gIHByaXZhdGUgcmVhZG9ubHkgaXNJblN0YXJ0QmxvY2s6IFNpZ25hbDxib29sZWFuPiA9IGNvbXB1dGVkKFxuICAgICgpID0+IHRoaXMuc2VsZWN0ZWRQYWdlKCkgPCB0aGlzLm9wdGlvbnMuc3RhcnRQYWdlICsgdGhpcy5vcHRpb25zLnN0YXJ0QmxvY2tNYXhMZW5ndGhcbiAgKTtcblxuICAvKiogSXMgbGFzdCBlbGVtZW50IHNlbGVjdGVkICovXG4gIHB1YmxpYyByZWFkb25seSBpc0xhc3RQYWdlOiBTaWduYWw8Ym9vbGVhbj4gPSBjb21wdXRlZCgoKSA9PiB0aGlzLnNlbGVjdGVkUGFnZSgpID09PSB0aGlzLmxhc3RQYWdlKCkpO1xuXG4gIC8qKiBMYXN0IHBhZ2UgKi9cbiAgcHJpdmF0ZSByZWFkb25seSBsYXN0UGFnZTogU2lnbmFsPG51bWJlcj4gPSBjb21wdXRlZCgoKSA9PlxuICAgIHRoaXMub3B0aW9ucy5tYXhQYWdlTnVtYmVyID09PSBudWxsXG4gICAgICA/IHRoaXMuaWRlYWxMYXN0UGFnZSgpXG4gICAgICA6IE1hdGgubWluKHRoaXMub3B0aW9ucy5tYXhQYWdlTnVtYmVyLCB0aGlzLmlkZWFsTGFzdFBhZ2UoKSlcbiAgKTtcblxuICAvKiogUGFnZXMgdG8gc2hvdyBpbiB0aGUgbWlkZGxlICovXG4gIHByaXZhdGUgcmVhZG9ubHkgbWlkZGxlQmxvY2s6IFNpZ25hbDxudW1iZXJbXT4gPSBjb21wdXRlZCgoKSA9PiB7XG4gICAgaWYgKCF0aGlzLmlzSW5NaWRkbGVCbG9jaygpKSByZXR1cm4gW107XG4gICAgY29uc3QgbWlkZGxlQmxvY2tQYWRkaW5nID0gTWF0aC5mbG9vcih0aGlzLm9wdGlvbnMubWlkZGxlQmxvY2tNYXhMZW5ndGggLyAyKTtcbiAgICBpZiAodGhpcy5zZWxlY3RlZFBhZ2UoKSAtIG1pZGRsZUJsb2NrUGFkZGluZyA8PSB0aGlzLm9wdGlvbnMuc3RhcnRQYWdlKVxuICAgICAgcmV0dXJuIGdlbmVyYXRlQXJyYXkoXG4gICAgICAgIHRoaXMuc2VsZWN0ZWRQYWdlKCkgLSAodGhpcy5zZWxlY3RlZFBhZ2UoKSAtIHRoaXMub3B0aW9ucy5zdGFydFBhZ2UpICsgMSxcbiAgICAgICAgdGhpcy5vcHRpb25zLm1pZGRsZUJsb2NrTWF4TGVuZ3RoXG4gICAgICApO1xuICAgIGlmICh0aGlzLnNlbGVjdGVkUGFnZSgpICsgbWlkZGxlQmxvY2tQYWRkaW5nID49IHRoaXMubGFzdFBhZ2UoKSlcbiAgICAgIHJldHVybiBnZW5lcmF0ZUFycmF5KFxuICAgICAgICB0aGlzLnNlbGVjdGVkUGFnZSgpICsgKHRoaXMubGFzdFBhZ2UoKSAtIHRoaXMuc2VsZWN0ZWRQYWdlKCkpIC0gdGhpcy5vcHRpb25zLm1pZGRsZUJsb2NrTWF4TGVuZ3RoLFxuICAgICAgICB0aGlzLm9wdGlvbnMubWlkZGxlQmxvY2tNYXhMZW5ndGhcbiAgICAgICk7XG4gICAgcmV0dXJuIGdlbmVyYXRlQXJyYXkodGhpcy5zZWxlY3RlZFBhZ2UoKSAtIG1pZGRsZUJsb2NrUGFkZGluZywgdGhpcy5vcHRpb25zLm1pZGRsZUJsb2NrTWF4TGVuZ3RoKTtcbiAgfSk7XG5cbiAgLyoqIEFycmF5IG9mIHBhZ2VzIGFycmF5cyB0byBsb29wIG92ZXIgKi9cbiAgcHVibGljIHJlYWRvbmx5IHBhZ2VzOiBTaWduYWw8KHN0cmluZyB8IG51bWJlcilbXT4gPSBjb21wdXRlZCgoKSA9PiB7XG4gICAgaWYgKHRoaXMub3B0aW9ucy5jb21wYWN0KSByZXR1cm4gdGhpcy5jb21wYWN0UGFnZXM7XG4gICAgcmV0dXJuIHRoaXMuY2FuUGFnaW5hdGUoKVxuICAgICAgPyBbdGhpcy5zdGFydEJsb2NrKCksIHRoaXMubWlkZGxlQmxvY2soKSwgdGhpcy5lbmRCbG9jaygpXVxuICAgICAgICAgIC5tYXAoKGJsb2NrKSA9PiAoYmxvY2subGVuZ3RoID8gWy4uLmJsb2NrLCB0aGlzLm9wdGlvbnMuZGVsaW1pdGVyXSA6IFtdKSlcbiAgICAgICAgICAuZmxhdCgpXG4gICAgICAgICAgLnNsaWNlKDAsIC0xKVxuICAgICAgOiBnZW5lcmF0ZUFycmF5KHRoaXMub3B0aW9ucy5zdGFydFBhZ2UsIHRoaXMubGFzdFBhZ2UoKSAtIHRoaXMub3B0aW9ucy5zdGFydFBhZ2UgKyAxKTtcbiAgfSk7XG5cbiAgLyoqIFBhZ2VzIHRvIHNob3cgYXQgdGhlIHN0YXJ0ICovXG4gIHByaXZhdGUgcmVhZG9ubHkgc3RhcnRCbG9jazogU2lnbmFsPG51bWJlcltdPiA9IGNvbXB1dGVkKCgpID0+XG4gICAgdGhpcy5pc0luU3RhcnRCbG9jaygpXG4gICAgICA/IGdlbmVyYXRlQXJyYXkodGhpcy5vcHRpb25zLnN0YXJ0UGFnZSwgdGhpcy5vcHRpb25zLnN0YXJ0QmxvY2tNYXhMZW5ndGgpXG4gICAgICA6IFt0aGlzLm9wdGlvbnMuc3RhcnRQYWdlXVxuICApO1xuXG4gIC8vLyBVVElMSVRJRVM6XG5cbiAgLyoqIEdldHRlciBmb3Igc2VsZWN0ZWRQYWdlLCB3ZSBzaG91bGRuJ3QgZGlyZWN0bHkgbWFuaXB1bGF0ZSB0aGUgYHNlbGVjdGVkUGFnZWAgc2lnbmFsLCB1c2UgYGdvVG9QYWdlYCB0byBkbyB0aGlzIHNhZmVseSAqL1xuICBwdWJsaWMgZ2V0IGN1cnJlbnRQYWdlKCk6IG51bWJlciB7XG4gICAgcmV0dXJuIHRoaXMuc2VsZWN0ZWRQYWdlKCk7XG4gIH1cblxuICBwcml2YXRlIGdldCBjb21wYWN0UGFnZXMoKTogbnVtYmVyW10ge1xuICAgIGNvbnN0IHsgYmxvY2tNYXhMZW5ndGggfSA9IHRoaXMub3B0aW9ucztcblxuICAgIC8vIFNob3cgYWxsIHBhZ2VzIGlmIHdlIGhhdmUgbGVzcyB0aGFuIGJsb2NrTWF4TGVuZ3RoXG4gICAgaWYgKGJsb2NrTWF4TGVuZ3RoID4gdGhpcy50b3RhbFBhZ2VzKCkpXG4gICAgICByZXR1cm4gZ2VuZXJhdGVBcnJheSh0aGlzLm9wdGlvbnMuc3RhcnRQYWdlLCB0aGlzLmxhc3RQYWdlKCkgLSB0aGlzLm9wdGlvbnMuc3RhcnRQYWdlICsgMSk7XG5cbiAgICAvLyBTaG93IGNodW5rIG9mIGJsb2NrTWF4TGVuZ3RoIHBhZ2VzXG4gICAgY29uc3QgcGFkZGluZyA9IE1hdGguZmxvb3IoYmxvY2tNYXhMZW5ndGggLyAyKTtcbiAgICBpZiAodGhpcy5zZWxlY3RlZFBhZ2UoKSAtIHBhZGRpbmcgPD0gdGhpcy5vcHRpb25zLnN0YXJ0UGFnZSlcbiAgICAgIHJldHVybiBnZW5lcmF0ZUFycmF5KHRoaXMub3B0aW9ucy5zdGFydFBhZ2UsIGJsb2NrTWF4TGVuZ3RoKTtcbiAgICBpZiAodGhpcy5zZWxlY3RlZFBhZ2UoKSArIHBhZGRpbmcgPj0gdGhpcy5sYXN0UGFnZSgpKVxuICAgICAgcmV0dXJuIGdlbmVyYXRlQXJyYXkodGhpcy5sYXN0UGFnZSgpIC0gYmxvY2tNYXhMZW5ndGggKyAxLCBibG9ja01heExlbmd0aCk7XG4gICAgcmV0dXJuIGdlbmVyYXRlQXJyYXkodGhpcy5zZWxlY3RlZFBhZ2UoKSAtIHBhZGRpbmcsIGJsb2NrTWF4TGVuZ3RoKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBDYWxjdWxhdGVzIHdoaWNoIHJhbmdlIG9mIGl0ZW1zIHRoYXQgaXMgY3VycmVudGx5IHZpc2libGUgZnJvbSBwYWdpbmF0aW9uXG4gICAqIEBwYXJhbSB7bnVtYmVyfSBpdGVtcyAtIGhvdyBtYW55IGl0ZW1zIHdlIGhhdmVcbiAgICogQHBhcmFtIHtudW1iZXJ9IGl0ZW1zUGVyUGFnZSAtIGhvdyBtYW55IGl0ZW1zIHRoZXJlIGFyZSwgcGVyIHBhZ2VcbiAgICogQHJldHVybnMgdG8gZnJvbSBvYmplY3Qgd2l0aCBjYWxjdWxhdGVkIHZhbHVlc1xuICAgKi9cbiAgcHVibGljIGdldFRvRnJvbShpdGVtczogbnVtYmVyLCBpdGVtc1BlclBhZ2U6IG51bWJlcikge1xuICAgIHJldHVybiBQYWdpbmF0aW9uQ29udHJvbC5nZXRUb0Zyb20oaXRlbXMsIGl0ZW1zUGVyUGFnZSwgdGhpcy5zZWxlY3RlZFBhZ2UoKSwgdGhpcy5vcHRpb25zLnN0YXJ0UGFnZSk7XG4gIH1cblxuICAvKiogSGVscGVyIHRvIGNhbGN1bGF0ZSB0b3RhbCBwYWdlcyAqL1xuICBwdWJsaWMgZ2V0VG90YWxQYWdlcyA9IFBhZ2luYXRpb25Db250cm9sLmdldFRvdGFsUGFnZXM7XG5cbiAgLyoqIE9uIGZpcnN0IHBhZ2UgZXZlbnQgKi9cbiAgcHVibGljIGdvVG9GaXJzdFBhZ2UoKTogdm9pZCB7XG4gICAgdGhpcy5nb1RvUGFnZSh0aGlzLm9wdGlvbnMuc3RhcnRQYWdlKTtcbiAgfVxuXG4gIC8qKiBPbiBsYXN0IHBhZ2UgZXZlbnQgKi9cbiAgcHVibGljIGdvVG9MYXN0UGFnZSgpOiB2b2lkIHtcbiAgICB0aGlzLmdvVG9QYWdlKHRoaXMubGFzdFBhZ2UoKSk7XG4gIH1cblxuICAvKiogT24gbmV4dCBwYWdlIGV2ZW50ICovXG4gIHB1YmxpYyBnb1RvTmV4dFBhZ2UoKTogdm9pZCB7XG4gICAgdGhpcy5nb1RvUGFnZSh0aGlzLnNlbGVjdGVkUGFnZSgpICsgMSk7XG4gIH1cblxuICAvKiogT24gcGFnZSBjaGFuZ2UgZXZlbnQgKi9cbiAgcHVibGljIGdvVG9QYWdlKHBhZ2VOdW1iZXI6IG51bWJlciB8IHN0cmluZyk6IHZvaWQge1xuICAgIGlmIChOdW1iZXIuaXNOYU4oK3BhZ2VOdW1iZXIpKSB0aHJvdyBuZXcgRXJyb3IoXCJDYW4ndCBnbyB0byBwYWdlLCBpbnZhbGlkIG51bWJlclwiKTtcbiAgICBpZiAoKHBhZ2VOdW1iZXIgYXMgbnVtYmVyKSA+IHRoaXMubGFzdFBhZ2UoKSkgdGhpcy5zZWxlY3RlZFBhZ2Uuc2V0KHRoaXMubGFzdFBhZ2UoKSk7XG4gICAgZWxzZSBpZiAoKHBhZ2VOdW1iZXIgYXMgbnVtYmVyKSA8IHRoaXMub3B0aW9ucy5zdGFydFBhZ2UpIHRoaXMuc2VsZWN0ZWRQYWdlLnNldCh0aGlzLm9wdGlvbnMuc3RhcnRQYWdlKTtcbiAgICBlbHNlIHRoaXMuc2VsZWN0ZWRQYWdlLnNldChwYWdlTnVtYmVyIGFzIG51bWJlcik7XG4gIH1cblxuICAvKiogT24gcHJldmlvdXMgcGFnZSBldmVudCAqL1xuICBwdWJsaWMgZ29Ub1ByZXZpb3VzUGFnZSgpOiB2b2lkIHtcbiAgICB0aGlzLmdvVG9QYWdlKHRoaXMuc2VsZWN0ZWRQYWdlKCkgLSAxKTtcbiAgfVxuXG4gIC8qKiBSZXR1cm5zIGlmIHBhZ2UgaXMgY3VycmVudCBwYWdlICovXG4gIHB1YmxpYyBpc0N1cnJlbnRQYWdlKHBhZ2U6IG51bWJlciB8IHN0cmluZyk6IGJvb2xlYW4ge1xuICAgIHJldHVybiBwYWdlID09PSB0aGlzLnNlbGVjdGVkUGFnZSgpO1xuICB9XG5cbiAgLyoqXG4gICAqIEluIHRoZSBjb250ZXh0IHdoZXJlIHRvdGFsIHBhZ2VzIGlzIGNhbGN1bGF0ZWQgdXNpbmcgaXRlbXMgcGVyIHBhZ2UgKG11Y2ggbGlrZSB0YWJsZXMgdXNlKSB3ZSBjYW4gdXNlIHRoaXMgdXRpbGl0eSB0byBlYXNpbHkgYWRqdXN0IHRoZSBwYWdpbmF0aW9uIGNvbnRyb2wgYXV0b21hdGljYWxseS5cbiAgICogTk9URTogYnkgZGVmYXVsdCB0aGlzIHJlc2V0cyB0aGUgcGFnaW5hdGlvbiB0byB0aGUgZmlyc3QgcGFnZSB3aGVuIGNhbGxlZC5cbiAgICovXG4gIHB1YmxpYyByZXNldFBhZ2VDb3VudCh0b3RhbEl0ZW1zOiBudW1iZXIsIGl0ZW1zUGVyUGFnZTogbnVtYmVyLCBhdXRvUmVzZXRUb0ZpcnN0UGFnZSA9IHRydWUpOiB2b2lkIHtcbiAgICBjb25zdCB0b3RhbFBhZ2VzID0gdGhpcy5nZXRUb3RhbFBhZ2VzKHRvdGFsSXRlbXMsIGl0ZW1zUGVyUGFnZSk7XG4gICAgdGhpcy50b3RhbFBhZ2VzLnNldCh0b3RhbFBhZ2VzKTtcbiAgICBpZiAoYXV0b1Jlc2V0VG9GaXJzdFBhZ2UpIHRoaXMuZ29Ub0ZpcnN0UGFnZSgpO1xuICB9XG5cbiAgLy8vIFNUQVRJQyBVVElMSVRJRVM6XG5cbiAgLyoqXG4gICAqIENhbGN1bGF0ZXMgd2hpY2ggcmFuZ2Ugb2YgaXRlbXMgdGhhdCBpcyBjdXJyZW50bHkgdmlzaWJsZSBmcm9tIHBhZ2luYXRpb25cbiAgICogQHBhcmFtIHtudW1iZXJ9IGl0ZW1zIC0gaG93IG1hbnkgaXRlbXMgd2UgaGF2ZVxuICAgKiBAcGFyYW0ge251bWJlcn0gaXRlbXNQZXJQYWdlIC0gaG93IG1hbnkgaXRlbXMgdGhlcmUgYXJlLCBwZXIgcGFnZVxuICAgKiBAcGFyYW0ge251bWJlcn0gY3VycmVudFBhZ2UgLSB3aGljaCBwYWdlIGlzIHZpc2libGVcbiAgICogQHBhcmFtIHtudW1iZXJ9IHN0YXJ0UGFnZSAtIHdoaWNoIHBhZ2Ugd2UncmUgc3RhcnRpbmcgZnJvbSwgZGVmYXVsdHMgdG8gcGFnZSAxIChvcHRpb25hbClcbiAgICogQHJldHVybnMgdG8gZnJvbSBvYmplY3Qgd2l0aCBjYWxjdWxhdGVkIHZhbHVlc1xuICAgKi9cbiAgcHVibGljIHN0YXRpYyBnZXRUb0Zyb20gPSAoaXRlbXM6IG51bWJlciwgaXRlbXNQZXJQYWdlOiBudW1iZXIsIGN1cnJlbnRQYWdlOiBudW1iZXIsIHN0YXJ0UGFnZTogbnVtYmVyID0gMSkgPT4ge1xuICAgIGlmIChpdGVtc1BlclBhZ2UgPCAxIHx8IGl0ZW1zIDwgMSkgcmV0dXJuIHsgMDogMCwgMTogMCwgZnJvbTogMCwgdG86IDAgfTtcbiAgICBjb25zdCBub3JtYWxpemVkUGFnZU51bWJlciA9IGN1cnJlbnRQYWdlIC0gc3RhcnRQYWdlICsgMTtcbiAgICBjb25zdCBmcm9tID0gTWF0aC5tYXgoKG5vcm1hbGl6ZWRQYWdlTnVtYmVyIC0gMSkgKiBpdGVtc1BlclBhZ2UgKyAxLCAwKTtcbiAgICBjb25zdCB0byA9IE1hdGgubWF4KGZyb20gKyBpdGVtc1BlclBhZ2UgLSAxID4gaXRlbXMgPyBpdGVtcyA6IGZyb20gKyBpdGVtc1BlclBhZ2UgLSAxLCAwKTtcbiAgICByZXR1cm4geyAwOiBmcm9tLCAxOiB0bywgZnJvbSwgdG8gfTtcbiAgfTtcblxuICAvKipcbiAgICogQ2FsY3VsYXRlcyBob3cgbWFueSBwYWdlcyB0aGVyZSBhcmVcbiAgICogQHBhcmFtIHtudW1iZXJ9IGl0ZW1zIC0gaG93IG1hbnkgaXRlbXMgd2UgaGF2ZVxuICAgKiBAcGFyYW0ge251bWJlcn0gaXRlbXNQZXJQYWdlIC0gaG93IG1hbnkgaXRlbXMgdGhlcmUgYXJlLCBwZXIgcGFnZVxuICAgKiBAcmV0dXJucyB7bnVtYmVyfSBob3cgbWFueSBwYWdlcyB0aGVyZSBhcmUgaW4gdG90YWxcbiAgICovXG4gIHB1YmxpYyBzdGF0aWMgZ2V0VG90YWxQYWdlcyhpdGVtczogbnVtYmVyLCBpdGVtc1BlclBhZ2U6IG51bWJlcik6IG51bWJlciB7XG4gICAgcmV0dXJuIE1hdGguY2VpbChpdGVtcyAvIGl0ZW1zUGVyUGFnZSk7XG4gIH1cbn1cbiJdfQ==