UNPKG

@bespunky/angular-zen

Version:

The Angular tools you always wished were there.

195 lines 27.7 kB
import { Inject, Injectable } from '@angular/core'; import { UrlReflectionService } from '@bespunky/angular-zen/router-x'; import { LanguageIntegrationService } from '../../services/language-integration.service'; import { UrlLocalization } from '../config/url-localization-config'; import { UrlLocalizer } from './url-localizer'; import * as i0 from "@angular/core"; import * as i1 from "@bespunky/angular-zen/router-x"; import * as i2 from "../../services/language-integration.service"; /** * Provides tools for localization and delocalization of the currently navigated url by adding or removing * a route segment dedicated for language. * * @export * @class RoutePositionUrlLocalizer * @extends {UrlLocalizer} */ export class RoutePositionUrlLocalizer extends UrlLocalizer { constructor({ strategy }, urlReflection, language) { super(urlReflection); this.language = language; this.position = strategy; } /** * Localizes the currently navigated url by adding or updating the language segment of the route. * If `position` is positive, language lookup will be performed from the beginning of route. * If `position` is negative, language lookup will be performed from the end of route. * If `position` points to an index out of bounds, the last/first element will be treated as the language. * * #### Example * Position 1 - /en/some/route - first segment from the left. * Position 2 - /some/en/route - second segment from the left. * Position 5 - /some/route/en - out of bounds. last segment from the left. * * Position -1 - /some/route/en - first segment from the right. * Position -2 - /some/en/route - second segment from the right. * Position -5 - /en/some/route - out of bounds. last segment from the right. * * @param {string} lang * @returns {string} The currently navigated url localized to the specified language. */ localize(lang) { return this.transformUrl((segments, langIndex, isLanguage) => this.insertOrReplaceLanguage(lang, segments, langIndex, isLanguage)); } /** * Delocalizes the currently navigated url by removing the language segment from the route. * If `position` is positive, language lookup will be performed from the beginning of route. * If `position` is negative, language lookup will be performed from the end of route. * If `position` points to an index out of bounds, the last/first element will be treated as the language. * If no language exists at the language position, returns the url unchanged. * * #### Example * Position 1 - /en/some/route - first segment from the left. * Position 2 - /some/en/route - second segment from the left. * Position 5 - /some/route/en - out of bounds. last segment from the left. * * Position -1 - /some/route/en - first segment from the right. * Position -2 - /some/en/route - second segment from the right. * Position -5 - /en/some/route - out of bounds. last segment from the right. * * @returns {string} The delocalized currently navigated url. */ delocalize() { return this.transformUrl((segments, langIndex, isLanguage) => this.removeLanguage(segments, langIndex, isLanguage), // When removing the language segment, the index should always be in range. Unlike when inserting, an overflowing index // will not be converted to the last index automatically by `.splice()`. (segments, langIndex) => langIndex >= segments.length ? segments.length - 1 : langIndex); } transformUrl(transform, sanitizeIndex) { // Position of zero will not touch the url as zero's functionality is not defined if (this.position === 0) return this.urlReflection.fullUrl; const segments = this.urlReflection.routeSegments; // Convert the position to replace/add to an index (might result in large negatives or positives, exceeding array bounds) let langIndex = this.indexOfPosition(); this.accessSegmentsSafely(segments, () => { if (sanitizeIndex) langIndex = sanitizeIndex(segments, langIndex); // Determine if a language segment exists at the specified index const isLanguage = this.isLanguage(segments[langIndex]); return transform(segments, langIndex, isLanguage); }); return this.composeUrl(segments); } /** * Updates the specified route segments array with the specified language. * * @protected * @param {string} lang The new language to set to the route. * @param {string[]} segments The current route segments. * @param {number} langIndex The index of the expected language segment. * @param {boolean} isLanguage `true` if the current value at `langIndex` is a supported language; otherwise `false`. */ insertOrReplaceLanguage(lang, segments, langIndex, isLanguage) { // Define how many items to remove. If the segment is already a language and should be replaced, zero items should be removed. const deleteCount = isLanguage ? 1 : 0; // Replace existing language segment or add a new one. If the specified index exceeds the length of the array, splice will add a new item at the end/beginning of the array. segments.splice(langIndex, deleteCount, lang); } /** * Removes the language segment from a route segments array. * If the language index points to a non-language segment, returns without changing the segments. * * @protected * @param {string[]} segments The current route segments. * @param {number} langIndex The index of the expected langauge segment. * @param {boolean} isLanguage `true` if the current value at `langIndex` is a supported language; otherwise `false`. */ removeLanguage(segments, langIndex, isLanguage) { if (!isLanguage) return; segments.splice(langIndex, 1); } /** * Accessing segments by index requires the `this.position` to be translated into an index. * As the position can either be positive or negative, there are two different formulas for index calculation. * In turn, this means two different scenarios with different edge cases. * * To unify the cases and reduce complexity, when position is negative, this method reverses the segments array, runs the segments manipulation, then reverses it again to restore the original order. * This way the indexing is always done from one side of the array. * * @protected * @param {string[]} segments The segments about to be manipulated. * @param {() => void} accessSegments The function that needs safe access by index to the */ accessSegmentsSafely(segments, accessSegments) { if (this.isNegativeLookup) segments.reverse(); accessSegments(); if (this.isNegativeLookup) segments.reverse(); } /** * Indicates whether the configured language position is positive, resulting in a lookup from the left (positive lookup). * `true` if positive lookup should be performed; otherwise `false`. * * @readonly * @protected * @type {boolean} */ get isPositiveLookup() { return this.position > 0; } /** * Indicates whether the configured language position is negative, resulting in a lookup from the right (negative lookup). * `true` if negative lookup should be performed; otherwise `false`. * * @readonly * @protected * @type {boolean} */ get isNegativeLookup() { return this.position < 0; } /** * Calculates the absolute index for the configured language position. * * @protected * @returns {number} */ indexOfPosition() { return Math.abs(this.position) - 1; } /** * Checks whether the specified value is a language supported by the language integration services. * * @protected * @param {string} value The value to check. * @returns {boolean} `true` if the value is a supported language; otherwise `false`. */ isLanguage(value) { return this.language.supported?.includes(value) || false; } /** * Concats the host url as given by the url reflection service with the segments and the current query string to create * a fully qualified url. * * @protected * @param {string[]} segments The route segments to place in the url. * @returns {string} The fully qualified url composed of the host url as given by the url reflection service, the specified route segments, and the current query params. */ composeUrl(segments) { const { hostUrl, queryString } = this.urlReflection; return `${hostUrl}/${segments.join('/')}${queryString}`; } } RoutePositionUrlLocalizer.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.2.12", ngImport: i0, type: RoutePositionUrlLocalizer, deps: [{ token: UrlLocalization }, { token: i1.UrlReflectionService }, { token: i2.LanguageIntegrationService }], target: i0.ɵɵFactoryTarget.Injectable }); RoutePositionUrlLocalizer.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "14.2.12", ngImport: i0, type: RoutePositionUrlLocalizer, providedIn: 'root' }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.2.12", ngImport: i0, type: RoutePositionUrlLocalizer, decorators: [{ type: Injectable, args: [{ providedIn: 'root' }] }], ctorParameters: function () { return [{ type: undefined, decorators: [{ type: Inject, args: [UrlLocalization] }] }, { type: i1.UrlReflectionService }, { type: i2.LanguageIntegrationService }]; } }); //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicm91dGUtcG9zaXRpb24tdXJsLWxvY2FsaXplci5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uLy4uLy4uLy4uL2xpYnMvYW5ndWxhci16ZW4vbGFuZ3VhZ2Uvc3JjL3VybC1sb2NhbGl6YXRpb24vbG9jYWxpemVycy9yb3V0ZS1wb3NpdGlvbi11cmwtbG9jYWxpemVyLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sRUFBRSxNQUFNLEVBQUUsVUFBVSxFQUFFLE1BQU0sZUFBZSxDQUFDO0FBRW5ELE9BQU8sRUFBRSxvQkFBb0IsRUFBb0IsTUFBTSxnQ0FBZ0MsQ0FBQztBQUN4RixPQUFPLEVBQUUsMEJBQTBCLEVBQWMsTUFBTSw2Q0FBNkMsQ0FBQztBQUNyRyxPQUFPLEVBQUUsZUFBZSxFQUF5QixNQUFNLG1DQUFtQyxDQUFDO0FBQzNGLE9BQU8sRUFBRSxZQUFZLEVBQTRCLE1BQU0saUJBQWlCLENBQUM7Ozs7QUFFekU7Ozs7Ozs7R0FPRztBQUVILE1BQU0sT0FBTyx5QkFBMEIsU0FBUSxZQUFZO0lBWXZELFlBQzZCLEVBQUUsUUFBUSxFQUE0QixFQUNwQyxhQUFtQyxFQUNuQyxRQUF5QztRQUdwRSxLQUFLLENBQUMsYUFBYSxDQUFDLENBQUM7UUFITSxhQUFRLEdBQVIsUUFBUSxDQUFpQztRQUtwRSxJQUFJLENBQUMsUUFBUSxHQUFHLFFBQWtCLENBQUM7SUFDdkMsQ0FBQztJQUVEOzs7Ozs7Ozs7Ozs7Ozs7OztPQWlCRztJQUNILFFBQVEsQ0FBQyxJQUFZO1FBRWpCLE9BQU8sSUFBSSxDQUFDLFlBQVksQ0FDcEIsQ0FBQyxRQUFRLEVBQUUsU0FBUyxFQUFFLFVBQVUsRUFBRSxFQUFFLENBQUMsSUFBSSxDQUFDLHVCQUF1QixDQUFDLElBQUksRUFBRSxRQUFRLEVBQUUsU0FBUyxFQUFFLFVBQVUsQ0FBQyxDQUMzRyxDQUFDO0lBQ04sQ0FBQztJQUVEOzs7Ozs7Ozs7Ozs7Ozs7OztPQWlCRztJQUNILFVBQVU7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RUFBRSxRQUFRLENBQUMsS0FBSyxDQUFDLElBQUksS0FBSyxDQUFDO0lBQzdELENBQUM7SUFFRDs7Ozs7OztPQU9HO0lBQ08sVUFBVSxDQUFDLFFBQWtCO1FBRW5DLE1BQU0sRUFBRSxPQUFPLEVBQUUsV0FBVyxFQUFFLEdBQUcsSUFBSSxDQUFDLGFBQWEsQ0FBQztRQUVwRCxPQUFPLEdBQUcsT0FBTyxJQUFJLFFBQVEsQ0FBQyxJQUFJLENBQUMsR0FBRyxDQUFDLEdBQUcsV0FBVyxFQUFFLENBQUE7SUFDM0QsQ0FBQzs7dUhBdE5RLHlCQUF5QixrQkFhdEIsZUFBZTsySEFibEIseUJBQXlCLGNBRFosTUFBTTs0RkFDbkIseUJBQXlCO2tCQURyQyxVQUFVO21CQUFDLEVBQUUsVUFBVSxFQUFFLE1BQU0sRUFBQzs7MEJBY3hCLE1BQU07MkJBQUMsZUFBZSIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IEluamVjdCwgSW5qZWN0YWJsZSB9IGZyb20gJ0Bhbmd1bGFyL2NvcmUnO1xuXG5pbXBvcnQgeyBVcmxSZWZsZWN0aW9uU2VydmljZSAgICAgICAgICAgICAgICAgICB9IGZyb20gJ0BiZXNwdW5reS9hbmd1bGFyLXplbi9yb3V0ZXIteCc7XG5pbXBvcnQgeyBMYW5ndWFnZUludGVncmF0aW9uU2VydmljZSAgICAgICAgICAgICB9IGZyb20gJy4uLy4uL3NlcnZpY2VzL2xhbmd1YWdlLWludGVncmF0aW9uLnNlcnZpY2UnO1xuaW1wb3J0IHsgVXJsTG9jYWxpemF0aW9uLCBVcmxMb2NhbGl6YXRpb25Db25maWcgfSBmcm9tICcuLi9jb25maWcvdXJsLWxvY2FsaXphdGlvbi1jb25maWcnO1xuaW1wb3J0IHsgVXJsTG9jYWxpemVyICAgICAgICAgICAgICAgICAgICAgICAgICAgfSBmcm9tICcuL3VybC1sb2NhbGl6ZXInO1xuXG4vKipcbiAqIFByb3ZpZGVzIHRvb2xzIGZvciBsb2NhbGl6YXRpb24gYW5kIGRlbG9jYWxpemF0aW9uIG9mIHRoZSBjdXJyZW50bHkgbmF2aWdhdGVkIHVybCBieSBhZGRpbmcgb3IgcmVtb3ZpbmdcbiAqIGEgcm91dGUgc2VnbWVudCBkZWRpY2F0ZWQgZm9yIGxhbmd1YWdlLlxuICpcbiAqIEBleHBvcnRcbiAqIEBjbGFzcyBSb3V0ZVBvc2l0aW9uVXJsTG9jYWxpemVyXG4gKiBAZXh0ZW5kcyB7VXJsTG9jYWxpemVyfVxuICovXG5ASW5qZWN0YWJsZSh7IHByb3ZpZGVkSW46ICdyb290J30pXG5leHBvcnQgY2xhc3MgUm91dGVQb3NpdGlvblVybExvY2FsaXplciBleHRlbmRzIFVybExvY2FsaXplclxue1xuICAgIC8qKlxuICAgICAqIFRoZSBwb3NpdGlvbiBvZiB0aGUgbGFuZ3VhZ2Ugc2VnbWVudCBpbiB0aGUgcm91dGUgb2YgdGhlIGN1cnJlbnRseSBuYXZpZ2F0ZWQgdXJsLlxuICAgICAqIFBvc2l0aXZlIG51bWJlcnMgaW5kaWNhdGUgcG9zaXRpb24gZnJvbSB0aGUgYmVnaW5uaW5nIG9mIHRoZSByb3V0ZS5cbiAgICAgKiBOZWdhdGl2ZSBudW1iZXJzIGluZGljYXRlIHBvc2l0aW9uIGZyb20gdGhlIGVuZCBvZiB0aGUgcm91dGUuXG4gICAgICogWmVybyBpcyBpZ25vcmVkIGFuZCB3aWxsIGNhdXNlIG1ldGhvZHMgdG8gcmV0dXJuIGFuIHVuY2hhbmdlZCB1cmwuXG4gICAgICogXG4gICAgICogQHR5cGUge251bWJlcn1cbiAgICAgKi9cbiAgICBwdWJsaWMgcmVhZG9ubHkgcG9zaXRpb246IG51bWJlcjtcblxuICAgIGNvbnN0cnVjdG9yKFxuICAgICAgICBASW5qZWN0KFVybExvY2FsaXphdGlvbikgeyBzdHJhdGVneSB9ICAgOiBVcmxMb2NhbGl6YXRpb25Db25maWcsXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHVybFJlZmxlY3Rpb246IFVybFJlZmxlY3Rpb25TZXJ2aWNlLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgcHJpdmF0ZSBsYW5ndWFnZSAgICAgOiBMYW5ndWFnZUludGVncmF0aW9uU2VydmljZVxuICAgIClcbiAgICB7XG4gICAgICAgIHN1cGVyKHVybFJlZmxlY3Rpb24pO1xuXG4gICAgICAgIHRoaXMucG9zaXRpb24gPSBzdHJhdGVneSBhcyBudW1iZXI7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogTG9jYWxpemVzIHRoZSBjdXJyZW50bHkgbmF2aWdhdGVkIHVybCBieSBhZGRpbmcgb3IgdXBkYXRpbmcgdGhlIGxhbmd1YWdlIHNlZ21lbnQgb2YgdGhlIHJvdXRlLlxuICAgICAqIElmIGBwb3NpdGlvbmAgaXMgcG9zaXRpdmUsIGxhbmd1YWdlIGxvb2t1cCB3aWxsIGJlIHBlcmZvcm1lZCBmcm9tIHRoZSBiZWdpbm5pbmcgb2Ygcm91dGUuXG4gICAgICogSWYgYHBvc2l0aW9uYCBpcyBuZWdhdGl2ZSwgbGFuZ3VhZ2UgbG9va3VwIHdpbGwgYmUgcGVyZm9ybWVkIGZyb20gdGhlIGVuZCBvZiByb3V0ZS5cbiAgICAgKiBJZiBgcG9zaXRpb25gIHBvaW50cyB0byBhbiBpbmRleCBvdXQgb2YgYm91bmRzLCB0aGUgbGFzdC9maXJzdCBlbGVtZW50IHdpbGwgYmUgdHJlYXRlZCBhcyB0aGUgbGFuZ3VhZ2UuXG4gICAgICpcbiAgICAgKiAjIyMjIEV4YW1wbGVcbiAgICAgKiBQb3NpdGlvbiAgMSAtIC9lbi9zb21lL3JvdXRlIC0gZmlyc3Qgc2VnbWVudCBmcm9tIHRoZSBsZWZ0LiAgXG4gICAgICogUG9zaXRpb24gIDIgLSAvc29tZS9lbi9yb3V0ZSAtIHNlY29uZCBzZWdtZW50IGZyb20gdGhlIGxlZnQuICBcbiAgICAgKiBQb3NpdGlvbiAgNSAtIC9zb21lL3JvdXRlL2VuIC0gb3V0IG9mIGJvdW5kcy4gbGFzdCBzZWdtZW50IGZyb20gdGhlIGxlZnQuICBcbiAgICAgKiAgIFxuICAgICAqIFBvc2l0aW9uIC0xIC0gL3NvbWUvcm91dGUvZW4gLSBmaXJzdCBzZWdtZW50IGZyb20gdGhlIHJpZ2h0LiAgXG4gICAgICogUG9zaXRpb24gLTIgLSAvc29tZS9lbi9yb3V0ZSAtIHNlY29uZCBzZWdtZW50IGZyb20gdGhlIHJpZ2h0LiAgXG4gICAgICogUG9zaXRpb24gLTUgLSAvZW4vc29tZS9yb3V0ZSAtIG91dCBvZiBib3VuZHMuIGxhc3Qgc2VnbWVudCBmcm9tIHRoZSByaWdodC4gIFxuICAgICAqIFxuICAgICAqIEBwYXJhbSB7c3RyaW5nfSBsYW5nXG4gICAgICogQHJldHVybnMge3N0cmluZ30gVGhlIGN1cnJlbnRseSBuYXZpZ2F0ZWQgdXJsIGxvY2FsaXplZCB0byB0aGUgc3BlY2lmaWVkIGxhbmd1YWdlLlxuICAgICAqL1xuICAgIGxvY2FsaXplKGxhbmc6IHN0cmluZyk6IHN0cmluZ1xuICAgIHtcbiAgICAgICAgcmV0dXJuIHRoaXMudHJhbnNmb3JtVXJsKFxuICAgICAgICAgICAgKHNlZ21lbnRzLCBsYW5nSW5kZXgsIGlzTGFuZ3VhZ2UpID0+IHRoaXMuaW5zZXJ0T3JSZXBsYWNlTGFuZ3VhZ2UobGFuZywgc2VnbWVudHMsIGxhbmdJbmRleCwgaXNMYW5ndWFnZSlcbiAgICAgICAgKTtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBEZWxvY2FsaXplcyB0aGUgY3VycmVudGx5IG5hdmlnYXRlZCB1cmwgYnkgcmVtb3ZpbmcgdGhlIGxhbmd1YWdlIHNlZ21lbnQgZnJvbSB0aGUgcm91dGUuXG4gICAgICogSWYgYHBvc2l0aW9uYCBpcyBwb3NpdGl2ZSwgbGFuZ3VhZ2UgbG9va3VwIHdpbGwgYmUgcGVyZm9ybWVkIGZyb20gdGhlIGJlZ2lubmluZyBvZiByb3V0ZS5cbiAgICAgKiBJZiBgcG9zaXRpb25gIGlzIG5lZ2F0aXZlLCBsYW5ndWFnZSBsb29rdXAgd2lsbCBiZSBwZXJmb3JtZWQgZnJvbSB0aGUgZW5kIG9mIHJvdXRlLlxuICAgICAqIElmIGBwb3NpdGlvbmAgcG9pbnRzIHRvIGFuIGluZGV4IG91dCBvZiBib3VuZHMsIHRoZSBsYXN0L2ZpcnN0IGVsZW1lbnQgd2lsbCBiZSB0cmVhdGVkIGFzIHRoZSBsYW5ndWFnZS5cbiAgICAgKiBJZiBubyBsYW5ndWFnZSBleGlzdHMgYXQgdGhlIGxhbmd1YWdlIHBvc2l0aW9uLCByZXR1cm5zIHRoZSB1cmwgdW5jaGFuZ2VkLlxuICAgICAqXG4gICAgICogIyMjIyBFeGFtcGxlXG4gICAgICogUG9zaXRpb24gIDEgLSAvZW4vc29tZS9yb3V0ZSAtIGZpcnN0IHNlZ21lbnQgZnJvbSB0aGUgbGVmdC4gIFxuICAgICAqIFBvc2l0aW9uICAyIC0gL3NvbWUvZW4vcm91dGUgLSBzZWNvbmQgc2VnbWVudCBmcm9tIHRoZSBsZWZ0LiAgXG4gICAgICogUG9zaXRpb24gIDUgLSAvc29tZS9yb3V0ZS9lbiAtIG91dCBvZiBib3VuZHMuIGxhc3Qgc2VnbWVudCBmcm9tIHRoZSBsZWZ0LiAgXG4gICAgICogICBcbiAgICAgKiBQb3NpdGlvbiAtMSAtIC9zb21lL3JvdXRlL2VuIC0gZmlyc3Qgc2VnbWVudCBmcm9tIHRoZSByaWdodC4gIFxuICAgICAqIFBvc2l0aW9uIC0yIC0gL3NvbWUvZW4vcm91dGUgLSBzZWNvbmQgc2VnbWVudCBmcm9tIHRoZSByaWdodC4gIFxuICAgICAqIFBvc2l0aW9uIC01IC0gL2VuL3NvbWUvcm91dGUgLSBvdXQgb2YgYm91bmRzLiBsYXN0IHNlZ21lbnQgZnJvbSB0aGUgcmlnaHQuICBcbiAgICAgKiBcbiAgICAgKiBAcmV0dXJucyB7c3RyaW5nfSBUaGUgZGVsb2NhbGl6ZWQgY3VycmVudGx5IG5hdmlnYXRlZCB1cmwuXG4gICAgICovXG4gICAgZGVsb2NhbGl6ZSgpOiBzdHJpbmdcbiAgICB7XG4gICAgICAgIHJldHVybiB0aGlzLnRyYW5zZm9ybVVybChcbiAgICAgICAgICAgIChzZWdtZW50cywgbGFuZ0luZGV4LCBpc0xhbmd1YWdlKSA9PiB0aGlzLnJlbW92ZUxhbmd1YWdlKHNlZ21lbnRzLCBsYW5nSW5kZXgsIGlzTGFuZ3VhZ2UpLFxuICAgICAgICAgICAgLy8gV2hlbiByZW1vdmluZyB0aGUgbGFuZ3VhZ2Ugc2VnbWVudCwgdGhlIGluZGV4IHNob3VsZCBhbHdheXMgYmUgaW4gcmFuZ2UuIFVubGlrZSB3aGVuIGluc2VydGluZywgYW4gb3ZlcmZsb3dpbmcgaW5kZXhcbiAgICAgICAgICAgIC8vIHdpbGwgbm90IGJlIGNvbnZlcnRlZCB0byB0aGUgbGFzdCBpbmRleCBhdXRvbWF0aWNhbGx5IGJ5IGAuc3BsaWNlKClgLlxuICAgICAgICAgICAgKHNlZ21lbnRzLCBsYW5nSW5kZXggICAgICAgICAgICApID0+IGxhbmdJbmRleCA+PSBzZWdtZW50cy5sZW5ndGggPyBzZWdtZW50cy5sZW5ndGggLSAxOiBsYW5nSW5kZXhcbiAgICAgICAgKTtcbiAgICB9XG4gICAgXG4gICAgcHJpdmF0ZSB0cmFuc2Zvcm1VcmwodHJhbnNmb3JtOiAoc2VnbWVudHM6IHN0cmluZ1tdLCBsYW5nSW5kZXg6IG51bWJlciwgaXNMYW5ndWFnZTogYm9vbGVhbikgPT4gdm9pZCwgc2FuaXRpemVJbmRleD86IChzZWdtZW50czogc3RyaW5nW10sIGxhbmdJbmRleDogbnVtYmVyKSA9PiBudW1iZXIpOiBzdHJpbmdcbiAgICB7XG4gICAgICAgIC8vIFBvc2l0aW9uIG9mIHplcm8gd2lsbCBub3QgdG91Y2ggdGhlIHVybCBhcyB6ZXJvJ3MgZnVuY3Rpb25hbGl0eSBpcyBub3QgZGVmaW5lZFxuICAgICAgICBpZiAodGhpcy5wb3NpdGlvbiA9PT0gMCkgcmV0dXJuIHRoaXMudXJsUmVmbGVjdGlvbi5mdWxsVXJsO1xuXG4gICAgICAgIGNvbnN0IHNlZ21lbnRzID0gdGhpcy51cmxSZWZsZWN0aW9uLnJvdXRlU2VnbWVudHM7XG4gICAgICAgIC8vIENvbnZlcnQgdGhlIHBvc2l0aW9uIHRvIHJlcGxhY2UvYWRkIHRvIGFuIGluZGV4IChtaWdodCByZXN1bHQgaW4gbGFyZ2UgbmVnYXRpdmVzIG9yIHBvc2l0aXZlcywgZXhjZWVkaW5nIGFycmF5IGJvdW5kcylcbiAgICAgICAgbGV0IGxhbmdJbmRleCAgPSB0aGlzLmluZGV4T2ZQb3NpdGlvbigpO1xuICAgICAgICBcbiAgICAgICAgdGhpcy5hY2Nlc3NTZWdtZW50c1NhZmVseShzZWdtZW50cywgKCkgPT5cbiAgICAgICAge1xuICAgICAgICAgICAgaWYgKHNhbml0aXplSW5kZXgpIGxhbmdJbmRleCA9IHNhbml0aXplSW5kZXgoc2VnbWVudHMsIGxhbmdJbmRleCk7XG4gICAgICAgICAgICAvLyBEZXRlcm1pbmUgaWYgYSBsYW5ndWFnZSBzZWdtZW50IGV4aXN0cyBhdCB0aGUgc3BlY2lmaWVkIGluZGV4XG4gICAgICAgICAgICBjb25zdCBpc0xhbmd1YWdlID0gdGhpcy5pc0xhbmd1YWdlKHNlZ21lbnRzW2xhbmdJbmRleF0pO1xuXG4gICAgICAgICAgICByZXR1cm4gdHJhbnNmb3JtKHNlZ21lbnRzLCBsYW5nSW5kZXgsIGlzTGFuZ3VhZ2UpO1xuICAgICAgICB9KTtcblxuICAgICAgICByZXR1cm4gdGhpcy5jb21wb3NlVXJsKHNlZ21lbnRzKTtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBVcGRhdGVzIHRoZSBzcGVjaWZpZWQgcm91dGUgc2VnbWVudHMgYXJyYXkgd2l0aCB0aGUgc3BlY2lmaWVkIGxhbmd1YWdlLlxuICAgICAqXG4gICAgICogQHByb3RlY3RlZFxuICAgICAqIEBwYXJhbSB7c3RyaW5nfSBsYW5nIFRoZSBuZXcgbGFuZ3VhZ2UgdG8gc2V0IHRvIHRoZSByb3V0ZS5cbiAgICAgKiBAcGFyYW0ge3N0cmluZ1tdfSBzZWdtZW50cyBUaGUgY3VycmVudCByb3V0ZSBzZWdtZW50cy5cbiAgICAgKiBAcGFyYW0ge251bWJlcn0gbGFuZ0luZGV4IFRoZSBpbmRleCBvZiB0aGUgZXhwZWN0ZWQgbGFuZ3VhZ2Ugc2VnbWVudC5cbiAgICAgKiBAcGFyYW0ge2Jvb2xlYW59IGlzTGFuZ3VhZ2UgYHRydWVgIGlmIHRoZSBjdXJyZW50IHZhbHVlIGF0IGBsYW5nSW5kZXhgIGlzIGEgc3VwcG9ydGVkIGxhbmd1YWdlOyBvdGhlcndpc2UgYGZhbHNlYC5cbiAgICAgKi9cbiAgICBwcm90ZWN0ZWQgaW5zZXJ0T3JSZXBsYWNlTGFuZ3VhZ2UobGFuZzogc3RyaW5nLCBzZWdtZW50czogc3RyaW5nW10sIGxhbmdJbmRleDogbnVtYmVyLCBpc0xhbmd1YWdlOiBib29sZWFuKTogdm9pZFxuICAgIHtcbiAgICAgICAgLy8gRGVmaW5lIGhvdyBtYW55IGl0ZW1zIHRvIHJlbW92ZS4gSWYgdGhlIHNlZ21lbnQgaXMgYWxyZWFkeSBhIGxhbmd1YWdlIGFuZCBzaG91bGQgYmUgcmVwbGFjZWQsIHplcm8gaXRlbXMgc2hvdWxkIGJlIHJlbW92ZWQuXG4gICAgICAgIGNvbnN0IGRlbGV0ZUNvdW50ID0gaXNMYW5ndWFnZSA/IDEgOiAwO1xuXG4gICAgICAgIC8vIFJlcGxhY2UgZXhpc3RpbmcgbGFuZ3VhZ2Ugc2VnbWVudCBvciBhZGQgYSBuZXcgb25lLiBJZiB0aGUgc3BlY2lmaWVkIGluZGV4IGV4Y2VlZHMgdGhlIGxlbmd0aCBvZiB0aGUgYXJyYXksIHNwbGljZSB3aWxsIGFkZCBhIG5ldyBpdGVtIGF0IHRoZSBlbmQvYmVnaW5uaW5nIG9mIHRoZSBhcnJheS5cbiAgICAgICAgc2VnbWVudHMuc3BsaWNlKGxhbmdJbmRleCwgZGVsZXRlQ291bnQsIGxhbmcpO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIFJlbW92ZXMgdGhlIGxhbmd1YWdlIHNlZ21lbnQgZnJvbSBhIHJvdXRlIHNlZ21lbnRzIGFycmF5LlxuICAgICAqIElmIHRoZSBsYW5ndWFnZSBpbmRleCBwb2ludHMgdG8gYSBub24tbGFuZ3VhZ2Ugc2VnbWVudCwgcmV0dXJucyB3aXRob3V0IGNoYW5naW5nIHRoZSBzZWdtZW50cy5cbiAgICAgKlxuICAgICAqIEBwcm90ZWN0ZWRcbiAgICAgKiBAcGFyYW0ge3N0cmluZ1tdfSBzZWdtZW50cyBUaGUgY3VycmVudCByb3V0ZSBzZWdtZW50cy5cbiAgICAgKiBAcGFyYW0ge251bWJlcn0gbGFuZ0luZGV4IFRoZSBpbmRleCBvZiB0aGUgZXhwZWN0ZWQgbGFuZ2F1Z2Ugc2VnbWVudC5cbiAgICAgKiBAcGFyYW0ge2Jvb2xlYW59IGlzTGFuZ3VhZ2UgYHRydWVgIGlmIHRoZSBjdXJyZW50IHZhbHVlIGF0IGBsYW5nSW5kZXhgIGlzIGEgc3VwcG9ydGVkIGxhbmd1YWdlOyBvdGhlcndpc2UgYGZhbHNlYC5cbiAgICAgKi9cbiAgICBwcm90ZWN0ZWQgcmVtb3ZlTGFuZ3VhZ2Uoc2VnbWVudHM6IHN0cmluZ1tdLCBsYW5nSW5kZXg6IG51bWJlciwgaXNMYW5ndWFnZTogYm9vbGVhbik6IHZvaWRcbiAgICB7XG4gICAgICAgIGlmICghaXNMYW5ndWFnZSkgcmV0dXJuO1xuXG4gICAgICAgIHNlZ21lbnRzLnNwbGljZShsYW5nSW5kZXgsIDEpO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIEFjY2Vzc2luZyBzZWdtZW50cyBieSBpbmRleCByZXF1aXJlcyB0aGUgYHRoaXMucG9zaXRpb25gIHRvIGJlIHRyYW5zbGF0ZWQgaW50byBhbiBpbmRleC5cbiAgICAgKiBBcyB0aGUgcG9zaXRpb24gY2FuIGVpdGhlciBiZSBwb3NpdGl2ZSBvciBuZWdhdGl2ZSwgdGhlcmUgYXJlIHR3byBkaWZmZXJlbnQgZm9ybXVsYXMgZm9yIGluZGV4IGNhbGN1bGF0aW9uLlxuICAgICAqIEluIHR1cm4sIHRoaXMgbWVhbnMgdHdvIGRpZmZlcmVudCBzY2VuYXJpb3Mgd2l0aCBkaWZmZXJlbnQgZWRnZSBjYXNlcy5cbiAgICAgKiBcbiAgICAgKiBUbyB1bmlmeSB0aGUgY2FzZXMgYW5kIHJlZHVjZSBjb21wbGV4aXR5LCB3aGVuIHBvc2l0aW9uIGlzIG5lZ2F0aXZlLCB0aGlzIG1ldGhvZCByZXZlcnNlcyB0aGUgc2VnbWVudHMgYXJyYXksIHJ1bnMgdGhlIHNlZ21lbnRzIG1hbmlwdWxhdGlvbiwgdGhlbiByZXZlcnNlcyBpdCBhZ2FpbiB0byByZXN0b3JlIHRoZSBvcmlnaW5hbCBvcmRlci5cbiAgICAgKiBUaGlzIHdheSB0aGUgaW5kZXhpbmcgaXMgYWx3YXlzIGRvbmUgZnJvbSBvbmUgc2lkZSBvZiB0aGUgYXJyYXkuXG4gICAgICogXG4gICAgICogQHByb3RlY3RlZFxuICAgICAqIEBwYXJhbSB7c3RyaW5nW119IHNlZ21lbnRzIFRoZSBzZWdtZW50cyBhYm91dCB0byBiZSBtYW5pcHVsYXRlZC5cbiAgICAgKiBAcGFyYW0geygpID0+IHZvaWR9IGFjY2Vzc1NlZ21lbnRzIFRoZSBmdW5jdGlvbiB0aGF0IG5lZWRzIHNhZmUgYWNjZXNzIGJ5IGluZGV4IHRvIHRoZSBcbiAgICAgKi9cbiAgICBwcm90ZWN0ZWQgYWNjZXNzU2VnbWVudHNTYWZlbHkoc2VnbWVudHM6IHN0cmluZ1tdLCBhY2Nlc3NTZWdtZW50czogKCkgPT4gdm9pZCk6IHZvaWRcbiAgICB7XG4gICAgICAgIGlmICh0aGlzLmlzTmVnYXRpdmVMb29rdXApIHNlZ21lbnRzLnJldmVyc2UoKTtcbiAgICAgICAgXG4gICAgICAgIGFjY2Vzc1NlZ21lbnRzKCk7XG4gICAgICAgIFxuICAgICAgICBpZiAodGhpcy5pc05lZ2F0aXZlTG9va3VwKSBzZWdtZW50cy5yZXZlcnNlKCk7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogSW5kaWNhdGVzIHdoZXRoZXIgdGhlIGNvbmZpZ3VyZWQgbGFuZ3VhZ2UgcG9zaXRpb24gaXMgcG9zaXRpdmUsIHJlc3VsdGluZyBpbiBhIGxvb2t1cCBmcm9tIHRoZSBsZWZ0IChwb3NpdGl2ZSBsb29rdXApLlxuICAgICAqIGB0cnVlYCBpZiBwb3NpdGl2ZSBsb29rdXAgc2hvdWxkIGJlIHBlcmZvcm1lZDsgb3RoZXJ3aXNlIGBmYWxzZWAuXG4gICAgICogXG4gICAgICogQHJlYWRvbmx5XG4gICAgICogQHByb3RlY3RlZFxuICAgICAqIEB0eXBlIHtib29sZWFufVxuICAgICAqL1xuICAgIHByb3RlY3RlZCBnZXQgaXNQb3NpdGl2ZUxvb2t1cCgpOiBib29sZWFuXG4gICAge1xuICAgICAgICByZXR1cm4gdGhpcy5wb3NpdGlvbiA+IDA7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogSW5kaWNhdGVzIHdoZXRoZXIgdGhlIGNvbmZpZ3VyZWQgbGFuZ3VhZ2UgcG9zaXRpb24gaXMgbmVnYXRpdmUsIHJlc3VsdGluZyBpbiBhIGxvb2t1cCBmcm9tIHRoZSByaWdodCAobmVnYXRpdmUgbG9va3VwKS5cbiAgICAgKiBgdHJ1ZWAgaWYgbmVnYXRpdmUgbG9va3VwIHNob3VsZCBiZSBwZXJmb3JtZWQ7IG90aGVyd2lzZSBgZmFsc2VgLlxuICAgICAqXG4gICAgICogQHJlYWRvbmx5XG4gICAgICogQHByb3RlY3RlZFxuICAgICAqIEB0eXBlIHtib29sZWFufVxuICAgICAqL1xuICAgIHByb3RlY3RlZCBnZXQgaXNOZWdhdGl2ZUxvb2t1cCgpOiBib29sZWFuXG4gICAge1xuICAgICAgICByZXR1cm4gdGhpcy5wb3NpdGlvbiA8IDA7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogQ2FsY3VsYXRlcyB0aGUgYWJzb2x1dGUgaW5kZXggZm9yIHRoZSBjb25maWd1cmVkIGxhbmd1YWdlIHBvc2l0aW9uLlxuICAgICAqXG4gICAgICogQHByb3RlY3RlZFxuICAgICAqIEByZXR1cm5zIHtudW1iZXJ9XG4gICAgICovXG4gICAgcHJvdGVjdGVkIGluZGV4T2ZQb3NpdGlvbigpOiBudW1iZXJcbiAgICB7XG4gICAgICAgIHJldHVybiBNYXRoLmFicyh0aGlzLnBvc2l0aW9uKSAtIDE7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogQ2hlY2tzIHdoZXRoZXIgdGhlIHNwZWNpZmllZCB2YWx1ZSBpcyBhIGxhbmd1YWdlIHN1cHBvcnRlZCBieSB0aGUgbGFuZ3VhZ2UgaW50ZWdyYXRpb24gc2VydmljZXMuXG4gICAgICpcbiAgICAgKiBAcHJvdGVjdGVkXG4gICAgICogQHBhcmFtIHtzdHJpbmd9IHZhbHVlIFRoZSB2YWx1ZSB0byBjaGVjay5cbiAgICAgKiBAcmV0dXJucyB7Ym9vbGVhbn0gYHRydWVgIGlmIHRoZSB2YWx1ZSBpcyBhIHN1cHBvcnRlZCBsYW5ndWFnZTsgb3RoZXJ3aXNlIGBmYWxzZWAuXG4gICAgICovXG4gICAgcHJvdGVjdGVkIGlzTGFuZ3VhZ2UodmFsdWU6IHN0cmluZyk6IGJvb2xlYW5cbiAgICB7XG4gICAgICAgIHJldHVybiB0aGlzLmxhbmd1YWdlLnN1cHBvcnRlZD8uaW5jbHVkZXModmFsdWUpIHx8IGZhbHNlO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIENvbmNhdHMgdGhlIGhvc3QgdXJsIGFzIGdpdmVuIGJ5IHRoZSB1cmwgcmVmbGVjdGlvbiBzZXJ2aWNlIHdpdGggdGhlIHNlZ21lbnRzIGFuZCB0aGUgY3VycmVudCBxdWVyeSBzdHJpbmcgdG8gY3JlYXRlXG4gICAgICogYSBmdWxseSBxdWFsaWZpZWQgdXJsLlxuICAgICAqXG4gICAgICogQHByb3RlY3RlZFxuICAgICAqIEBwYXJhbSB7c3RyaW5nW119IHNlZ21lbnRzIFRoZSByb3V0ZSBzZWdtZW50cyB0byBwbGFjZSBpbiB0aGUgdXJsLlxuICAgICAqIEByZXR1cm5zIHtzdHJpbmd9IFRoZSBmdWxseSBxdWFsaWZpZWQgdXJsIGNvbXBvc2VkIG9mIHRoZSBob3N0IHVybCBhcyBnaXZlbiBieSB0aGUgdXJsIHJlZmxlY3Rpb24gc2VydmljZSwgdGhlIHNwZWNpZmllZCByb3V0ZSBzZWdtZW50cywgYW5kIHRoZSBjdXJyZW50IHF1ZXJ5IHBhcmFtcy5cbiAgICAgKi9cbiAgICBwcm90ZWN0ZWQgY29tcG9zZVVybChzZWdtZW50czogc3RyaW5nW10pOiBzdHJpbmdcbiAgICB7XG4gICAgICAgIGNvbnN0IHsgaG9zdFVybCwgcXVlcnlTdHJpbmcgfSA9IHRoaXMudXJsUmVmbGVjdGlvbjtcblxuICAgICAgICByZXR1cm4gYCR7aG9zdFVybH0vJHtzZWdtZW50cy5qb2luKCcvJyl9JHtxdWVyeVN0cmluZ31gXG4gICAgfVxufSJdfQ==