UNPKG

@visa/nova-angular

Version:

Visa Product Design System Nova Angular library

204 lines 36 kB
/** * Copyright (c) 2025 Visa, Inc. * * 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,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicGFnaW5hdGlvbi5jb250cm9sLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vLi4vLi4vbGlicy9ub3ZhLWxpYi9zcmMvbGliL3BhZ2luYXRpb24tY29udHJvbC9wYWdpbmF0aW9uLmNvbnRyb2wudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUE7Ozs7Ozs7Ozs7Ozs7OztJQWVJO0FBQ0osNkNBQTZDO0FBQzdDLE9BQU8sRUFBRSxRQUFRLEVBQVUsTUFBTSxFQUFrQixNQUFNLGVBQWUsQ0FBQztBQUV6RTs7Ozs7R0FLRztBQUNILE1BQU0sQ0FBQyxNQUFNLGFBQWEsR0FBRyxDQUFDLElBQVksRUFBRSxNQUFjLEVBQVksRUFBRSxDQUFDLEtBQUssQ0FBQyxJQUFJLENBQUMsRUFBRSxNQUFNLEVBQUUsRUFBRSxDQUFDLENBQUMsRUFBRSxDQUFDLEVBQUUsRUFBRSxDQUFDLENBQUMsR0FBRyxJQUFJLENBQUMsQ0FBQztBQTJCcEgsTUFBTSxjQUFjLEdBQUc7SUFDckIsY0FBYyxFQUFFLENBQUM7SUFDakIsT0FBTyxFQUFFLEtBQUs7SUFDZCxlQUFlLEVBQUUsQ0FBQztJQUNsQixpQkFBaUIsRUFBRSxDQUFDO0lBQ3BCLFNBQVMsRUFBRSxDQUFDLENBQUM7SUFDYixhQUFhLEVBQUUsSUFBSTtJQUNuQixTQUFTLEVBQUUsQ0FBQztDQUMrQixDQUFDO0FBRTlDOzs7R0FHRztBQUNILE1BQU0sT0FBTyxpQkFBaUI7SUFDNUIsWUFBWSxPQUEyQztRQXlCdkMsZUFBVSxHQUEyQixNQUFNLENBQVMsQ0FBQyxDQUFDLENBQUM7UUFFdkUsa0JBQWtCO1FBRWxCLDBDQUEwQztRQUN6QixnQkFBVyxHQUFvQixRQUFRLENBQ3RELEdBQUcsRUFBRSxDQUNILElBQUksQ0FBQyxVQUFVLEVBQUUsR0FBRyxJQUFJLENBQUMsR0FBRyxDQUFDLElBQUksQ0FBQyxPQUFPLENBQUMsaUJBQWlCLEVBQUUsSUFBSSxDQUFDLE9BQU8sQ0FBQyxtQkFBbUIsQ0FBQyxHQUFHLENBQUMsSUFBSSxvRkFBb0Y7WUFDMUwsSUFBSSxDQUFDLFVBQVUsRUFBRSxHQUFHLElBQUksQ0FBQyxPQUFPLENBQUMsb0JBQW9CLEdBQUcsQ0FBQyxDQUFDLDZFQUE2RTtTQUMxSSxDQUFDO1FBRUYsK0JBQStCO1FBQ2QsYUFBUSxHQUFxQixRQUFRLENBQUMsR0FBRyxFQUFFLENBQzFELElBQUksQ0FBQyxZQUFZLEVBQUU7WUFDakIsQ0FBQyxDQUFDLGFBQWEsQ0FBQyxJQUFJLENBQUMsUUFBUSxFQUFFLEdBQUcsSUFBSSxDQUFDLE9BQU8sQ0FBQyxpQkFBaUIsR0FBRyxDQUFDLEVBQUUsSUFBSSxDQUFDLE9BQU8sQ0FBQyxpQkFBaUIsQ0FBQztZQUNyRyxDQUFDLENBQUMsQ0FBQyxJQUFJLENBQUMsUUFBUSxFQUFFLENBQUMsQ0FDdEIsQ0FBQztRQUVGLHdEQUF3RDtRQUN2QyxrQkFBYSxHQUFtQixRQUFRLENBQUMsR0FBRyxFQUFFLENBQUMsSUFBSSxDQUFDLFVBQVUsRUFBRSxHQUFHLElBQUksQ0FBQyxPQUFPLENBQUMsU0FBUyxHQUFHLENBQUMsQ0FBQyxDQUFDO1FBRWhILGdDQUFnQztRQUNoQixnQkFBVyxHQUFvQixRQUFRLENBQUMsR0FBRyxFQUFFLENBQUMsSUFBSSxDQUFDLFlBQVksRUFBRSxLQUFLLElBQUksQ0FBQyxPQUFPLENBQUMsU0FBUyxDQUFDLENBQUM7UUFFOUcsb0NBQW9DO1FBQ25CLGlCQUFZLEdBQW9CLFFBQVEsQ0FDdkQsR0FBRyxFQUFFLENBQUMsSUFBSSxDQUFDLFlBQVksRUFBRSxHQUFHLElBQUksQ0FBQyxRQUFRLEVBQUUsR0FBRyxJQUFJLENBQUMsT0FBTyxDQUFDLGlCQUFpQixDQUM3RSxDQUFDO1FBRUYsdUNBQXVDO1FBQ3RCLG9CQUFlLEdBQW9CLFFBQVEsQ0FBQyxHQUFHLEVBQUUsQ0FBQyxDQUFDLElBQUksQ0FBQyxjQUFjLEVBQUUsSUFBSSxDQUFDLElBQUksQ0FBQyxZQUFZLEVBQUUsQ0FBQyxDQUFDO1FBRW5ILHNDQUFzQztRQUNyQixtQkFBYyxHQUFvQixRQUFRLENBQ3pELEdBQUcsRUFBRSxDQUFDLElBQUksQ0FBQyxZQUFZLEVBQUUsR0FBRyxJQUFJLENBQUMsT0FBTyxDQUFDLFNBQVMsR0FBRyxJQUFJLENBQUMsT0FBTyxDQUFDLG1CQUFtQixDQUN0RixDQUFDO1FBRUYsK0JBQStCO1FBQ2YsZUFBVSxHQUFvQixRQUFRLENBQUMsR0FBRyxFQUFFLENBQUMsSUFBSSxDQUFDLFlBQVksRUFBRSxLQUFLLElBQUksQ0FBQyxRQUFRLEVBQUUsQ0FBQyxDQUFDO1FBRXRHLGdCQUFnQjtRQUNDLGFBQVEsR0FBbUIsUUFBUSxDQUFDLEdBQUcsRUFBRSxDQUN4RCxJQUFJLENBQUMsT0FBTyxDQUFDLGFBQWEsS0FBSyxJQUFJO1lBQ2pDLENBQUMsQ0FBQyxJQUFJLENBQUMsYUFBYSxFQUFFO1lBQ3RCLENBQUMsQ0FBQyxJQUFJLENBQUMsR0FBRyxDQUFDLElBQUksQ0FBQyxPQUFPLENBQUMsYUFBYSxFQUFFLElBQUksQ0FBQyxhQUFhLEVBQUUsQ0FBQyxDQUMvRCxDQUFDO1FBRUYsa0NBQWtDO1FBQ2pCLGdCQUFXLEdBQXFCLFFBQVEsQ0FBQyxHQUFHLEVBQUU7WUFDN0QsSUFBSSxDQUFDLElBQUksQ0FBQyxlQUFlLEVBQUU7Z0JBQUUsT0FBTyxFQUFFLENBQUM7WUFDdkMsTUFBTSxrQkFBa0IsR0FBRyxJQUFJLENBQUMsS0FBSyxDQUFDLElBQUksQ0FBQyxPQUFPLENBQUMsb0JBQW9CLEdBQUcsQ0FBQyxDQUFDLENBQUM7WUFDN0UsSUFBSSxJQUFJLENBQUMsWUFBWSxFQUFFLEdBQUcsa0JBQWtCLElBQUksSUFBSSxDQUFDLE9BQU8sQ0FBQyxTQUFTO2dCQUNwRSxPQUFPLGFBQWEsQ0FDbEIsSUFBSSxDQUFDLFlBQVksRUFBRSxHQUFHLENBQUMsSUFBSSxDQUFDLFlBQVksRUFBRSxHQUFHLElBQUksQ0FBQyxPQUFPLENBQUMsU0FBUyxDQUFDLEdBQUcsQ0FBQyxFQUN4RSxJQUFJLENBQUMsT0FBTyxDQUFDLG9CQUFvQixDQUNsQyxDQUFDO1lBQ0osSUFBSSxJQUFJLENBQUMsWUFBWSxFQUFFLEdBQUcsa0JBQWtCLElBQUksSUFBSSxDQUFDLFFBQVEsRUFBRTtnQkFDN0QsT0FBTyxhQUFhLENBQ2xCLElBQUksQ0FBQyxZQUFZLEVBQUUsR0FBRyxDQUFDLElBQUksQ0FBQyxRQUFRLEVBQUUsR0FBRyxJQUFJLENBQUMsWUFBWSxFQUFFLENBQUMsR0FBRyxJQUFJLENBQUMsT0FBTyxDQUFDLG9CQUFvQixFQUNqRyxJQUFJLENBQUMsT0FBTyxDQUFDLG9CQUFvQixDQUNsQyxDQUFDO1lBQ0osT0FBTyxhQUFhLENBQUMsSUFBSSxDQUFDLFlBQVksRUFBRSxHQUFHLGtCQUFrQixFQUFFLElBQUksQ0FBQyxPQUFPLENBQUMsb0JBQW9CLENBQUMsQ0FBQztRQUNwRyxDQUFDLENBQUMsQ0FBQztRQUVILHlDQUF5QztRQUN6QixVQUFLLEdBQWdDLFFBQVEsQ0FBQyxHQUFHLEVBQUU7WUFDakUsSUFBSSxJQUFJLENBQUMsT0FBTyxDQUFDLE9BQU87Z0JBQUUsT0FBTyxJQUFJLENBQUMsWUFBWSxDQUFDO1lBQ25ELE9BQU8sSUFBSSxDQUFDLFdBQVcsRUFBRTtnQkFDdkIsQ0FBQyxDQUFDLENBQUMsSUFBSSxDQUFDLFVBQVUsRUFBRSxFQUFFLElBQUksQ0FBQyxXQUFXLEVBQUUsRUFBRSxJQUFJLENBQUMsUUFBUSxFQUFFLENBQUM7cUJBQ3JELEdBQUcsQ0FBQyxDQUFDLEtBQUssRUFBRSxFQUFFLENBQUMsQ0FBQyxLQUFLLENBQUMsTUFBTSxDQUFDLENBQUMsQ0FBQyxDQUFDLEdBQUcsS0FBSyxFQUFFLElBQUksQ0FBQyxPQUFPLENBQUMsU0FBUyxDQUFDLENBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxDQUFDO3FCQUN4RSxJQUFJLEVBQUU7cUJBQ04sS0FBSyxDQUFDLENBQUMsRUFBRSxDQUFDLENBQUMsQ0FBQztnQkFDakIsQ0FBQyxDQUFDLGFBQWEsQ0FBQyxJQUFJLENBQUMsT0FBTyxDQUFDLFNBQVMsRUFBRSxJQUFJLENBQUMsUUFBUSxFQUFFLEdBQUcsSUFBSSxDQUFDLE9BQU8sQ0FBQyxTQUFTLEdBQUcsQ0FBQyxDQUFDLENBQUM7UUFDMUYsQ0FBQyxDQUFDLENBQUM7UUFFSCxpQ0FBaUM7UUFDaEIsZUFBVSxHQUFxQixRQUFRLENBQUMsR0FBRyxFQUFFLENBQzVELElBQUksQ0FBQyxjQUFjLEVBQUU7WUFDbkIsQ0FBQyxDQUFDLGFBQWEsQ0FBQyxJQUFJLENBQUMsT0FBTyxDQUFDLFNBQVMsRUFBRSxJQUFJLENBQUMsT0FBTyxDQUFDLG1CQUFtQixDQUFDO1lBQ3pFLENBQUMsQ0FBQyxDQUFDLElBQUksQ0FBQyxPQUFPLENBQUMsU0FBUyxDQUFDLENBQzdCLENBQUM7UUFtQ0Ysc0NBQXNDO1FBQy9CLGtCQUFhLEdBQUcsaUJBQWlCLENBQUMsYUFBYSxDQUFDO1FBNUlyRCxNQUFNLGNBQWMsR0FBRyxPQUFPLEVBQUUsY0FBYyxJQUFJLGNBQWMsQ0FBQyxjQUFjLENBQUM7UUFDaEYseUlBQXlJO1FBQ3pJLElBQUksQ0FBQyxPQUFPLEdBQUc7WUFDYixHQUFHLGNBQWM7WUFDakIsaUJBQWlCLEVBQUUsY0FBYztZQUNqQyxvQkFBb0IsRUFBRSxjQUFjO1lBQ3BDLG1CQUFtQixFQUFFLGNBQWM7WUFDbkMsR0FBRyxPQUFPO1NBQ2lCLENBQUM7UUFDOUIsSUFBSSxDQUFDLFVBQVUsQ0FBQyxHQUFHLENBQUMsSUFBSSxDQUFDLE9BQU8sQ0FBQyxpQkFBaUIsQ0FBQyxDQUFDO1FBQ3BELE1BQU0sZ0JBQWdCLEdBQUcsSUFBSSxDQUFDLEdBQUcsQ0FDL0IsSUFBSSxDQUFDLEdBQUcsQ0FBQyxJQUFJLENBQUMsT0FBTyxDQUFDLGVBQWUsRUFBRSxJQUFJLENBQUMsT0FBTyxDQUFDLFNBQVMsQ0FBQyxFQUM5RCxJQUFJLENBQUMsT0FBTyxDQUFDLGlCQUFpQixDQUMvQixDQUFDO1FBQ0YsSUFBSSxDQUFDLFlBQVksR0FBRyxJQUFJLENBQUMsT0FBTyxDQUFDLFlBQVksSUFBSSxNQUFNLENBQUMsZ0JBQWdCLENBQUMsQ0FBQztRQUMxRSxJQUFJLENBQUMsWUFBWSxDQUFDLEdBQUcsQ0FBQyxnQkFBZ0IsQ0FBQyxDQUFDO0lBQzFDLENBQUM7SUEwRkQsY0FBYztJQUVkLDRIQUE0SDtJQUM1SCxJQUFXLFdBQVc7UUFDcEIsT0FBTyxJQUFJLENBQUMsWUFBWSxFQUFFLENBQUM7SUFDN0IsQ0FBQztJQUVELElBQVksWUFBWTtRQUN0QixNQUFNLEVBQUUsY0FBYyxFQUFFLEdBQUcsSUFBSSxDQUFDLE9BQU8sQ0FBQztRQUV4QyxxREFBcUQ7UUFDckQsSUFBSSxjQUFjLEdBQUcsSUFBSSxDQUFDLFVBQVUsRUFBRTtZQUNwQyxPQUFPLGFBQWEsQ0FBQyxJQUFJLENBQUMsT0FBTyxDQUFDLFNBQVMsRUFBRSxJQUFJLENBQUMsUUFBUSxFQUFFLEdBQUcsSUFBSSxDQUFDLE9BQU8sQ0FBQyxTQUFTLEdBQUcsQ0FBQyxDQUFDLENBQUM7UUFFN0YscUNBQXFDO1FBQ3JDLE1BQU0sT0FBTyxHQUFHLElBQUksQ0FBQyxLQUFLLENBQUMsY0FBYyxHQUFHLENBQUMsQ0FBQyxDQUFDO1FBQy9DLElBQUksSUFBSSxDQUFDLFlBQVksRUFBRSxHQUFHLE9BQU8sSUFBSSxJQUFJLENBQUMsT0FBTyxDQUFDLFNBQVM7WUFDekQsT0FBTyxhQUFhLENBQUMsSUFBSSxDQUFDLE9BQU8sQ0FBQyxTQUFTLEVBQUUsY0FBYyxDQUFDLENBQUM7UUFDL0QsSUFBSSxJQUFJLENBQUMsWUFBWSxFQUFFLEdBQUcsT0FBTyxJQUFJLElBQUksQ0FBQyxRQUFRLEVBQUU7WUFDbEQsT0FBTyxhQUFhLENBQUMsSUFBSSxDQUFDLFFBQVEsRUFBRSxHQUFHLGNBQWMsR0FBRyxDQUFDLEVBQUUsY0FBYyxDQUFDLENBQUM7UUFDN0UsT0FBTyxhQUFhLENBQUMsSUFBSSxDQUFDLFlBQVksRUFBRSxHQUFHLE9BQU8sRUFBRSxjQUFjLENBQUMsQ0FBQztJQUN0RSxDQUFDO0lBRUQ7Ozs7O09BS0c7SUFDSSxTQUFTLENBQUMsS0FBYSxFQUFFLFlBQW9CO1FBQ2xELE9BQU8saUJBQWlCLENBQUMsU0FBUyxDQUFDLEtBQUssRUFBRSxZQUFZLEVBQUUsSUFBSSxDQUFDLFlBQVksRUFBRSxFQUFFLElBQUksQ0FBQyxPQUFPLENBQUMsU0FBUyxDQUFDLENBQUM7SUFDdkcsQ0FBQztJQUtELDBCQUEwQjtJQUNuQixhQUFhO1FBQ2xCLElBQUksQ0FBQyxRQUFRLENBQUMsSUFBSSxDQUFDLE9BQU8sQ0FBQyxTQUFTLENBQUMsQ0FBQztJQUN4QyxDQUFDO0lBRUQseUJBQXlCO0lBQ2xCLFlBQVk7UUFDakIsSUFBSSxDQUFDLFFBQVEsQ0FBQyxJQUFJLENBQUMsUUFBUSxFQUFFLENBQUMsQ0FBQztJQUNqQyxDQUFDO0lBRUQseUJBQXlCO0lBQ2xCLFlBQVk7UUFDakIsSUFBSSxDQUFDLFFBQVEsQ0FBQyxJQUFJLENBQUMsWUFBWSxFQUFFLEdBQUcsQ0FBQyxDQUFDLENBQUM7SUFDekMsQ0FBQztJQUVELDJCQUEyQjtJQUNwQixRQUFRLENBQUMsVUFBMkI7UUFDekMsSUFBSSxNQUFNLENBQUMsS0FBSyxDQUFDLENBQUMsVUFBVSxDQUFDO1lBQUUsTUFBTSxJQUFJLEtBQUssQ0FBQyxrQ0FBa0MsQ0FBQyxDQUFDO1FBQ25GLElBQUssVUFBcUIsR0FBRyxJQUFJLENBQUMsUUFBUSxFQUFFO1lBQUUsSUFBSSxDQUFDLFlBQVksQ0FBQyxHQUFHLENBQUMsSUFBSSxDQUFDLFFBQVEsRUFBRSxDQUFDLENBQUM7YUFDaEYsSUFBSyxVQUFxQixHQUFHLElBQUksQ0FBQyxPQUFPLENBQUMsU0FBUztZQUFFLElBQUksQ0FBQyxZQUFZLENBQUMsR0FBRyxDQUFDLElBQUksQ0FBQyxPQUFPLENBQUMsU0FBUyxDQUFDLENBQUM7O1lBQ25HLElBQUksQ0FBQyxZQUFZLENBQUMsR0FBRyxDQUFDLFVBQW9CLENBQUMsQ0FBQztJQUNuRCxDQUFDO0lBRUQsNkJBQTZCO0lBQ3RCLGdCQUFnQjtRQUNyQixJQUFJLENBQUMsUUFBUSxDQUFDLElBQUksQ0FBQyxZQUFZLEVBQUUsR0FBRyxDQUFDLENBQUMsQ0FBQztJQUN6QyxDQUFDO0lBRUQsc0NBQXNDO0lBQy9CLGFBQWEsQ0FBQyxJQUFxQjtRQUN4QyxPQUFPLElBQUksS0FBSyxJQUFJLENBQUMsWUFBWSxFQUFFLENBQUM7SUFDdEMsQ0FBQztJQUVEOzs7T0FHRztJQUNJLGNBQWMsQ0FBQyxVQUFrQixFQUFFLFlBQW9CLEVBQUUsb0JBQW9CLEdBQUcsSUFBSTtRQUN6RixNQUFNLFVBQVUsR0FBRyxJQUFJLENBQUMsYUFBYSxDQUFDLFVBQVUsRUFBRSxZQUFZLENBQUMsQ0FBQztRQUNoRSxJQUFJLENBQUMsVUFBVSxDQUFDLEdBQUcsQ0FBQyxVQUFVLENBQUMsQ0FBQztRQUNoQyxJQUFJLG9CQUFvQjtZQUFFLElBQUksQ0FBQyxhQUFhLEVBQUUsQ0FBQztJQUNqRCxDQUFDO0lBRUQscUJBQXFCO0lBRXJCOzs7Ozs7O09BT0c7YUFDVyxjQUFTLEdBQUcsQ0FBQyxLQUFhLEVBQUUsWUFBb0IsRUFBRSxXQUFtQixFQUFFLFlBQW9CLENBQUMsRUFBRSxFQUFFO1FBQzVHLElBQUksWUFBWSxHQUFHLENBQUMsSUFBSSxLQUFLLEdBQUcsQ0FBQztZQUFFLE9BQU8sRUFBRSxDQUFDLEVBQUUsQ0FBQyxFQUFFLENBQUMsRUFBRSxDQUFDLEVBQUUsSUFBSSxFQUFFLENBQUMsRUFBRSxFQUFFLEVBQUUsQ0FBQyxFQUFFLENBQUM7UUFDekUsTUFBTSxvQkFBb0IsR0FBRyxXQUFXLEdBQUcsU0FBUyxHQUFHLENBQUMsQ0FBQztRQUN6RCxNQUFNLElBQUksR0FBRyxJQUFJLENBQUMsR0FBRyxDQUFDLENBQUMsb0JBQW9CLEdBQUcsQ0FBQyxDQUFDLEdBQUcsWUFBWSxHQUFHLENBQUMsRUFBRSxDQUFDLENBQUMsQ0FBQztRQUN4RSxNQUFNLEVBQUUsR0FBRyxJQUFJLENBQUMsR0FBRyxDQUFDLElBQUksR0FBRyxZQUFZLEdBQUcsQ0FBQyxHQUFHLEtBQUssQ0FBQyxDQUFDLENBQUMsS0FBSyxDQUFDLENBQUMsQ0FBQyxJQUFJLEdBQUcsWUFBWSxHQUFHLENBQUMsRUFBRSxDQUFDLENBQUMsQ0FBQztRQUMxRixPQUFPLEVBQUUsQ0FBQyxFQUFFLElBQUksRUFBRSxDQUFDLEVBQUUsRUFBRSxFQUFFLElBQUksRUFBRSxFQUFFLEVBQUUsQ0FBQztJQUN0QyxDQUFDLEFBTnNCLENBTXJCO0lBRUY7Ozs7O09BS0c7SUFDSSxNQUFNLENBQUMsYUFBYSxDQUFDLEtBQWEsRUFBRSxZQUFvQjtRQUM3RCxPQUFPLElBQUksQ0FBQyxJQUFJLENBQUMsS0FBSyxHQUFHLFlBQVksQ0FBQyxDQUFDO0lBQ3pDLENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyIvKipcbiAqICAgICAgICAgICAgICBDb3B5cmlnaHQgKGMpIDIwMjUgVmlzYSwgSW5jLlxuICpcbiAqIExpY2Vuc2VkIHVuZGVyIHRoZSBBcGFjaGUgTGljZW5zZSwgVmVyc2lvbiAyLjAgKHRoZSBcIkxpY2Vuc2VcIik7XG4gKiB5b3UgbWF5IG5vdCB1c2UgdGhpcyBmaWxlIGV4Y2VwdCBpbiBjb21wbGlhbmNlIHdpdGggdGhlIExpY2Vuc2UuXG4gKiBZb3UgbWF5IG9idGFpbiBhIGNvcHkgb2YgdGhlIExpY2Vuc2UgYXRcbiAqXG4gKiAgICAgICAgIGh0dHA6Ly93d3cuYXBhY2hlLm9yZy9saWNlbnNlcy9MSUNFTlNFLTIuMFxuICpcbiAqIFVubGVzcyByZXF1aXJlZCBieSBhcHBsaWNhYmxlIGxhdyBvciBhZ3JlZWQgdG8gaW4gd3JpdGluZywgc29mdHdhcmVcbiAqIGRpc3RyaWJ1dGVkIHVuZGVyIHRoZSBMaWNlbnNlIGlzIGRpc3RyaWJ1dGVkIG9uIGFuIFwiQVMgSVNcIiBCQVNJUyxcbiAqIFdJVEhPVVQgV0FSUkFOVElFUyBPUiBDT05ESVRJT05TIE9GIEFOWSBLSU5ELCBlaXRoZXIgZXhwcmVzcyBvciBpbXBsaWVkLlxuICogU2VlIHRoZSBMaWNlbnNlIGZvciB0aGUgc3BlY2lmaWMgbGFuZ3VhZ2UgZ292ZXJuaW5nIHBlcm1pc3Npb25zIGFuZFxuICogbGltaXRhdGlvbnMgdW5kZXIgdGhlIExpY2Vuc2UuXG4gKlxuICoqL1xuLyogZXNsaW50LWRpc2FibGUgbm8tbWl4ZWQtc3BhY2VzLWFuZC10YWJzICovXG5pbXBvcnQgeyBjb21wdXRlZCwgU2lnbmFsLCBzaWduYWwsIFdyaXRhYmxlU2lnbmFsIH0gZnJvbSAnQGFuZ3VsYXIvY29yZSc7XG5cbi8qKlxuICogR2VuZXJhdGVzIGFuIGFycmF5IGZyb20gbnVtYmVyIHRvIGZyb20gKyBsZW5ndGhcbiAqIEBwYXJhbSB7bnVtYmVyfSBmcm9tXG4gKiBAcGFyYW0ge251bWJlcn0gbGVuZ3RoXG4gKiBAcmV0dXJucyB7bnVtYmVyW119XG4gKi9cbmV4cG9ydCBjb25zdCBnZW5lcmF0ZUFycmF5ID0gKGZyb206IG51bWJlciwgbGVuZ3RoOiBudW1iZXIpOiBudW1iZXJbXSA9PiBBcnJheS5mcm9tKHsgbGVuZ3RoIH0sIChfLCBpKSA9PiBpICsgZnJvbSk7XG5cbmV4cG9ydCB0eXBlIFBhZ2luYXRpb25Db250cm9sT3B0aW9ucyA9IHtcbiAgLyoqIE1heCBibG9jayBsZW5ndGggZm9yIGFsbCBibG9ja3MsIHRoaXMgZ2V0cyBvdmVyd3JpdHRlbiBieSBgc3RhcnRCbG9ja01heExlbmd0aGAsIGBtaWRkbGVCbG9ja01heExlbmd0aGAsIGBlbmRCbG9ja01heExlbmd0aGAgKi9cbiAgYmxvY2tNYXhMZW5ndGg6IG51bWJlcjtcbiAgLyoqIEZvcmNlcyBwYWdlcyBub3QgdG8gcGFnaW5hdGUgKi9cbiAgY29tcGFjdDogYm9vbGVhbjtcbiAgLyoqIERlZmF1bHQgc2VsZWN0ZWQgcGFnZSAqL1xuICBkZWZhdWx0U2VsZWN0ZWQ6IG51bWJlcjtcbiAgLyoqIERlZmF1bHQgdG90YWwgYW1vdW50IG9mIHBhZ2UgKi9cbiAgZGVmYXVsdFRvdGFsUGFnZXM6IG51bWJlcjtcbiAgLyoqIFdoYXQgdG8gc2VwYXJhdGUgdGhlIHBhZ2luYXRpb24gYXJyYXkgdXAgd2l0aCwgdXN1YWxseSB0aGlzIGRlbGltaXRlciB3aWxsIGJlIHJlcGxhY2VkIHdpdGggaWNvbiBvciBlbGxpcHNlcyB3aGVuIHNob3duIGluIHRoZSBVSSAqL1xuICBkZWxpbWl0ZXI6IG51bWJlciB8IHN0cmluZztcbiAgLyoqIE1heGltdW0gbGVuZ3RoIG9mIHBhZ2VzIHRvIHNob3cgb24gdGhlIGVuZCBwYWdpbmF0aW9uIGJsb2NrLCBvdmVyd3JpdGVzIGBibG9ja01heExlbmd0aGAgZm9yIGVuZCBibG9jayAqL1xuICBlbmRCbG9ja01heExlbmd0aDogbnVtYmVyO1xuICAvKiogTWF4aW11bSBwYWdlIG51bWJlciB0byBiZSBzaG93biwgKGRlZmF1bHQgbnVsbCBmb3Igbm8gbWF4aW11bSkgKi9cbiAgbWF4UGFnZU51bWJlcjogbnVtYmVyIHwgbnVsbDtcbiAgLyoqIE1heGltdW0gbGVuZ3RoIG9mIHBhZ2VzIHRvIHNob3cgb24gdGhlIG1pZGRsZSBwYWdpbmF0aW9uIGJsb2NrLCBvdmVyd3JpdGVzIGBibG9ja01heExlbmd0aGAgZm9yIG1pZGRsZSBibG9jayAqL1xuICBtaWRkbGVCbG9ja01heExlbmd0aDogbnVtYmVyO1xuICAvKiogU2lnbmFsIHRvIGJlIHVzZWQgZm9yIHNlbGVjdGVkIHBhZ2UsIG90aGVyd2lzZSBjb250cm9sIHdpbGwgY3JlYXRlIG9uZSAqL1xuICBzZWxlY3RlZFBhZ2U/OiBXcml0YWJsZVNpZ25hbDxudW1iZXI+IHwgbnVsbDtcbiAgLyoqIE1heGltdW0gbGVuZ3RoIG9mIHBhZ2VzIHRvIHNob3cgb24gdGhlIHN0YXJ0IHBhZ2luYXRpb24gYmxvY2ssIG92ZXJ3cml0ZXMgYGJsb2NrTWF4TGVuZ3RoYCBmb3Igc3RhcnQgYmxvY2sgKi9cbiAgc3RhcnRCbG9ja01heExlbmd0aDogbnVtYmVyO1xuICAvKiogU3RhcnQgZnJvbSB0aGlzIHBhZ2UgKi9cbiAgc3RhcnRQYWdlOiBudW1iZXI7XG59O1xuXG5jb25zdCBkZWZhdWx0T3B0aW9ucyA9IHtcbiAgYmxvY2tNYXhMZW5ndGg6IDMsXG4gIGNvbXBhY3Q6IGZhbHNlLFxuICBkZWZhdWx0U2VsZWN0ZWQ6IDEsXG4gIGRlZmF1bHRUb3RhbFBhZ2VzOiAxLFxuICBkZWxpbWl0ZXI6IC0xLFxuICBtYXhQYWdlTnVtYmVyOiBudWxsLFxuICBzdGFydFBhZ2U6IDFcbn0gc2F0aXNmaWVzIFBhcnRpYWw8UGFnaW5hdGlvbkNvbnRyb2xPcHRpb25zPjtcblxuLyoqXG4gKiBBIHNpZ25hbHMgYmFzZWQgYXBwcm9hY2ggdG8gaGFuZGxpbmcgYW5kIGNvbnRyb2xsaW5nIHBhZ2luYXRpb24gY29tcG9uZW50cy4gSXQgaXMgdmVyeSBjdXN0b21pemFibGUsIHJlLXVzYWJsZSwgYW5kIGV2ZW4gYWxsb3dzIHlvdSB0byBicmluZyB5b3VyIG93biBzaWduYWwgZm9yIHNlbGVjdGVkIHBhZ2UuXG4gKiBAZG9jcyB7QGxpbmsgaHR0cHM6Ly9kZXNpZ24udmlzYS5jb20vYW5ndWxhci9jb21wb25lbnRzL3BhZ2luYXRpb24gfCBTZWUgZG9jc31cbiAqL1xuZXhwb3J0IGNsYXNzIFBhZ2luYXRpb25Db250cm9sIHtcbiAgY29uc3RydWN0b3Iob3B0aW9ucz86IFBhcnRpYWw8UGFnaW5hdGlvbkNvbnRyb2xPcHRpb25zPikge1xuICAgIGNvbnN0IGJsb2NrTWF4TGVuZ3RoID0gb3B0aW9ucz8uYmxvY2tNYXhMZW5ndGggPz8gZGVmYXVsdE9wdGlvbnMuYmxvY2tNYXhMZW5ndGg7XG4gICAgLy8gSWYgd2UgaGF2ZSBhIGJsb2NrTWF4TGVuZ3RoLCB3ZSBzaG91bGQgc2V0IGl0IGZvciBhbGwgYmxvY2sgbWF4IGxlbmd0aHMsIHRoZW4gd2Ugb3ZlcnJpZGUgaXQgd2l0aCBhbGwgdGhlIG9wdGlvbnMgcHJvdmlkZWQgYnkgdGhlIHVzZXJcbiAgICB0aGlzLm9wdGlvbnMgPSB7XG4gICAgICAuLi5kZWZhdWx0T3B0aW9ucyxcbiAgICAgIGVuZEJsb2NrTWF4TGVuZ3RoOiBibG9ja01heExlbmd0aCxcbiAgICAgIG1pZGRsZUJsb2NrTWF4TGVuZ3RoOiBibG9ja01heExlbmd0aCxcbiAgICAgIHN0YXJ0QmxvY2tNYXhMZW5ndGg6IGJsb2NrTWF4TGVuZ3RoLFxuICAgICAgLi4ub3B0aW9uc1xuICAgIH0gYXMgUGFnaW5hdGlvbkNvbnRyb2xPcHRpb25zO1xuICAgIHRoaXMudG90YWxQYWdlcy5zZXQodGhpcy5vcHRpb25zLmRlZmF1bHRUb3RhbFBhZ2VzKTtcbiAgICBjb25zdCBkZWZhdWx0U3RhcnRQYWdlID0gTWF0aC5taW4oXG4gICAgICBNYXRoLm1heCh0aGlzLm9wdGlvbnMuZGVmYXVsdFNlbGVjdGVkLCB0aGlzLm9wdGlvbnMuc3RhcnRQYWdlKSxcbiAgICAgIHRoaXMub3B0aW9ucy5kZWZhdWx0VG90YWxQYWdlc1xuICAgICk7XG4gICAgdGhpcy5zZWxlY3RlZFBhZ2UgPSB0aGlzLm9wdGlvbnMuc2VsZWN0ZWRQYWdlID8/IHNpZ25hbChkZWZhdWx0U3RhcnRQYWdlKTtcbiAgICB0aGlzLnNlbGVjdGVkUGFnZS5zZXQoZGVmYXVsdFN0YXJ0UGFnZSk7XG4gIH1cblxuICAvLy8gU1RBVEU6XG5cbiAgcHJpdmF0ZSByZWFkb25seSBvcHRpb25zOiBQYWdpbmF0aW9uQ29udHJvbE9wdGlvbnM7XG5cbiAgcHJpdmF0ZSByZWFkb25seSBzZWxlY3RlZFBhZ2U6IFdyaXRhYmxlU2lnbmFsPG51bWJlcj47XG5cbiAgcHVibGljIHJlYWRvbmx5IHRvdGFsUGFnZXM6IFdyaXRhYmxlU2lnbmFsPG51bWJlcj4gPSBzaWduYWw8bnVtYmVyPigwKTtcblxuICAvLy8gREVSSVZFRCBTVEFURTpcblxuICAvKiogQ2FuIHBhZ2luYXRlIG9yIGp1c3Qgc2hvdyBhbGwgcGFnZXMgKi9cbiAgcHJpdmF0ZSByZWFkb25seSBjYW5QYWdpbmF0ZTogU2lnbmFsPGJvb2xlYW4+ID0gY29tcHV0ZWQoXG4gICAgKCkgPT5cbiAgICAgIHRoaXMudG90YWxQYWdlcygpID4gTWF0aC5tYXgodGhpcy5vcHRpb25zLmVuZEJsb2NrTWF4TGVuZ3RoLCB0aGlzLm9wdGlvbnMuc3RhcnRCbG9ja01heExlbmd0aCkgKyAyICYmIC8vIDEgZm9yIGVuZCBvciBzdGFydCBudW1iZXIgKyAxIGZvciBzaW5nbGUgc2VwYXJhdG9yIHNob3cgd2hpbGUgaW4gc3RhcnQvZW5kIGJsb2Nrc1xuICAgICAgdGhpcy50b3RhbFBhZ2VzKCkgPiB0aGlzLm9wdGlvbnMubWlkZGxlQmxvY2tNYXhMZW5ndGggKyA0IC8vIDIgZm9yIHN0YXJ0IGFuZCBlbmQgbnVtYmVycyArIDIgZm9yIHNlcGFyYXRvcnMgc2hvd24gd2hpbGUgaW4gbWlkZGxlIGJsb2NrXG4gICk7XG5cbiAgLyoqIFBhZ2VzIHRvIHNob3cgYXQgdGhlIGVuZCAqL1xuICBwcml2YXRlIHJlYWRvbmx5IGVuZEJsb2NrOiBTaWduYWw8bnVtYmVyW10+ID0gY29tcHV0ZWQoKCkgPT5cbiAgICB0aGlzLmlzSW5FbmRCbG9jaygpXG4gICAgICA/IGdlbmVyYXRlQXJyYXkodGhpcy5sYXN0UGFnZSgpIC0gdGhpcy5vcHRpb25zLmVuZEJsb2NrTWF4TGVuZ3RoICsgMSwgdGhpcy5vcHRpb25zLmVuZEJsb2NrTWF4TGVuZ3RoKVxuICAgICAgOiBbdGhpcy5sYXN0UGFnZSgpXVxuICApO1xuXG4gIC8qKiBJZGVhbCBsYXN0IHBhZ2Ugd2l0aG91dCBtYXhQYWdlTnVtYmVyIGludGVyZmVyaW5nICovXG4gIHByaXZhdGUgcmVhZG9ubHkgaWRlYWxMYXN0UGFnZTogU2lnbmFsPG51bWJlcj4gPSBjb21wdXRlZCgoKSA9PiB0aGlzLnRvdGFsUGFnZXMoKSArIHRoaXMub3B0aW9ucy5zdGFydFBhZ2UgLSAxKTtcblxuICAvKiogSXMgZmlyc3QgZWxlbWVudCBzZWxlY3RlZCAqL1xuICBwdWJsaWMgcmVhZG9ubHkgaXNGaXJzdFBhZ2U6IFNpZ25hbDxib29sZWFuPiA9IGNvbXB1dGVkKCgpID0+IHRoaXMuc2VsZWN0ZWRQYWdlKCkgPT09IHRoaXMub3B0aW9ucy5zdGFydFBhZ2UpO1xuXG4gIC8qKiBTZWxlY3RlZCBwYWdlIGlzIGluIGVuZCBibG9jayAqL1xuICBwcml2YXRlIHJlYWRvbmx5IGlzSW5FbmRCbG9jazogU2lnbmFsPGJvb2xlYW4+ID0gY29tcHV0ZWQoXG4gICAgKCkgPT4gdGhpcy5zZWxlY3RlZFBhZ2UoKSA+IHRoaXMubGFzdFBhZ2UoKSAtIHRoaXMub3B0aW9ucy5lbmRCbG9ja01heExlbmd0aFxuICApO1xuXG4gIC8qKiBTZWxlY3RlZCBwYWdlIGlzIGluIG1pZGRsZSBibG9jayAqL1xuICBwcml2YXRlIHJlYWRvbmx5IGlzSW5NaWRkbGVCbG9jazogU2lnbmFsPGJvb2xlYW4+ID0gY29tcHV0ZWQoKCkgPT4gIXRoaXMuaXNJblN0YXJ0QmxvY2soKSAmJiAhdGhpcy5pc0luRW5kQmxvY2soKSk7XG5cbiAgLyoqIFNlbGVjdGVkIHBhZ2UgaXMgaW4gc3RhcnQgYmxvY2sgKi9cbiAgcHJpdmF0ZSByZWFkb25seSBpc0luU3RhcnRCbG9jazogU2lnbmFsPGJvb2xlYW4+ID0gY29tcHV0ZWQoXG4gICAgKCkgPT4gdGhpcy5zZWxlY3RlZFBhZ2UoKSA8IHRoaXMub3B0aW9ucy5zdGFydFBhZ2UgKyB0aGlzLm9wdGlvbnMuc3RhcnRCbG9ja01heExlbmd0aFxuICApO1xuXG4gIC8qKiBJcyBsYXN0IGVsZW1lbnQgc2VsZWN0ZWQgKi9cbiAgcHVibGljIHJlYWRvbmx5IGlzTGFzdFBhZ2U6IFNpZ25hbDxib29sZWFuPiA9IGNvbXB1dGVkKCgpID0+IHRoaXMuc2VsZWN0ZWRQYWdlKCkgPT09IHRoaXMubGFzdFBhZ2UoKSk7XG5cbiAgLyoqIExhc3QgcGFnZSAqL1xuICBwcml2YXRlIHJlYWRvbmx5IGxhc3RQYWdlOiBTaWduYWw8bnVtYmVyPiA9IGNvbXB1dGVkKCgpID0+XG4gICAgdGhpcy5vcHRpb25zLm1heFBhZ2VOdW1iZXIgPT09IG51bGxcbiAgICAgID8gdGhpcy5pZGVhbExhc3RQYWdlKClcbiAgICAgIDogTWF0aC5taW4odGhpcy5vcHRpb25zLm1heFBhZ2VOdW1iZXIsIHRoaXMuaWRlYWxMYXN0UGFnZSgpKVxuICApO1xuXG4gIC8qKiBQYWdlcyB0byBzaG93IGluIHRoZSBtaWRkbGUgKi9cbiAgcHJpdmF0ZSByZWFkb25seSBtaWRkbGVCbG9jazogU2lnbmFsPG51bWJlcltdPiA9IGNvbXB1dGVkKCgpID0+IHtcbiAgICBpZiAoIXRoaXMuaXNJbk1pZGRsZUJsb2NrKCkpIHJldHVybiBbXTtcbiAgICBjb25zdCBtaWRkbGVCbG9ja1BhZGRpbmcgPSBNYXRoLmZsb29yKHRoaXMub3B0aW9ucy5taWRkbGVCbG9ja01heExlbmd0aCAvIDIpO1xuICAgIGlmICh0aGlzLnNlbGVjdGVkUGFnZSgpIC0gbWlkZGxlQmxvY2tQYWRkaW5nIDw9IHRoaXMub3B0aW9ucy5zdGFydFBhZ2UpXG4gICAgICByZXR1cm4gZ2VuZXJhdGVBcnJheShcbiAgICAgICAgdGhpcy5zZWxlY3RlZFBhZ2UoKSAtICh0aGlzLnNlbGVjdGVkUGFnZSgpIC0gdGhpcy5vcHRpb25zLnN0YXJ0UGFnZSkgKyAxLFxuICAgICAgICB0aGlzLm9wdGlvbnMubWlkZGxlQmxvY2tNYXhMZW5ndGhcbiAgICAgICk7XG4gICAgaWYgKHRoaXMuc2VsZWN0ZWRQYWdlKCkgKyBtaWRkbGVCbG9ja1BhZGRpbmcgPj0gdGhpcy5sYXN0UGFnZSgpKVxuICAgICAgcmV0dXJuIGdlbmVyYXRlQXJyYXkoXG4gICAgICAgIHRoaXMuc2VsZWN0ZWRQYWdlKCkgKyAodGhpcy5sYXN0UGFnZSgpIC0gdGhpcy5zZWxlY3RlZFBhZ2UoKSkgLSB0aGlzLm9wdGlvbnMubWlkZGxlQmxvY2tNYXhMZW5ndGgsXG4gICAgICAgIHRoaXMub3B0aW9ucy5taWRkbGVCbG9ja01heExlbmd0aFxuICAgICAgKTtcbiAgICByZXR1cm4gZ2VuZXJhdGVBcnJheSh0aGlzLnNlbGVjdGVkUGFnZSgpIC0gbWlkZGxlQmxvY2tQYWRkaW5nLCB0aGlzLm9wdGlvbnMubWlkZGxlQmxvY2tNYXhMZW5ndGgpO1xuICB9KTtcblxuICAvKiogQXJyYXkgb2YgcGFnZXMgYXJyYXlzIHRvIGxvb3Agb3ZlciAqL1xuICBwdWJsaWMgcmVhZG9ubHkgcGFnZXM6IFNpZ25hbDwoc3RyaW5nIHwgbnVtYmVyKVtdPiA9IGNvbXB1dGVkKCgpID0+IHtcbiAgICBpZiAodGhpcy5vcHRpb25zLmNvbXBhY3QpIHJldHVybiB0aGlzLmNvbXBhY3RQYWdlcztcbiAgICByZXR1cm4gdGhpcy5jYW5QYWdpbmF0ZSgpXG4gICAgICA/IFt0aGlzLnN0YXJ0QmxvY2soKSwgdGhpcy5taWRkbGVCbG9jaygpLCB0aGlzLmVuZEJsb2NrKCldXG4gICAgICAgICAgLm1hcCgoYmxvY2spID0+IChibG9jay5sZW5ndGggPyBbLi4uYmxvY2ssIHRoaXMub3B0aW9ucy5kZWxpbWl0ZXJdIDogW10pKVxuICAgICAgICAgIC5mbGF0KClcbiAgICAgICAgICAuc2xpY2UoMCwgLTEpXG4gICAgICA6IGdlbmVyYXRlQXJyYXkodGhpcy5vcHRpb25zLnN0YXJ0UGFnZSwgdGhpcy5sYXN0UGFnZSgpIC0gdGhpcy5vcHRpb25zLnN0YXJ0UGFnZSArIDEpO1xuICB9KTtcblxuICAvKiogUGFnZXMgdG8gc2hvdyBhdCB0aGUgc3RhcnQgKi9cbiAgcHJpdmF0ZSByZWFkb25seSBzdGFydEJsb2NrOiBTaWduYWw8bnVtYmVyW10+ID0gY29tcHV0ZWQoKCkgPT5cbiAgICB0aGlzLmlzSW5TdGFydEJsb2NrKClcbiAgICAgID8gZ2VuZXJhdGVBcnJheSh0aGlzLm9wdGlvbnMuc3RhcnRQYWdlLCB0aGlzLm9wdGlvbnMuc3RhcnRCbG9ja01heExlbmd0aClcbiAgICAgIDogW3RoaXMub3B0aW9ucy5zdGFydFBhZ2VdXG4gICk7XG5cbiAgLy8vIFVUSUxJVElFUzpcblxuICAvKiogR2V0dGVyIGZvciBzZWxlY3RlZFBhZ2UsIHdlIHNob3VsZG4ndCBkaXJlY3RseSBtYW5pcHVsYXRlIHRoZSBgc2VsZWN0ZWRQYWdlYCBzaWduYWwsIHVzZSBgZ29Ub1BhZ2VgIHRvIGRvIHRoaXMgc2FmZWx5ICovXG4gIHB1YmxpYyBnZXQgY3VycmVudFBhZ2UoKTogbnVtYmVyIHtcbiAgICByZXR1cm4gdGhpcy5zZWxlY3RlZFBhZ2UoKTtcbiAgfVxuXG4gIHByaXZhdGUgZ2V0IGNvbXBhY3RQYWdlcygpOiBudW1iZXJbXSB7XG4gICAgY29uc3QgeyBibG9ja01heExlbmd0aCB9ID0gdGhpcy5vcHRpb25zO1xuXG4gICAgLy8gU2hvdyBhbGwgcGFnZXMgaWYgd2UgaGF2ZSBsZXNzIHRoYW4gYmxvY2tNYXhMZW5ndGhcbiAgICBpZiAoYmxvY2tNYXhMZW5ndGggPiB0aGlzLnRvdGFsUGFnZXMoKSlcbiAgICAgIHJldHVybiBnZW5lcmF0ZUFycmF5KHRoaXMub3B0aW9ucy5zdGFydFBhZ2UsIHRoaXMubGFzdFBhZ2UoKSAtIHRoaXMub3B0aW9ucy5zdGFydFBhZ2UgKyAxKTtcblxuICAgIC8vIFNob3cgY2h1bmsgb2YgYmxvY2tNYXhMZW5ndGggcGFnZXNcbiAgICBjb25zdCBwYWRkaW5nID0gTWF0aC5mbG9vcihibG9ja01heExlbmd0aCAvIDIpO1xuICAgIGlmICh0aGlzLnNlbGVjdGVkUGFnZSgpIC0gcGFkZGluZyA8PSB0aGlzLm9wdGlvbnMuc3RhcnRQYWdlKVxuICAgICAgcmV0dXJuIGdlbmVyYXRlQXJyYXkodGhpcy5vcHRpb25zLnN0YXJ0UGFnZSwgYmxvY2tNYXhMZW5ndGgpO1xuICAgIGlmICh0aGlzLnNlbGVjdGVkUGFnZSgpICsgcGFkZGluZyA+PSB0aGlzLmxhc3RQYWdlKCkpXG4gICAgICByZXR1cm4gZ2VuZXJhdGVBcnJheSh0aGlzLmxhc3RQYWdlKCkgLSBibG9ja01heExlbmd0aCArIDEsIGJsb2NrTWF4TGVuZ3RoKTtcbiAgICByZXR1cm4gZ2VuZXJhdGVBcnJheSh0aGlzLnNlbGVjdGVkUGFnZSgpIC0gcGFkZGluZywgYmxvY2tNYXhMZW5ndGgpO1xuICB9XG5cbiAgLyoqXG4gICAqIENhbGN1bGF0ZXMgd2hpY2ggcmFuZ2Ugb2YgaXRlbXMgdGhhdCBpcyBjdXJyZW50bHkgdmlzaWJsZSBmcm9tIHBhZ2luYXRpb25cbiAgICogQHBhcmFtIHtudW1iZXJ9IGl0ZW1zIC0gaG93IG1hbnkgaXRlbXMgd2UgaGF2ZVxuICAgKiBAcGFyYW0ge251bWJlcn0gaXRlbXNQZXJQYWdlIC0gaG93IG1hbnkgaXRlbXMgdGhlcmUgYXJlLCBwZXIgcGFnZVxuICAgKiBAcmV0dXJucyB0byBmcm9tIG9iamVjdCB3aXRoIGNhbGN1bGF0ZWQgdmFsdWVzXG4gICAqL1xuICBwdWJsaWMgZ2V0VG9Gcm9tKGl0ZW1zOiBudW1iZXIsIGl0ZW1zUGVyUGFnZTogbnVtYmVyKSB7XG4gICAgcmV0dXJuIFBhZ2luYXRpb25Db250cm9sLmdldFRvRnJvbShpdGVtcywgaXRlbXNQZXJQYWdlLCB0aGlzLnNlbGVjdGVkUGFnZSgpLCB0aGlzLm9wdGlvbnMuc3RhcnRQYWdlKTtcbiAgfVxuXG4gIC8qKiBIZWxwZXIgdG8gY2FsY3VsYXRlIHRvdGFsIHBhZ2VzICovXG4gIHB1YmxpYyBnZXRUb3RhbFBhZ2VzID0gUGFnaW5hdGlvbkNvbnRyb2wuZ2V0VG90YWxQYWdlcztcblxuICAvKiogT24gZmlyc3QgcGFnZSBldmVudCAqL1xuICBwdWJsaWMgZ29Ub0ZpcnN0UGFnZSgpOiB2b2lkIHtcbiAgICB0aGlzLmdvVG9QYWdlKHRoaXMub3B0aW9ucy5zdGFydFBhZ2UpO1xuICB9XG5cbiAgLyoqIE9uIGxhc3QgcGFnZSBldmVudCAqL1xuICBwdWJsaWMgZ29Ub0xhc3RQYWdlKCk6IHZvaWQge1xuICAgIHRoaXMuZ29Ub1BhZ2UodGhpcy5sYXN0UGFnZSgpKTtcbiAgfVxuXG4gIC8qKiBPbiBuZXh0IHBhZ2UgZXZlbnQgKi9cbiAgcHVibGljIGdvVG9OZXh0UGFnZSgpOiB2b2lkIHtcbiAgICB0aGlzLmdvVG9QYWdlKHRoaXMuc2VsZWN0ZWRQYWdlKCkgKyAxKTtcbiAgfVxuXG4gIC8qKiBPbiBwYWdlIGNoYW5nZSBldmVudCAqL1xuICBwdWJsaWMgZ29Ub1BhZ2UocGFnZU51bWJlcjogbnVtYmVyIHwgc3RyaW5nKTogdm9pZCB7XG4gICAgaWYgKE51bWJlci5pc05hTigrcGFnZU51bWJlcikpIHRocm93IG5ldyBFcnJvcihcIkNhbid0IGdvIHRvIHBhZ2UsIGludmFsaWQgbnVtYmVyXCIpO1xuICAgIGlmICgocGFnZU51bWJlciBhcyBudW1iZXIpID4gdGhpcy5sYXN0UGFnZSgpKSB0aGlzLnNlbGVjdGVkUGFnZS5zZXQodGhpcy5sYXN0UGFnZSgpKTtcbiAgICBlbHNlIGlmICgocGFnZU51bWJlciBhcyBudW1iZXIpIDwgdGhpcy5vcHRpb25zLnN0YXJ0UGFnZSkgdGhpcy5zZWxlY3RlZFBhZ2Uuc2V0KHRoaXMub3B0aW9ucy5zdGFydFBhZ2UpO1xuICAgIGVsc2UgdGhpcy5zZWxlY3RlZFBhZ2Uuc2V0KHBhZ2VOdW1iZXIgYXMgbnVtYmVyKTtcbiAgfVxuXG4gIC8qKiBPbiBwcmV2aW91cyBwYWdlIGV2ZW50ICovXG4gIHB1YmxpYyBnb1RvUHJldmlvdXNQYWdlKCk6IHZvaWQge1xuICAgIHRoaXMuZ29Ub1BhZ2UodGhpcy5zZWxlY3RlZFBhZ2UoKSAtIDEpO1xuICB9XG5cbiAgLyoqIFJldHVybnMgaWYgcGFnZSBpcyBjdXJyZW50IHBhZ2UgKi9cbiAgcHVibGljIGlzQ3VycmVudFBhZ2UocGFnZTogbnVtYmVyIHwgc3RyaW5nKTogYm9vbGVhbiB7XG4gICAgcmV0dXJuIHBhZ2UgPT09IHRoaXMuc2VsZWN0ZWRQYWdlKCk7XG4gIH1cblxuICAvKipcbiAgICogSW4gdGhlIGNvbnRleHQgd2hlcmUgdG90YWwgcGFnZXMgaXMgY2FsY3VsYXRlZCB1c2luZyBpdGVtcyBwZXIgcGFnZSAobXVjaCBsaWtlIHRhYmxlcyB1c2UpIHdlIGNhbiB1c2UgdGhpcyB1dGlsaXR5IHRvIGVhc2lseSBhZGp1c3QgdGhlIHBhZ2luYXRpb24gY29udHJvbCBhdXRvbWF0aWNhbGx5LlxuICAgKiBOT1RFOiBieSBkZWZhdWx0IHRoaXMgcmVzZXRzIHRoZSBwYWdpbmF0aW9uIHRvIHRoZSBmaXJzdCBwYWdlIHdoZW4gY2FsbGVkLlxuICAgKi9cbiAgcHVibGljIHJlc2V0UGFnZUNvdW50KHRvdGFsSXRlbXM6IG51bWJlciwgaXRlbXNQZXJQYWdlOiBudW1iZXIsIGF1dG9SZXNldFRvRmlyc3RQYWdlID0gdHJ1ZSk6IHZvaWQge1xuICAgIGNvbnN0IHRvdGFsUGFnZXMgPSB0aGlzLmdldFRvdGFsUGFnZXModG90YWxJdGVtcywgaXRlbXNQZXJQYWdlKTtcbiAgICB0aGlzLnRvdGFsUGFnZXMuc2V0KHRvdGFsUGFnZXMpO1xuICAgIGlmIChhdXRvUmVzZXRUb0ZpcnN0UGFnZSkgdGhpcy5nb1RvRmlyc3RQYWdlKCk7XG4gIH1cblxuICAvLy8gU1RBVElDIFVUSUxJVElFUzpcblxuICAvKipcbiAgICogQ2FsY3VsYXRlcyB3aGljaCByYW5nZSBvZiBpdGVtcyB0aGF0IGlzIGN1cnJlbnRseSB2aXNpYmxlIGZyb20gcGFnaW5hdGlvblxuICAgKiBAcGFyYW0ge251bWJlcn0gaXRlbXMgLSBob3cgbWFueSBpdGVtcyB3ZSBoYXZlXG4gICAqIEBwYXJhbSB7bnVtYmVyfSBpdGVtc1BlclBhZ2UgLSBob3cgbWFueSBpdGVtcyB0aGVyZSBhcmUsIHBlciBwYWdlXG4gICAqIEBwYXJhbSB7bnVtYmVyfSBjdXJyZW50UGFnZSAtIHdoaWNoIHBhZ2UgaXMgdmlzaWJsZVxuICAgKiBAcGFyYW0ge251bWJlcn0gc3RhcnRQYWdlIC0gd2hpY2ggcGFnZSB3ZSdyZSBzdGFydGluZyBmcm9tLCBkZWZhdWx0cyB0byBwYWdlIDEgKG9wdGlvbmFsKVxuICAgKiBAcmV0dXJucyB0byBmcm9tIG9iamVjdCB3aXRoIGNhbGN1bGF0ZWQgdmFsdWVzXG4gICAqL1xuICBwdWJsaWMgc3RhdGljIGdldFRvRnJvbSA9IChpdGVtczogbnVtYmVyLCBpdGVtc1BlclBhZ2U6IG51bWJlciwgY3VycmVudFBhZ2U6IG51bWJlciwgc3RhcnRQYWdlOiBudW1iZXIgPSAxKSA9PiB7XG4gICAgaWYgKGl0ZW1zUGVyUGFnZSA8IDEgfHwgaXRlbXMgPCAxKSByZXR1cm4geyAwOiAwLCAxOiAwLCBmcm9tOiAwLCB0bzogMCB9O1xuICAgIGNvbnN0IG5vcm1hbGl6ZWRQYWdlTnVtYmVyID0gY3VycmVudFBhZ2UgLSBzdGFydFBhZ2UgKyAxO1xuICAgIGNvbnN0IGZyb20gPSBNYXRoLm1heCgobm9ybWFsaXplZFBhZ2VOdW1iZXIgLSAxKSAqIGl0ZW1zUGVyUGFnZSArIDEsIDApO1xuICAgIGNvbnN0IHRvID0gTWF0aC5tYXgoZnJvbSArIGl0ZW1zUGVyUGFnZSAtIDEgPiBpdGVtcyA/IGl0ZW1zIDogZnJvbSArIGl0ZW1zUGVyUGFnZSAtIDEsIDApO1xuICAgIHJldHVybiB7IDA6IGZyb20sIDE6IHRvLCBmcm9tLCB0byB9O1xuICB9O1xuXG4gIC8qKlxuICAgKiBDYWxjdWxhdGVzIGhvdyBtYW55IHBhZ2VzIHRoZXJlIGFyZVxuICAgKiBAcGFyYW0ge251bWJlcn0gaXRlbXMgLSBob3cgbWFueSBpdGVtcyB3ZSBoYXZlXG4gICAqIEBwYXJhbSB7bnVtYmVyfSBpdGVtc1BlclBhZ2UgLSBob3cgbWFueSBpdGVtcyB0aGVyZSBhcmUsIHBlciBwYWdlXG4gICAqIEByZXR1cm5zIHtudW1iZXJ9IGhvdyBtYW55IHBhZ2VzIHRoZXJlIGFyZSBpbiB0b3RhbFxuICAgKi9cbiAgcHVibGljIHN0YXRpYyBnZXRUb3RhbFBhZ2VzKGl0ZW1zOiBudW1iZXIsIGl0ZW1zUGVyUGFnZTogbnVtYmVyKTogbnVtYmVyIHtcbiAgICByZXR1cm4gTWF0aC5jZWlsKGl0ZW1zIC8gaXRlbXNQZXJQYWdlKTtcbiAgfVxufVxuIl19