UNPKG

@bespunky/angular-zen

Version:

The Angular tools you always wished were there.

236 lines 25 kB
import { Inject, Injectable, Optional } from '@angular/core'; import { ActivatedRoute, Router } from '@angular/router'; import { DocumentRef } from '@bespunky/angular-zen/core'; import { RouterX } from '../config/router-x-config.provider'; import * as i0 from "@angular/core"; import * as i1 from "@bespunky/angular-zen/core"; import * as i2 from "@angular/router"; /** * Provides tools for breaking the current and any url to their different parts. * * @export * @class UrlReflectionService */ export class UrlReflectionService { constructor(document, router, route, config) { this.document = document; this.router = router; this.route = route; this.config = config; /** * A regular expression to match the route part of a url. The url can be fully qualified or start at the route. * The extracted group will be named 'route'. * * @example * The regex will extract '/this/is/the/route' for all of the following: * * Fully qualified urls: * `https://some.website.com/this/is/the/route?a=1&b=2&c=3` * `https://some.website.com/this/is/the/route#someFragment` * `https://some.website.com/this/is/the/route?debug=true#fragment` * * Relative routes: * `/this/is/the/route?a=1&b=2&c=3` * `/this/is/the/route#someFragment` * `/this/is/the/route?debug=true#fragment` * * The regex will extract 'this/is/the/route' (no head slash) for all of the following: * `this/is/the/route?a=1&b=2&c=3` * `this/is/the/route#someFragment` * `this/is/the/route?debug=true#fragment` **/ this.RouteRegex = /^(?:http[s]?:\/\/[^/]+)?(?<route>[^?#]+)(?=[?#]|$)/; /** * A regular expression to match all segments of a route. * Looks for `/<segment>/` parts and extract them without the slashes. * The extracted groups will be named 'segment'. */ this.RouteSegmentsRegex = /(?!\/)(?<segment>[^/]+)/g; /** * A regular expression to match the question mark and everything that follows in a url. * The extracted group will be named 'queryString'. * * @example * The regex will extract '?a=1&b=2&c=3' for all of the following: * https://some.website.com/some/route?a=1&b=2&c=3 * https://some.website.com/some/route?a=1&b=2&c=3#fragment * /some/route?a=1&b=2&c=3#fragment * ?a=1&b=2&c=3#fragment */ this.QueryStringRegex = /(?<queryString>\?[^#]*)/; /** * A regular expression to match the hash sign and everything that follows in a url. * The extracted group will be named 'fragment'. * * @example * The regex will extract '#fragment' for all of the following: * https://some.website.com/some/route?a=1&b=2&c=3#fragment * /some/route?a=1&b=2&c=3#fragment * some/route?a=1&b=2&c=3#fragment */ this.FragmentRegex = /(?<fragment>#.*)$/; const hostUrl = this.config?.hostUrl; // If the hostUrl has been provided by the user, use it; otherwise, fetch from the location service this.hostUrl = hostUrl || this.document.nativeDocument.location.origin; } /** * Extracts the route portion of a given url. * * @example * routeOf('https://some.website.com/some/route?a=1&b=2&c=3') === '/some/route' * * @param {string} url The url for which to extract the route portion. * @returns {string} The route portion of the url. */ routeOf(url) { return url.match(this.RouteRegex)?.groups?.['route'] || ''; } /** * Extracts the route portion of a url as an array of route segments, not including the empty root segment. * * @example * routeSegmentsOf('https://some.website.com/some/route?a=1&b=2&c=3') === ['some', 'route'] * routeSegmentsOf('/some/route') === ['some', 'route'] * * @param {string} routeOrUrl The route or complete url from which to extract the route segments. * @returns {string[]} The segments of the route. */ routeSegmentsOf(routeOrUrl) { // Extract the route portion only, then match with the regex to extract the array of segments return this.routeOf(routeOrUrl).match(this.RouteSegmentsRegex) || []; } /** * Extracts the query string of a specified url. * * @example * queryStringOf('https://some.website.com/some/route?a=1&b=2&c=3') === '?a=1&b=2&c=3' * * @param {string} url The url from which to extract the query string. * @returns {string} The query string extracted from the url. */ queryStringOf(url) { const matches = url.match(this.QueryStringRegex) || ['']; return matches[0]; } /** * Removes the query portion of a url. * * @example * stripQuery('https://some.website.com/some/route?a=1&b=2&c=3#fragment') === 'https://some.website.com/some/route#fragment' * * @param {string} url The url from which to remove the query. * @returns {string} The specified url without the query portion. */ stripQuery(url) { return url.replace(this.QueryStringRegex, ''); } /** * Extracts the fragment from a url. * * @example * fragmentOf('https://some.website.com/some/route?a=1&b=2&c=3#fragment') === '#fragment' * * @param {string} url The url from which to extract the fragment. * @returns {string} The fragment extracted from the url. */ fragmentOf(url) { const matches = url.match(this.FragmentRegex) || ['']; return matches[0]; } /** * Removes the fragment portion of a url. * * @example * stripFragment('https://some.website.com/some/route?a=1&b=2&c=3#fragment') === 'https://some.website.com/some/route?a=1&b=2&c=3' * * @param {string} url The url to remove the fragment. * @returns {string} The url without the fragment portion. */ stripFragment(url) { return url.replace(this.FragmentRegex, ''); } /** * Makes sure the url is prefixed with https instead of http. * * @param {string} url The url to secure. * @returns {string} The secure url. */ forceHttps(url) { return url.replace(/^http:\/\//, 'https://'); } /** * The fully qualified url of the currently navigated route (e.g. 'https://some.website.com/some/route?a=1&b=2&c=3#fragment'). * * @readonly * @type {string} */ get fullUrl() { return `${this.hostUrl}${this.router.url}`; } /** * The route url of the currently navigated route (e.g. '/some/route'). * * @readonly * @type {string} */ get routeUrl() { return this.routeOf(this.router.url); } /** * The segments of the currently navigated route (e.g. ['some', 'route']). * * @readonly * @type {string[]} */ get routeSegments() { return this.routeSegmentsOf(this.routeUrl); } /** * The object representing the query params in the currently navigated route. * * @readonly * @type {*} */ get queryParams() { return { ...this.route.snapshot.queryParams }; } /** * The query string portion of the currently navigated route (e.g. '?a=1&b=2&c=3'). * * @readonly * @type {string} */ get queryString() { return this.queryStringOf(this.router.url); } /** * The fragment portion of the currently navigated route, without the hash sign (e.g. 'fragment'). * * @readonly * @type {string} */ get fragment() { return this.route.snapshot.fragment || ''; } /** * The fragment portion of the currently navigated route, with the hash sign (e.g. '#fragment'). * * @readonly * @type {string} */ get fragmentString() { return `#${this.fragment}`; } } UrlReflectionService.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.2.12", ngImport: i0, type: UrlReflectionService, deps: [{ token: i1.DocumentRef }, { token: i2.Router }, { token: i2.ActivatedRoute }, { token: RouterX, optional: true }], target: i0.ɵɵFactoryTarget.Injectable }); UrlReflectionService.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "14.2.12", ngImport: i0, type: UrlReflectionService, providedIn: 'root' }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.2.12", ngImport: i0, type: UrlReflectionService, decorators: [{ type: Injectable, args: [{ providedIn: 'root' }] }], ctorParameters: function () { return [{ type: i1.DocumentRef }, { type: i2.Router }, { type: i2.ActivatedRoute }, { type: undefined, decorators: [{ type: Optional }, { type: Inject, args: [RouterX] }] }]; } }); //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidXJsLXJlZmxlY3Rpb24uc2VydmljZS5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uLy4uLy4uL2xpYnMvYW5ndWxhci16ZW4vcm91dGVyLXgvc3JjL3NlcnZpY2VzL3VybC1yZWZsZWN0aW9uLnNlcnZpY2UudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUFFLE1BQU0sRUFBRSxVQUFVLEVBQUUsUUFBUSxFQUFJLE1BQU0sZUFBZSxDQUFDO0FBQy9ELE9BQU8sRUFBRSxjQUFjLEVBQVUsTUFBTSxFQUFFLE1BQU0saUJBQWlCLENBQUM7QUFFakUsT0FBTyxFQUFFLFdBQVcsRUFBSSxNQUFNLDRCQUE0QixDQUFDO0FBRTNELE9BQU8sRUFBRSxPQUFPLEVBQVEsTUFBTSxvQ0FBb0MsQ0FBQzs7OztBQUVuRTs7Ozs7R0FLRztBQUVILE1BQU0sT0FBTyxvQkFBb0I7SUErRDdCLFlBQ2tELFFBQXFCLEVBQ3JCLE1BQWdCLEVBQ2hCLEtBQXdCLEVBQ3hCLE1BQXVCO1FBSHZCLGFBQVEsR0FBUixRQUFRLENBQWE7UUFDckIsV0FBTSxHQUFOLE1BQU0sQ0FBVTtRQUNoQixVQUFLLEdBQUwsS0FBSyxDQUFtQjtRQUN4QixXQUFNLEdBQU4sTUFBTSxDQUFpQjtRQWpFekU7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7OztZQXFCSTtRQUNZLGVBQVUsR0FBVyxvREFBb0QsQ0FBQztRQUMxRjs7OztXQUlHO1FBQ2EsdUJBQWtCLEdBQUcsMEJBQTBCLENBQUM7UUFDaEU7Ozs7Ozs7Ozs7V0FVRztRQUNhLHFCQUFnQixHQUFLLHlCQUF5QixDQUFDO1FBQy9EOzs7Ozs7Ozs7V0FTRztRQUNhLGtCQUFhLEdBQVEsbUJBQW1CLENBQUM7UUFpQnJELE1BQU0sT0FBTyxHQUFHLElBQUksQ0FBQyxNQUFNLEVBQUUsT0FBTyxDQUFDO1FBRXJDLG1HQUFtRztRQUNuRyxJQUFJLENBQUMsT0FBTyxHQUFHLE9BQU8sSUFBSSxJQUFJLENBQUMsUUFBUSxDQUFDLGNBQWMsQ0FBQyxRQUFRLENBQUMsTUFBTSxDQUFDO0lBQzNFLENBQUM7SUFFRDs7Ozs7Ozs7T0FRRztJQUNJLE9BQU8sQ0FBQyxHQUFXO1FBRXRCLE9BQU8sR0FBRyxDQUFDLEtBQUssQ0FBQyxJQUFJLENBQUMsVUFBVSxDQUFDLEVBQUUsTUFBTSxFQUFFLENBQUMsT0FBTyxDQUFDLElBQUksRUFBRSxDQUFDO0lBQy9ELENBQUM7SUFFRDs7Ozs7Ozs7O09BU0c7SUFDSSxlQUFlLENBQUMsVUFBa0I7UUFFckMsNkZBQTZGO1FBQzdGLE9BQU8sSUFBSSxDQUFDLE9BQU8sQ0FBQyxVQUFVLENBQUMsQ0FBQyxLQUFLLENBQUMsSUFBSSxDQUFDLGtCQUFrQixDQUFDLElBQUksRUFBRSxDQUFDO0lBQ3pFLENBQUM7SUFFRDs7Ozs7Ozs7T0FRRztJQUNJLGFBQWEsQ0FBQyxHQUFXO1FBRTVCLE1BQU0sT0FBTyxHQUFHLEdBQUcsQ0FBQyxLQUFLLENBQUMsSUFBSSxDQUFDLGdCQUFnQixDQUFDLElBQUksQ0FBQyxFQUFFLENBQUMsQ0FBQztRQUV6RCxPQUFPLE9BQU8sQ0FBQyxDQUFDLENBQUMsQ0FBQztJQUN0QixDQUFDO0lBRUQ7Ozs7Ozs7O09BUUc7SUFDSSxVQUFVLENBQUMsR0FBVztRQUV6QixPQUFPLEdBQUcsQ0FBQyxPQUFPLENBQUMsSUFBSSxDQUFDLGdCQUFnQixFQUFFLEVBQUUsQ0FBQyxDQUFDO0lBQ2xELENBQUM7SUFFRDs7Ozs7Ozs7T0FRRztJQUNJLFVBQVUsQ0FBQyxHQUFXO1FBRXpCLE1BQU0sT0FBTyxHQUFHLEdBQUcsQ0FBQyxLQUFLLENBQUMsSUFBSSxDQUFDLGFBQWEsQ0FBQyxJQUFJLENBQUMsRUFBRSxDQUFDLENBQUM7UUFFdEQsT0FBTyxPQUFPLENBQUMsQ0FBQyxDQUFDLENBQUM7SUFDdEIsQ0FBQztJQUVEOzs7Ozs7OztPQVFHO0lBQ0ksYUFBYSxDQUFDLEdBQVc7UUFFNUIsT0FBTyxHQUFHLENBQUMsT0FBTyxDQUFDLElBQUksQ0FBQyxhQUFhLEVBQUUsRUFBRSxDQUFDLENBQUM7SUFDL0MsQ0FBQztJQUVEOzs7OztPQUtHO0lBQ0ksVUFBVSxDQUFDLEdBQVc7UUFFekIsT0FBTyxHQUFHLENBQUMsT0FBTyxDQUFDLFlBQVksRUFBRSxVQUFVLENBQUMsQ0FBQztJQUNqRCxDQUFDO0lBRUQ7Ozs7O09BS0c7SUFDSCxJQUFXLE9BQU87UUFFZCxPQUFPLEdBQUcsSUFBSSxDQUFDLE9BQU8sR0FBRyxJQUFJLENBQUMsTUFBTSxDQUFDLEdBQUcsRUFBRSxDQUFDO0lBQy9DLENBQUM7SUFFRDs7Ozs7T0FLRztJQUNILElBQVcsUUFBUTtRQUVmLE9BQU8sSUFBSSxDQUFDLE9BQU8sQ0FBQyxJQUFJLENBQUMsTUFBTSxDQUFDLEdBQUcsQ0FBQyxDQUFDO0lBQ3pDLENBQUM7SUFFRDs7Ozs7T0FLRztJQUNILElBQVcsYUFBYTtRQUVwQixPQUFPLElBQUksQ0FBQyxlQUFlLENBQUMsSUFBSSxDQUFDLFFBQVEsQ0FBQyxDQUFDO0lBQy9DLENBQUM7SUFFRDs7Ozs7T0FLRztJQUNILElBQVcsV0FBVztRQUVsQixPQUFPLEVBQUUsR0FBRyxJQUFJLENBQUMsS0FBSyxDQUFDLFFBQVEsQ0FBQyxXQUFXLEVBQUUsQ0FBQztJQUNsRCxDQUFDO0lBRUQ7Ozs7O09BS0c7SUFDSCxJQUFXLFdBQVc7UUFFbEIsT0FBTyxJQUFJLENBQUMsYUFBYSxDQUFDLElBQUksQ0FBQyxNQUFNLENBQUMsR0FBRyxDQUFDLENBQUM7SUFDL0MsQ0FBQztJQUVEOzs7OztPQUtHO0lBQ0gsSUFBVyxRQUFRO1FBRWYsT0FBTyxJQUFJLENBQUMsS0FBSyxDQUFDLFFBQVEsQ0FBQyxRQUFRLElBQUksRUFBRSxDQUFDO0lBQzlDLENBQUM7SUFFRDs7Ozs7T0FLRztJQUNILElBQVcsY0FBYztRQUVyQixPQUFPLElBQUksSUFBSSxDQUFDLFFBQVEsRUFBRSxDQUFDO0lBQy9CLENBQUM7O2tIQTVQUSxvQkFBb0IsaUdBbUVMLE9BQU87c0hBbkV0QixvQkFBb0IsY0FEUCxNQUFNOzRGQUNuQixvQkFBb0I7a0JBRGhDLFVBQVU7bUJBQUMsRUFBRSxVQUFVLEVBQUUsTUFBTSxFQUFDOzswQkFvRXhCLFFBQVE7OzBCQUFJLE1BQU07MkJBQUMsT0FBTyIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IEluamVjdCwgSW5qZWN0YWJsZSwgT3B0aW9uYWwgICB9IGZyb20gJ0Bhbmd1bGFyL2NvcmUnO1xuaW1wb3J0IHsgQWN0aXZhdGVkUm91dGUsIFBhcmFtcywgUm91dGVyIH0gZnJvbSAnQGFuZ3VsYXIvcm91dGVyJztcblxuaW1wb3J0IHsgRG9jdW1lbnRSZWYgICB9IGZyb20gJ0BiZXNwdW5reS9hbmd1bGFyLXplbi9jb3JlJztcbmltcG9ydCB7IFJvdXRlclhDb25maWcgfSBmcm9tICcuLi9jb25maWcvcm91dGVyLXgtY29uZmlnJztcbmltcG9ydCB7IFJvdXRlclggICAgICAgfSBmcm9tICcuLi9jb25maWcvcm91dGVyLXgtY29uZmlnLnByb3ZpZGVyJztcblxuLyoqXG4gKiBQcm92aWRlcyB0b29scyBmb3IgYnJlYWtpbmcgdGhlIGN1cnJlbnQgYW5kIGFueSB1cmwgdG8gdGhlaXIgZGlmZmVyZW50IHBhcnRzLlxuICpcbiAqIEBleHBvcnRcbiAqIEBjbGFzcyBVcmxSZWZsZWN0aW9uU2VydmljZVxuICovXG5ASW5qZWN0YWJsZSh7IHByb3ZpZGVkSW46ICdyb290J30pXG5leHBvcnQgY2xhc3MgVXJsUmVmbGVjdGlvblNlcnZpY2VcbntcbiAgICAvKipcbiAgICAgKiBBIHJlZ3VsYXIgZXhwcmVzc2lvbiB0byBtYXRjaCB0aGUgcm91dGUgcGFydCBvZiBhIHVybC4gVGhlIHVybCBjYW4gYmUgZnVsbHkgcXVhbGlmaWVkIG9yIHN0YXJ0IGF0IHRoZSByb3V0ZS5cbiAgICAgKiBUaGUgZXh0cmFjdGVkIGdyb3VwIHdpbGwgYmUgbmFtZWQgJ3JvdXRlJy5cbiAgICAgKiBcbiAgICAgKiBAZXhhbXBsZVxuICAgICAqIFRoZSByZWdleCB3aWxsIGV4dHJhY3QgJy90aGlzL2lzL3RoZS9yb3V0ZScgZm9yIGFsbCBvZiB0aGUgZm9sbG93aW5nOlxuICAgICAqXG4gICAgICogRnVsbHkgcXVhbGlmaWVkIHVybHM6XG4gICAgICogYGh0dHBzOi8vc29tZS53ZWJzaXRlLmNvbS90aGlzL2lzL3RoZS9yb3V0ZT9hPTEmYj0yJmM9M2BcbiAgICAgKiBgaHR0cHM6Ly9zb21lLndlYnNpdGUuY29tL3RoaXMvaXMvdGhlL3JvdXRlI3NvbWVGcmFnbWVudGBcbiAgICAgKiBgaHR0cHM6Ly9zb21lLndlYnNpdGUuY29tL3RoaXMvaXMvdGhlL3JvdXRlP2RlYnVnPXRydWUjZnJhZ21lbnRgXG4gICAgICogXG4gICAgICogUmVsYXRpdmUgcm91dGVzOlxuICAgICAqIGAvdGhpcy9pcy90aGUvcm91dGU/YT0xJmI9MiZjPTNgXG4gICAgICogYC90aGlzL2lzL3RoZS9yb3V0ZSNzb21lRnJhZ21lbnRgXG4gICAgICogYC90aGlzL2lzL3RoZS9yb3V0ZT9kZWJ1Zz10cnVlI2ZyYWdtZW50YFxuICAgICAqIFxuICAgICAqIFRoZSByZWdleCB3aWxsIGV4dHJhY3QgJ3RoaXMvaXMvdGhlL3JvdXRlJyAobm8gaGVhZCBzbGFzaCkgZm9yIGFsbCBvZiB0aGUgZm9sbG93aW5nOlxuICAgICAqIGB0aGlzL2lzL3RoZS9yb3V0ZT9hPTEmYj0yJmM9M2BcbiAgICAgKiBgdGhpcy9pcy90aGUvcm91dGUjc29tZUZyYWdtZW50YFxuICAgICAqIGB0aGlzL2lzL3RoZS9yb3V0ZT9kZWJ1Zz10cnVlI2ZyYWdtZW50YFxuICAgICAqKi9cbiAgICBwdWJsaWMgcmVhZG9ubHkgUm91dGVSZWdleCAgICAgICAgID0gL14oPzpodHRwW3NdPzpcXC9cXC9bXi9dKyk/KD88cm91dGU+W14/I10rKSg/PVs/I118JCkvO1xuICAgIC8qKlxuICAgICAqIEEgcmVndWxhciBleHByZXNzaW9uIHRvIG1hdGNoIGFsbCBzZWdtZW50cyBvZiBhIHJvdXRlLlxuICAgICAqIExvb2tzIGZvciBgLzxzZWdtZW50Pi9gIHBhcnRzIGFuZCBleHRyYWN0IHRoZW0gd2l0aG91dCB0aGUgc2xhc2hlcy5cbiAgICAgKiBUaGUgZXh0cmFjdGVkIGdyb3VwcyB3aWxsIGJlIG5hbWVkICdzZWdtZW50Jy5cbiAgICAgKi9cbiAgICBwdWJsaWMgcmVhZG9ubHkgUm91dGVTZWdtZW50c1JlZ2V4ID0gLyg/IVxcLykoPzxzZWdtZW50PlteL10rKS9nO1xuICAgIC8qKlxuICAgICAqIEEgcmVndWxhciBleHByZXNzaW9uIHRvIG1hdGNoIHRoZSBxdWVzdGlvbiBtYXJrIGFuZCBldmVyeXRoaW5nIHRoYXQgZm9sbG93cyBpbiBhIHVybC5cbiAgICAgKiBUaGUgZXh0cmFjdGVkIGdyb3VwIHdpbGwgYmUgbmFtZWQgJ3F1ZXJ5U3RyaW5nJy5cbiAgICAgKiBcbiAgICAgKiBAZXhhbXBsZVxuICAgICAqIFRoZSByZWdleCB3aWxsIGV4dHJhY3QgJz9hPTEmYj0yJmM9MycgZm9yIGFsbCBvZiB0aGUgZm9sbG93aW5nOlxuICAgICAqIGh0dHBzOi8vc29tZS53ZWJzaXRlLmNvbS9zb21lL3JvdXRlP2E9MSZiPTImYz0zXG4gICAgICogaHR0cHM6Ly9zb21lLndlYnNpdGUuY29tL3NvbWUvcm91dGU/YT0xJmI9MiZjPTMjZnJhZ21lbnRcbiAgICAgKiAvc29tZS9yb3V0ZT9hPTEmYj0yJmM9MyNmcmFnbWVudFxuICAgICAqID9hPTEmYj0yJmM9MyNmcmFnbWVudFxuICAgICAqL1xuICAgIHB1YmxpYyByZWFkb25seSBRdWVyeVN0cmluZ1JlZ2V4ICAgPSAvKD88cXVlcnlTdHJpbmc+XFw/W14jXSopLztcbiAgICAvKipcbiAgICAgKiBBIHJlZ3VsYXIgZXhwcmVzc2lvbiB0byBtYXRjaCB0aGUgaGFzaCBzaWduIGFuZCBldmVyeXRoaW5nIHRoYXQgZm9sbG93cyBpbiBhIHVybC5cbiAgICAgKiBUaGUgZXh0cmFjdGVkIGdyb3VwIHdpbGwgYmUgbmFtZWQgJ2ZyYWdtZW50Jy5cbiAgICAgKiBcbiAgICAgKiBAZXhhbXBsZVxuICAgICAqIFRoZSByZWdleCB3aWxsIGV4dHJhY3QgJyNmcmFnbWVudCcgZm9yIGFsbCBvZiB0aGUgZm9sbG93aW5nOlxuICAgICAqIGh0dHBzOi8vc29tZS53ZWJzaXRlLmNvbS9zb21lL3JvdXRlP2E9MSZiPTImYz0zI2ZyYWdtZW50XG4gICAgICogL3NvbWUvcm91dGU/YT0xJmI9MiZjPTMjZnJhZ21lbnRcbiAgICAgKiBzb21lL3JvdXRlP2E9MSZiPTImYz0zI2ZyYWdtZW50XG4gICAgICovXG4gICAgcHVibGljIHJlYWRvbmx5IEZyYWdtZW50UmVnZXggICAgICA9IC8oPzxmcmFnbWVudD4jLiopJC87XG5cbiAgICAvKipcbiAgICAgKiBUaGUgY29tcGxldGUgaG9zdCBwb3J0aW9uIChlLmcuIGh0dHBzOi8vd3d3LmV4YW1wbGUuY29tKSBvZiB0aGUgY3VycmVudGx5IG5hdmlnYXRlZCB1cmwgYXMgZmV0Y2hlZCBmcm9tIHRoZSBgZG9jdW1lbnQubG9jYXRpb25gIG9iamVjdC5cbiAgICAgKiBJZiB0aGUgYGhvc3RVcmxgIG9wdGlvbiB3YXMgcHJvdmlkZWQgd2hlbiBpbXBvcnRpbmcgdGhlIGxhbmd1YWdlIGludGVncmF0aW9uIG1vZHVsZSwgaXQgd2lsbCBiZSB1c2VkIGluc3RlYWQuXG4gICAgICpcbiAgICAgKiBAdHlwZSB7c3RyaW5nfVxuICAgICAqL1xuICAgIHB1YmxpYyByZWFkb25seSBob3N0VXJsOiBzdHJpbmc7XG5cbiAgICBjb25zdHJ1Y3RvcihcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwcml2YXRlICAgICAgICAgIGRvY3VtZW50OiBEb2N1bWVudFJlZixcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwdWJsaWMgIHJlYWRvbmx5IHJvdXRlciAgOiBSb3V0ZXIsXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcHVibGljICByZWFkb25seSByb3V0ZSAgIDogQWN0aXZhdGVkUm91dGUsXG4gICAgICAgIEBPcHRpb25hbCgpIEBJbmplY3QoUm91dGVyWCkgcHJpdmF0ZSAgICAgICAgICBjb25maWc/IDogUm91dGVyWENvbmZpZ1xuICAgIClcbiAgICB7XG4gICAgICAgIGNvbnN0IGhvc3RVcmwgPSB0aGlzLmNvbmZpZz8uaG9zdFVybDtcblxuICAgICAgICAvLyBJZiB0aGUgaG9zdFVybCBoYXMgYmVlbiBwcm92aWRlZCBieSB0aGUgdXNlciwgdXNlIGl0OyBvdGhlcndpc2UsIGZldGNoIGZyb20gdGhlIGxvY2F0aW9uIHNlcnZpY2VcbiAgICAgICAgdGhpcy5ob3N0VXJsID0gaG9zdFVybCB8fCB0aGlzLmRvY3VtZW50Lm5hdGl2ZURvY3VtZW50LmxvY2F0aW9uLm9yaWdpbjtcbiAgICB9XG4gICAgXG4gICAgLyoqXG4gICAgICogRXh0cmFjdHMgdGhlIHJvdXRlIHBvcnRpb24gb2YgYSBnaXZlbiB1cmwuXG4gICAgICogXG4gICAgICogQGV4YW1wbGVcbiAgICAgKiByb3V0ZU9mKCdodHRwczovL3NvbWUud2Vic2l0ZS5jb20vc29tZS9yb3V0ZT9hPTEmYj0yJmM9MycpID09PSAnL3NvbWUvcm91dGUnXG4gICAgICpcbiAgICAgKiBAcGFyYW0ge3N0cmluZ30gdXJsIFRoZSB1cmwgZm9yIHdoaWNoIHRvIGV4dHJhY3QgdGhlIHJvdXRlIHBvcnRpb24uXG4gICAgICogQHJldHVybnMge3N0cmluZ30gVGhlIHJvdXRlIHBvcnRpb24gb2YgdGhlIHVybC5cbiAgICAgKi9cbiAgICBwdWJsaWMgcm91dGVPZih1cmw6IHN0cmluZyk6IHN0cmluZ1xuICAgIHtcbiAgICAgICAgcmV0dXJuIHVybC5tYXRjaCh0aGlzLlJvdXRlUmVnZXgpPy5ncm91cHM/Llsncm91dGUnXSB8fCAnJztcbiAgICB9XG4gICAgXG4gICAgLyoqXG4gICAgICogRXh0cmFjdHMgdGhlIHJvdXRlIHBvcnRpb24gb2YgYSB1cmwgYXMgYW4gYXJyYXkgb2Ygcm91dGUgc2VnbWVudHMsIG5vdCBpbmNsdWRpbmcgdGhlIGVtcHR5IHJvb3Qgc2VnbWVudC5cbiAgICAgKlxuICAgICAqIEBleGFtcGxlXG4gICAgICogcm91dGVTZWdtZW50c09mKCdodHRwczovL3NvbWUud2Vic2l0ZS5jb20vc29tZS9yb3V0ZT9hPTEmYj0yJmM9MycpID09PSBbJ3NvbWUnLCAncm91dGUnXVxuICAgICAqIHJvdXRlU2VnbWVudHNPZignL3NvbWUvcm91dGUnKSA9PT0gWydzb21lJywgJ3JvdXRlJ11cbiAgICAgKlxuICAgICAqIEBwYXJhbSB7c3RyaW5nfSByb3V0ZU9yVXJsIFRoZSByb3V0ZSBvciBjb21wbGV0ZSB1cmwgZnJvbSB3aGljaCB0byBleHRyYWN0IHRoZSByb3V0ZSBzZWdtZW50cy5cbiAgICAgKiBAcmV0dXJucyB7c3RyaW5nW119IFRoZSBzZWdtZW50cyBvZiB0aGUgcm91dGUuXG4gICAgICovXG4gICAgcHVibGljIHJvdXRlU2VnbWVudHNPZihyb3V0ZU9yVXJsOiBzdHJpbmcpOiBzdHJpbmdbXVxuICAgIHtcbiAgICAgICAgLy8gRXh0cmFjdCB0aGUgcm91dGUgcG9ydGlvbiBvbmx5LCB0aGVuIG1hdGNoIHdpdGggdGhlIHJlZ2V4IHRvIGV4dHJhY3QgdGhlIGFycmF5IG9mIHNlZ21lbnRzXG4gICAgICAgIHJldHVybiB0aGlzLnJvdXRlT2Yocm91dGVPclVybCkubWF0Y2godGhpcy5Sb3V0ZVNlZ21lbnRzUmVnZXgpIHx8IFtdO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIEV4dHJhY3RzIHRoZSBxdWVyeSBzdHJpbmcgb2YgYSBzcGVjaWZpZWQgdXJsLlxuICAgICAqXG4gICAgICogQGV4YW1wbGVcbiAgICAgKiBxdWVyeVN0cmluZ09mKCdodHRwczovL3NvbWUud2Vic2l0ZS5jb20vc29tZS9yb3V0ZT9hPTEmYj0yJmM9MycpID09PSAnP2E9MSZiPTImYz0zJ1xuICAgICAqXG4gICAgICogQHBhcmFtIHtzdHJpbmd9IHVybCBUaGUgdXJsIGZyb20gd2hpY2ggdG8gZXh0cmFjdCB0aGUgcXVlcnkgc3RyaW5nLlxuICAgICAqIEByZXR1cm5zIHtzdHJpbmd9IFRoZSBxdWVyeSBzdHJpbmcgZXh0cmFjdGVkIGZyb20gdGhlIHVybC5cbiAgICAgKi9cbiAgICBwdWJsaWMgcXVlcnlTdHJpbmdPZih1cmw6IHN0cmluZyk6IHN0cmluZ1xuICAgIHtcbiAgICAgICAgY29uc3QgbWF0Y2hlcyA9IHVybC5tYXRjaCh0aGlzLlF1ZXJ5U3RyaW5nUmVnZXgpIHx8IFsnJ107XG5cbiAgICAgICAgcmV0dXJuIG1hdGNoZXNbMF07XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogUmVtb3ZlcyB0aGUgcXVlcnkgcG9ydGlvbiBvZiBhIHVybC5cbiAgICAgKlxuICAgICAqIEBleGFtcGxlXG4gICAgICogc3RyaXBRdWVyeSgnaHR0cHM6Ly9zb21lLndlYnNpdGUuY29tL3NvbWUvcm91dGU/YT0xJmI9MiZjPTMjZnJhZ21lbnQnKSA9PT0gJ2h0dHBzOi8vc29tZS53ZWJzaXRlLmNvbS9zb21lL3JvdXRlI2ZyYWdtZW50J1xuICAgICAqXG4gICAgICogQHBhcmFtIHtzdHJpbmd9IHVybCBUaGUgdXJsIGZyb20gd2hpY2ggdG8gcmVtb3ZlIHRoZSBxdWVyeS5cbiAgICAgKiBAcmV0dXJucyB7c3RyaW5nfSBUaGUgc3BlY2lmaWVkIHVybCB3aXRob3V0IHRoZSBxdWVyeSBwb3J0aW9uLlxuICAgICAqL1xuICAgIHB1YmxpYyBzdHJpcFF1ZXJ5KHVybDogc3RyaW5nKTogc3RyaW5nXG4gICAge1xuICAgICAgICByZXR1cm4gdXJsLnJlcGxhY2UodGhpcy5RdWVyeVN0cmluZ1JlZ2V4LCAnJyk7XG4gICAgfVxuICAgIFxuICAgIC8qKlxuICAgICAqIEV4dHJhY3RzIHRoZSBmcmFnbWVudCBmcm9tIGEgdXJsLlxuICAgICAqXG4gICAgICogQGV4YW1wbGVcbiAgICAgKiBmcmFnbWVudE9mKCdodHRwczovL3NvbWUud2Vic2l0ZS5jb20vc29tZS9yb3V0ZT9hPTEmYj0yJmM9MyNmcmFnbWVudCcpID09PSAnI2ZyYWdtZW50J1xuICAgICAqXG4gICAgICogQHBhcmFtIHtzdHJpbmd9IHVybCBUaGUgdXJsIGZyb20gd2hpY2ggdG8gZXh0cmFjdCB0aGUgZnJhZ21lbnQuXG4gICAgICogQHJldHVybnMge3N0cmluZ30gVGhlIGZyYWdtZW50IGV4dHJhY3RlZCBmcm9tIHRoZSB1cmwuXG4gICAgICovXG4gICAgcHVibGljIGZyYWdtZW50T2YodXJsOiBzdHJpbmcpOiBzdHJpbmdcbiAgICB7XG4gICAgICAgIGNvbnN0IG1hdGNoZXMgPSB1cmwubWF0Y2godGhpcy5GcmFnbWVudFJlZ2V4KSB8fCBbJyddO1xuXG4gICAgICAgIHJldHVybiBtYXRjaGVzWzBdO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIFJlbW92ZXMgdGhlIGZyYWdtZW50IHBvcnRpb24gb2YgYSB1cmwuXG4gICAgICpcbiAgICAgKiBAZXhhbXBsZVxuICAgICAqIHN0cmlwRnJhZ21lbnQoJ2h0dHBzOi8vc29tZS53ZWJzaXRlLmNvbS9zb21lL3JvdXRlP2E9MSZiPTImYz0zI2ZyYWdtZW50JykgPT09ICdodHRwczovL3NvbWUud2Vic2l0ZS5jb20vc29tZS9yb3V0ZT9hPTEmYj0yJmM9MydcbiAgICAgKiBcbiAgICAgKiBAcGFyYW0ge3N0cmluZ30gdXJsIFRoZSB1cmwgdG8gcmVtb3ZlIHRoZSBmcmFnbWVudC5cbiAgICAgKiBAcmV0dXJucyB7c3RyaW5nfSBUaGUgdXJsIHdpdGhvdXQgdGhlIGZyYWdtZW50IHBvcnRpb24uXG4gICAgICovXG4gICAgcHVibGljIHN0cmlwRnJhZ21lbnQodXJsOiBzdHJpbmcpOiBzdHJpbmdcbiAgICB7XG4gICAgICAgIHJldHVybiB1cmwucmVwbGFjZSh0aGlzLkZyYWdtZW50UmVnZXgsICcnKTtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBNYWtlcyBzdXJlIHRoZSB1cmwgaXMgcHJlZml4ZWQgd2l0aCBodHRwcyBpbnN0ZWFkIG9mIGh0dHAuXG4gICAgICpcbiAgICAgKiBAcGFyYW0ge3N0cmluZ30gdXJsIFRoZSB1cmwgdG8gc2VjdXJlLlxuICAgICAqIEByZXR1cm5zIHtzdHJpbmd9IFRoZSBzZWN1cmUgdXJsLlxuICAgICAqL1xuICAgIHB1YmxpYyBmb3JjZUh0dHBzKHVybDogc3RyaW5nKTogc3RyaW5nXG4gICAge1xuICAgICAgICByZXR1cm4gdXJsLnJlcGxhY2UoL15odHRwOlxcL1xcLy8sICdodHRwczovLycpO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIFRoZSBmdWxseSBxdWFsaWZpZWQgdXJsIG9mIHRoZSBjdXJyZW50bHkgbmF2aWdhdGVkIHJvdXRlIChlLmcuICdodHRwczovL3NvbWUud2Vic2l0ZS5jb20vc29tZS9yb3V0ZT9hPTEmYj0yJmM9MyNmcmFnbWVudCcpLlxuICAgICAqXG4gICAgICogQHJlYWRvbmx5XG4gICAgICogQHR5cGUge3N0cmluZ31cbiAgICAgKi9cbiAgICBwdWJsaWMgZ2V0IGZ1bGxVcmwoKTogc3RyaW5nXG4gICAge1xuICAgICAgICByZXR1cm4gYCR7dGhpcy5ob3N0VXJsfSR7dGhpcy5yb3V0ZXIudXJsfWA7XG4gICAgfVxuICAgIFxuICAgIC8qKlxuICAgICAqIFRoZSByb3V0ZSB1cmwgb2YgdGhlIGN1cnJlbnRseSBuYXZpZ2F0ZWQgcm91dGUgKGUuZy4gJy9zb21lL3JvdXRlJykuXG4gICAgICpcbiAgICAgKiBAcmVhZG9ubHlcbiAgICAgKiBAdHlwZSB7c3RyaW5nfVxuICAgICAqL1xuICAgIHB1YmxpYyBnZXQgcm91dGVVcmwoKTogc3RyaW5nXG4gICAge1xuICAgICAgICByZXR1cm4gdGhpcy5yb3V0ZU9mKHRoaXMucm91dGVyLnVybCk7XG4gICAgfVxuICAgIFxuICAgIC8qKlxuICAgICAqIFRoZSBzZWdtZW50cyBvZiB0aGUgY3VycmVudGx5IG5hdmlnYXRlZCByb3V0ZSAoZS5nLiBbJ3NvbWUnLCAncm91dGUnXSkuXG4gICAgICpcbiAgICAgKiBAcmVhZG9ubHlcbiAgICAgKiBAdHlwZSB7c3RyaW5nW119XG4gICAgICovXG4gICAgcHVibGljIGdldCByb3V0ZVNlZ21lbnRzKCk6IHN0cmluZ1tdXG4gICAge1xuICAgICAgICByZXR1cm4gdGhpcy5yb3V0ZVNlZ21lbnRzT2YodGhpcy5yb3V0ZVVybCk7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogVGhlIG9iamVjdCByZXByZXNlbnRpbmcgdGhlIHF1ZXJ5IHBhcmFtcyBpbiB0aGUgY3VycmVudGx5IG5hdmlnYXRlZCByb3V0ZS5cbiAgICAgKlxuICAgICAqIEByZWFkb25seVxuICAgICAqIEB0eXBlIHsqfVxuICAgICAqL1xuICAgIHB1YmxpYyBnZXQgcXVlcnlQYXJhbXMoKTogUGFyYW1zXG4gICAge1xuICAgICAgICByZXR1cm4geyAuLi50aGlzLnJvdXRlLnNuYXBzaG90LnF1ZXJ5UGFyYW1zIH07XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogVGhlIHF1ZXJ5IHN0cmluZyBwb3J0aW9uIG9mIHRoZSBjdXJyZW50bHkgbmF2aWdhdGVkIHJvdXRlIChlLmcuICc/YT0xJmI9MiZjPTMnKS5cbiAgICAgKlxuICAgICAqIEByZWFkb25seVxuICAgICAqIEB0eXBlIHtzdHJpbmd9XG4gICAgICovXG4gICAgcHVibGljIGdldCBxdWVyeVN0cmluZygpOiBzdHJpbmdcbiAgICB7XG4gICAgICAgIHJldHVybiB0aGlzLnF1ZXJ5U3RyaW5nT2YodGhpcy5yb3V0ZXIudXJsKTtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBUaGUgZnJhZ21lbnQgcG9ydGlvbiBvZiB0aGUgY3VycmVudGx5IG5hdmlnYXRlZCByb3V0ZSwgd2l0aG91dCB0aGUgaGFzaCBzaWduIChlLmcuICdmcmFnbWVudCcpLlxuICAgICAqXG4gICAgICogQHJlYWRvbmx5XG4gICAgICogQHR5cGUge3N0cmluZ31cbiAgICAgKi9cbiAgICBwdWJsaWMgZ2V0IGZyYWdtZW50KCk6IHN0cmluZ1xuICAgIHtcbiAgICAgICAgcmV0dXJuIHRoaXMucm91dGUuc25hcHNob3QuZnJhZ21lbnQgfHwgJyc7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogVGhlIGZyYWdtZW50IHBvcnRpb24gb2YgdGhlIGN1cnJlbnRseSBuYXZpZ2F0ZWQgcm91dGUsIHdpdGggdGhlIGhhc2ggc2lnbiAoZS5nLiAnI2ZyYWdtZW50JykuXG4gICAgICpcbiAgICAgKiBAcmVhZG9ubHlcbiAgICAgKiBAdHlwZSB7c3RyaW5nfVxuICAgICAqL1xuICAgIHB1YmxpYyBnZXQgZnJhZ21lbnRTdHJpbmcoKTogc3RyaW5nXG4gICAge1xuICAgICAgICByZXR1cm4gYCMke3RoaXMuZnJhZ21lbnR9YDtcbiAgICB9XG59XG4iXX0=