UNPKG

@ngqp/core

Version:

Synchronizing form controls with the URL for Angular

314 lines 53.9 kB
import { Inject, Injectable, isDevMode, Optional } from '@angular/core'; import { EMPTY, forkJoin, from, Subject, zip } from 'rxjs'; import { catchError, concatMap, debounceTime, distinctUntilChanged, filter, map, startWith, switchMap, takeUntil, tap } from 'rxjs/operators'; import { compareParamMaps, filterParamMap, isMissing, isPresent, NOP } from '../util'; import { PartitionedQueryParam } from '../model/query-param'; import { NGQP_ROUTER_ADAPTER, NGQP_ROUTER_OPTIONS } from '../router-adapter/router-adapter.interface'; /** @internal */ function isMultiQueryParam(queryParam) { return queryParam.multi; } /** @internal */ class NavigationData { constructor(params, synthetic = false) { this.params = params; this.synthetic = synthetic; } } /** * Service implementing the synchronization logic * * This service is the key to the synchronization process by binding a {@link QueryParamGroup} * to the router. * * @internal */ export class QueryParamGroupService { constructor(routerAdapter, globalRouterOptions) { this.routerAdapter = routerAdapter; this.globalRouterOptions = globalRouterOptions; /** The {@link QueryParamGroup} to bind. */ this.queryParamGroup = null; /** List of {@link QueryParamAccessor} registered to this service. */ this.directives = new Map(); /** * Queue of navigation parameters * * A queue is used for navigations as we need to make sure all parameter changes * are executed in sequence as otherwise navigations might overwrite each other. */ this.queue$ = new Subject(); /** @ignore */ this.synchronizeRouter$ = new Subject(); /** @ignore */ this.destroy$ = new Subject(); this.setupNavigationQueue(); } /** @ignore */ ngOnDestroy() { var _a, _b, _c; this.destroy$.next(); this.destroy$.complete(); this.synchronizeRouter$.complete(); (_a = this.queryParamGroup) === null || _a === void 0 ? void 0 : _a._clearChangeFunctions(); if ((_c = (_b = this.queryParamGroup) === null || _b === void 0 ? void 0 : _b.options) === null || _c === void 0 ? void 0 : _c.clearOnDestroy) { const nullParams = Object.values(this.queryParamGroup.queryParams) .map(queryParam => this.wrapIntoPartition(queryParam)) .map(partitionedQueryParam => partitionedQueryParam.queryParams.map(queryParam => queryParam.urlParam)) .reduce((a, b) => [...a, ...b], []) .map(urlParam => ({ [urlParam]: null })) .reduce((a, b) => (Object.assign(Object.assign({}, a), b)), {}); this.routerAdapter.navigate(nullParams, { replaceUrl: true, }).then(); } } /** * Uses the given {@link QueryParamGroup} for synchronization. */ setQueryParamGroup(queryParamGroup) { // FIXME: If this is called when we already have a group, we probably need to do // some cleanup first. if (this.queryParamGroup) { throw new Error(`A QueryParamGroup has already been setup. Changing the group is currently not supported.`); } this.queryParamGroup = queryParamGroup; this.startSynchronization(); } /** * Registers a {@link QueryParamAccessor}. */ registerQueryParamDirective(directive) { if (!directive.valueAccessor) { throw new Error(`No value accessor found for the form control. Please make sure to implement ControlValueAccessor on this component.`); } // Capture the name here, particularly for the queue below to avoid re-evaluating // it as it might change over time. const queryParamName = directive.name; const partitionedQueryParam = this.getQueryParamAsPartition(queryParamName); // Chances are that we read the initial route before a directive has been registered here. // The value in the model will be correct, but we need to sync it to the view once initially. directive.valueAccessor.writeValue(partitionedQueryParam.value); // Proxy updates from the view to debounce them (if needed). const queues = partitionedQueryParam.queryParams.map(() => new Subject()); zip(...queues.map((queue$, index) => { const queryParam = partitionedQueryParam.queryParams[index]; return queue$.pipe(isPresent(queryParam.debounceTime) ? debounceTime(queryParam.debounceTime) : tap()); })).pipe( // Do not synchronize while the param is detached from the group filter(() => !!this.getQueryParamGroup().get(queryParamName)), map((newValue) => this.getParamsForValue(partitionedQueryParam, partitionedQueryParam.reduce(newValue))), takeUntil(this.destroy$)).subscribe(params => this.enqueueNavigation(new NavigationData(params))); directive.valueAccessor.registerOnChange((newValue) => { const partitioned = partitionedQueryParam.partition(newValue); queues.forEach((queue$, index) => queue$.next(partitioned[index])); }); this.directives.set(queryParamName, [...(this.directives.get(queryParamName) || []), directive]); } /** * Deregisters a {@link QueryParamAccessor} by referencing its name. */ deregisterQueryParamDirective(queryParamName) { if (!queryParamName) { return; } const directives = this.directives.get(queryParamName); if (!directives) { return; } directives.forEach(directive => { directive.valueAccessor.registerOnChange(NOP); directive.valueAccessor.registerOnTouched(NOP); }); this.directives.delete(queryParamName); const queryParam = this.getQueryParamGroup().get(queryParamName); if (queryParam) { queryParam._clearChangeFunctions(); } } startSynchronization() { this.setupGroupChangeListener(); this.setupParamChangeListeners(); this.setupRouterListener(); this.watchNewParams(); } /** Listens for programmatic changes on group level and synchronizes to the router. */ setupGroupChangeListener() { this.getQueryParamGroup()._registerOnChange((newValue) => { if (newValue === null) { throw new Error(`Received null value from QueryParamGroup.`); } let params = {}; Object.keys(newValue).forEach(queryParamName => { const queryParam = this.getQueryParamGroup().get(queryParamName); if (isMissing(queryParam)) { return; } params = Object.assign(Object.assign({}, params), this.getParamsForValue(queryParam, newValue[queryParamName])); }); this.enqueueNavigation(new NavigationData(params, true)); }); } /** Listens for programmatic changes on parameter level and synchronizes to the router. */ setupParamChangeListeners() { Object.keys(this.getQueryParamGroup().queryParams) .forEach(queryParamName => this.setupParamChangeListener(queryParamName)); } setupParamChangeListener(queryParamName) { const queryParam = this.getQueryParamGroup().get(queryParamName); if (!queryParam) { throw new Error(`No param in group found for name ${queryParamName}`); } queryParam._registerOnChange((newValue) => this.enqueueNavigation(new NavigationData(this.getParamsForValue(queryParam, newValue), true))); } /** Listens for changes in the router and synchronizes to the model. */ setupRouterListener() { this.synchronizeRouter$.pipe(startWith(undefined), switchMap(() => this.routerAdapter.queryParamMap.pipe( // We want to ignore changes to query parameters which aren't related to this // particular group; however, we do need to react if one of our parameters has // vanished when it was set before. distinctUntilChanged((previousMap, currentMap) => { const keys = Object.values(this.getQueryParamGroup().queryParams) .map(queryParam => this.wrapIntoPartition(queryParam)) .map(partitionedQueryParam => partitionedQueryParam.queryParams.map(queryParam => queryParam.urlParam)) .reduce((a, b) => [...a, ...b], []); // It is important that we filter the maps only here so that both are filtered // with the same set of keys; otherwise, e.g. removing a parameter from the group // would interfere. return compareParamMaps(filterParamMap(previousMap, keys), filterParamMap(currentMap, keys)); }))), switchMap(queryParamMap => { // We need to capture this right here since this is only set during the on-going navigation. const synthetic = this.isSyntheticNavigation(); const queryParamNames = Object.keys(this.getQueryParamGroup().queryParams); return forkJoin(...queryParamNames .map(queryParamName => { const partitionedQueryParam = this.getQueryParamAsPartition(queryParamName); return forkJoin(...partitionedQueryParam.queryParams .map(queryParam => isMultiQueryParam(queryParam) ? queryParam.deserializeValue(queryParamMap.getAll(queryParam.urlParam)) : queryParam.deserializeValue(queryParamMap.get(queryParam.urlParam)))).pipe(map(newValues => partitionedQueryParam.reduce(newValues)), tap(newValue => { const directives = this.directives.get(queryParamName); if (directives) { directives.forEach(directive => directive.valueAccessor.writeValue(newValue)); } }), map(newValue => { return { [queryParamName]: newValue }; }), takeUntil(this.destroy$)); })).pipe(map((values) => values.reduce((groupValue, value) => { return Object.assign(Object.assign({}, groupValue), value); }, {})), tap(groupValue => this.getQueryParamGroup().setValue(groupValue, { emitEvent: !synthetic, emitModelToViewChange: false, }))); }), takeUntil(this.destroy$)).subscribe(); } /** Listens for newly added parameters and starts synchronization for them. */ watchNewParams() { this.getQueryParamGroup().queryParamAdded$.pipe(takeUntil(this.destroy$)).subscribe(queryParamName => { this.setupParamChangeListener(queryParamName); this.synchronizeRouter$.next(); }); } /** Returns true if the current navigation is synthetic. */ isSyntheticNavigation() { const navigation = this.routerAdapter.getCurrentNavigation(); if (!navigation || navigation.trigger !== 'imperative') { // When using the back / forward buttons, the state is passed along with it, even though // for us it's now a navigation initiated by the user. Therefore, a navigation can only // be synthetic if it has been triggered imperatively. // See https://github.com/angular/angular/issues/28108. return false; } return navigation.extras && navigation.extras.state && navigation.extras.state['synthetic']; } /** Subscribes to the parameter queue and executes navigations in sequence. */ setupNavigationQueue() { this.queue$.pipe(takeUntil(this.destroy$), concatMap(data => this.navigateSafely(data))).subscribe(); } navigateSafely(data) { return from(this.routerAdapter.navigate(data.params, Object.assign(Object.assign({}, this.routerOptions), { state: { synthetic: data.synthetic } }))).pipe(catchError((err) => { if (isDevMode()) { console.error(`There was an error while navigating`, err); } return EMPTY; })); } /** Sends a change of parameters to the queue. */ enqueueNavigation(data) { this.queue$.next(data); } /** * Returns the full set of parameters given a value for a parameter model. * * This consists mainly of properly serializing the model value and ensuring to take * side effect changes into account that may have been configured. */ getParamsForValue(queryParam, value) { const partitionedQueryParam = this.wrapIntoPartition(queryParam); const partitioned = partitionedQueryParam.partition(value); const combinedParams = partitionedQueryParam.queryParams .map((current, index) => isMissing(current.combineWith) ? null : current.combineWith(partitioned[index])) .reduce((a, b) => { return Object.assign(Object.assign({}, (a || {})), (b || {})); }, {}); const newValues = partitionedQueryParam.queryParams .map((current, index) => { return { [current.urlParam]: current.serializeValue(partitioned[index]), }; }) .reduce((a, b) => { return Object.assign(Object.assign({}, a), b); }, {}); // Note that we list the side-effect parameters first so that our actual parameter can't be // overridden by it. return Object.assign(Object.assign({}, combinedParams), newValues); } /** * Returns the current set of options to pass to the router. * * This merges the global configuration with the group specific configuration. */ get routerOptions() { const groupOptions = this.getQueryParamGroup().routerOptions; return Object.assign(Object.assign({}, (this.globalRouterOptions || {})), (groupOptions || {})); } /** * Returns the query parameter with the given name as a partition. * * If the query parameter is partitioned, it is returned unchanged. Otherwise * it is wrapped into a noop partition. This makes it easy to operate on * query parameters independent of whether they are partitioned. */ getQueryParamAsPartition(queryParamName) { const queryParam = this.getQueryParamGroup().get(queryParamName); if (!queryParam) { throw new Error(`Could not find query param with name ${queryParamName}. Did you forget to add it to your QueryParamGroup?`); } return this.wrapIntoPartition(queryParam); } /** * Wraps a query parameter into a partition if it isn't already. */ wrapIntoPartition(queryParam) { if (queryParam instanceof PartitionedQueryParam) { return queryParam; } return new PartitionedQueryParam([queryParam], { partition: value => [value], reduce: values => values[0], }); } getQueryParamGroup() { if (!this.queryParamGroup) { throw new Error(`No QueryParamGroup has been registered yet.`); } return this.queryParamGroup; } } QueryParamGroupService.decorators = [ { type: Injectable } ]; QueryParamGroupService.ctorParameters = () => [ { type: undefined, decorators: [{ type: Inject, args: [NGQP_ROUTER_ADAPTER,] }] }, { type: undefined, decorators: [{ type: Optional }, { type: Inject, args: [NGQP_ROUTER_OPTIONS,] }] } ]; //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicXVlcnktcGFyYW0tZ3JvdXAuc2VydmljZS5qcyIsInNvdXJjZVJvb3QiOiIuLi8uLi8uLi8uLi9wcm9qZWN0cy9uZ3FwL2NvcmUvc3JjLyIsInNvdXJjZXMiOlsibGliL2RpcmVjdGl2ZXMvcXVlcnktcGFyYW0tZ3JvdXAuc2VydmljZS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQUUsTUFBTSxFQUFFLFVBQVUsRUFBRSxTQUFTLEVBQWEsUUFBUSxFQUFFLE1BQU0sZUFBZSxDQUFDO0FBRW5GLE9BQU8sRUFBRSxLQUFLLEVBQUUsUUFBUSxFQUFFLElBQUksRUFBYyxPQUFPLEVBQUUsR0FBRyxFQUFFLE1BQU0sTUFBTSxDQUFDO0FBQ3ZFLE9BQU8sRUFDSCxVQUFVLEVBQ1YsU0FBUyxFQUNULFlBQVksRUFDWixvQkFBb0IsRUFDcEIsTUFBTSxFQUNOLEdBQUcsRUFDSCxTQUFTLEVBQ1QsU0FBUyxFQUNULFNBQVMsRUFDVCxHQUFHLEVBQ04sTUFBTSxnQkFBZ0IsQ0FBQztBQUN4QixPQUFPLEVBQUUsZ0JBQWdCLEVBQUUsY0FBYyxFQUFFLFNBQVMsRUFBRSxTQUFTLEVBQUUsR0FBRyxFQUFFLE1BQU0sU0FBUyxDQUFDO0FBRXRGLE9BQU8sRUFBbUIscUJBQXFCLEVBQWMsTUFBTSxzQkFBc0IsQ0FBQztBQUMxRixPQUFPLEVBQUUsbUJBQW1CLEVBQUUsbUJBQW1CLEVBQWdDLE1BQU0sNENBQTRDLENBQUM7QUFHcEksZ0JBQWdCO0FBQ2hCLFNBQVMsaUJBQWlCLENBQUksVUFBOEM7SUFDeEUsT0FBTyxVQUFVLENBQUMsS0FBSyxDQUFDO0FBQzVCLENBQUM7QUFFRCxnQkFBZ0I7QUFDaEIsTUFBTSxjQUFjO0lBQ2hCLFlBQW1CLE1BQWMsRUFBUyxZQUFxQixLQUFLO1FBQWpELFdBQU0sR0FBTixNQUFNLENBQVE7UUFBUyxjQUFTLEdBQVQsU0FBUyxDQUFpQjtJQUNwRSxDQUFDO0NBQ0o7QUFFRDs7Ozs7OztHQU9HO0FBRUgsTUFBTSxPQUFP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QUFFLENBQUMsTUFBTSxDQUFDLENBQUMsQ0FBQztTQUM5QixDQUFDLENBQUM7SUFDUCxDQUFDO0lBRU8sa0JBQWtCO1FBQ3RCLElBQUksQ0FBQyxJQUFJLENBQUMsZUFBZSxFQUFFO1lBQ3ZCLE1BQU0sSUFBSSxLQUFLLENBQUMsNkNBQTZDLENBQUMsQ0FBQztTQUNsRTtRQUVELE9BQU8sSUFBSSxDQUFDLGVBQWUsQ0FBQztJQUNoQyxDQUFDOzs7WUE3WEosVUFBVTs7OzRDQXdCRixNQUFNLFNBQUMsbUJBQW1COzRDQUMxQixRQUFRLFlBQUksTUFBTSxTQUFDLG1CQUFtQiIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IEluamVjdCwgSW5qZWN0YWJsZSwgaXNEZXZNb2RlLCBPbkRlc3Ryb3ksIE9wdGlvbmFsIH0gZnJvbSAnQGFuZ3VsYXIvY29yZSc7XG5pbXBvcnQgeyBQYXJhbXMgfSBmcm9tICdAYW5ndWxhci9yb3V0ZXInO1xuaW1wb3J0IHsgRU1QVFksIGZvcmtKb2luLCBmcm9tLCBPYnNlcnZhYmxlLCBTdWJqZWN0LCB6aXAgfSBmcm9tICdyeGpzJztcbmltcG9ydCB7XG4gICAgY2F0Y2hFcnJvcixcbiAgICBjb25jYXRNYXAsXG4gICAgZGVib3VuY2VUaW1lLFxuICAgIGRpc3RpbmN0VW50aWxDaGFuZ2VkLFxuICAgIGZpbHRlcixcbiAgICBtYXAsXG4gICAgc3RhcnRXaXRoLFxuICAgIHN3aXRjaE1hcCxcbiAgICB0YWtlVW50aWwsXG4gICAgdGFwXG59IGZyb20gJ3J4anMvb3BlcmF0b3JzJztcbmltcG9ydCB7IGNvbXBhcmVQYXJhbU1hcHMsIGZpbHRlclBhcmFtTWFwLCBpc01pc3NpbmcsIGlzUHJlc2VudCwgTk9QIH0gZnJvbSAnLi4vdXRpbCc7XG5pbXBvcnQgeyBRdWVyeVBhcmFtR3JvdXAgfSBmcm9tICcuLi9tb2RlbC9xdWVyeS1wYXJhbS1ncm91cCc7XG5pbXBvcnQgeyBNdWx0aVF1ZXJ5UGFyYW0sIFBhcnRpdGlvbmVkUXVlcnlQYXJhbSwgUXVlcnlQYXJhbSB9IGZyb20gJy4uL21vZGVsL3F1ZXJ5LXBhcmFtJztcbmltcG9ydCB7IE5HUVBfUk9VVEVSX0FEQVBURVIsIE5HUVBfUk9VVEVSX09QVElPTlMsIFJvdXRlckFkYXB0ZXIsIFJvdXRlck9wdGlvbnMgfSBmcm9tICcuLi9yb3V0ZXItYWRhcHRlci9yb3V0ZXItYWRhcHRlci5pbnRlcmZhY2UnO1xuaW1wb3J0IHsgUXVlcnlQYXJhbUFjY2Vzc29yIH0gZnJvbSAnLi9xdWVyeS1wYXJhbS1hY2Nlc3Nvci5pbnRlcmZhY2UnO1xuXG4vKiogQGludGVybmFsICovXG5mdW5jdGlvbiBpc011bHRpUXVlcnlQYXJhbTxUPihxdWVyeVBhcmFtOiBRdWVyeVBhcmFtPFQ+IHwgTXVsdGlRdWVyeVBhcmFtPFQ+KTogcXVlcnlQYXJhbSBpcyBNdWx0aVF1ZXJ5UGFyYW08VD4ge1xuICAgIHJldHVybiBxdWVyeVBhcmFtLm11bHRpO1xufVxuXG4vKiogQGludGVybmFsICovXG5jbGFzcyBOYXZpZ2F0aW9uRGF0YSB7XG4gICAgY29uc3RydWN0b3IocHVibGljIHBhcmFtczogUGFyYW1zLCBwdWJsaWMgc3ludGhldGljOiBib29sZWFuID0gZmFsc2UpIHtcbiAgICB9XG59XG5cbi8qKlxuICogU2VydmljZSBpbXBsZW1lbnRpbmcgdGhlIHN5bmNocm9uaXphdGlvbiBsb2dpY1xuICpcbiAqIFRoaXMgc2VydmljZSBpcyB0aGUga2V5IHRvIHRoZSBzeW5jaHJvbml6YXRpb24gcHJvY2VzcyBieSBiaW5kaW5nIGEge0BsaW5rIFF1ZXJ5UGFyYW1Hcm91cH1cbiAqIHRvIHRoZSByb3V0ZXIuXG4gKlxuICogQGludGVybmFsXG4gKi9cbkBJbmplY3RhYmxlKClcbmV4cG9ydCBjbGFzcyBRdWVyeVBhcmFtR3JvdXBTZXJ2aWNlIGltcGxlbWVudHMgT25EZXN0cm95IHtcblxuICAgIC8qKiBUaGUge0BsaW5rIFF1ZXJ5UGFyYW1Hcm91cH0gdG8gYmluZC4gKi9cbiAgICBwcml2YXRlIHF1ZXJ5UGFyYW1Hcm91cDogUXVlcnlQYXJhbUdyb3VwIHwgbnVsbCA9IG51bGw7XG5cbiAgICAvKiogTGlzdCBvZiB7QGxpbmsgUXVlcnlQYXJhbUFjY2Vzc29yfSByZWdpc3RlcmVkIHRvIHRoaXMgc2VydmljZS4gKi9cbiAgICBwcml2YXRlIGRpcmVjdGl2ZXMgPSBuZXcgTWFwPHN0cmluZywgUXVlcnlQYXJhbUFjY2Vzc29yW10+KCk7XG5cbiAgICAvKipcbiAgICAgKiBRdWV1ZSBvZiBuYXZpZ2F0aW9uIHBhcmFtZXRlcnNcbiAgICAgKlxuICAgICAqIEEgcXVldWUgaXMgdXNlZCBmb3IgbmF2aWdhdGlvbnMgYXMgd2UgbmVlZCB0byBtYWtlIHN1cmUgYWxsIHBhcmFtZXRlciBjaGFuZ2VzXG4gICAgICogYXJlIGV4ZWN1dGVkIGluIHNlcXVlbmNlIGFzIG90aGVyd2lzZSBuYXZpZ2F0aW9ucyBtaWdodCBvdmVyd3JpdGUgZWFjaCBvdGhlci5cbiAgICAgKi9cbiAgICBwcml2YXRlIHF1ZXVlJCA9IG5ldyBTdWJqZWN0PE5hdmlnYXRpb25EYXRhPigpO1xuXG4gICAgLyoqIEBpZ25vcmUgKi9cbiAgICBwcml2YXRlIHN5bmNocm9uaXplUm91dGVyJCA9IG5ldyBTdWJqZWN0PHZvaWQ+KCk7XG5cbiAgICAvKiogQGlnbm9yZSAqL1xuICAgIHByaXZhdGUgZGVzdHJveSQgPSBuZXcgU3ViamVjdDx2b2lkPigpO1xuXG4gICAgY29uc3RydWN0b3IoXG4gICAgICAgIEBJbmplY3QoTkdRUF9ST1VURVJfQURBUFRFUikgcHJpdmF0ZSByb3V0ZXJBZGFwdGVyOiBSb3V0ZXJBZGFwdGVyLFxuICAgICAgICBAT3B0aW9uYWwoKSBASW5qZWN0KE5HUVBfUk9VVEVSX09QVElPTlMpIHByaXZhdGUgZ2xvYmFsUm91dGVyT3B0aW9uczogUm91dGVyT3B0aW9uc1xuICAgICkge1xuICAgICAgICB0aGlzLnNldHVwTmF2aWdhdGlvblF1ZXVlKCk7XG4gICAgfVxuXG4gICAgLyoqIEBpZ25vcmUgKi9cbiAgICBwdWJsaWMgbmdPbkRlc3Ryb3koKSB7XG4gICAgICAgIHRoaXMuZGVzdHJveSQubmV4dCgpO1xuICAgICAgICB0aGlzLmRlc3Ryb3kkLmNvbXBsZXRlKCk7XG5cbiAgICAgICAgdGhpcy5zeW5jaHJvbml6ZVJvdXRlciQuY29tcGxldGUoKTtcblxuICAgICAgICB0aGlzLnF1ZXJ5UGFyYW1Hcm91cD8uX2NsZWFyQ2hhbmdlRnVuY3Rpb25zKCk7XG4gICAgICAgIGlmICh0aGlzLnF1ZXJ5UGFyYW1Hcm91cD8ub3B0aW9ucz8uY2xlYXJPbkRlc3Ryb3kpIHtcbiAgICAgICAgICAgIGNvbnN0IG51bGxQYXJhbXMgPSBPYmplY3QudmFsdWVzKHRoaXMucXVlcnlQYXJhbUdyb3VwLnF1ZXJ5UGFyYW1zKVxuICAgICAgICAgICAgICAgIC5tYXAocXVlcnlQYXJhbSA9PiB0aGlzLndyYXBJbnRvUGFydGl0aW9uKHF1ZXJ5UGFyYW0pKVxuICAgICAgICAgICAgICAgIC5tYXAocGFydGl0aW9uZWRRdWVyeVBhcmFtID0+IHBhcnRpdGlvbmVkUXVlcnlQYXJhbS5xdWVyeVBhcmFtcy5tYXAocXVlcnlQYXJhbSA9PiBxdWVyeVBhcmFtLnVybFBhcmFtKSlcbiAgICAgICAgICAgICAgICAucmVkdWNlKChhLCBiKSA9PiBbLi4uYSwgLi4uYl0sIFtdKVxuICAgICAgICAgICAgICAgIC5tYXAodXJsUGFyYW0gPT4gKHtbdXJsUGFyYW1dOiBudWxsfSkpXG4gICAgICAgICAgICAgICAgLnJlZHVjZSgoYSwgYikgPT4gKHsuLi5hLCAuLi5ifSksIHt9KTtcbiAgICAgICAgICAgIHRoaXMucm91dGVyQWRhcHRlci5uYXZpZ2F0ZShudWxsUGFyYW1zLCB7XG4gICAgICAgICAgICAgICAgcmVwbGFjZVVybDogdHJ1ZSxcbiAgICAgICAgICAgIH0pLnRoZW4oKTtcbiAgICAgICAgfVxuICAgIH1cblxuXG4gICAgLyoqXG4gICAgICogVXNlcyB0aGUgZ2l2ZW4ge0BsaW5rIFF1ZXJ5UGFyYW1Hcm91cH0gZm9yIHN5bmNocm9uaXphdGlvbi5cbiAgICAgKi9cbiAgICBwdWJsaWMgc2V0UXVlcnlQYXJhbUdyb3VwKHF1ZXJ5UGFyYW1Hcm91cDogUXVlcnlQYXJhbUdyb3VwKTogdm9pZCB7XG4gICAgICAgIC8vIEZJWE1FOiBJZiB0aGlzIGlzIGNhbGxlZCB3aGVuIHdlIGFscmVhZHkgaGF2ZSBhIGdyb3VwLCB3ZSBwcm9iYWJseSBuZWVkIHRvIGRvXG4gICAgICAgIC8vICAgICAgICBzb21lIGNsZWFudXAgZmlyc3QuXG4gICAgICAgIGlmICh0aGlzLnF1ZXJ5UGFyYW1Hcm91cCkge1xuICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKGBBIFF1ZXJ5UGFyYW1Hcm91cCBoYXMgYWxyZWFkeSBiZWVuIHNldHVwLiBDaGFuZ2luZyB0aGUgZ3JvdXAgaXMgY3VycmVudGx5IG5vdCBzdXBwb3J0ZWQuYCk7XG4gICAgICAgIH1cblxuICAgICAgICB0aGlzLnF1ZXJ5UGFyYW1Hcm91cCA9IHF1ZXJ5UGFyYW1Hcm91cDtcbiAgICAgICAgdGhpcy5zdGFydFN5bmNocm9uaXphdGlvbigpO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIFJlZ2lzdGVycyBhIHtAbGluayBRdWVyeVBhcmFtQWNjZXNzb3J9LlxuICAgICAqL1xuICAgIHB1YmxpYyByZWdpc3RlclF1ZXJ5UGFyYW1EaXJlY3RpdmUoZGlyZWN0aXZlOiBRdWVyeVBhcmFtQWNjZXNzb3IpOiB2b2lkIHtcbiAgICAgICAgaWYgKCFkaXJlY3RpdmUudmFsdWVBY2Nlc3Nvcikge1xuICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKGBObyB2YWx1ZSBhY2Nlc3NvciBmb3VuZCBmb3IgdGhlIGZvcm0gY29udHJvbC4gUGxlYXNlIG1ha2Ugc3VyZSB0byBpbXBsZW1lbnQgQ29udHJvbFZhbHVlQWNjZXNzb3Igb24gdGhpcyBjb21wb25lbnQuYCk7XG4gICAgICAgIH1cblxuICAgICAgICAvLyBDYXB0dXJlIHRoZSBuYW1lIGhlcmUsIHBhcnRpY3VsYXJseSBmb3IgdGhlIHF1ZXVlIGJlbG93IHRvIGF2b2lkIHJlLWV2YWx1YXRpbmdcbiAgICAgICAgLy8gaXQgYXMgaXQgbWlnaHQgY2hhbmdlIG92ZXIgdGltZS5cbiAgICAgICAgY29uc3QgcXVlcnlQYXJhbU5hbWUgPSBkaXJlY3RpdmUubmFtZTtcbiAgICAgICAgY29uc3QgcGFydGl0aW9uZWRRdWVyeVBhcmFtID0gdGhpcy5nZXRRdWVyeVBhcmFtQXNQYXJ0aXRpb24ocXVlcnlQYXJhbU5hbWUpO1xuXG4gICAgICAgIC8vIENoYW5jZXMgYXJlIHRoYXQgd2UgcmVhZCB0aGUgaW5pdGlhbCByb3V0ZSBiZWZvcmUgYSBkaXJlY3RpdmUgaGFzIGJlZW4gcmVnaXN0ZXJlZCBoZXJlLlxuICAgICAgICAvLyBUaGUgdmFsdWUgaW4gdGhlIG1vZGVsIHdpbGwgYmUgY29ycmVjdCwgYnV0IHdlIG5lZWQgdG8gc3luYyBpdCB0byB0aGUgdmlldyBvbmNlIGluaXRpYWxseS5cbiAgICAgICAgZGlyZWN0aXZlLnZhbHVlQWNjZXNzb3Iud3JpdGVWYWx1ZShwYXJ0aXRpb25lZFF1ZXJ5UGFyYW0udmFsdWUpO1xuXG4gICAgICAgIC8vIFByb3h5IHVwZGF0ZXMgZnJvbSB0aGUgdmlldyB0byBkZWJvdW5jZSB0aGVtIChpZiBuZWVkZWQpLlxuICAgICAgICBjb25zdCBxdWV1ZXMgPSBwYXJ0aXRpb25lZFF1ZXJ5UGFyYW0ucXVlcnlQYXJhbXMubWFwKCgpID0+IG5ldyBTdWJqZWN0PHVua25vd24+KCkpO1xuICAgICAgICB6aXAoXG4gICAgICAgICAgICAuLi5xdWV1ZXMubWFwKChxdWV1ZSQsIGluZGV4KSA9PiB7XG4gICAgICAgICAgICAgICAgY29uc3QgcXVlcnlQYXJhbSA9IHBhcnRpdGlvbmVkUXVlcnlQYXJhbS5xdWVyeVBhcmFtc1tpbmRleF07XG4gICAgICAgICAgICAgICAgcmV0dXJuIHF1ZXVlJC5waXBlKFxuICAgICAgICAgICAgICAgICAgICBpc1ByZXNlbnQocXVlcnlQYXJhbS5kZWJvdW5jZVRpbWUpID8gZGVib3VuY2VUaW1lKHF1ZXJ5UGFyYW0uZGVib3VuY2VUaW1lKSA6IHRhcCgpLFxuICAgICAgICAgICAgICAgICk7XG4gICAgICAgICAgICB9KVxuICAgICAgICApLnBpcGUoXG4gICAgICAgICAgICAvLyBEbyBub3Qgc3luY2hyb25pemUgd2hpbGUgdGhlIHBhcmFtIGlzIGRldGFjaGVkIGZyb20gdGhlIGdyb3VwXG4gICAgICAgICAgICBmaWx0ZXIoKCkgPT4gISF0aGlzLmdldFF1ZXJ5UGFyYW1Hcm91cCgpLmdldChxdWVyeVBhcmFtTmFtZSkpLFxuICAgICAgICAgICAgbWFwKChuZXdWYWx1ZTogdW5rbm93bltdKSA9PiB0aGlzLmdldFBhcmFtc0ZvclZhbHVlKHBhcnRpdGlvbmVkUXVlcnlQYXJhbSwgcGFydGl0aW9uZWRRdWVyeVBhcmFtLnJlZHVjZShuZXdWYWx1ZSkpKSxcbiAgICAgICAgICAgIHRha2VVbnRpbCh0aGlzLmRlc3Ryb3kkKSxcbiAgICAgICAgKS5zdWJzY3JpYmUocGFyYW1zID0+IHRoaXMuZW5xdWV1ZU5hdmlnYXRpb24obmV3IE5hdmlnYXRpb25EYXRhKHBhcmFtcykpKTtcblxuICAgICAgICBkaXJlY3RpdmUudmFsdWVBY2Nlc3Nvci5yZWdpc3Rlck9uQ2hhbmdlKChuZXdWYWx1ZTogdW5rbm93bikgPT4ge1xuICAgICAgICAgICAgY29uc3QgcGFydGl0aW9uZWQgPSBwYXJ0aXRpb25lZFF1ZXJ5UGFyYW0ucGFydGl0aW9uKG5ld1ZhbHVlKTtcbiAgICAgICAgICAgIHF1ZXVlcy5mb3JFYWNoKChxdWV1ZSQsIGluZGV4KSA9PiBxdWV1ZSQubmV4dChwYXJ0aXRpb25lZFtpbmRleF0pKTtcbiAgICAgICAgfSk7XG5cbiAgICAgICAgdGhpcy5kaXJlY3RpdmVzLnNldChxdWVyeVBhcmFtTmFtZSwgWy4uLih0aGlzLmRpcmVjdGl2ZXMuZ2V0KHF1ZXJ5UGFyYW1OYW1lKSB8fCBbXSksIGRpcmVjdGl2ZV0pO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIERlcmVnaXN0ZXJzIGEge0BsaW5rIFF1ZXJ5UGFyYW1BY2Nlc3Nvcn0gYnkgcmVmZXJlbmNpbmcgaXRzIG5hbWUuXG4gICAgICovXG4gICAgcHVibGljIGRlcmVnaXN0ZXJRdWVyeVBhcmFtRGlyZWN0aXZlKHF1ZXJ5UGFyYW1OYW1lOiBzdHJpbmcpOiB2b2lkIHtcbiAgICAgICAgaWYgKCFxdWVyeVBhcmFtTmFtZSkge1xuICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICB9XG5cbiAgICAgICAgY29uc3QgZGlyZWN0aXZlcyA9IHRoaXMuZGlyZWN0aXZlcy5nZXQocXVlcnlQYXJhbU5hbWUpO1xuICAgICAgICBpZiAoIWRpcmVjdGl2ZXMpIHtcbiAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgfVxuXG4gICAgICAgIGRpcmVjdGl2ZXMuZm9yRWFjaChkaXJlY3RpdmUgPT4ge1xuICAgICAgICAgICAgZGlyZWN0aXZlLnZhbHVlQWNjZXNzb3IucmVnaXN0ZXJPbkNoYW5nZShOT1ApO1xuICAgICAgICAgICAgZGlyZWN0aXZlLnZhbHVlQWNjZXNzb3IucmVnaXN0ZXJPblRvdWNoZWQoTk9QKTtcbiAgICAgICAgfSk7XG5cbiAgICAgICAgdGhpcy5kaXJlY3RpdmVzLmRlbGV0ZShxdWVyeVBhcmFtTmFtZSk7XG4gICAgICAgIGNvbnN0IHF1ZXJ5UGFyYW0gPSB0aGlzLmdldFF1ZXJ5UGFyYW1Hcm91cCgpLmdldChxdWVyeVBhcmFtTmFtZSk7XG4gICAgICAgIGlmIChxdWVyeVBhcmFtKSB7XG4gICAgICAgICAgICBxdWVyeVBhcmFtLl9jbGVhckNoYW5nZUZ1bmN0aW9ucygpO1xuICAgICAgICB9XG4gICAgfVxuXG4gICAgcHJpdmF0ZSBzdGFydFN5bmNocm9uaXphdGlvbigpIHtcbiAgICAgICAgdGhpcy5zZXR1cEdyb3VwQ2hhbmdlTGlzdGVuZXIoKTtcbiAgICAgICAgdGhpcy5zZXR1cFBhcmFtQ2hhbmdlTGlzdGVuZXJzKCk7XG4gICAgICAgIHRoaXMuc2V0dXBSb3V0ZXJMaXN0ZW5lcigpO1xuXG4gICAgICAgIHRoaXMud2F0Y2hOZXdQYXJhbXMoKTtcbiAgICB9XG5cbiAgICAvKiogTGlzdGVucyBmb3IgcHJvZ3JhbW1hdGljIGNoYW5nZXMgb24gZ3JvdXAgbGV2ZWwgYW5kIHN5bmNocm9uaXplcyB0byB0aGUgcm91dGVyLiAqL1xuICAgIHByaXZhdGUgc2V0dXBHcm91cENoYW5nZUxpc3RlbmVyKCk6IHZvaWQge1xuICAgICAgICB0aGlzLmdldFF1ZXJ5UGFyYW1Hcm91cCgpLl9yZWdpc3Rlck9uQ2hhbmdlKChuZXdWYWx1ZTogUmVjb3JkPHN0cmluZywgdW5rbm93bj4gfCBudWxsKSA9PiB7XG4gICAgICAgICAgICBpZiAobmV3VmFsdWUgPT09IG51bGwpIHtcbiAgICAgICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoYFJlY2VpdmVkIG51bGwgdmFsdWUgZnJvbSBRdWVyeVBhcmFtR3JvdXAuYCk7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIGxldCBwYXJhbXM6IFBhcmFtcyA9IHt9O1xuICAgICAgICAgICAgT2JqZWN0LmtleXMobmV3VmFsdWUpLmZvckVhY2gocXVlcnlQYXJhbU5hbWUgPT4ge1xuICAgICAgICAgICAgICAgIGNvbnN0IHF1ZXJ5UGFyYW0gPSB0aGlzLmdldFF1ZXJ5UGFyYW1Hcm91cCgpLmdldChxdWVyeVBhcmFtTmFtZSk7XG4gICAgICAgICAgICAgICAgaWYgKGlzTWlzc2luZyhxdWVyeVBhcmFtKSkge1xuICAgICAgICAgICAgICAgICAgICByZXR1cm47XG4gICAgICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAgICAgcGFyYW1zID0geyAuLi5wYXJhbXMsIC4uLnRoaXMuZ2V0UGFyYW1zRm9yVmFsdWUocXVlcnlQYXJhbSwgbmV3VmFsdWVbIHF1ZXJ5UGFyYW1OYW1lIF0pIH07XG4gICAgICAgICAgICB9KTtcblxuICAgICAgICAgICAgdGhpcy5lbnF1ZXVlTmF2aWdhdGlvbihuZXcgTmF2aWdhdGlvbkRhdGEocGFyYW1zLCB0cnVlKSk7XG4gICAgICAgIH0pO1xuICAgIH1cblxuICAgIC8qKiBMaXN0ZW5zIGZvciBwcm9ncmFtbWF0aWMgY2hhbmdlcyBvbiBwYXJhbWV0ZXIgbGV2ZWwgYW5kIHN5bmNocm9uaXplcyB0byB0aGUgcm91dGVyLiAqL1xuICAgIHByaXZhdGUgc2V0dXBQYXJhbUNoYW5nZUxpc3RlbmVycygpOiB2b2lkIHtcbiAgICAgICAgT2JqZWN0LmtleXModGhpcy5nZXRRdWVyeVBhcmFtR3JvdXAoKS5xdWVyeVBhcmFtcylcbiAgICAgICAgICAgIC5mb3JFYWNoKHF1ZXJ5UGFyYW1OYW1lID0+IHRoaXMuc2V0dXBQYXJhbUNoYW5nZUxpc3RlbmVyKHF1ZXJ5UGFyYW1OYW1lKSk7XG4gICAgfVxuXG4gICAgcHJpdmF0ZSBzZXR1cFBhcmFtQ2hhbmdlTGlzdGVuZXIocXVlcnlQYXJhbU5hbWU6IHN0cmluZyk6IHZvaWQge1xuICAgICAgICBjb25zdCBxdWVyeVBhcmFtID0gdGhpcy5nZXRRdWVyeVBhcmFtR3JvdXAoKS5nZXQocXVlcnlQYXJhbU5hbWUpO1xuICAgICAgICBpZiAoIXF1ZXJ5UGFyYW0pIHtcbiAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcihgTm8gcGFyYW0gaW4gZ3JvdXAgZm91bmQgZm9yIG5hbWUgJHtxdWVyeVBhcmFtTmFtZX1gKTtcbiAgICAgICAgfVxuXG4gICAgICAgIHF1ZXJ5UGFyYW0uX3JlZ2lzdGVyT25DaGFuZ2UoKG5ld1ZhbHVlOiB1bmtub3duKSA9PlxuICAgICAgICAgICAgdGhpcy5lbnF1ZXVlTmF2aWdhdGlvbihuZXcgTmF2aWdhdGlvbkRhdGEodGhpcy5nZXRQYXJhbXNGb3JWYWx1ZShxdWVyeVBhcmFtLCBuZXdWYWx1ZSksIHRydWUpKVxuICAgICAgICApO1xuICAgIH1cblxuICAgIC8qKiBMaXN0ZW5zIGZvciBjaGFuZ2VzIGluIHRoZSByb3V0ZXIgYW5kIHN5bmNocm9uaXplcyB0byB0aGUgbW9kZWwuICovXG4gICAgcHJpdmF0ZSBzZXR1cFJvdXRlckxpc3RlbmVyKCk6IHZvaWQge1xuICAgICAgICB0aGlzLnN5bmNocm9uaXplUm91dGVyJC5waXBlKFxuICAgICAgICAgICAgc3RhcnRXaXRoKHVuZGVmaW5lZCksXG4gICAgICAgICAgICBzd2l0Y2hNYXAoKCkgPT4gdGhpcy5yb3V0ZXJBZGFwdGVyLnF1ZXJ5UGFyYW1NYXAucGlwZShcbiAgICAgICAgICAgICAgICAvLyBXZSB3YW50IHRvIGlnbm9yZSBjaGFuZ2VzIHRvIHF1ZXJ5IHBhcmFtZXRlcnMgd2hpY2ggYXJlbid0IHJlbGF0ZWQgdG8gdGhpc1xuICAgICAgICAgICAgICAgIC8vIHBhcnRpY3VsYXIgZ3JvdXA7IGhvd2V2ZXIsIHdlIGRvIG5lZWQgdG8gcmVhY3QgaWYgb25lIG9mIG91ciBwYXJhbWV0ZXJzIGhhc1xuICAgICAgICAgICAgICAgIC8vIHZhbmlzaGVkIHdoZW4gaXQgd2FzIHNldCBiZWZvcmUuXG4gICAgICAgICAgICAgICAgZGlzdGluY3RVbnRpbENoYW5nZWQoKHByZXZpb3VzTWFwLCBjdXJyZW50TWFwKSA9PiB7XG4gICAgICAgICAgICAgICAgICAgIGNvbnN0IGtleXMgPSBPYmplY3QudmFsdWVzKHRoaXMuZ2V0UXVlcnlQYXJhbUdyb3VwKCkucXVlcnlQYXJhbXMpXG4gICAgICAgICAgICAgICAgICAgICAgICAubWFwKHF1ZXJ5UGFyYW0gPT4gdGhpcy53cmFwSW50b1BhcnRpdGlvbihxdWVyeVBhcmFtKSlcbiAgICAgICAgICAgICAgICAgICAgICAgIC5tYXAocGFydGl0aW9uZWRRdWVyeVBhcmFtID0+IHBhcnRpdGlvbmVkUXVlcnlQYXJhbS5xdWVyeVBhcmFtcy5tYXAocXVlcnlQYXJhbSA9PiBxdWVyeVBhcmFtLnVybFBhcmFtKSlcbiAgICAgICAgICAgICAgICAgICAgICAgIC5yZWR1Y2UoKGEsIGIpID0+IFsuLi5hLCAuLi5iXSwgW10pO1xuXG4gICAgICAgICAgICAgICAgICAgIC8vIEl0IGlzIGltcG9ydGFudCB0aGF0IHdlIGZpbHRlciB0aGUgbWFwcyBvbmx5IGhlcmUgc28gdGhhdCBib3RoIGFyZSBmaWx0ZXJlZFxuICAgICAgICAgICAgICAgICAgICAvLyB3aXRoIHRoZSBzYW1lIHNldCBvZiBrZXlzOyBvdGhlcndpc2UsIGUuZy4gcmVtb3ZpbmcgYSBwYXJhbWV0ZXIgZnJvbSB0aGUgZ3JvdXBcbiAgICAgICAgICAgICAgICAgICAgLy8gd291bGQgaW50ZXJmZXJlLlxuICAgICAgICAgICAgICAgICAgICByZXR1cm4gY29tcGFyZVBhcmFtTWFwcyhmaWx0ZXJQYXJhbU1hcChwcmV2aW91c01hcCwga2V5cyksIGZpbHRlclBhcmFtTWFwKGN1cnJlbnRNYXAsIGtleXMpKTtcbiAgICAgICAgICAgICAgICB9KSxcbiAgICAgICAgICAgICkpLFxuICAgICAgICAgICAgc3dpdGNoTWFwKHF1ZXJ5UGFyYW1NYXAgPT4ge1xuICAgICAgICAgICAgICAgIC8vIFdlIG5lZWQgdG8gY2FwdHVyZSB0aGlzIHJpZ2h0IGhlcmUgc2luY2UgdGhpcyBpcyBvbmx5IHNldCBkdXJpbmcgdGhlIG9uLWdvaW5nIG5hdmlnYXRpb24uXG4gICAgICAgICAgICAgICAgY29uc3Qgc3ludGhldGljID0gdGhpcy5pc1N5bnRoZXRpY05hdmlnYXRpb24oKTtcbiAgICAgICAgICAgICAgICBjb25zdCBxdWVyeVBhcmFtTmFtZXMgPSBPYmplY3Qua2V5cyh0aGlzLmdldFF1ZXJ5UGFyYW1Hcm91cCgpLnF1ZXJ5UGFyYW1zKTtcblxuICAgICAgICAgICAgICAgIHJldHVybiBmb3JrSm9pbjxSZWNvcmQ8c3RyaW5nLCB1bmtub3duPj4oLi4ucXVlcnlQYXJhbU5hbWVzXG4gICAgICAgICAgICAgICAgICAgIC5tYXAocXVlcnlQYXJhbU5hbWUgPT4ge1xuICAgICAgICAgICAgICAgICAgICAgICAgY29uc3QgcGFydGl0aW9uZWRRdWVyeVBhcmFtID0gdGhpcy5nZXRRdWVyeVBhcmFtQXNQYXJ0aXRpb24ocXVlcnlQYXJhbU5hbWUpO1xuXG4gICAgICAgICAgICAgICAgICAgICAgICByZXR1cm4gZm9ya0pvaW48dW5rbm93bj4oLi4ucGFydGl0aW9uZWRRdWVyeVBhcmFtLnF1ZXJ5UGFyYW1zXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgLm1hcChxdWVyeVBhcmFtID0+IGlzTXVsdGlRdWVyeVBhcmFtPHVua25vd24+KHF1ZXJ5UGFyYW0pXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgID8gcXVlcnlQYXJhbS5kZXNlcmlhbGl6ZVZhbHVlKHF1ZXJ5UGFyYW1NYXAuZ2V0QWxsKHF1ZXJ5UGFyYW0udXJsUGFyYW0pKVxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA6IHF1ZXJ5UGFyYW0uZGVzZXJpYWxpemVWYWx1ZShxdWVyeVBhcmFtTWFwLmdldChxdWVyeVBhcmFtLnVybFBhcmFtKSlcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICApXG4gICAgICAgICAgICAgICAgICAgICAgICApLnBpcGUoXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgbWFwKG5ld1ZhbHVlcyA9PiBwYXJ0aXRpb25lZFF1ZXJ5UGFyYW0ucmVkdWNlKG5ld1ZhbHVlcykpLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRhcChuZXdWYWx1ZSA9PiB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbnN0IGRpcmVjdGl2ZXMgPSB0aGlzLmRpcmVjdGl2ZXMuZ2V0KHF1ZXJ5UGFyYW1OYW1lKTtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaWYgKGRpcmVjdGl2ZXMpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRpcmVjdGl2ZXMuZm9yRWFjaChkaXJlY3RpdmUgPT4gZGlyZWN0aXZlLnZhbHVlQWNjZXNzb3Iud3JpdGVWYWx1ZShuZXdWYWx1ZSkpO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgfSksXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgbWFwKG5ld1ZhbHVlID0+IHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcmV0dXJuIHsgWyBxdWVyeVBhcmFtTmFtZSBdOiBuZXdWYWx1ZSB9O1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIH0pLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRha2VVbnRpbCh0aGlzLmRlc3Ryb3kkKSxcbiAgICAgICAgICAgICAgICAgICAgICAgICk7XG4gICAgICAgICAgICAgICAgICAgIH0pXG4gICAgICAgICAgICAgICAgKS5waXBlKFxuICAgICAgICAgICAgICAgICAgICBtYXAoKHZhbHVlczogUmVjb3JkPHN0cmluZywgdW5rbm93bj5bXSkgPT4gdmFsdWVzLnJlZHVjZSgoZ3JvdXBWYWx1ZSwgdmFsdWUpID0+IHtcbiAgICAgICAgICAgICAgICAgICAgICAgIHJldHVybiB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgLi4uZ3JvdXBWYWx1ZSxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAuLi52YWx1ZSxcbiAgICAgICAgICAgICAgICAgICAgICAgIH07XG4gICAgICAgICAgICAgICAgICAgIH0sIHt9KSksXG4gICAgICAgICAgICAgICAgICAgIHRhcChncm91cFZhbHVlID0+IHRoaXMuZ2V0UXVlcnlQYXJhbUdyb3VwKCkuc2V0VmFsdWUoZ3JvdXBWYWx1ZSwge1xuICAgICAgICAgICAgICAgICAgICAgICAgZW1pdEV2ZW50OiAhc3ludGhldGljLFxuICAgICAgICAgICAgICAgICAgICAgICAgZW1pdE1vZGVsVG9WaWV3Q2hhbmdlOiBmYWxzZSxcbiAgICAgICAgICAgICAgICAgICAgfSkpLFxuICAgICAgICAgICAgICAgICk7XG4gICAgICAgICAgICB9KSxcbiAgICAgICAgICAgIHRha2VVbnRpbCh0aGlzLmRlc3Ryb3kkKSxcbiAgICAgICAgKS5zdWJzY3JpYmUoKTtcbiAgICB9XG5cbiAgICAvKiogTGlzdGVucyBmb3IgbmV3bHkgYWRkZWQgcGFyYW1ldGVycyBhbmQgc3RhcnRzIHN5bmNocm9uaXphdGlvbiBmb3IgdGhlbS4gKi9cbiAgICBwcml2YXRlIHdhdGNoTmV3UGFyYW1zKCk6IHZvaWQge1xuICAgICAgICB0aGlzLmdldFF1ZXJ5UGFyYW1Hcm91cCgpLnF1ZXJ5UGFyYW1BZGRlZCQucGlwZShcbiAgICAgICAgICAgIHRha2VVbnRpbCh0aGlzLmRlc3Ryb3kkKVxuICAgICAgICApLnN1YnNjcmliZShxdWVyeVBhcmFtTmFtZSA9PiB7XG4gICAgICAgICAgICB0aGlzLnNldHVwUGFyYW1DaGFuZ2VMaXN0ZW5lcihxdWVyeVBhcmFtTmFtZSk7XG4gICAgICAgICAgICB0aGlzLnN5bmNocm9uaXplUm91dGVyJC5uZXh0KCk7XG4gICAgICAgIH0pO1xuICAgIH1cblxuICAgIC8qKiBSZXR1cm5zIHRydWUgaWYgdGhlIGN1cnJlbnQgbmF2aWdhdGlvbiBpcyBzeW50aGV0aWMuICovXG4gICAgcHJpdmF0ZSBpc1N5bnRoZXRpY05hdmlnYXRpb24oKTogYm9vbGVhbiB7XG4gICAgICAgIGNvbnN0IG5hdmlnYXRpb24gPSB0aGlzLnJvdXRlckFkYXB0ZXIuZ2V0Q3VycmVudE5hdmlnYXRpb24oKTtcbiAgICAgICAgaWYgKCFuYXZpZ2F0aW9uIHx8IG5hdmlnYXRpb24udHJpZ2dlciAhPT0gJ2ltcGVyYXRpdmUnKSB7XG4gICAgICAgICAgICAvLyBXaGVuIHVzaW5nIHRoZSBiYWNrIC8gZm9yd2FyZCBidXR0b25zLCB0aGUgc3RhdGUgaXMgcGFzc2VkIGFsb25nIHdpdGggaXQsIGV2ZW4gdGhvdWdoXG4gICAgICAgICAgICAvLyBmb3IgdXMgaXQncyBub3cgYSBuYXZpZ2F0aW9uIGluaXRpYXRlZCBieSB0aGUgdXNlci4gVGhlcmVmb3JlLCBhIG5hdmlnYXRpb24gY2FuIG9ubHlcbiAgICAgICAgICAgIC8vIGJlIHN5bnRoZXRpYyBpZiBpdCBoYXMgYmVlbiB0cmlnZ2VyZWQgaW1wZXJhdGl2ZWx5LlxuICAgICAgICAgICAgLy8gU2VlIGh0dHBzOi8vZ2l0aHViLmNvbS9hbmd1bGFyL2FuZ3VsYXIvaXNzdWVzLzI4MTA4LlxuICAgICAgICAgICAgcmV0dXJuIGZhbHNlO1xuICAgICAgICB9XG5cbiAgICAgICAgcmV0dXJuIG5hdmlnYXRpb24uZXh0cmFzICYmIG5hdmlnYXRpb24uZXh0cmFzLnN0YXRlICYmIG5hdmlnYXRpb24uZXh0cmFzLnN0YXRlWydzeW50aGV0aWMnXTtcbiAgICB9XG5cbiAgICAvKiogU3Vic2NyaWJlcyB0byB0aGUgcGFyYW1ldGVyIHF1ZXVlIGFuZCBleGVjdXRlcyBuYXZpZ2F0aW9ucyBpbiBzZXF1ZW5jZS4gKi9cbiAgICBwcml2YXRlIHNldHVwTmF2aWdhdGlvblF1ZXVlKCkge1xuICAgICAgICB0aGlzLnF1ZXVlJC5waXBlKFxuICAgICAgICAgICAgdGFrZVVudGlsKHRoaXMuZGVzdHJveSQpLFxuICAgICAgICAgICAgY29uY2F0TWFwKGRhdGEgPT4gdGhpcy5uYXZpZ2F0ZVNhZmVseShkYXRhKSksXG4gICAgICAgICkuc3Vic2NyaWJlKCk7XG4gICAgfVxuXG4gICAgcHJpdmF0ZSBuYXZpZ2F0ZVNhZmVseShkYXRhOiBOYXZpZ2F0aW9uRGF0YSk6IE9ic2VydmFibGU8Ym9vbGVhbj4ge1xuICAgICAgICByZXR1cm4gZnJvbSh0aGlzLnJvdXRlckFkYXB0ZXIubmF2aWdhdGUoZGF0YS5wYXJhbXMsIHtcbiAgICAgICAgICAgIC4uLnRoaXMucm91dGVyT3B0aW9ucyxcbiAgICAgICAgICAgIHN0YXRlOiB7IHN5bnRoZXRpYzogZGF0YS5zeW50aGV0aWMgfSxcbiAgICAgICAgfSkpLnBpcGUoXG4gICAgICAgICAgICBjYXRjaEVycm9yKChlcnI6IHVua25vd24pID0+IHtcbiAgICAgICAgICAgICAgICBpZiAoaXNEZXZNb2RlKCkpIHtcbiAgICAgICAgICAgICAgICAgICAgY29uc29sZS5lcnJvcihgVGhlcmUgd2FzIGFuIGVycm9yIHdoaWxlIG5hdmlnYXRpbmdgLCBlcnIpO1xuICAgICAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgICAgIHJldHVybiBFTVBUWTtcbiAgICAgICAgICAgIH0pXG4gICAgICAgICk7XG4gICAgfVxuXG4gICAgLyoqIFNlbmRzIGEgY2hhbmdlIG9mIHBhcmFtZXRlcnMgdG8gdGhlIHF1ZXVlLiAqL1xuICAgIHByaXZhdGUgZW5xdWV1ZU5hdmlnYXRpb24oZGF0YTogTmF2aWdhdGlvbkRhdGEpOiB2b2lkIHtcbiAgICAgICAgdGhpcy5xdWV1ZSQubmV4dChkYXRhKTtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBSZXR1cm5zIHRoZSBmdWxsIHNldCBvZiBwYXJhbWV0ZXJzIGdpdmVuIGEgdmFsdWUgZm9yIGEgcGFyYW1ldGVyIG1vZGVsLlxuICAgICAqXG4gICAgICogVGhpcyBjb25zaXN0cyBtYWlubHkgb2YgcHJvcGVybHkgc2VyaWFsaXppbmcgdGhlIG1vZGVsIHZhbHVlIGFuZCBlbnN1cmluZyB0byB0YWtlXG4gICAgICogc2lkZSBlZmZlY3QgY2hhbmdlcyBpbnRvIGFjY291bnQgdGhhdCBtYXkgaGF2ZSBiZWVuIGNvbmZpZ3VyZWQuXG4gICAgICovXG4gICAgcHJpdmF0ZSBnZXRQYXJhbXNGb3JWYWx1ZShxdWVyeVBhcmFtOiBRdWVyeVBhcmFtPHVua25vd24+IHwgTXVsdGlRdWVyeVBhcmFtPHVua25vd24+IHwgUGFydGl0aW9uZWRRdWVyeVBhcmFtPHVua25vd24+LCB2YWx1ZTogYW55KTogUGFyYW1zIHtcbiAgICAgICAgY29uc3QgcGFydGl0aW9uZWRRdWVyeVBhcmFtID0gdGhpcy53cmFwSW50b1BhcnRpdGlvbihxdWVyeVBhcmFtKTtcbiAgICAg