@ngqp/core
Version:
314 lines • 53.9 kB
JavaScript
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