UNPKG

@spartacus/storefront

Version:

Spartacus Storefront is a package that you can include in your application, which allows you to add default storefront features.

305 lines 36 kB
import { Injectable } from '@angular/core'; import { PaginationItemType, PaginationNavigationPosition, } from './pagination.model'; import * as i0 from "@angular/core"; import * as i1 from "./config/pagination.config"; const FALLBACK_PAGINATION_OPTIONS = { rangeCount: 3, dotsLabel: '...', startLabel: '«', previousLabel: '‹', nextLabel: '›', endLabel: '»', }; /** * Builds a pagination structures based on a pageCount and current page number. * There are various {@link PaginationConfig} options which can be used to configure * the behavior of the build. Alternatively, CSS can be used to further customize * the pagination. * * Examples: * The full blown pagination items contain the follow elements: * * `« ‹ 1 ... 4 (5) 6 ... 9 › »` * * This includes pagination items to the following pages: * - start page * - previous page * - first page * - page range * - last page * - next page * - end page * * All of those links are configurable, including the size of the page range. * The current page will always be centered in the page range to provide direct access * to the previous and next page. */ export class PaginationBuilder { constructor(paginationConfig) { this.paginationConfig = paginationConfig; } /** * Builds a list of `PaginationItem`. The give pageCount and current are used * to build out the full pagination. There are various {@link PaginationConfig} options * which can be used to configure the behavior of the build. Alternatively, CSS * can be used to further specialize visibility of the pagination. * * @param pageCount The total number of pages * @param current The current page number, 0-index based * @returns An array of `PaginationItem` */ paginate(pageCount, current) { const pages = []; if (!pageCount || pageCount < 2) { return pages; } this.addPages(pages, pageCount, current); this.addDots(pages, pageCount); this.addFirstLast(pages, pageCount); this.addNavigation(pages, pageCount, current); return pages; } /** * Returns the current page with surrounding pages (based on the `config.rangeCount`). * The current page is always centered to provide direct access to the previous and next page. * * @param pages The list of page items that is used to amend * @param pageCount The total number of pages * @param current The current page number, 0-index based */ addPages(pages, pageCount, current) { const start = this.getStartOfRange(pageCount, current); const max = Math.min(this.config.rangeCount, pageCount); Array.from(Array(max)).forEach((_, i) => { pages.push({ number: i + start, label: String(i + start + 1), type: PaginationItemType.PAGE, }); }); } /** * Adds dots before and after the given pages, if configured (defaults to true). * If the dots only represent a single page, the page number is added instead of * the dots, unless the configuration requires dots always. * * @param pages The list of page items that is used to amend * @param pageCount The total number of pages */ addDots(pages, pageCount) { if (!this.config.addDots) { return; } const addFirstGap = () => { const firstItemNumber = pages[0].number; const gapNumber = this.config.addFirst ? 1 : 0; if (firstItemNumber > gapNumber) { const isGap = !this.config.substituteDotsForSingularPage || firstItemNumber !== gapNumber + 1; const isSubstituted = this.config.addFirst && this.config.substituteDotsForSingularPage && gapNumber === 0; const type = isGap ? PaginationItemType.GAP : isSubstituted ? PaginationItemType.FIRST : PaginationItemType.PAGE; return [ Object.assign({ label: isGap ? this.config.dotsLabel : String(gapNumber + 1), type, }, isGap ? null : { number: gapNumber }), ]; } else return []; }; const addLastGap = () => { const nextPageNumber = pages[pages.length - 1].number + 1; const last = pageCount - (this.config.addLast ? 2 : 1); if (nextPageNumber <= last) { const isSubstituted = this.config.addLast && this.config.substituteDotsForSingularPage && nextPageNumber === last; const isGap = nextPageNumber < pageCount - (this.config.substituteDotsForSingularPage ? 1 : 0) - (this.config.addLast ? 1 : 0); const type = isGap ? PaginationItemType.GAP : isSubstituted ? PaginationItemType.LAST : PaginationItemType.PAGE; return [ Object.assign({ label: isGap ? this.config.dotsLabel : String(nextPageNumber + 1), type, }, isGap ? null : { number: nextPageNumber }), ]; } else return []; }; pages.unshift(...addFirstGap()); pages.push(...addLastGap()); } /** * Add links to the first and last page, if configured to do so. * * @param pages The list of page items that is used to amend * @param pageCount The total number of pages * */ addFirstLast(pages, pageCount) { if (this.config.addFirst && pages[0].number !== 0) { pages.unshift({ number: 0, label: '1', type: PaginationItemType.FIRST, }); } if (this.config.addLast && pages[pages.length - 1].number !== pageCount - 1) { pages.push({ number: pageCount - 1, label: String(pageCount), type: PaginationItemType.LAST, }); } } /** * Add links to the start, previous, next and last page, if configured to do so. * The order of the links can be configured by using the {@link PaginationConfig}, * using the `PaginationNavigationPosition` (`BEFORE` or `AFTER`). * The `PaginationNavigationPosition` allows for 3 flavours: * * - by default the pagination starts with start and previous and ends with the next and end links * - BEFORE – all navigation links are added in the front of the pagination list * - AFTER – all navigation links are pushed to the end of the pagination list * * @param pages The list of page items that is used to amend * @param pageCount The total number of pages * @param current The current page number, 0-index based * */ addNavigation(pages, pageCount, current) { const before = this.getBeforeLinks(current); const after = this.getAfterLinks(pageCount, current); const pos = this.config.navigationPosition; if (!pos || pos === PaginationNavigationPosition.ASIDE) { pages.unshift(...before); pages.push(...after); } else { if (pos === PaginationNavigationPosition.BEFORE) { pages.unshift(...before, ...after); } if (pos === PaginationNavigationPosition.AFTER) { pages.push(...before, ...after); } } } /** * Returns the start and previous links, if applicable. */ getBeforeLinks(current) { const list = []; if (this.config.addStart) { const start = () => { return Object.assign({ label: this.config.startLabel, type: PaginationItemType.START, }, current > 0 ? { number: 0 } : null); }; list.push(start()); } if (this.config.addPrevious) { const previous = () => { return Object.assign({ label: this.config.previousLabel, type: PaginationItemType.PREVIOUS, }, current > 0 ? { number: current - 1 } : null); }; list.push(previous()); } return list; } /** * Returns the next and end links, if applicable. */ getAfterLinks(pageCount, current) { const list = []; if (this.config.addNext) { const next = () => { return Object.assign({ label: this.config.nextLabel, type: PaginationItemType.NEXT, }, current < pageCount - 1 ? { number: current + 1 } : null); }; list.push(next()); } if (this.config.addEnd) { const end = () => { return Object.assign({ label: this.config.endLabel, type: PaginationItemType.END, }, current < pageCount - 1 ? { number: pageCount - 1 } : null); }; list.push(end()); } return list; } /** * Resolves the first page of the range we need to build. * This is the page that is leading up to the range of the * current page. * * @param pageCount The total number of pages. * @param current The current page number, 0-index based. */ getStartOfRange(pageCount, current) { const count = this.config.rangeCount - 1; // the least number of pages before and after the current const delta = Math.round(count / 2); // ensure that we start with at least the first page const minStart = Math.max(0, current - delta); // ensures that we start with at least 1 and do not pass the last range const maxStart = Math.max(0, pageCount - count - 1); // ensure that we get at least a full range at the end return Math.min(maxStart, minStart); } /** * Returns the pagination configuration. The configuration is driven by the * (default) application configuration. * * The default application is limited to adding the start and end link: * ```ts * addStart: true, * addEnd: true * ``` * * The application configuration is however merged into the following static configuration: * ```ts * { * rangeCount: 3, * dotsLabel: '...', * startLabel: '«', * previousLabel: '‹', * nextLabel: '›', * endLabel: '»' * } * ``` */ get config() { return Object.assign(FALLBACK_PAGINATION_OPTIONS, this.paginationConfig.pagination); } } PaginationBuilder.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.0.5", ngImport: i0, type: PaginationBuilder, deps: [{ token: i1.PaginationConfig }], target: i0.ɵɵFactoryTarget.Injectable }); PaginationBuilder.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "12.0.5", ngImport: i0, type: PaginationBuilder, providedIn: 'root' }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.0.5", ngImport: i0, type: PaginationBuilder, decorators: [{ type: Injectable, args: [{ providedIn: 'root', }] }], ctorParameters: function () { return [{ type: i1.PaginationConfig }]; } }); //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicGFnaW5hdGlvbi5idWlsZGVyLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vLi4vLi4vLi4vcHJvamVjdHMvc3RvcmVmcm9udGxpYi9zaGFyZWQvY29tcG9uZW50cy9saXN0LW5hdmlnYXRpb24vcGFnaW5hdGlvbi9wYWdpbmF0aW9uLmJ1aWxkZXIudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUFFLFVBQVUsRUFBRSxNQUFNLGVBQWUsQ0FBQztBQUUzQyxPQUFPLEVBRUwsa0JBQWtCLEVBQ2xCLDRCQUE0QixHQUU3QixNQUFNLG9CQUFvQixDQUFDOzs7QUFFNUIsTUFBTSwyQkFBMkIsR0FBc0I7SUFDckQsVUFBVSxFQUFFLENBQUM7SUFDYixTQUFTLEVBQUUsS0FBSztJQUNoQixVQUFVLEVBQUUsR0FBRztJQUNmLGFBQWEsRUFBRSxHQUFHO0lBQ2xCLFNBQVMsRUFBRSxHQUFHO0lBQ2QsUUFBUSxFQUFFLEdBQUc7Q0FDZCxDQUFDO0FBRUY7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7O0dBdUJHO0FBSUgsTUFBTSxPQUFPLGlCQUFpQjtJQUM1QixZQUFzQixnQkFBa0M7UUFBbEMscUJBQWdCLEdBQWhCLGdCQUFnQixDQUFrQjtJQUFHLENBQUM7SUFFNUQ7Ozs7Ozs7OztPQVNHO0lBQ0gsUUFBUSxDQUFDLFNBQWlCLEVBQUUsT0FBZTtRQUN6QyxNQUFNLEtBQUssR0FBcUIsRUFBRSxDQUFDO1FBQ25DLElBQUksQ0FBQyxTQUFTLElBQUksU0FBUyxHQUFHLENBQUMsRUFBRTtZQUMvQixPQUFPLEtBQUssQ0FBQztTQUNkO1FBQ0QsSUFBSSxDQUFDLFFBQVEsQ0FBQyxLQUFLLEVBQUUsU0FBUyxFQUFFLE9BQU8sQ0FBQyxDQUFDO1FBQ3pDLElBQUksQ0FBQyxPQUFPLENBQUMsS0FBSyxFQUFFLFNBQVMsQ0FBQyxDQUFDO1FBQy9CLElBQUksQ0FBQyxZQUFZLENBQUMsS0FBSyxFQUFFLFNBQVMsQ0FBQyxDQUFDO1FB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RixJQUFJLENBQUMsSUFBSSxDQUFDLEdBQUcsRUFBRSxDQUFDLENBQUM7U0FDbEI7UUFFRCxPQUFPLElBQUksQ0FBQztJQUNkLENBQUM7SUFDRDs7Ozs7OztPQU9HO0lBQ08sZUFBZSxDQUFDLFNBQWlCLEVBQUUsT0FBZTtRQUMxRCxNQUFNLEtBQUssR0FBRyxJQUFJLENBQUMsTUFBTSxDQUFDLFVBQVUsR0FBRyxDQUFDLENBQUM7UUFDekMseURBQXlEO1FBQ3pELE1BQU0sS0FBSyxHQUFHLElBQUksQ0FBQyxLQUFLLENBQUMsS0FBSyxHQUFHLENBQUMsQ0FBQyxDQUFDO1FBRXBDLG9EQUFvRDtRQUNwRCxNQUFNLFFBQVEsR0FBRyxJQUFJLENBQUMsR0FBRyxDQUFDLENBQUMsRUFBRSxPQUFPLEdBQUcsS0FBSyxDQUFDLENBQUM7UUFDOUMsdUVBQXVFO1FBQ3ZFLE1BQU0sUUFBUSxHQUFHLElBQUksQ0FBQyxHQUFHLENBQUMsQ0FBQyxFQUFFLFNBQVMsR0FBRyxLQUFLLEdBQUcsQ0FBQyxDQUFDLENBQUM7UUFFcEQsc0RBQXNEO1FBQ3RELE9BQU8sSUFBSSxDQUFDLEdBQUcsQ0FBQyxRQUFRLEVBQUUsUUFBUSxDQUFDLENBQUM7SUFDdEMsQ0FBQztJQUVEOzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7T0FxQkc7SUFDSCxJQUFjLE1BQU07UUFDbEIsT0FBTyxNQUFNLENBQUMsTUFBTSxDQUNsQiwyQkFBMkIsRUFDM0IsSUFBSSxDQUFDLGdCQUFnQixDQUFDLFVBQVUsQ0FDakMsQ0FBQztJQUNKLENBQUM7OzhHQW5UVSxpQkFBaUI7a0hBQWpCLGlCQUFpQixjQUZoQixNQUFNOzJGQUVQLGlCQUFpQjtrQkFIN0IsVUFBVTttQkFBQztvQkFDVixVQUFVLEVBQUUsTUFBTTtpQkFDbkIiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBJbmplY3RhYmxlIH0gZnJvbSAnQGFuZ3VsYXIvY29yZSc7XG5pbXBvcnQgeyBQYWdpbmF0aW9uQ29uZmlnIH0gZnJvbSAnLi9jb25maWcvcGFnaW5hdGlvbi5jb25maWcnO1xuaW1wb3J0IHtcbiAgUGFnaW5hdGlvbkl0ZW0sXG4gIFBhZ2luYXRpb25JdGVtVHlwZSxcbiAgUGFnaW5hdGlvbk5hdmlnYXRpb25Qb3NpdGlvbixcbiAgUGFnaW5hdGlvbk9wdGlvbnMsXG59IGZyb20gJy4vcGFnaW5hdGlvbi5tb2RlbCc7XG5cbmNvbnN0IEZBTExCQUNLX1BBR0lOQVRJT05fT1BUSU9OUzogUGFnaW5hdGlvbk9wdGlvbnMgPSB7XG4gIHJhbmdlQ291bnQ6IDMsXG4gIGRvdHNMYWJlbDogJy4uLicsXG4gIHN0YXJ0TGFiZWw6ICfCqycsXG4gIHByZXZpb3VzTGFiZWw6ICfigLknLFxuICBuZXh0TGFiZWw6ICfigLonLFxuICBlbmRMYWJlbDogJ8K7Jyxcbn07XG5cbi8qKlxuICogQnVpbGRzIGEgcGFnaW5hdGlvbiBzdHJ1Y3R1cmVzIGJhc2VkIG9uIGEgcGFnZUNvdW50IGFuZCBjdXJyZW50IHBhZ2UgbnVtYmVyLlxuICogVGhlcmUgYXJlIHZhcmlvdXMge0BsaW5rIFBhZ2luYXRpb25Db25maWd9IG9wdGlvbnMgd2hpY2ggY2FuIGJlIHVzZWQgdG8gY29uZmlndXJlXG4gKiB0aGUgYmVoYXZpb3Igb2YgdGhlIGJ1aWxkLiBBbHRlcm5hdGl2ZWx5LCBDU1MgY2FuIGJlIHVzZWQgdG8gZnVydGhlciBjdXN0b21pemVcbiAqIHRoZSBwYWdpbmF0aW9uLlxuICpcbiAqIEV4YW1wbGVzOlxuICogVGhlIGZ1bGwgYmxvd24gcGFnaW5hdGlvbiBpdGVtcyBjb250YWluIHRoZSBmb2xsb3cgZWxlbWVudHM6XG4gKlxuICogYMKrIOKAuSAxIC4uLiA0ICg1KSA2IC4uLiA5IOKAuiDCu2BcbiAqXG4gKiBUaGlzIGluY2x1ZGVzIHBhZ2luYXRpb24gaXRlbXMgdG8gdGhlIGZvbGxvd2luZyBwYWdlczpcbiAqIC0gc3RhcnQgcGFnZVxuICogLSBwcmV2aW91cyBwYWdlXG4gKiAtIGZpcnN0IHBhZ2VcbiAqIC0gcGFnZSByYW5nZVxuICogLSBsYXN0IHBhZ2VcbiAqIC0gbmV4dCBwYWdlXG4gKiAtIGVuZCBwYWdlXG4gKlxuICogQWxsIG9mIHRob3NlIGxpbmtzIGFyZSBjb25maWd1cmFibGUsIGluY2x1ZGluZyB0aGUgc2l6ZSBvZiB0aGUgcGFnZSByYW5nZS5cbiAqIFRoZSBjdXJyZW50IHBhZ2Ugd2lsbCBhbHdheXMgYmUgY2VudGVyZWQgaW4gdGhlIHBhZ2UgcmFuZ2UgdG8gcHJvdmlkZSBkaXJlY3QgYWNjZXNzXG4gKiB0byB0aGUgcHJldmlvdXMgYW5kIG5leHQgcGFnZS5cbiAqL1xuQEluamVjdGFibGUoe1xuICBwcm92aWRlZEluOiAncm9vdCcsXG59KVxuZXhwb3J0IGNsYXNzIFBhZ2luYXRpb25CdWlsZGVyIHtcbiAgY29uc3RydWN0b3IocHJvdGVjdGVkIHBhZ2luYXRpb25Db25maWc6IFBhZ2luYXRpb25Db25maWcpIHt9XG5cbiAgLyoqXG4gICAqIEJ1aWxkcyBhIGxpc3Qgb2YgYFBhZ2luYXRpb25JdGVtYC4gVGhlIGdpdmUgcGFnZUNvdW50IGFuZCBjdXJyZW50IGFyZSB1c2VkXG4gICAqIHRvIGJ1aWxkIG91dCB0aGUgZnVsbCBwYWdpbmF0aW9uLiBUaGVyZSBhcmUgdmFyaW91cyB7QGxpbmsgUGFnaW5hdGlvbkNvbmZpZ30gb3B0aW9uc1xuICAgKiB3aGljaCBjYW4gYmUgdXNlZCB0byBjb25maWd1cmUgdGhlIGJlaGF2aW9yIG9mIHRoZSBidWlsZC4gQWx0ZXJuYXRpdmVseSwgQ1NTXG4gICAqIGNhbiBiZSB1c2VkIHRvIGZ1cnRoZXIgc3BlY2lhbGl6ZSB2aXNpYmlsaXR5IG9mIHRoZSBwYWdpbmF0aW9uLlxuICAgKlxuICAgKiBAcGFyYW0gcGFnZUNvdW50IFRoZSB0b3RhbCBudW1iZXIgb2YgcGFnZXNcbiAgICogQHBhcmFtIGN1cnJlbnQgVGhlIGN1cnJlbnQgcGFnZSBudW1iZXIsIDAtaW5kZXggYmFzZWRcbiAgICogQHJldHVybnMgQW4gYXJyYXkgb2YgYFBhZ2luYXRpb25JdGVtYFxuICAgKi9cbiAgcGFnaW5hdGUocGFnZUNvdW50OiBudW1iZXIsIGN1cnJlbnQ6IG51bWJlcik6IFBhZ2luYXRpb25JdGVtW10ge1xuICAgIGNvbnN0IHBhZ2VzOiBQYWdpbmF0aW9uSXRlbVtdID0gW107XG4gICAgaWYgKCFwYWdlQ291bnQgfHwgcGFnZUNvdW50IDwgMikge1xuICAgICAgcmV0dXJuIHBhZ2VzO1xuICAgIH1cbiAgICB0aGlzLmFkZFBhZ2VzKHBhZ2VzLCBwYWdlQ291bnQsIGN1cnJlbnQpO1xuICAgIHRoaXMuYWRkRG90cyhwYWdlcywgcGFnZUNvdW50KTtcbiAgICB0aGlzLmFkZEZpcnN0TGFzdChwYWdlcywgcGFnZUNvdW50KTtcbiAgICB0aGlzLmFkZE5hdmlnYXRpb24ocGFnZXMsIHBhZ2VDb3VudCwgY3VycmVudCk7XG5cbiAgICByZXR1cm4gcGFnZXM7XG4gIH1cblxuICAvKipcbiAgICogUmV0dXJucyB0aGUgY3VycmVudCBwYWdlIHdpdGggc3Vycm91bmRpbmcgcGFnZXMgKGJhc2VkIG9uIHRoZSBgY29uZmlnLnJhbmdlQ291bnRgKS5cbiAgICogVGhlIGN1cnJlbnQgcGFnZSBpcyBhbHdheXMgY2VudGVyZWQgdG8gcHJvdmlkZSBkaXJlY3QgYWNjZXNzIHRvIHRoZSBwcmV2aW91cyBhbmQgbmV4dCBwYWdlLlxuICAgKlxuICAgKiBAcGFyYW0gcGFnZXMgVGhlIGxpc3Qgb2YgcGFnZSBpdGVtcyB0aGF0IGlzIHVzZWQgdG8gYW1lbmRcbiAgICogQHBhcmFtIHBhZ2VDb3VudCBUaGUgdG90YWwgbnVtYmVyIG9mIHBhZ2VzXG4gICAqIEBwYXJhbSBjdXJyZW50IFRoZSBjdXJyZW50IHBhZ2UgbnVtYmVyLCAwLWluZGV4IGJhc2VkXG4gICAqL1xuICBwcm90ZWN0ZWQgYWRkUGFnZXMoXG4gICAgcGFnZXM6IFBhZ2luYXRpb25JdGVtW10sXG4gICAgcGFnZUNvdW50OiBudW1iZXIsXG4gICAgY3VycmVudDogbnVtYmVyXG4gICk6IHZvaWQge1xuICAgIGNvbnN0IHN0YXJ0ID0gdGhpcy5nZXRTdGFydE9mUmFuZ2UocGFnZUNvdW50LCBjdXJyZW50KTtcbiAgICBjb25zdCBtYXggPSBNYXRoLm1pbih0aGlzLmNvbmZpZy5yYW5nZUNvdW50LCBwYWdlQ291bnQpO1xuICAgIEFycmF5LmZyb20oQXJyYXkobWF4KSkuZm9yRWFjaCgoXywgaSkgPT4ge1xuICAgICAgcGFnZXMucHVzaCh7XG4gICAgICAgIG51bWJlcjogaSArIHN0YXJ0LFxuICAgICAgICBsYWJlbDogU3RyaW5nKGkgKyBzdGFydCArIDEpLFxuICAgICAgICB0eXBlOiBQYWdpbmF0aW9uSXRlbVR5cGUuUEFHRSxcbiAgICAgIH0pO1xuICAgIH0pO1xuICB9XG5cbiAgLyoqXG4gICAqIEFkZHMgZG90cyBiZWZvcmUgYW5kIGFmdGVyIHRoZSBnaXZlbiBwYWdlcywgaWYgY29uZmlndXJlZCAoZGVmYXVsdHMgdG8gdHJ1ZSkuXG4gICAqIElmIHRoZSBkb3RzIG9ubHkgcmVwcmVzZW50IGEgc2luZ2xlIHBhZ2UsIHRoZSBwYWdlIG51bWJlciBpcyBhZGRlZCBpbnN0ZWFkIG9mXG4gICAqIHRoZSBkb3RzLCB1bmxlc3MgdGhlIGNvbmZpZ3VyYXRpb24gcmVxdWlyZXMgZG90cyBhbHdheXMuXG4gICAqXG4gICAqIEBwYXJhbSBwYWdlcyBUaGUgbGlzdCBvZiBwYWdlIGl0ZW1zIHRoYXQgaXMgdXNlZCB0byBhbWVuZFxuICAgKiBAcGFyYW0gcGFnZUNvdW50IFRoZSB0b3RhbCBudW1iZXIgb2YgcGFnZXNcbiAgICovXG4gIHByb3RlY3RlZCBhZGREb3RzKHBhZ2VzOiBQYWdpbmF0aW9uSXRlbVtdLCBwYWdlQ291bnQ6IG51bWJlcik6IHZvaWQge1xuICAgIGlmICghdGhpcy5jb25maWcuYWRkRG90cykge1xuICAgICAgcmV0dXJuO1xuICAgIH1cblxuICAgIGNvbnN0IGFkZEZpcnN0R2FwID0gKCkgPT4ge1xuICAgICAgY29uc3QgZmlyc3RJdGVtTnVtYmVyID0gcGFnZXNbMF0ubnVtYmVyO1xuICAgICAgY29uc3QgZ2FwTnVtYmVyID0gdGhpcy5jb25maWcuYWRkRmlyc3QgPyAxIDogMDtcbiAgICAgIGlmIChmaXJzdEl0ZW1OdW1iZXIgPiBnYXBOdW1iZXIpIHtcbiAgICAgICAgY29uc3QgaXNHYXAgPVxuICAgICAgICAgICF0aGlzLmNvbmZpZy5zdWJzdGl0dXRlRG90c0ZvclNpbmd1bGFyUGFnZSB8fFxuICAgICAgICAgIGZpcnN0SXRlbU51bWJlciAhPT0gZ2FwTnVtYmVyICsgMTtcbiAgICAgICAgY29uc3QgaXNTdWJzdGl0dXRlZCA9XG4gICAgICAgICAgdGhpcy5jb25maWcuYWRkRmlyc3QgJiZcbiAgICAgICAgICB0aGlzLmNvbmZpZy5zdWJzdGl0dXRlRG90c0ZvclNpbmd1bGFyUGFnZSAmJlxuICAgICAgICAgIGdhcE51bWJlciA9PT0gMDtcbiAgICAgICAgY29uc3QgdHlwZSA9IGlzR2FwXG4gICAgICAgICAgPyBQYWdpbmF0aW9uSXRlbVR5cGUuR0FQXG4gICAgICAgICAgOiBpc1N1YnN0aXR1dGVkXG4gICAgICAgICAgPyBQYWdpbmF0aW9uSXRlbVR5cGUuRklSU1RcbiAgICAgICAgICA6IFBhZ2luYXRpb25JdGVtVHlwZS5QQUdFO1xuICAgICAgICByZXR1cm4gW1xuICAgICAgICAgIE9iamVjdC5hc3NpZ24oXG4gICAgICAgICAgICB7XG4gICAgICAgICAgICAgIGxhYmVsOiBpc0dhcCA/IHRoaXMuY29uZmlnLmRvdHNMYWJlbCA6IFN0cmluZyhnYXBOdW1iZXIgKyAxKSxcbiAgICAgICAgICAgICAgdHlwZSxcbiAgICAgICAgICAgIH0sXG4gICAgICAgICAgICBpc0dhcCA/IG51bGwgOiB7IG51bWJlcjogZ2FwTnVtYmVyIH1cbiAgICAgICAgICApLFxuICAgICAgICBdO1xuICAgICAgfSBlbHNlIHJldHVybiBbXTtcbiAgICB9O1xuXG4gICAgY29uc3QgYWRkTGFzdEdhcCA9ICgpID0+IHtcbiAgICAgIGNvbnN0IG5leHRQYWdlTnVtYmVyID0gcGFnZXNbcGFnZXMubGVuZ3RoIC0gMV0ubnVtYmVyICsgMTtcbiAgICAgIGNvbnN0IGxhc3QgPSBwYWdlQ291bnQgLSAodGhpcy5jb25maWcuYWRkTGFzdCA/IDIgOiAxKTtcbiAgICAgIGlmIChuZXh0UGFnZU51bWJlciA8PSBsYXN0KSB7XG4gICAgICAgIGNvbnN0IGlzU3Vic3RpdHV0ZWQgPVxuICAgICAgICAgIHRoaXMuY29uZmlnLmFkZExhc3QgJiZcbiAgICAgICAgICB0aGlzLmNvbmZpZy5zdWJzdGl0dXRlRG90c0ZvclNpbmd1bGFyUGFnZSAmJlxuICAgICAgICAgIG5leHRQYWdlTnVtYmVyID09PSBsYXN0O1xuICAgICAgICBjb25zdCBpc0dhcCA9XG4gICAgICAgICAgbmV4dFBhZ2VOdW1iZXIgPFxuICAgICAgICAgIHBhZ2VDb3VudCAtXG4gICAgICAgICAgICAodGhpcy5jb25maWcuc3Vic3RpdHV0ZURvdHNGb3JTaW5ndWxhclBhZ2UgPyAxIDogMCkgLVxuICAgICAgICAgICAgKHRoaXMuY29uZmlnLmFkZExhc3QgPyAxIDogMCk7XG5cbiAgICAgICAgY29uc3QgdHlwZSA9IGlzR2FwXG4gICAgICAgICAgPyBQYWdpbmF0aW9uSXRlbVR5cGUuR0FQXG4gICAgICAgICAgOiBpc1N1YnN0aXR1dGVkXG4gICAgICAgICAgPyBQYWdpbmF0aW9uSXRlbVR5cGUuTEFTVFxuICAgICAgICAgIDogUGFnaW5hdGlvbkl0ZW1UeXBlLlBBR0U7XG4gICAgICAgIHJldHVybiBbXG4gICAgICAgICAgT2JqZWN0LmFzc2lnbihcbiAgICAgICAgICAgIHtcbiAgICAgICAgICAgICAgbGFiZWw6IGlzR2FwID8gdGhpcy5jb25maWcuZG90c0xhYmVsIDogU3RyaW5nKG5leHRQYWdlTnVtYmVyICsgMSksXG4gICAgICAgICAgICAgIHR5cGUsXG4gICAgICAgICAgICB9LFxuICAgICAgICAgICAgaXNHYXAgPyBudWxsIDogeyBudW1iZXI6IG5leHRQYWdlTnVtYmVyIH1cbiAgICAgICAgICApLFxuICAgICAgICBdO1xuICAgICAgfSBlbHNlIHJldHVybiBbXTtcbiAgICB9O1xuXG4gICAgcGFnZXMudW5zaGlmdCguLi5hZGRGaXJzdEdhcCgpKTtcbiAgICBwYWdlcy5wdXNoKC4uLmFkZExhc3RHYXAoKSk7XG4gIH1cblxuICAvKipcbiAgICogQWRkIGxpbmtzIHRvIHRoZSBmaXJzdCBhbmQgbGFzdCBwYWdlLCBpZiBjb25maWd1cmVkIHRvIGRvIHNvLlxuICAgKlxuICAgKiBAcGFyYW0gcGFnZXMgVGhlIGxpc3Qgb2YgcGFnZSBpdGVtcyB0aGF0IGlzIHVzZWQgdG8gYW1lbmRcbiAgICogQHBhcmFtIHBhZ2VDb3VudCBUaGUgdG90YWwgbnVtYmVyIG9mIHBhZ2VzXG4gICAqXG4gICAqL1xuICBwcm90ZWN0ZWQgYWRkRmlyc3RMYXN0KHBhZ2VzOiBQYWdpbmF0aW9uSXRlbVtdLCBwYWdlQ291bnQ6IG51bWJlcikge1xuICAgIGlmICh0aGlzLmNvbmZpZy5hZGRGaXJzdCAmJiBwYWdlc1swXS5udW1iZXIgIT09IDApIHtcbiAgICAgIHBhZ2VzLnVuc2hpZnQoe1xuICAgICAgICBudW1iZXI6IDAsXG4gICAgICAgIGxhYmVsOiAnMScsXG4gICAgICAgIHR5cGU6IFBhZ2luYXRpb25JdGVtVHlwZS5GSVJTVCxcbiAgICAgIH0pO1xuICAgIH1cbiAgICBpZiAoXG4gICAgICB0aGlzLmNvbmZpZy5hZGRMYXN0ICYmXG4gICAgICBwYWdlc1twYWdlcy5sZW5ndGggLSAxXS5udW1iZXIgIT09IHBhZ2VDb3VudCAtIDFcbiAgICApIHtcbiAgICAgIHBhZ2VzLnB1c2goe1xuICAgICAgICBudW1iZXI6IHBhZ2VDb3VudCAtIDEsXG4gICAgICAgIGxhYmVsOiBTdHJpbmcocGFnZUNvdW50KSxcbiAgICAgICAgdHlwZTogUGFnaW5hdGlvbkl0ZW1UeXBlLkxBU1QsXG4gICAgICB9KTtcbiAgICB9XG4gIH1cblxuICAvKipcbiAgICogQWRkIGxpbmtzIHRvIHRoZSBzdGFydCwgcHJldmlvdXMsIG5leHQgYW5kIGxhc3QgcGFnZSwgaWYgY29uZmlndXJlZCB0byBkbyBzby5cbiAgICogVGhlIG9yZGVyIG9mIHRoZSBsaW5rcyBjYW4gYmUgY29uZmlndXJlZCBieSB1c2luZyB0aGUge0BsaW5rIFBhZ2luYXRpb25Db25maWd9LFxuICAgKiB1c2luZyB0aGUgYFBhZ2luYXRpb25OYXZpZ2F0aW9uUG9zaXRpb25gIChgQkVGT1JFYCBvciBgQUZURVJgKS5cbiAgICogVGhlIGBQYWdpbmF0aW9uTmF2aWdhdGlvblBvc2l0aW9uYCBhbGxvd3MgZm9yIDMgZmxhdm91cnM6XG4gICAqXG4gICAqIC0gYnkgZGVmYXVsdCB0aGUgcGFnaW5hdGlvbiBzdGFydHMgd2l0aCBzdGFydCBhbmQgcHJldmlvdXMgYW5kIGVuZHMgd2l0aCB0aGUgbmV4dCBhbmQgZW5kIGxpbmtzXG4gICAqIC0gQkVGT1JFIOKAk8KgYWxsIG5hdmlnYXRpb24gbGlua3MgYXJlIGFkZGVkIGluIHRoZSBmcm9udCBvZiB0aGUgcGFnaW5hdGlvbiBsaXN0XG4gICAqIC0gQUZURVIg4oCTwqBhbGwgbmF2aWdhdGlvbiBsaW5rcyBhcmUgcHVzaGVkIHRvIHRoZSBlbmQgb2YgdGhlIHBhZ2luYXRpb24gbGlzdFxuICAgKlxuICAgKiBAcGFyYW0gcGFnZXMgVGhlIGxpc3Qgb2YgcGFnZSBpdGVtcyB0aGF0IGlzIHVzZWQgdG8gYW1lbmRcbiAgICogQHBhcmFtIHBhZ2VDb3VudCBUaGUgdG90YWwgbnVtYmVyIG9mIHBhZ2VzXG4gICAqIEBwYXJhbSBjdXJyZW50IFRoZSBjdXJyZW50IHBhZ2UgbnVtYmVyLCAwLWluZGV4IGJhc2VkXG4gICAqXG4gICAqL1xuICBwcm90ZWN0ZWQgYWRkTmF2aWdhdGlvbihcbiAgICBwYWdlczogUGFnaW5hdGlvbkl0ZW1bXSxcbiAgICBwYWdlQ291bnQ6IG51bWJlcixcbiAgICBjdXJyZW50OiBudW1iZXJcbiAgKTogdm9pZCB7XG4gICAgY29uc3QgYmVmb3JlID0gdGhpcy5nZXRCZWZvcmVMaW5rcyhjdXJyZW50KTtcbiAgICBjb25zdCBhZnRlciA9IHRoaXMuZ2V0QWZ0ZXJMaW5rcyhwYWdlQ291bnQsIGN1cnJlbnQpO1xuICAgIGNvbnN0IHBvcyA9IHRoaXMuY29uZmlnLm5hdmlnYXRpb25Qb3NpdGlvbjtcbiAgICBpZiAoIXBvcyB8fCBwb3MgPT09IFBhZ2luYXRpb25OYXZpZ2F0aW9uUG9zaXRpb24uQVNJREUpIHtcbiAgICAgIHBhZ2VzLnVuc2hpZnQoLi4uYmVmb3JlKTtcbiAgICAgIHBhZ2VzLnB1c2goLi4uYWZ0ZXIpO1xuICAgIH0gZWxzZSB7XG4gICAgICBpZiAocG9zID09PSBQYWdpbmF0aW9uTmF2aWdhdGlvblBvc2l0aW9uLkJFRk9SRSkge1xuICAgICAgICBwYWdlcy51bnNoaWZ0KC4uLmJlZm9yZSwgLi4uYWZ0ZXIpO1xuICAgICAgfVxuICAgICAgaWYgKHBvcyA9PT0gUGFnaW5hdGlvbk5hdmlnYXRpb25Qb3NpdGlvbi5BRlRFUikge1xuICAgICAgICBwYWdlcy5wdXNoKC4uLmJlZm9yZSwgLi4uYWZ0ZXIpO1xuICAgICAgfVxuICAgIH1cbiAgfVxuXG4gIC8qKlxuICAgKiBSZXR1cm5zIHRoZSBzdGFydCBhbmQgcHJldmlvdXMgbGlua3MsIGlmIGFwcGxpY2FibGUuXG4gICAqL1xuICBwcm90ZWN0ZWQgZ2V0QmVmb3JlTGlua3MoY3VycmVudDogbnVtYmVyKTogUGFnaW5hdGlvbkl0ZW1bXSB7XG4gICAgY29uc3QgbGlzdCA9IFtdO1xuXG4gICAgaWYgKHRoaXMuY29uZmlnLmFkZFN0YXJ0KSB7XG4gICAgICBjb25zdCBzdGFydCA9ICgpID0+IHtcbiAgICAgICAgcmV0dXJuIE9iamVjdC5hc3NpZ24oXG4gICAgICAgICAge1xuICAgICAgICAgICAgbGFiZWw6IHRoaXMuY29uZmlnLnN0YXJ0TGFiZWwsXG4gICAgICAgICAgICB0eXBlOiBQYWdpbmF0aW9uSXRlbVR5cGUuU1RBUlQsXG4gICAgICAgICAgfSxcbiAgICAgICAgICBjdXJyZW50ID4gMCA/IHsgbnVtYmVyOiAwIH0gOiBudWxsXG4gICAgICAgICk7XG4gICAgICB9O1xuICAgICAgbGlzdC5wdXNoKHN0YXJ0KCkpO1xuICAgIH1cbiAgICBpZiAodGhpcy5jb25maWcuYWRkUHJldmlvdXMpIHtcbiAgICAgIGNvbnN0IHByZXZpb3VzID0gKCkgPT4ge1xuICAgICAgICByZXR1cm4gT2JqZWN0LmFzc2lnbihcbiAgICAgICAgICB7XG4gICAgICAgICAgICBsYWJlbDogdGhpcy5jb25maWcucHJldmlvdXNMYWJlbCxcbiAgICAgICAgICAgIHR5cGU6IFBhZ2luYXRpb25JdGVtVHlwZS5QUkVWSU9VUyxcbiAgICAgICAgICB9LFxuICAgICAgICAgIGN1cnJlbnQgPiAwID8geyBudW1iZXI6IGN1cnJlbnQgLSAxIH0gOiBudWxsXG4gICAgICAgICk7XG4gICAgICB9O1xuICAgICAgbGlzdC5wdXNoKHByZXZpb3VzKCkpO1xuICAgIH1cbiAgICByZXR1cm4gbGlzdDtcbiAgfVxuXG4gIC8qKlxuICAgKiBSZXR1cm5zIHRoZSBuZXh0IGFuZCBlbmQgbGlua3MsIGlmIGFwcGxpY2FibGUuXG4gICAqL1xuICBwcm90ZWN0ZWQgZ2V0QWZ0ZXJMaW5rcyhcbiAgICBwYWdlQ291bnQ6IG51bWJlcixcbiAgICBjdXJyZW50OiBudW1iZXJcbiAgKTogUGFnaW5hdGlvbkl0ZW1bXSB7XG4gICAgY29uc3QgbGlzdCA9IFtdO1xuXG4gICAgaWYgKHRoaXMuY29uZmlnLmFkZE5leHQpIHtcbiAgICAgIGNvbnN0IG5leHQgPSAoKSA9PiB7XG4gICAgICAgIHJldHVybiBPYmplY3QuYXNzaWduKFxuICAgICAgICAgIHtcbiAgICAgICAgICAgIGxhYmVsOiB0aGlzLmNvbmZpZy5uZXh0TGFiZWwsXG4gICAgICAgICAgICB0eXBlOiBQYWdpbmF0aW9uSXRlbVR5cGUuTkVYVCxcbiAgICAgICAgICB9LFxuICAgICAgICAgIGN1cnJlbnQgPCBwYWdlQ291bnQgLSAxID8geyBudW1iZXI6IGN1cnJlbnQgKyAxIH0gOiBudWxsXG4gICAgICAgICk7XG4gICAgICB9O1xuICAgICAgbGlzdC5wdXNoKG5leHQoKSk7XG4gICAgfVxuICAgIGlmICh0aGlzLmNvbmZpZy5hZGRFbmQpIHtcbiAgICAgIGNvbnN0IGVuZCA9ICgpID0+IHtcbiAgICAgICAgcmV0dXJuIE9iamVjdC5hc3NpZ24oXG4gICAgICAgICAge1xuICAgICAgICAgICAgbGFiZWw6IHRoaXMuY29uZmlnLmVuZExhYmVsLFxuICAgICAgICAgICAgdHlwZTogUGFnaW5hdGlvbkl0ZW1UeXBlLkVORCxcbiAgICAgICAgICB9LFxuICAgICAgICAgIGN1cnJlbnQgPCBwYWdlQ291bnQgLSAxID8geyBudW1iZXI6IHBhZ2VDb3VudCAtIDEgfSA6IG51bGxcbiAgICAgICAgKTtcbiAgICAgIH07XG4gICAgICBsaXN0LnB1c2goZW5kKCkpO1xuICAgIH1cblxuICAgIHJldHVybiBsaXN0O1xuICB9XG4gIC8qKlxuICAgKiBSZXNvbHZlcyB0aGUgZmlyc3QgcGFnZSBvZiB0aGUgcmFuZ2Ugd2UgbmVlZCB0byBidWlsZC5cbiAgICogVGhpcyBpcyB0aGUgcGFnZSB0aGF0IGlzIGxlYWRpbmcgdXAgdG8gdGhlIHJhbmdlIG9mIHRoZVxuICAgKiBjdXJyZW50IHBhZ2UuXG4gICAqXG4gICAqIEBwYXJhbSBwYWdlQ291bnQgVGhlIHRvdGFsIG51bWJlciBvZiBwYWdlcy5cbiAgICogQHBhcmFtIGN1cnJlbnQgVGhlIGN1cnJlbnQgcGFnZSBudW1iZXIsIDAtaW5kZXggYmFzZWQuXG4gICAqL1xuICBwcm90ZWN0ZWQgZ2V0U3RhcnRPZlJhbmdlKHBhZ2VDb3VudDogbnVtYmVyLCBjdXJyZW50OiBudW1iZXIpOiBudW1iZXIge1xuICAgIGNvbnN0IGNvdW50ID0gdGhpcy5jb25maWcucmFuZ2VDb3VudCAtIDE7XG4gICAgLy8gdGhlIGxlYXN0IG51bWJlciBvZiBwYWdlcyBiZWZvcmUgYW5kIGFmdGVyIHRoZSBjdXJyZW50XG4gICAgY29uc3QgZGVsdGEgPSBNYXRoLnJvdW5kKGNvdW50IC8gMik7XG5cbiAgICAvLyBlbnN1cmUgdGhhdCB3ZSBzdGFydCB3aXRoIGF0IGxlYXN0IHRoZSBmaXJzdCBwYWdlXG4gICAgY29uc3QgbWluU3RhcnQgPSBNYXRoLm1heCgwLCBjdXJyZW50IC0gZGVsdGEpO1xuICAgIC8vIGVuc3VyZXMgdGhhdCB3ZSBzdGFydCB3aXRoIGF0IGxlYXN0IDEgYW5kIGRvIG5vdCBwYXNzIHRoZSBsYXN0IHJhbmdlXG4gICAgY29uc3QgbWF4U3RhcnQgPSBNYXRoLm1heCgwLCBwYWdlQ291bnQgLSBjb3VudCAtIDEpO1xuXG4gICAgLy8gZW5zdXJlIHRoYXQgd2UgZ2V0IGF0IGxlYXN0IGEgZnVsbCByYW5nZSBhdCB0aGUgZW5kXG4gICAgcmV0dXJuIE1hdGgubWluKG1heFN0YXJ0LCBtaW5TdGFydCk7XG4gIH1cblxuICAvKipcbiAgICogUmV0dXJucyB0aGUgcGFnaW5hdGlvbiBjb25maWd1cmF0aW9uLiBUaGUgY29uZmlndXJhdGlvbiBpcyBkcml2ZW4gYnkgdGhlXG4gICAqIChkZWZhdWx0KSBhcHBsaWNhdGlvbiBjb25maWd1cmF0aW9uLlxuICAgKlxuICAgKiBUaGUgZGVmYXVsdCBhcHBsaWNhdGlvbiBpcyBsaW1pdGVkIHRvIGFkZGluZyB0aGUgc3RhcnQgYW5kIGVuZCBsaW5rOlxuICAgKiBgYGB0c1xuICAgKiAgIGFkZFN0YXJ0OiB0cnVlLFxuICAgKiAgIGFkZEVuZDogdHJ1ZVxuICAgKiBgYGBcbiAgICpcbiAgICogVGhlIGFwcGxpY2F0aW9uIGNvbmZpZ3VyYXRpb24gaXMgaG93ZXZlciBtZXJnZWQgaW50byB0aGUgZm9sbG93aW5nIHN0YXRpYyBjb25maWd1cmF0aW9uOlxuICAgKiBgYGB0c1xuICAgKiB7XG4gICAqICAgcmFuZ2VDb3VudDogMyxcbiAgICogICBkb3RzTGFiZWw6ICcuLi4nLFxuICAgKiAgIHN0YXJ0TGFiZWw6ICfCqycsXG4gICAqICAgcHJldmlvdXNMYWJlbDogJ+KAuScsXG4gICAqICAgbmV4dExhYmVsOiAn4oC6JyxcbiAgICogICBlbmRMYWJlbDogJ8K7J1xuICAgKiB9XG4gICAqIGBgYFxuICAgKi9cbiAgcHJvdGVjdGVkIGdldCBjb25maWcoKTogUGFnaW5hdGlvbk9wdGlvbnMge1xuICAgIHJldHVybiBPYmplY3QuYXNzaWduKFxuICAgICAgRkFMTEJBQ0tfUEFHSU5BVElPTl9PUFRJT05TLFxuICAgICAgdGhpcy5wYWdpbmF0aW9uQ29uZmlnLnBhZ2luYXRpb25cbiAgICApO1xuICB9XG59XG4iXX0=