UNPKG

right-angled

Version:

Lightweight and easy to use angular data grids. Integrates with your markup and styles rather than generating its own.

261 lines 39.4 kB
import { Injectable } from '@angular/core'; import { cloneAsLiteral, coerceValue } from '../utilities'; import { BehaviorSubject, Subject } from 'rxjs'; import * as i0 from "@angular/core"; /** * Used for declarative building of objects which represent valuable state of `target object`. * * Since this declaration is pretty abstract and hard to understand, let's look at a specific sample. * * Typical usage of this service is something like this: * ```JavaScript * class EndUserClass { * @filter * public parameter1 = 'Hey'; * @filter * public parameter2 = 'There'; * } * let endUserClassInstance = new EndUserClass(); * let filterService = new FilterService(endUserClassInstance); * ``` * Now we can use created `filtersService` instance for several cases: * - by calling {@link getRequestState} we can get serializable representation of object state * ```JavaScript * { * parameter1: 'Hey', * parameter2: 'There' * } * ``` * - by calling {@link resetValues} we can reset values of annotated properties to initial values (or to what was specified in {@link FilterConfig.defaultValue} property). * - by calling {@link applyParams} we can automatically apply any set of values to annotated properties (we can pass queryString object to automatically apply values from it, for example). * - by calling {@link getRequestState} with some filters we can "query" the state of filters and save it to the settings storage, for example. * - by calling {@link registerFilterTarget} you can add any count of additional objects and get their * composed state via {@link getRequestState} method as well as process them all with {@link resetValues} and {@link applyParams}. */ export class RTFiltersService { constructor() { /** * Collection of {@link FilterConfig} settings that matches configuration for all objects that were registered in current service instance via {@link registerFilterTarget} method. * * This collection is also filled up with configurations of passed `target objects` base classes since config applicability is determined by `instanceof` check. * * This collection is "lazy" and will be filled up on first call of {@link resetValues}, {@link applyParams} or {@link getRequestState} method. */ this.appliedFiltersMap = new Map(); } /** * Global collection of all filters configuration. * * Used to build {@link appliedFiltersMap} for concrete set of objects that were registered as `target objects` via {@link registerFilterTarget} for concrete service instance. */ static { this.filterPropertiesMap = new Map(); } /** * @param target `target object` that will be registered with {@link registerFilterTarget} method. */ /** * Used to register type property as `target property` with specified filter config for later usage with {@link FiltersService}. * * This method is called by {@link filter} annotation, for example. * @param targetType type definition that contains specified property declaration. * @param propertyConfig configuration for property as a filter. */ static registerFilterConfig(targetType, propertyConfig) { const typeConfigs = RTFiltersService.filterPropertiesMap.has(targetType) ? RTFiltersService.filterPropertiesMap.get(targetType) : new Array(); typeConfigs.push(propertyConfig); RTFiltersService.filterPropertiesMap.set(targetType, typeConfigs); } /** * Used to build resulted value of `target property` based on specified {@link FilterConfig}. * * This method is used by {@link getRequestState} and also calls oneself for the case of array values. * * * In addition to {@link FilterConfig} configuration, this method checks if `target property` has method `toRequest()`. If so this method will be used to get serialized value. * * This convention has sense in several scenarios: * - Serialization of complex object can be performed by it's own method which was declared once instead of copy-paste it in {@link FilterConfig.serializeFormatter} declarations. * - Very tricky but sometimes useful usage of this convention is to declare `toRequest` in `Date` prototype. * * This gives ability to easily send `Date` objects to the server in appropriate format which server can apply or, for example, always send UTC-dates. * * But be accurate with this approach. There's a lot of problems with extending of embedded types. * * @param target `target` object which holds specified `target property`. Used as `this` scope for {@link FilterConfig.serializeFormatter} method. * @param value raw value of `target` property. * @param config filter configuration for `target` property. */ static buildFilterValue(target, value, config) { let result = value; if (config && config.serializeFormatter) { return config.serializeFormatter.call(target, result); } result = config && config.emptyIsNull ? result || null : result; result = config && config.coerce ? coerceValue(result) : result; if (result && result.toRequest) { return result.toRequest(); } if (Array.isArray(result)) { const temp = []; for (let i = 0; i < result.length; i++) { temp[i] = RTFiltersService.buildFilterValue(target, result[i], null); } return temp; } return result; } /** * Performs service destroy. */ destroy() { this.appliedFiltersMap.clear(); } /** * Goes through all `target properties` of all `target objects` and sets their values to configured default. * * Default value will be determined as: * - If value for {@link FilterConfig.defaultValue} is specified it will be applied. * - Otherwise this service writes to {@link FilterConfig.defaultValue} value of `target property` at the moment of first call of * {@link resetValues}, {@link applyParams} or {@link getRequestState}. * * This method performs next actions: * - If value specified as {@link FilterConfig.defaultValue} is function it will be called with `target object` as `this` scope. If specified value is not a function it will be used by itself. * - Result of previous step will be cloned by {@link cloneLiteral} function to avoid possible reference types problems. * - If {@link FilterConfig.parseFormatter} method is specified it will be called with previous step result as parameter. * - Result of previous steps is applied as value to `target property`. */ resetValues() { this.appliedFiltersMap.forEach((targetConfig, target) => { for (const config of targetConfig) { const defaultValue = typeof config.defaultValue === 'function' ? config.defaultValue.call(target) : config.defaultValue; const clonedObject = cloneAsLiteral({ defaultValue }); this.setPropertyValue(target, config, config.parseFormatter ? config.parseFormatter.call(target, clonedObject.defaultValue) : clonedObject.defaultValue); } }); } /** * Goes through all `target properties` of all `target objects` and tries to find property within passed object which name is equal * to configured {@link FilterConfig.parameterName}. * * If match is found, value of the property from passed object is applied to `target property` in accordance with * {@link FilterConfig.ignoreOnAutoMap}, {@link FilterConfig.emptyIsNull}, {@link FilterConfig.coerce}, {@link FilterConfig.parseFormatter}. * @param params - object with values to apply. */ applyParams(params) { this.appliedFiltersMap.forEach((targetConfig, target) => { for (const config of targetConfig) { if (params && Object.prototype.hasOwnProperty.call(params, config.parameterName) && false === config.ignoreOnAutoMap) { let proposedVal = config.emptyIsNull ? params[config.parameterName] || null : params[config.parameterName]; proposedVal = config.coerce ? coerceValue(proposedVal) : proposedVal; this.setPropertyValue(target, config, config.parseFormatter ? config.parseFormatter.call(target, proposedVal, params) : proposedVal); } } }); } /** * Goes through all `target properties` of all `target objects` and applies their values to one resulted object literal. * * Typical usage of this method is building request to send it to the server. * * Names of properties in result object depends on {@link FilterConfig.parameterName}. Final values would be constructed by {@link buildFilterValue} method. * @param filterFn - optional function to filter applied values. * @returns resulted object literal. */ getRequestState(filterFn) { const result = {}; this.appliedFiltersMap.forEach((targetConfig, target) => { for (let config of targetConfig) { config = { ...config }; const proposedVal = this.getPropertyValue(target, config); if (filterFn ? filterFn(config, proposedVal, target) : true) { const resultValue = RTFiltersService.buildFilterValue(target, proposedVal, config); if (!config.omitIfNullOrUndefined || (resultValue !== null && typeof resultValue !== 'undefined')) { result[config.parameterName] = resultValue; } } } }); return result; } /** * Registers passed object as `target object` for current service instance. * * {@link getRequestState} method will compose result from objects that were registered by this method. * * {@link applyParams} and {@link resetValues} methods processes registered objects that were registered by this method. * @param targets object(s) to register as `target object`. */ registerFilterTarget(...targets) { targets.forEach((target) => { if (target === null || target === undefined) { return; } this.appliedFiltersMap.set(target, null); this.buildFilterTargetMap(target); }); } /** * Removes passed object from `target objects` collection for current service instance. * * This means that {@link getRequestState}, {@link applyParams} and {@link resetValues} methods stops to process this objects. * @param targets object(s) to remove from collection of `target object`. */ removeFilterTarget(...targets) { targets.forEach((target) => { this.appliedFiltersMap.delete(target); }); } /** * Builds map of settings for passed `target` object. */ buildFilterTargetMap(target) { let targetConfig = new Array(); RTFiltersService.filterPropertiesMap.forEach((typeConfig, type) => { if (target instanceof type) { targetConfig = targetConfig.concat(typeConfig); for (const config of targetConfig) { if (typeof config.defaultValue === 'undefined') { config.defaultValue = cloneAsLiteral({ defaultValue: this.getPropertyValue(target, config) }).defaultValue; } } } }); if (targetConfig.length > 0) { this.appliedFiltersMap.set(target, targetConfig); } else { this.appliedFiltersMap.delete(target); } } getPropertyValue(target, config) { if (target[config.propertyName] instanceof BehaviorSubject) { return target[config.propertyName].getValue(); } // duck type reactive form control if (!!target[config.propertyName] && !!target[config.propertyName].setValue && !!target[config.propertyName].status) { return target[config.propertyName].value; } return target[config.propertyName]; } setPropertyValue(target, config, value) { if (!!target[config.propertyName] && target[config.propertyName] instanceof Subject) { target[config.propertyName].next(value); return; } // duck type reactive form control if (!!target[config.propertyName] && target[config.propertyName].setValue) { target[config.propertyName].setValue(value); return; } target[config.propertyName] = value; } static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: RTFiltersService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); } static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: RTFiltersService }); } } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: RTFiltersService, decorators: [{ type: Injectable }] }); //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZmlsdGVycy5zZXJ2aWNlLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vLi4vcHJvamVjdHMvcmlnaHQtYW5nbGVkL3NyYy9saWIvZmlsdGVycy9maWx0ZXJzLnNlcnZpY2UudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUFFLFVBQVUsRUFBRSxNQUFNLGVBQWUsQ0FBQztBQUUzQyxPQUFPLEVBQUUsY0FBYyxFQUFFLFdBQVcsRUFBRSxNQUFNLGNBQWMsQ0FBQztBQUMzRCxPQUFPLEVBQUUsZUFBZSxFQUFFLE9BQU8sRUFBRSxNQUFNLE1BQU0sQ0FBQzs7QUFDaEQ7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7O0dBNkJHO0FBRUgsTUFBTSxPQUFPLGdCQUFnQjtJQUQ3QjtRQVFFOzs7Ozs7V0FNRztRQUNhLHNCQUFpQixHQUFnQyxJQUFJLEdBQUcsRUFBMEIsQ0FBQztLQWtOcEc7SUEvTkM7Ozs7T0FJRzthQUNXLHdCQUFtQixHQUE2QixJQUFJLEdBQUcsRUFBdUIsQUFBM0QsQ0FBNEQ7SUFTN0Y7O09BRUc7SUFDSDs7Ozs7O09BTUc7SUFDSSxNQUFNLENBQUMsb0JBQW9CLENBQUMsVUFBa0IsRUFBRSxjQUE0QjtRQUNqRixNQUFNLFdBQVcsR0FBRyxnQkFBZ0IsQ0FBQyxtQkFBbUIsQ0FBQyxHQUFHLENBQUMsVUFBVSxDQUFDO1lBQ3RFLENBQUMsQ0FBQyxnQkFBZ0IsQ0FBQyxtQkFBbUIsQ0FBQyxHQUFHLENBQUMsVUFBVSxDQUFDO1lBQ3RELENBQUMsQ0FBQyxJQUFJLEtBQUssRUFBZ0IsQ0FBQztRQUM5QixXQUFXLENBQUMsSUFBSSxDQUFDLGNBQWMsQ0FBQyxDQUFDO1FBQ2pDLGdCQUFnQixDQUFDLG1CQUFtQixDQUFDLEdBQUcsQ0FBQyxVQUFVLEVBQUUsV0FBVyxDQUFDLENBQUM7SUFDcEUsQ0FBQztJQUNEOzs7Ozs7Ozs7Ozs7Ozs7Ozs7O09BbUJHO0lBQ0ssTUFBTSxDQUFDLGdCQUFnQixD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QyxZQUFZLENBQUMsWUFBWSxPQUFPLEVBQUU7WUFDbEYsTUFBTSxDQUFDLE1BQU0sQ0FBQyxZQUFZLENBQWtCLENBQUMsSUFBSSxDQUFDLEtBQUssQ0FBQyxDQUFDO1lBQzFELE9BQU87U0FDUjtRQUNELGtDQUFrQztRQUNsQyxJQUFJLENBQUMsQ0FBQyxNQUFNLENBQUMsTUFBTSxDQUFDLFlBQVksQ0FBQyxJQUFJLE1BQU0sQ0FBQyxNQUFNLENBQUMsWUFBWSxDQUFDLENBQUMsUUFBUSxFQUFFO1lBQ3pFLE1BQU0sQ0FBQyxNQUFNLENBQUMsWUFBWSxDQUFDLENBQUMsUUFBUSxDQUFDLEtBQUssQ0FBQyxDQUFDO1lBQzVDLE9BQU87U0FDUjtRQUNELE1BQU0sQ0FBQyxNQUFNLENBQUMsWUFBWSxDQUFDLEdBQUcsS0FBSyxDQUFDO0lBQ3RDLENBQUM7K0dBL05VLGdCQUFnQjttSEFBaEIsZ0JBQWdCOzs0RkFBaEIsZ0JBQWdCO2tCQUQ1QixVQUFVIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgSW5qZWN0YWJsZSB9IGZyb20gJ0Bhbmd1bGFyL2NvcmUnO1xyXG5pbXBvcnQgeyBGaWx0ZXJDb25maWcgfSBmcm9tICcuLi9jb3JlL2ZpbHRlci1jb25maWcnO1xyXG5pbXBvcnQgeyBjbG9uZUFzTGl0ZXJhbCwgY29lcmNlVmFsdWUgfSBmcm9tICcuLi91dGlsaXRpZXMnO1xyXG5pbXBvcnQgeyBCZWhhdmlvclN1YmplY3QsIFN1YmplY3QgfSBmcm9tICdyeGpzJztcclxuLyoqXHJcbiAqIFVzZWQgZm9yIGRlY2xhcmF0aXZlIGJ1aWxkaW5nIG9mIG9iamVjdHMgd2hpY2ggcmVwcmVzZW50IHZhbHVhYmxlIHN0YXRlIG9mIGB0YXJnZXQgb2JqZWN0YC5cclxuICpcclxuICogU2luY2UgdGhpcyBkZWNsYXJhdGlvbiBpcyBwcmV0dHkgYWJzdHJhY3QgYW5kIGhhcmQgdG8gdW5kZXJzdGFuZCwgbGV0J3MgbG9vayBhdCBhIHNwZWNpZmljIHNhbXBsZS5cclxuICpcclxuICogVHlwaWNhbCB1c2FnZSBvZiB0aGlzIHNlcnZpY2UgaXMgc29tZXRoaW5nIGxpa2UgdGhpczpcclxuICogYGBgSmF2YVNjcmlwdFxyXG4gKiAgICAgIGNsYXNzIEVuZFVzZXJDbGFzcyB7XHJcbiAqICAgICAgICAgQGZpbHRlclxyXG4gKiAgICAgICAgIHB1YmxpYyBwYXJhbWV0ZXIxID0gJ0hleSc7XHJcbiAqICAgICAgICAgQGZpbHRlclxyXG4gKiAgICAgICAgIHB1YmxpYyBwYXJhbWV0ZXIyID0gJ1RoZXJlJztcclxuICogICAgICB9XHJcbiAqICAgICAgbGV0IGVuZFVzZXJDbGFzc0luc3RhbmNlID0gbmV3IEVuZFVzZXJDbGFzcygpO1xyXG4gKiAgICAgIGxldCBmaWx0ZXJTZXJ2aWNlID0gbmV3IEZpbHRlclNlcnZpY2UoZW5kVXNlckNsYXNzSW5zdGFuY2UpO1xyXG4gKiBgYGBcclxuICogTm93IHdlIGNhbiB1c2UgY3JlYXRlZCBgZmlsdGVyc1NlcnZpY2VgIGluc3RhbmNlIGZvciBzZXZlcmFsIGNhc2VzOlxyXG4gKiAgLSBieSBjYWxsaW5nIHtAbGluayBnZXRSZXF1ZXN0U3RhdGV9IHdlIGNhbiBnZXQgc2VyaWFsaXphYmxlIHJlcHJlc2VudGF0aW9uIG9mIG9iamVjdCBzdGF0ZVxyXG4gKiBgYGBKYXZhU2NyaXB0XHJcbiAqICAgICAge1xyXG4gKiAgICAgICAgIHBhcmFtZXRlcjE6ICdIZXknLFxyXG4gKiAgICAgICAgIHBhcmFtZXRlcjI6ICdUaGVyZSdcclxuICogICAgICB9XHJcbiAqIGBgYFxyXG4gKiAgLSBieSBjYWxsaW5nIHtAbGluayByZXNldFZhbHVlc30gd2UgY2FuIHJlc2V0IHZhbHVlcyBvZiBhbm5vdGF0ZWQgcHJvcGVydGllcyB0byBpbml0aWFsIHZhbHVlcyAob3IgdG8gd2hhdCB3YXMgc3BlY2lmaWVkIGluIHtAbGluayBGaWx0ZXJDb25maWcuZGVmYXVsdFZhbHVlfSBwcm9wZXJ0eSkuXHJcbiAqICAtIGJ5IGNhbGxpbmcge0BsaW5rIGFwcGx5UGFyYW1zfSB3ZSBjYW4gYXV0b21hdGljYWxseSBhcHBseSBhbnkgc2V0IG9mIHZhbHVlcyB0byBhbm5vdGF0ZWQgcHJvcGVydGllcyAod2UgY2FuIHBhc3MgcXVlcnlTdHJpbmcgb2JqZWN0IHRvIGF1dG9tYXRpY2FsbHkgYXBwbHkgdmFsdWVzIGZyb20gaXQsIGZvciBleGFtcGxlKS5cclxuICogIC0gYnkgY2FsbGluZyB7QGxpbmsgZ2V0UmVxdWVzdFN0YXRlfSB3aXRoIHNvbWUgZmlsdGVycyB3ZSBjYW4gXCJxdWVyeVwiIHRoZSBzdGF0ZSBvZiBmaWx0ZXJzIGFuZCBzYXZlIGl0IHRvIHRoZSBzZXR0aW5ncyBzdG9yYWdlLCBmb3IgZXhhbXBsZS5cclxuICogIC0gYnkgY2FsbGluZyB7QGxpbmsgcmVnaXN0ZXJGaWx0ZXJUYXJnZXR9IHlvdSBjYW4gYWRkIGFueSBjb3VudCBvZiBhZGRpdGlvbmFsIG9iamVjdHMgYW5kIGdldCB0aGVpclxyXG4gKiBjb21wb3NlZCBzdGF0ZSB2aWEge0BsaW5rIGdldFJlcXVlc3RTdGF0ZX0gbWV0aG9kIGFzIHdlbGwgYXMgcHJvY2VzcyB0aGVtIGFsbCB3aXRoIHtAbGluayByZXNldFZhbHVlc30gYW5kIHtAbGluayBhcHBseVBhcmFtc30uXHJcbiAqL1xyXG5ASW5qZWN0YWJsZSgpXHJcbmV4cG9ydCBjbGFzcyBSVEZpbHRlcnNTZXJ2aWNlIHtcclxuICAvKipcclxuICAgKiBHbG9iYWwgY29sbGVjdGlvbiBvZiBhbGwgZmlsdGVycyBjb25maWd1cmF0aW9uLlxyXG4gICAqXHJcbiAgICogVXNlZCB0byBidWlsZCB7QGxpbmsgYXBwbGllZEZpbHRlcnNNYXB9IGZvciBjb25jcmV0ZSBzZXQgb2Ygb2JqZWN0cyB0aGF0IHdlcmUgcmVnaXN0ZXJlZCBhcyBgdGFyZ2V0IG9iamVjdHNgIHZpYSB7QGxpbmsgcmVnaXN0ZXJGaWx0ZXJUYXJnZXR9IGZvciBjb25jcmV0ZSBzZXJ2aWNlIGluc3RhbmNlLlxyXG4gICAqL1xyXG4gIHB1YmxpYyBzdGF0aWMgZmlsdGVyUHJvcGVydGllc01hcDogTWFwPGFueSwgRmlsdGVyQ29uZmlnW10+ID0gbmV3IE1hcDxhbnksIEZpbHRlckNvbmZpZ1tdPigpO1xyXG4gIC8qKlxyXG4gICAqIENvbGxlY3Rpb24gb2Yge0BsaW5rIEZpbHRlckNvbmZpZ30gc2V0dGluZ3MgdGhhdCBtYXRjaGVzIGNvbmZpZ3VyYXRpb24gZm9yIGFsbCBvYmplY3RzIHRoYXQgd2VyZSByZWdpc3RlcmVkIGluIGN1cnJlbnQgc2VydmljZSBpbnN0YW5jZSB2aWEge0BsaW5rIHJlZ2lzdGVyRmlsdGVyVGFyZ2V0fSBtZXRob2QuXHJcbiAgICpcclxuICAgKiBUaGlzIGNvbGxlY3Rpb24gaXMgYWxzbyBmaWxsZWQgdXAgd2l0aCBjb25maWd1cmF0aW9ucyBvZiBwYXNzZWQgYHRhcmdldCBvYmplY3RzYCBiYXNlIGNsYXNzZXMgc2luY2UgY29uZmlnIGFwcGxpY2FiaWxpdHkgaXMgZGV0ZXJtaW5lZCBieSBgaW5zdGFuY2VvZmAgY2hlY2suXHJcbiAgICpcclxuICAgKiBUaGlzIGNvbGxlY3Rpb24gaXMgXCJsYXp5XCIgYW5kIHdpbGwgYmUgZmlsbGVkIHVwIG9uIGZpcnN0IGNhbGwgb2Yge0BsaW5rIHJlc2V0VmFsdWVzfSwge0BsaW5rIGFwcGx5UGFyYW1zfSBvciB7QGxpbmsgZ2V0UmVxdWVzdFN0YXRlfSBtZXRob2QuXHJcbiAgICovXHJcbiAgcHVibGljIHJlYWRvbmx5IGFwcGxpZWRGaWx0ZXJzTWFwOiBNYXA8b2JqZWN0LCBGaWx0ZXJDb25maWdbXT4gPSBuZXcgTWFwPG9iamVjdCwgRmlsdGVyQ29uZmlnW10+KCk7XHJcbiAgLyoqXHJcbiAgICogQHBhcmFtIHRhcmdldCBgdGFyZ2V0IG9iamVjdGAgdGhhdCB3aWxsIGJlIHJlZ2lzdGVyZWQgd2l0aCB7QGxpbmsgcmVnaXN0ZXJGaWx0ZXJUYXJnZXR9IG1ldGhvZC5cclxuICAgKi9cclxuICAvKipcclxuICAgKiBVc2VkIHRvIHJlZ2lzdGVyIHR5cGUgcHJvcGVydHkgYXMgYHRhcmdldCBwcm9wZXJ0eWAgd2l0aCBzcGVjaWZpZWQgZmlsdGVyIGNvbmZpZyBmb3IgbGF0ZXIgdXNhZ2Ugd2l0aCB7QGxpbmsgRmlsdGVyc1NlcnZpY2V9LlxyXG4gICAqXHJcbiAgICogVGhpcyBtZXRob2QgaXMgY2FsbGVkIGJ5IHtAbGluayBmaWx0ZXJ9IGFubm90YXRpb24sIGZvciBleGFtcGxlLlxyXG4gICAqIEBwYXJhbSB0YXJnZXRUeXBlIHR5cGUgZGVmaW5pdGlvbiB0aGF0IGNvbnRhaW5zIHNwZWNpZmllZCBwcm9wZXJ0eSBkZWNsYXJhdGlvbi5cclxuICAgKiBAcGFyYW0gcHJvcGVydHlDb25maWcgY29uZmlndXJhdGlvbiBmb3IgcHJvcGVydHkgYXMgYSBmaWx0ZXIuXHJcbiAgICovXHJcbiAgcHVibGljIHN0YXRpYyByZWdpc3RlckZpbHRlckNvbmZpZyh0YXJnZXRUeXBlOiBvYmplY3QsIHByb3BlcnR5Q29uZmlnOiBGaWx0ZXJDb25maWcpOiB2b2lkIHtcclxuICAgIGNvbnN0IHR5cGVDb25maWdzID0gUlRGaWx0ZXJzU2VydmljZS5maWx0ZXJQcm9wZXJ0aWVzTWFwLmhhcyh0YXJnZXRUeXBlKVxyXG4gICAgICA/IFJURmlsdGVyc1NlcnZpY2UuZmlsdGVyUHJvcGVydGllc01hcC5nZXQodGFyZ2V0VHlwZSlcclxuICAgICAgOiBuZXcgQXJyYXk8RmlsdGVyQ29uZmlnPigpO1xyXG4gICAgdHlwZUNvbmZpZ3MucHVzaChwcm9wZXJ0eUNvbmZpZyk7XHJcbiAgICBSVEZpbHRlcnNTZXJ2aWNlLmZpbHRlclByb3BlcnRpZXNNYXAuc2V0KHRhcmdldFR5cGUsIHR5cGVDb25maWdzKTtcclxuICB9XHJcbiAgLyoqXHJcbiAgICogVXNlZCB0byBidWlsZCByZXN1bHRlZCB2YWx1ZSBvZiBgdGFyZ2V0IHByb3BlcnR5YCBiYXNlZCBvbiBzcGVjaWZpZWQge0BsaW5rIEZpbHRlckNvbmZpZ30uXHJcbiAgICpcclxuICAgKiBUaGlzIG1ldGhvZCBpcyB1c2VkIGJ5IHtAbGluayBnZXRSZXF1ZXN0U3RhdGV9IGFuZCBhbHNvIGNhbGxzIG9uZXNlbGYgZm9yIHRoZSBjYXNlIG9mIGFycmF5IHZhbHVlcy5cclxuICAgKlxyXG4gICAqXHJcbiAgICogSW4gYWRkaXRpb24gdG8ge0BsaW5rIEZpbHRlckNvbmZpZ30gY29uZmlndXJhdGlvbiwgdGhpcyBtZXRob2QgY2hlY2tzIGlmIGB0YXJnZXQgcHJvcGVydHlgIGhhcyBtZXRob2QgYHRvUmVxdWVzdCgpYC4gSWYgc28gdGhpcyBtZXRob2Qgd2lsbCBiZSB1c2VkIHRvIGdldCBzZXJpYWxpemVkIHZhbHVlLlxyXG4gICAqXHJcbiAgICogVGhpcyBjb252ZW50aW9uIGhhcyBzZW5zZSBpbiBzZXZlcmFsIHNjZW5hcmlvczpcclxuICAgKiAgLSBTZXJpYWxpemF0aW9uIG9mIGNvbXBsZXggb2JqZWN0IGNhbiBiZSBwZXJmb3JtZWQgYnkgaXQncyBvd24gbWV0aG9kIHdoaWNoIHdhcyBkZWNsYXJlZCBvbmNlIGluc3RlYWQgb2YgY29weS1wYXN0ZSBpdCBpbiB7QGxpbmsgRmlsdGVyQ29uZmlnLnNlcmlhbGl6ZUZvcm1hdHRlcn0gZGVjbGFyYXRpb25zLlxyXG4gICAqICAtIFZlcnkgdHJpY2t5IGJ1dCBzb21ldGltZXMgdXNlZnVsIHVzYWdlIG9mIHRoaXMgY29udmVudGlvbiBpcyB0byBkZWNsYXJlIGB0b1JlcXVlc3RgIGluIGBEYXRlYCBwcm90b3R5cGUuXHJcbiAgICpcclxuICAgKiBUaGlzIGdpdmVzIGFiaWxpdHkgdG8gZWFzaWx5IHNlbmQgYERhdGVgIG9iamVjdHMgdG8gdGhlIHNlcnZlciBpbiBhcHByb3ByaWF0ZSBmb3JtYXQgd2hpY2ggc2VydmVyIGNhbiBhcHBseSBvciwgZm9yIGV4YW1wbGUsIGFsd2F5cyBzZW5kIFVUQy1kYXRlcy5cclxuICAgKlxyXG4gICAqIEJ1dCBiZSBhY2N1cmF0ZSB3aXRoIHRoaXMgYXBwcm9hY2guIFRoZXJlJ3MgYSBsb3Qgb2YgcHJvYmxlbXMgd2l0aCBleHRlbmRpbmcgb2YgZW1iZWRkZWQgdHlwZXMuXHJcbiAgICpcclxuICAgKiBAcGFyYW0gdGFyZ2V0IGB0YXJnZXRgIG9iamVjdCB3aGljaCBob2xkcyBzcGVjaWZpZWQgYHRhcmdldCBwcm9wZXJ0eWAuIFVzZWQgYXMgYHRoaXNgIHNjb3BlIGZvciB7QGxpbmsgRmlsdGVyQ29uZmlnLnNlcmlhbGl6ZUZvcm1hdHRlcn0gbWV0aG9kLlxyXG4gICAqIEBwYXJhbSB2YWx1ZSByYXcgdmFsdWUgb2YgYHRhcmdldGAgcHJvcGVydHkuXHJcbiAgICogQHBhcmFtIGNvbmZpZyBmaWx0ZXIgY29uZmlndXJhdGlvbiBmb3IgYHRhcmdldGAgcHJvcGVydHkuXHJcbiAgICovXHJcbiAgcHJpdmF0ZSBzdGF0aWMgYnVpbGRGaWx0ZXJWYWx1ZSh0YXJnZXQ6IG9iamVjdCwgdmFsdWU6IGFueSwgY29uZmlnOiBGaWx0ZXJDb25maWcpOiBvYmplY3Qge1xyXG4gICAgbGV0IHJlc3VsdCA9IHZhbHVlO1xyXG4gICAgaWYgKGNvbmZpZyAmJiBjb25maWcuc2VyaWFsaXplRm9ybWF0dGVyKSB7XHJcbiAgICAgIHJldHVybiBjb25maWcuc2VyaWFsaXplRm9ybWF0dGVyLmNhbGwodGFyZ2V0LCByZXN1bHQpO1xyXG4gICAgfVxyXG5cclxuICAgIHJlc3VsdCA9IGNvbmZpZyAmJiBjb25maWcuZW1wdHlJc051bGwgPyByZXN1bHQgfHwgbnVsbCA6IHJlc3VsdDtcclxuICAgIHJlc3VsdCA9IGNvbmZpZyAmJiBjb25maWcuY29lcmNlID8gY29lcmNlVmFsdWUocmVzdWx0KSA6IHJlc3VsdDtcclxuICAgIGlmIChyZXN1bHQgJiYgcmVzdWx0LnRvUmVxdWVzdCkge1xyXG4gICAgICByZXR1cm4gcmVzdWx0LnRvUmVxdWVzdCgpO1xyXG4gICAgfVxyXG4gICAgaWYgKEFycmF5LmlzQXJyYXkocmVzdWx0KSkge1xyXG4gICAgICBjb25zdCB0ZW1wID0gW107XHJcbiAgICAgIGZvciAobGV0IGkgPSAwOyBpIDwgcmVzdWx0Lmxlbmd0aDsgaSsrKSB7XHJcbiAgICAgICAgdGVtcFtpXSA9IFJURmlsdGVyc1NlcnZpY2UuYnVpbGRGaWx0ZXJWYWx1ZSh0YXJnZXQsIHJlc3VsdFtpXSwgbnVsbCk7XHJcbiAgICAgIH1cclxuICAgICAgcmV0dXJuIHRlbXA7XHJcbiAgICB9XHJcbiAgICByZXR1cm4gcmVzdWx0O1xyXG4gIH1cclxuXHJcbiAgLyoqXHJcbiAgICogUGVyZm9ybXMgc2VydmljZSBkZXN0cm95LlxyXG4gICAqL1xyXG4gIHB1YmxpYyBkZXN0cm95KCk6IHZvaWQge1xyXG4gICAgdGhpcy5hcHBsaWVkRmlsdGVyc01hcC5jbGVhcigpO1xyXG4gIH1cclxuICAvKipcclxuICAgKiBHb2VzIHRocm91Z2ggYWxsIGB0YXJnZXQgcHJvcGVydGllc2Agb2YgYWxsIGB0YXJnZXQgb2JqZWN0c2AgYW5kIHNldHMgdGhlaXIgdmFsdWVzIHRvIGNvbmZpZ3VyZWQgZGVmYXVsdC5cclxuICAgKlxyXG4gICAqIERlZmF1bHQgdmFsdWUgd2lsbCBiZSBkZXRlcm1pbmVkIGFzOlxyXG4gICAqICAtIElmIHZhbHVlIGZvciB7QGxpbmsgRmlsdGVyQ29uZmlnLmRlZmF1bHRWYWx1ZX0gaXMgc3BlY2lmaWVkIGl0IHdpbGwgYmUgYXBwbGllZC5cclxuICAgKiAgLSBPdGhlcndpc2UgdGhpcyBzZXJ2aWNlIHdyaXRlcyB0byB7QGxpbmsgRmlsdGVyQ29uZmlnLmRlZmF1bHRWYWx1ZX0gdmFsdWUgb2YgYHRhcmdldCBwcm9wZXJ0eWAgYXQgdGhlIG1vbWVudCBvZiBmaXJzdCBjYWxsIG9mXHJcbiAgICoge0BsaW5rIHJlc2V0VmFsdWVzfSwge0BsaW5rIGFwcGx5UGFyYW1zfSBvciB7QGxpbmsgZ2V0UmVxdWVzdFN0YXRlfS5cclxuICAgKlxyXG4gICAqIFRoaXMgbWV0aG9kIHBlcmZvcm1zIG5leHQgYWN0aW9uczpcclxuICAgKiAgLSBJZiB2YWx1ZSBzcGVjaWZpZWQgYXMge0BsaW5rIEZpbHRlckNvbmZpZy5kZWZhdWx0VmFsdWV9IGlzIGZ1bmN0aW9uIGl0IHdpbGwgYmUgY2FsbGVkIHdpdGggYHRhcmdldCBvYmplY3RgIGFzIGB0aGlzYCBzY29wZS4gSWYgc3BlY2lmaWVkIHZhbHVlIGlzIG5vdCBhIGZ1bmN0aW9uIGl0IHdpbGwgYmUgdXNlZCBieSBpdHNlbGYuXHJcbiAgICogIC0gUmVzdWx0IG9mIHByZXZpb3VzIHN0ZXAgd2lsbCBiZSBjbG9uZWQgYnkge0BsaW5rIGNsb25lTGl0ZXJhbH0gZnVuY3Rpb24gdG8gYXZvaWQgcG9zc2libGUgcmVmZXJlbmNlIHR5cGVzIHByb2JsZW1zLlxyXG4gICAqICAtIElmIHtAbGluayBGaWx0ZXJDb25maWcucGFyc2VGb3JtYXR0ZXJ9IG1ldGhvZCBpcyBzcGVjaWZpZWQgaXQgd2lsbCBiZSBjYWxsZWQgd2l0aCBwcmV2aW91cyBzdGVwIHJlc3VsdCBhcyBwYXJhbWV0ZXIuXHJcbiAgICogIC0gUmVzdWx0IG9mIHByZXZpb3VzIHN0ZXBzIGlzIGFwcGxpZWQgYXMgdmFsdWUgdG8gYHRhcmdldCBwcm9wZXJ0eWAuXHJcbiAgICovXHJcbiAgcHVibGljIHJlc2V0VmFsdWVzKCk6IHZvaWQge1xyXG4gICAgdGhpcy5hcHBsaWVkRmlsdGVyc01hcC5mb3JFYWNoKCh0YXJnZXRDb25maWc6IEZpbHRlckNvbmZpZ1tdLCB0YXJnZXQ6IHsgW2lkOiBzdHJpbmddOiBhbnkgfSkgPT4ge1xyXG4gICAgICBmb3IgKGNvbnN0IGNvbmZpZyBvZiB0YXJnZXRDb25maWcpIHtcclxuICAgICAgICBjb25zdCBkZWZhdWx0VmFsdWUgPSB0eXBlb2YgY29uZmlnLmRlZmF1bHRWYWx1ZSA9PT0gJ2Z1bmN0aW9uJyA/IChjb25maWcuZGVmYXVsdFZhbHVlIGFzICgpID0+IGFueSkuY2FsbCh0YXJnZXQpIDogY29uZmlnLmRlZmF1bHRWYWx1ZTtcclxuICAgICAgICBjb25zdCBjbG9uZWRPYmplY3QgPSBjbG9uZUFzTGl0ZXJhbCh7IGRlZmF1bHRWYWx1ZSB9KTtcclxuICAgICAgICB0aGlzLnNldFByb3BlcnR5VmFsdWUoXHJcbiAgICAgICAgICB0YXJnZXQsXHJcbiAgICAgICAgICBjb25maWcsXHJcbiAgICAgICAgICBjb25maWcucGFyc2VGb3JtYXR0ZXIgPyBjb25maWcucGFyc2VGb3JtYXR0ZXIuY2FsbCh0YXJnZXQsIGNsb25lZE9iamVjdC5kZWZhdWx0VmFsdWUpIDogY2xvbmVkT2JqZWN0LmRlZmF1bHRWYWx1ZVxyXG4gICAgICAgICk7XHJcbiAgICAgIH1cclxuICAgIH0pO1xyXG4gIH1cclxuICAvKipcclxuICAgKiBHb2VzIHRocm91Z2ggYWxsIGB0YXJnZXQgcHJvcGVydGllc2Agb2YgYWxsIGB0YXJnZXQgb2JqZWN0c2AgYW5kIHRyaWVzIHRvIGZpbmQgcHJvcGVydHkgd2l0aGluIHBhc3NlZCBvYmplY3Qgd2hpY2ggbmFtZSBpcyBlcXVhbFxyXG4gICAqIHRvIGNvbmZpZ3VyZWQge0BsaW5rIEZpbHRlckNvbmZpZy5wYXJhbWV0ZXJOYW1lfS5cclxuICAgKlxyXG4gICAqIElmIG1hdGNoIGlzIGZvdW5kLCB2YWx1ZSBvZiB0aGUgcHJvcGVydHkgZnJvbSBwYXNzZWQgb2JqZWN0IGlzIGFwcGxpZWQgdG8gYHRhcmdldCBwcm9wZXJ0eWAgaW4gYWNjb3JkYW5jZSB3aXRoXHJcbiAgICoge0BsaW5rIEZpbHRlckNvbmZpZy5pZ25vcmVPbkF1dG9NYXB9LCB7QGxpbmsgRmlsdGVyQ29uZmlnLmVtcHR5SXNOdWxsfSwge0BsaW5rIEZpbHRlckNvbmZpZy5jb2VyY2V9LCB7QGxpbmsgRmlsdGVyQ29uZmlnLnBhcnNlRm9ybWF0dGVyfS5cclxuICAgKiBAcGFyYW0gcGFyYW1zIC0gb2JqZWN0IHdpdGggdmFsdWVzIHRvIGFwcGx5LlxyXG4gICAqL1xyXG4gIHB1YmxpYyBhcHBseVBhcmFtcyhwYXJhbXM6IHsgW2lkOiBzdHJpbmddOiBhbnkgfSk6IHZvaWQge1xyXG4gICAgdGhpcy5hcHBsaWVkRmlsdGVyc01hcC5mb3JFYWNoKCh0YXJnZXRDb25maWc6IEZpbHRlckNvbmZpZ1tdLCB0YXJnZXQ6IHsgW2lkOiBzdHJpbmddOiBhbnkgfSkgPT4ge1xyXG4gICAgICBmb3IgKGNvbnN0IGNvbmZpZyBvZiB0YXJnZXRDb25maWcpIHtcclxuICAgICAgICBpZiAocGFyYW1zICYmIE9iamVjdC5wcm90b3R5cGUuaGFzT3duUHJvcGVydHkuY2FsbChwYXJhbXMsIGNvbmZpZy5wYXJhbWV0ZXJOYW1lKSAmJiBmYWxzZSA9PT0gY29uZmlnLmlnbm9yZU9uQXV0b01hcCkge1xyXG4gICAgICAgICAgbGV0IHByb3Bvc2VkVmFsID0gY29uZmlnLmVtcHR5SXNOdWxsID8gcGFyYW1zW2NvbmZpZy5wYXJhbWV0ZXJOYW1lXSB8fCBudWxsIDogcGFyYW1zW2NvbmZpZy5wYXJhbWV0ZXJOYW1lXTtcclxuICAgICAgICAgIHByb3Bvc2VkVmFsID0gY29uZmlnLmNvZXJjZSA/IGNvZXJjZVZhbHVlKHByb3Bvc2VkVmFsKSA6IHByb3Bvc2VkVmFsO1xyXG4gICAgICAgICAgdGhpcy5zZXRQcm9wZXJ0eVZhbHVlKHRhcmdldCwgY29uZmlnLCBjb25maWcucGFyc2VGb3JtYXR0ZXIgPyBjb25maWcucGFyc2VGb3JtYXR0ZXIuY2FsbCh0YXJnZXQsIHByb3Bvc2VkVmFsLCBwYXJhbXMpIDogcHJvcG9zZWRWYWwpO1xyXG4gICAgICAgIH1cclxuICAgICAgfVxyXG4gICAgfSk7XHJcbiAgfVxyXG4gIC8qKlxyXG4gICAqIEdvZXMgdGhyb3VnaCBhbGwgYHRhcmdldCBwcm9wZXJ0aWVzYCBvZiBhbGwgYHRhcmdldCBvYmplY3RzYCBhbmQgYXBwbGllcyB0aGVpciB2YWx1ZXMgdG8gb25lIHJlc3VsdGVkIG9iamVjdCBsaXRlcmFsLlxyXG4gICAqXHJcbiAgICogVHlwaWNhbCB1c2FnZSBvZiB0aGlzIG1ldGhvZCBpcyBidWlsZGluZyByZXF1ZXN0IHRvIHNlbmQgaXQgdG8gdGhlIHNlcnZlci5cclxuICAgKlxyXG4gICAqIE5hbWVzIG9mIHByb3BlcnRpZXMgaW4gcmVzdWx0IG9iamVjdCBkZXBlbmRzIG9uIHtAbGluayBGaWx0ZXJDb25maWcucGFyYW1ldGVyTmFtZX0uIEZpbmFsIHZhbHVlcyB3b3VsZCBiZSBjb25zdHJ1Y3RlZCBieSB7QGxpbmsgYnVpbGRGaWx0ZXJWYWx1ZX0gbWV0aG9kLlxyXG4gICAqIEBwYXJhbSBmaWx0ZXJGbiAtIG9wdGlvbmFsIGZ1bmN0aW9uIHRvIGZpbHRlciBhcHBsaWVkIHZhbHVlcy5cclxuICAgKiBAcmV0dXJucyByZXN1bHRlZCBvYmplY3QgbGl0ZXJhbC5cclxuICAgKi9cclxuICBwdWJsaWMgZ2V0UmVxdWVzdFN0YXRlKGZpbHRlckZuPzogKGNvbmZpZzogRmlsdGVyQ29uZmlnLCBwcm9wb3NlZFZhbHVlOiBhbnksIHRhcmdldE9iamVjdDogb2JqZWN0KSA9PiBib29sZWFuKTogYW55IHtcclxuICAgIGNvbnN0IHJlc3VsdDogeyBbaWQ6IHN0cmluZ106IGFueSB9ID0ge307XHJcbiAgICB0aGlzLmFwcGxpZWRGaWx0ZXJzTWFwLmZvckVhY2goKHRhcmdldENvbmZpZzogRmlsdGVyQ29uZmlnW10sIHRhcmdldDogeyBbaWQ6IHN0cmluZ106IGFueSB9KSA9PiB7XHJcbiAgICAgIGZvciAobGV0IGNvbmZpZyBvZiB0YXJnZXRDb25maWcpIHtcclxuICAgICAgICBjb25maWcgPSB7IC4uLmNvbmZpZyB9O1xyXG4gICAgICAgIGNvbnN0IHByb3Bvc2VkVmFsID0gdGhpcy5nZXRQcm9wZXJ0eVZhbHVlKHRhcmdldCwgY29uZmlnKTtcclxuICAgICAgICBpZiAoZmlsdGVyRm4gPyBmaWx0ZXJGbihjb25maWcsIHByb3Bvc2VkVmFsLCB0YXJnZXQpIDogdHJ1ZSkge1xyXG4gICAgICAgICAgY29uc3QgcmVzdWx0VmFsdWUgPSBSVEZpbHRlcnNTZXJ2aWNlLmJ1aWxkRmlsdGVyVmFsdWUodGFyZ2V0LCBwcm9wb3NlZFZhbCwgY29uZmlnKTtcclxuICAgICAgICAgIGlmICghY29uZmlnLm9taXRJZk51bGxPclVuZGVmaW5lZCB8fCAocmVzdWx0VmFsdWUgIT09IG51bGwgJiYgdHlwZW9mIHJlc3VsdFZhbHVlICE9PSAndW5kZWZpbmVkJykpIHtcclxuICAgICAgICAgICAgcmVzdWx0W2NvbmZpZy5wYXJhbWV0ZXJOYW1lXSA9IHJlc3VsdFZhbHVlO1xyXG4gICAgICAgICAgfVxyXG4gICAgICAgIH1cclxuICAgICAgfVxyXG4gICAgfSk7XHJcbiAgICByZXR1cm4gcmVzdWx0O1xyXG4gIH1cclxuXHJcbiAgLyoqXHJcbiAgICogUmVnaXN0ZXJzIHBhc3NlZCBvYmplY3QgYXMgYHRhcmdldCBvYmplY3RgIGZvciBjdXJyZW50IHNlcnZpY2UgaW5zdGFuY2UuXHJcbiAgICpcclxuICAgKiB7QGxpbmsgZ2V0UmVxdWVzdFN0YXRlfSBtZXRob2Qgd2lsbCBjb21wb3NlIHJlc3VsdCBmcm9tIG9iamVjdHMgdGhhdCB3ZXJlIHJlZ2lzdGVyZWQgYnkgdGhpcyBtZXRob2QuXHJcbiAgICpcclxuICAgKiB7QGxpbmsgYXBwbHlQYXJhbXN9IGFuZCB7QGxpbmsgcmVzZXRWYWx1ZXN9IG1ldGhvZHMgcHJvY2Vzc2VzIHJlZ2lzdGVyZWQgb2JqZWN0cyB0aGF0IHdlcmUgcmVnaXN0ZXJlZCBieSB0aGlzIG1ldGhvZC5cclxuICAgKiBAcGFyYW0gdGFyZ2V0cyBvYmplY3QocykgdG8gcmVnaXN0ZXIgYXMgYHRhcmdldCBvYmplY3RgLlxyXG4gICAqL1xyXG4gIHB1YmxpYyByZWdpc3RlckZpbHRlclRhcmdldCguLi50YXJnZXRzOiBvYmplY3RbXSk6IHZvaWQge1xyXG4gICAgdGFyZ2V0cy5mb3JFYWNoKCh0YXJnZXQ6IG9iamVjdCkgPT4ge1xyXG4gICAgICBpZiAodGFyZ2V0ID09PSBudWxsIHx8IHRhcmdldCA9PT0gdW5kZWZpbmVkKSB7XHJcbiAgICAgICAgcmV0dXJuO1xyXG4gICAgICB9XHJcbiAgICAgIHRoaXMuYXBwbGllZEZpbHRlcnNNYXAuc2V0KHRhcmdldCwgbnVsbCk7XHJcbiAgICAgIHRoaXMuYnVpbGRGaWx0ZXJUYXJnZXRNYXAodGFyZ2V0KTtcclxuICAgIH0pO1xyXG4gIH1cclxuICAvKipcclxuICAgKiBSZW1vdmVzIHBhc3NlZCBvYmplY3QgZnJvbSBgdGFyZ2V0IG9iamVjdHNgIGNvbGxlY3Rpb24gZm9yIGN1cnJlbnQgc2VydmljZSBpbnN0YW5jZS5cclxuICAgKlxyXG4gICAqIFRoaXMgbWVhbnMgdGhhdCB7QGxpbmsgZ2V0UmVxdWVzdFN0YXRlfSwge0BsaW5rIGFwcGx5UGFyYW1zfSBhbmQge0BsaW5rIHJlc2V0VmFsdWVzfSBtZXRob2RzIHN0b3BzIHRvIHByb2Nlc3MgdGhpcyBvYmplY3RzLlxyXG4gICAqIEBwYXJhbSB0YXJnZXRzIG9iamVjdChzKSB0byByZW1vdmUgZnJvbSBjb2xsZWN0aW9uIG9mIGB0YXJnZXQgb2JqZWN0YC5cclxuICAgKi9cclxuICBwdWJsaWMgcmVtb3ZlRmlsdGVyVGFyZ2V0KC4uLnRhcmdldHM6IG9iamVjdFtdKTogdm9pZCB7XHJcbiAgICB0YXJnZXRzLmZvckVhY2goKHRhcmdldDogb2JqZWN0KSA9PiB7XHJcbiAgICAgIHRoaXMuYXBwbGllZEZpbHRlcnNNYXAuZGVsZXRlKHRhcmdldCk7XHJcbiAgICB9KTtcclxuICB9XHJcbiAgLyoqXHJcbiAgICogQnVpbGRzIG1hcCBvZiBzZXR0aW5ncyBmb3IgcGFzc2VkIGB0YXJnZXRgIG9iamVjdC5cclxuICAgKi9cclxuICBwcml2YXRlIGJ1aWxkRmlsdGVyVGFyZ2V0TWFwKHRhcmdldDogeyBbaWQ6IHN0cmluZ106IGFueSB9KTogdm9pZCB7XHJcbiAgICBsZXQgdGFyZ2V0Q29uZmlnID0gbmV3IEFycmF5PEZpbHRlckNvbmZpZz4oKTtcclxuICAgIFJURmlsdGVyc1NlcnZpY2UuZmlsdGVyUHJvcGVydGllc01hcC5mb3JFYWNoKCh0eXBlQ29uZmlnOiBGaWx0ZXJDb25maWdbXSwgdHlwZTogYW55KSA9PiB7XHJcbiAgICAgIGlmICh0YXJnZXQgaW5zdGFuY2VvZiB0eXBlKSB7XHJcbiAgICAgICAgdGFyZ2V0Q29uZmlnID0gdGFyZ2V0Q29uZmlnLmNvbmNhdCh0eXBlQ29uZmlnKTtcclxuICAgICAgICBmb3IgKGNvbnN0IGNvbmZpZyBvZiB0YXJnZXRDb25maWcpIHtcclxuICAgICAgICAgIGlmICh0eXBlb2YgY29uZmlnLmRlZmF1bHRWYWx1ZSA9PT0gJ3VuZGVmaW5lZCcpIHtcclxuICAgICAgICAgICAgY29uZmlnLmRlZmF1bHRWYWx1ZSA9IGNsb25lQXNMaXRlcmFsKHtcclxuICAgICAgICAgICAgICBkZWZhdWx0VmFsdWU6IHRoaXMuZ2V0UHJvcGVydHlWYWx1ZSh0YXJnZXQsIGNvbmZpZylcclxuICAgICAgICAgICAgfSkuZGVmYXVsdFZhbHVlO1xyXG4gICAgICAgICAgfVxyXG4gICAgICAgIH1cclxuICAgICAgfVxyXG4gICAgfSk7XHJcbiAgICBpZiAodGFyZ2V0Q29uZmlnLmxlbmd0aCA+IDApIHtcclxuICAgICAgdGhpcy5hcHBsaWVkRmlsdGVyc01hcC5zZXQodGFyZ2V0LCB0YXJnZXRDb25maWcpO1xyXG4gICAgfSBlbHNlIHtcclxuICAgICAgdGhpcy5hcHBsaWVkRmlsdGVyc01hcC5kZWxldGUodGFyZ2V0KTtcclxuICAgIH1cclxuICB9XHJcbiAgcHJpdmF0ZSBnZXRQcm9wZXJ0eVZhbHVlKHRhcmdldDogeyBbaWQ6IHN0cmluZ106IGFueSB9LCBjb25maWc6IEZpbHRlckNvbmZpZykge1xyXG4gICAgaWYgKHRhcmdldFtjb25maWcucHJvcGVydHlOYW1lXSBpbnN0YW5jZW9mIEJlaGF2aW9yU3ViamVjdCkge1xyXG4gICAgICByZXR1cm4gKHRhcmdldFtjb25maWcucHJvcGVydHlOYW1lXSBhcyBCZWhhdmlvclN1YmplY3Q8YW55PikuZ2V0VmFsdWUoKTtcclxuICAgIH1cclxuICAgIC8vIGR1Y2sgdHlwZSByZWFjdGl2ZSBmb3JtIGNvbnRyb2xcclxuICAgIGlmICghIXRhcmdldFtjb25maWcucHJvcGVydHlOYW1lXSAmJiAhIXRhcmdldFtjb25maWcucHJvcGVydHlOYW1lXS5zZXRWYWx1ZSAmJiAhIXRhcmdldFtjb25maWcucHJvcGVydHlOYW1lXS5zdGF0dXMpIHtcclxuICAgICAgcmV0dXJuIHRhcmdldFtjb25maWcucHJvcGVydHlOYW1lXS52YWx1ZTtcclxuICAgIH1cclxuICAgIHJldHVybiB0YXJnZXRbY29uZmlnLnByb3BlcnR5TmFtZV07XHJcbiAgfVxyXG4gIHByaXZhdGUgc2V0UHJvcGVydHlWYWx1ZSh0YXJnZXQ6IHsgW2lkOiBzdHJpbmddOiBhbnkgfSwgY29uZmlnOiBGaWx0ZXJDb25maWcsIHZhbHVlOiBhbnkpIHtcclxuICAgIGlmICghIXRhcmdldFtjb25maWcucHJvcGVydHlOYW1lXSAmJiB0YXJnZXRbY29uZmlnLnByb3BlcnR5TmFtZV0gaW5zdGFuY2VvZiBTdWJqZWN0KSB7XHJcbiAgICAgICh0YXJnZXRbY29uZmlnLnByb3BlcnR5TmFtZV0gYXMgU3ViamVjdDxhbnk+KS5uZXh0KHZhbHVlKTtcclxuICAgICAgcmV0dXJuO1xyXG4gICAgfVxyXG4gICAgLy8gZHVjayB0eXBlIHJlYWN0aXZlIGZvcm0gY29udHJvbFxyXG4gICAgaWYgKCEhdGFyZ2V0W2NvbmZpZy5wcm9wZXJ0eU5hbWVdICYmIHRhcmdldFtjb25maWcucHJvcGVydHlOYW1lXS5zZXRWYWx1ZSkge1xyXG4gICAgICB0YXJnZXRbY29uZmlnLnByb3BlcnR5TmFtZV0uc2V0VmFsdWUodmFsdWUpO1xyXG4gICAgICByZXR1cm47XHJcbiAgICB9XHJcbiAgICB0YXJnZXRbY29uZmlnLnByb3BlcnR5TmFtZV0gPSB2YWx1ZTtcclxuICB9XHJcbn1cclxuIl19