UNPKG

@netgrif/components-core

Version:

Netgrif Application engine frontend core Angular library

335 lines 45.9 kB
import { Inject, Injectable, Optional } from '@angular/core'; import { BooleanOperator } from '../models/boolean-operator'; import { Filter } from '../../filter/models/filter'; import { BehaviorSubject, forkJoin, Observable, Subject } from 'rxjs'; import { SimpleFilter } from '../../filter/models/simple-filter'; import { MergeOperator } from '../../filter/models/merge-operator'; import { distinctUntilChanged, map, tap } from 'rxjs/operators'; import { EditableClausePredicateWithGenerators } from '../models/predicate/editable-clause-predicate-with-generators'; import { NAE_BASE_FILTER } from '../models/base-filter-injection-token'; import { LoadingEmitter } from '../../utility/loading-emitter'; import * as i0 from "@angular/core"; import * as i1 from "../../logger/services/logger.service"; import * as i2 from "../category-factory/category-factory"; /** * Holds information about the filter that is currently applied to the view component, that provides this services. */ export class SearchService { _log; _categoryFactory; /** * {@link Filter} that is applied to the view, even if the user doesn't search anything. */ _baseFilter; /** * Holds the {@link Predicate} tree root for user search queries. */ _rootPredicate; /** * Holds the {@link Filter} that is currently being applied to the view. */ _activeFilter; /** * Holds the full text {@link Filter} if set, `undefined` otherwise. */ _fullTextFilter; /** * The index of a removed {@link Predicate} is emmited into this stream */ _predicateRemoved$; _loadingFromMetadata$; /** * The `rootPredicate` uses this stream to notify the search service about changes to the held query */ _predicateQueryChanged$; subFilter; /** * The {@link Predicate} tree root uses an [AND]{@link BooleanOperator#AND} operator to combine the Predicates. * @param _log {@link LoggerService} * @param _categoryFactory a {@link CategoryFactory} instance. This dependency is optional. * It is required if we want to load predicate filter from saved metadata * @param baseFilter Filter that should be applied to the view when no searching is being performed. * Injected trough the {@link NAE_BASE_FILTER} injection token. */ constructor(_log, _categoryFactory, baseFilter) { this._log = _log; this._categoryFactory = _categoryFactory; if (baseFilter.filter instanceof Filter) { this._baseFilter = baseFilter.filter.clone(); } else if (baseFilter.filter instanceof Observable) { this._baseFilter = new SimpleFilter('', baseFilter.filterType, { process: { identifier: '__EMPTY__' } }); } else { throw new Error('Unsupported BaseFilter input! You must provide the NAE_BASE_FILTER injection token with proper values!'); } this._predicateQueryChanged$ = new Subject(); this._rootPredicate = new EditableClausePredicateWithGenerators(BooleanOperator.AND, this._predicateQueryChanged$, undefined, true); this._activeFilter = new BehaviorSubject(this._baseFilter); this._predicateRemoved$ = new Subject(); this._loadingFromMetadata$ = new LoadingEmitter(); if (baseFilter.filter instanceof Observable) { this.subFilter = baseFilter.filter.subscribe((filter) => { this._baseFilter = filter.clone(); this.updateActiveFilter(); }); } this.predicateQueryChanged$.subscribe(() => { this.updateActiveFilter(); }); } ngOnDestroy() { this._predicateRemoved$.complete(); this._activeFilter.complete(); this._predicateQueryChanged$.complete(); if (this.subFilter) { this.subFilter.unsubscribe(); } this._loadingFromMetadata$.complete(); this._rootPredicate.destroy(); } /** * @returns the Filter that is currently applied to the view */ get activeFilter() { return this._activeFilter.getValue(); } /** * @returns an `Observable` that updates every time the active Filter changes. */ get activeFilter$() { return this._activeFilter.asObservable(); } /** * @returns `true` if a filter other than the base filter is currently applied. * Returns `false` if only the base filter is currently applied. */ get additionalFiltersApplied() { return !this._rootPredicate.query.isEmpty || !!this._fullTextFilter; } /** * @returns `true` if any visible predicates are applied. * Returns `false` if there are no predicates, or if there are only hidden predicates applied */ get hasVisiblePredicates() { for (const predicate of this._rootPredicate.getPredicateMap().values()) { if (predicate.isVisible) { return true; } } return false; } /** * @returns a copy of the base filter */ get baseFilter() { return this._baseFilter.clone(); } /** * @returns an Observable that emits the index of the removed predicate whenever a predicate is removed */ get predicateRemoved$() { return this._predicateRemoved$.asObservable(); } /** * @returns the root predicate of the search service, that can be used to generate search requests with custom queries */ get rootPredicate() { return this._rootPredicate; } /** * @returns the type of the filter held in this search service instance */ get filterType() { return this.baseFilter.type; } /** * @returns whether the search service is currently loading its state from metadata or not. * * See [loadFromMetadata()]{@link SearchService#loadFromMetadata} */ get loadingFromMetadata() { return this._loadingFromMetadata$.value; } /** * @returns an `Observable` that emits `true` if the search service is currently loading its state from metadata, * emits `false` otherwise. * * See [loadFromMetadata()]{@link SearchService#loadFromMetadata} */ get loadingFromMetadata$() { return this._loadingFromMetadata$.asObservable(); } /** * @returns an Observable that emits whenever the root predicates query changes */ get predicateQueryChanged$() { return this._predicateQueryChanged$.asObservable().pipe(map(() => this._rootPredicate.query), distinctUntilChanged((prev, curr) => prev && prev.equals(curr))); } /** * Adds a {@link Predicate} to the Predicate root and updates the active Filter. * * Predicates added this way will not be visible in the search GUI. * If you want to make sure your predicates are visible (and editable) * use the [addGeneratedLeafPredicate()]{@link SearchService#addGeneratedLeafPredicate} method instead. * @param newPredicate Predicate that should be added to the search queries. * @returns the index of the added Predicate */ addPredicate(newPredicate) { return this._rootPredicate.addPredicate(newPredicate, false); } /** * Adds a new hidden branch of the predicate tree with a singular leaf node containing the provided Query. * * This can be used to add predicates to the search tree (think header search), * which can be made visible and editable in the search GUI later. * @param generator the generator that is in such state, that it generates the Query, that should be added as branch/leaf. * If the generator doesn't currently generate a query a node with an empty query will be added. */ addGeneratedLeafPredicate(generator) { const branchId = this._rootPredicate.addNewClausePredicate(BooleanOperator.OR, false); const branch = this._rootPredicate.getPredicateMap().get(branchId).getWrappedPredicate(); branch.addNewPredicateFromGenerator(generator); return branchId; } /** * Removes the {@link Predicate} object from the provided index. If the index is invalid does nothing. * Updates the the active Filter if the Predicate tree was affected. * @param index index of the Predicate that should be removed * @param clearInput whether the input, that corresponds to the predicate should be cleared */ removePredicate(index, clearInput = true) { if (this._rootPredicate.removePredicate(index)) { this._predicateRemoved$.next({ index, clearInput }); } } /** * Removes all {@link Predicate} objects that contribute to the search. Updates the active Filter if it was affected. * * @param clearHidden whether the hidden predicates should be cleared as well */ clearPredicates(clearHidden = false) { if (this._rootPredicate.getPredicateMap().size > 0) { for (const [id, predicate] of this._rootPredicate.getPredicateMap().entries()) { if (clearHidden || predicate.isVisible) { this.removePredicate(id); } } this.updateActiveFilter(); } } /** * Adds a {@link Filter} with the [fullText]{@link CaseSearchRequestBody#fullText} attribute set to the provided value. * If full text filter is already set, it will be replaced. * @param searchedSubstring value that should be searched on all full text fields */ setFullTextFilter(searchedSubstring) { const whiteSpacedSubstring = searchedSubstring?.replace(/ /g, '\\ '); this._fullTextFilter = new SimpleFilter('', this._baseFilter.type, { fullText: whiteSpacedSubstring }); this.updateActiveFilter(); } /** * Clears the full text filter (if set). If the full text filter is not set, does nothing. */ clearFullTextFilter() { const wasFulltextSet = this._fullTextFilter !== undefined; this._fullTextFilter = undefined; if (wasFulltextSet) { this.updateActiveFilter(); } } /** * Shows the predicates with the given ids. Skips ids that don't exist. * @param predicateIds the ids of the predicates that should be shown. */ show(predicateIds) { this._rootPredicate.showPredicates(predicateIds); } /** * Reads the current query from the predicate tree, combines it with the base Filter and full text Filter (if set) * and updates the active Filter. */ updateActiveFilter() { let additionalFilter; if (!this._rootPredicate.query.isEmpty) { additionalFilter = new SimpleFilter('', this._baseFilter.type, { query: this._rootPredicate.query.value }); } if (this._fullTextFilter) { if (additionalFilter) { additionalFilter = additionalFilter.merge(this._fullTextFilter, MergeOperator.AND); } else { additionalFilter = this._fullTextFilter; } } if (additionalFilter) { this._activeFilter.next(this._baseFilter.merge(additionalFilter, MergeOperator.AND)); } else { this._activeFilter.next(this._baseFilter.clone()); } } /** * @returns `undefined` if the predicate tree contains no complete query. * Otherwise returns the serialized form of the completed queries in the predicate tree. */ createPredicateMetadata() { return this._rootPredicate.createGeneratorMetadata(); } /** * Replaces the current predicate filter by the one corresponding to the provided generator metadata. * * The {@link CategoryFactory} instance must be provided for this service if we want to use this method. Logs an error and does nothing. * * The `filterType` of this search service must match the `filterType` of the provided metadata. Otherwise an error is thrown. * * @param metadata the serialized state of the predicate tree that should be restored to this search service */ loadFromMetadata(metadata) { if (this._categoryFactory === null) { this._log.error('A CategoryFactory instance must be provided for the SearchService' + ' if you want to reconstruct a predicate filter from saved metadata'); return; } if (metadata.filterType !== this.filterType) { throw Error(`The filter type of the provided metadata (${metadata.filterType}) does not match the filter type of the search service (${this.filterType})!`); } this.clearPredicates(true); this._loadingFromMetadata$.on(); const generatorObservables = []; if (Array.isArray(metadata.predicateMetadata)) { for (const clause of metadata.predicateMetadata) { const branchId = this._rootPredicate.addNewClausePredicate(BooleanOperator.OR); const branchPredicate = this._rootPredicate.getPredicateMap().get(branchId) .getWrappedPredicate(); for (const predicate of clause) { const localBranchReference = branchPredicate; generatorObservables.push(this._categoryFactory.getFromMetadata(predicate).pipe(tap(generator => { localBranchReference.addNewPredicateFromGenerator(generator); }))); } } } forkJoin(generatorObservables).subscribe(() => { this._loadingFromMetadata$.off(); this.updateActiveFilter(); }); } /** * @returns an Array of filter text segments that correspond to the currently displayed completed predicates */ createFilterTextSegments() { return this._rootPredicate.createFilterTextSegments(); } static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: SearchService, deps: [{ token: i1.LoggerService }, { token: i2.CategoryFactory, optional: true }, { token: NAE_BASE_FILTER }], target: i0.ɵɵFactoryTarget.Injectable }); static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: SearchService }); } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: SearchService, decorators: [{ type: Injectable }], ctorParameters: () => [{ type: i1.LoggerService }, { type: i2.CategoryFactory, decorators: [{ type: Optional }] }, { type: undefined, decorators: [{ type: Inject, args: [NAE_BASE_FILTER] }] }] }); //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic2VhcmNoLnNlcnZpY2UuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi8uLi9wcm9qZWN0cy9uZXRncmlmLWNvbXBvbmVudHMtY29yZS9zcmMvbGliL3NlYXJjaC9zZWFyY2gtc2VydmljZS9zZWFyY2guc2VydmljZS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQUMsTUFBTSxFQUFFLFVBQVUsRUFBYSxRQUFRLEVBQUMsTUFBTSxlQUFlLENBQUM7QUFDdEUsT0FBTyxFQUFDLGVBQWUsRUFBQyxNQUFNLDRCQUE0QixDQUFDO0FBQzNELE9BQU8sRUFBQyxNQUFNLEVBQUMsTUFBTSw0QkFBNEIsQ0FBQztBQUNsRCxPQUFPLEVBQUMsZUFBZSxFQUFFLFFBQVEsRUFBRSxVQUFVLEVBQUUsT0FBTyxFQUFlLE1BQU0sTUFBTSxDQUFDO0FBRWxGLE9BQU8sRUFBQyxZQUFZLEVBQUMsTUFBTSxtQ0FBbUMsQ0FBQztBQUMvRCxPQUFPLEVBQUMsYUFBYSxFQUFDLE1BQU0sb0NBQW9DLENBQUM7QUFHakUsT0FBTyxFQUFDLG9CQUFvQixFQUFFLEdBQUcsRUFBRSxHQUFHLEVBQUMsTUFBTSxnQkFBZ0IsQ0FBQztBQUM5RCxPQUFPLEVBQUMscUNBQXFDLEVBQUMsTUFBTSwrREFBK0QsQ0FBQztBQUdwSCxPQUFPLEVBQUMsZUFBZSxFQUFDLE1BQU0sdUNBQXVDLENBQUM7QUFLdEUsT0FBTyxFQUFDLGNBQWMsRUFBQyxNQUFNLCtCQUErQixDQUFDOzs7O0FBSTdEOztHQUVHO0FBRUgsTUFBTSxPQUFPLGFBQWE7SUFxQ0E7SUFDWTtJQXBDbEM7O09BRUc7SUFDTyxXQUFXLENBQVM7SUFDOUI7O09BRUc7SUFDTyxjQUFjLENBQXdDO0lBQ2hFOztPQUVHO0lBQ08sYUFBYSxDQUEwQjtJQUNqRDs7T0FFRztJQUNPLGVBQWUsQ0FBMkI7SUFDcEQ7O09BRUc7SUFDTyxrQkFBa0IsQ0FBaUM7SUFDbkQscUJBQXFCLENBQWlCO0lB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ZXNDb250ZW50IjpbImltcG9ydCB7SW5qZWN0LCBJbmplY3RhYmxlLCBPbkRlc3Ryb3ksIE9wdGlvbmFsfSBmcm9tICdAYW5ndWxhci9jb3JlJztcbmltcG9ydCB7Qm9vbGVhbk9wZXJhdG9yfSBmcm9tICcuLi9tb2RlbHMvYm9vbGVhbi1vcGVyYXRvcic7XG5pbXBvcnQge0ZpbHRlcn0gZnJvbSAnLi4vLi4vZmlsdGVyL21vZGVscy9maWx0ZXInO1xuaW1wb3J0IHtCZWhhdmlvclN1YmplY3QsIGZvcmtKb2luLCBPYnNlcnZhYmxlLCBTdWJqZWN0LCBTdWJzY3JpcHRpb259IGZyb20gJ3J4anMnO1xuaW1wb3J0IHtQcmVkaWNhdGV9IGZyb20gJy4uL21vZGVscy9wcmVkaWNhdGUvcHJlZGljYXRlJztcbmltcG9ydCB7U2ltcGxlRmlsdGVyfSBmcm9tICcuLi8uLi9maWx0ZXIvbW9kZWxzL3NpbXBsZS1maWx0ZXInO1xuaW1wb3J0IHtNZXJnZU9wZXJhdG9yfSBmcm9tICcuLi8uLi9maWx0ZXIvbW9kZWxzL21lcmdlLW9wZXJhdG9yJztcbmltcG9ydCB7UHJlZGljYXRlUmVtb3ZhbEV2ZW50fSBmcm9tICcuLi9tb2RlbHMvcHJlZGljYXRlLXJlbW92YWwtZXZlbnQnO1xuaW1wb3J0IHtRdWVyeX0gZnJvbSAnLi4vbW9kZWxzL3F1ZXJ5L3F1ZXJ5JztcbmltcG9ydCB7ZGlzdGluY3RVbnRpbENoYW5nZWQsIG1hcCwgdGFwfSBmcm9tICdyeGpzL29wZXJhdG9ycyc7XG5pbXBvcnQge0VkaXRhYmxlQ2xhdXNlUHJlZGljYXRlV2l0aEdlbmVyYXRvcnN9IGZyb20gJy4uL21vZGVscy9wcmVkaWNhdGUvZWRpdGFibGUtY2xhdXNlLXByZWRpY2F0ZS13aXRoLWdlbmVyYXRvcnMnO1xuaW1wb3J0IHtDYXRlZ29yeX0gZnJvbSAnLi4vbW9kZWxzL2NhdGVnb3J5L2NhdGVnb3J5JztcbmltcG9ydCB7UHJlZGljYXRlVHJlZU1ldGFkYXRhfSBmcm9tICcuLi9tb2RlbHMvcGVyc2lzdGFuY2UvZ2VuZXJhdG9yLW1ldGFkYXRhJztcbmltcG9ydCB7TkFFX0JBU0VfRklMVEVSfSBmcm9tICcuLi9tb2RlbHMvYmFzZS1maWx0ZXItaW5qZWN0aW9uLXRva2VuJztcbmltcG9ydCB7QmFzZUZpbHRlcn0gZnJvbSAnLi4vbW9kZWxzL2Jhc2UtZmlsdGVyJztcbmltcG9ydCB7TG9nZ2VyU2VydmljZX0gZnJvbSAnLi4vLi4vbG9nZ2VyL3NlcnZpY2VzL2xvZ2dlci5zZXJ2aWNlJztcbmltcG9ydCB7Q2F0ZWdvcnlGYWN0b3J5fSBmcm9tICcuLi9jYXRlZ29yeS1mYWN0b3J5L2NhdGVnb3J5LWZhY3RvcnknO1xuaW1wb3J0IHtGaWx0ZXJUeXBlfSBmcm9tICcuLi8uLi9maWx0ZXIvbW9kZWxzL2ZpbHRlci10eXBlJztcbmltcG9ydCB7TG9hZGluZ0VtaXR0ZXJ9IGZyb20gJy4uLy4uL3V0aWxpdHkvbG9hZGluZy1lbWl0dGVyJztcbmltcG9ydCB7RmlsdGVyTWV0YWRhdGF9IGZyb20gJy4uL21vZGVscy9wZXJzaXN0YW5jZS9maWx0ZXItbWV0YWRhdGEnO1xuaW1wb3J0IHtGaWx0ZXJUZXh0U2VnbWVudH0gZnJvbSAnLi4vbW9kZWxzL3BlcnNpc3RhbmNlL2ZpbHRlci10ZXh0LXNlZ21lbnQnO1xuXG4vKipcbiAqIEhvbGRzIGluZm9ybWF0aW9uIGFib3V0IHRoZSBmaWx0ZXIgdGhhdCBpcyBjdXJyZW50bHkgYXBwbGllZCB0byB0aGUgdmlldyBjb21wb25lbnQsIHRoYXQgcHJvdmlkZXMgdGhpcyBzZXJ2aWNlcy5cbiAqL1xuQEluamVjdGFibGUoKVxuZXhwb3J0IGNsYXNzIFNlYXJjaFNlcnZpY2UgaW1wbGVtZW50cyBPbkRlc3Ryb3kge1xuXG4gICAgLyoqXG4gICAgICoge0BsaW5rIEZpbHRlcn0gdGhhdCBpcyBhcHBsaWVkIHRvIHRoZSB2aWV3LCBldmVuIGlmIHRoZSB1c2VyIGRvZXNuJ3Qgc2VhcmNoIGFueXRoaW5nLlxuICAgICAqL1xuICAgIHByb3RlY3RlZCBfYmFzZUZpbHRlcjogRmlsdGVyO1xuICAgIC8qKlxuICAgICAqIEhvbGRzIHRoZSB7QGxpbmsgUHJlZGljYXRlfSB0cmVlIHJvb3QgZm9yIHVzZXIgc2VhcmNoIHF1ZXJpZXMuXG4gICAgICovXG4gICAgcHJvdGVjdGVkIF9yb290UHJlZGljYXRlOiBFZGl0YWJsZUNsYXVzZVByZWRpY2F0ZVdpdGhHZW5lcmF0b3JzO1xuICAgIC8qKlxuICAgICAqIEhvbGRzIHRoZSB7QGxpbmsgRmlsdGVyfSB0aGF0IGlzIGN1cnJlbnRseSBiZWluZyBhcHBsaWVkIHRvIHRoZSB2aWV3LlxuICAgICAqL1xuICAgIHByb3RlY3RlZCBfYWN0aXZlRmlsdGVyOiBCZWhhdmlvclN1YmplY3Q8RmlsdGVyPjtcbiAgICAvKipcbiAgICAgKiBIb2xkcyB0aGUgZnVsbCB0ZXh0IHtAbGluayBGaWx0ZXJ9IGlmIHNldCwgYHVuZGVmaW5lZGAgb3RoZXJ3aXNlLlxuICAgICAqL1xuICAgIHByb3RlY3RlZCBfZnVsbFRleHRGaWx0ZXI6IFNpbXBsZUZpbHRlciB8IHVuZGVmaW5lZDtcbiAgICAvKipcbiAgICAgKiBUaGUgaW5kZXggb2YgYSByZW1vdmVkIHtAbGluayBQcmVkaWNhdGV9IGlzIGVtbWl0ZWQgaW50byB0aGlzIHN0cmVhbVxuICAgICAqL1xuICAgIHByb3RlY3RlZCBfcHJlZGljYXRlUmVtb3ZlZCQ6IFN1YmplY3Q8UHJlZGljYXRlUmVtb3ZhbEV2ZW50PjtcbiAgICBwcm90ZWN0ZWQgX2xvYWRpbmdGcm9tTWV0YWRhdGEkOiBMb2FkaW5nRW1pdHRlcjtcbiAgICAvKipcbiAgICAgKiBUaGUgYHJvb3RQcmVkaWNhdGVgIHVzZXMgdGhpcyBzdHJlYW0gdG8gbm90aWZ5IHRoZSBzZWFyY2ggc2VydmljZSBhYm91dCBjaGFuZ2VzIHRvIHRoZSBoZWxkIHF1ZXJ5XG4gICAgICovXG4gICAgcHJpdmF0ZSByZWFkb25seSBfcHJlZGljYXRlUXVlcnlDaGFuZ2VkJDogU3ViamVjdDx2b2lkPjtcbiAgICBwcml2YXRlIHJlYWRvbmx5IHN1YkZpbHRlcjogU3Vic2NyaXB0aW9uO1xuXG4gICAgLyoqXG4gICAgICogVGhlIHtAbGluayBQcmVkaWNhdGV9IHRyZWUgcm9vdCB1c2VzIGFuIFtBTkRde0BsaW5rIEJvb2xlYW5PcGVyYXRvciNBTkR9IG9wZXJhdG9yIHRvIGNvbWJpbmUgdGhlIFByZWRpY2F0ZXMuXG4gICAgICogQHBhcmFtIF9sb2cge0BsaW5rIExvZ2dlclNlcnZpY2V9XG4gICAgICogQHBhcmFtIF9jYXRlZ29yeUZhY3RvcnkgYSB7QGxpbmsgQ2F0ZWdvcnlGYWN0b3J5fSBpbnN0YW5jZS4gVGhpcyBkZXBlbmRlbmN5IGlzIG9wdGlvbmFsLlxuICAgICAqIEl0IGlzIHJlcXVpcmVkIGlmIHdlIHdhbnQgdG8gbG9hZCBwcmVkaWNhdGUgZmlsdGVyIGZyb20gc2F2ZWQgbWV0YWRhdGFcbiAgICAgKiBAcGFyYW0gYmFzZUZpbHRlciBGaWx0ZXIgdGhhdCBzaG91bGQgYmUgYXBwbGllZCB0byB0aGUgdmlldyB3aGVuIG5vIHNlYXJjaGluZyBpcyBiZWluZyBwZXJmb3JtZWQuXG4gICAgICogSW5qZWN0ZWQgdHJvdWdoIHRoZSB7QGxpbmsgTkFFX0JBU0VfRklMVEVSfSBpbmplY3Rpb24gdG9rZW4uXG4gICAgICovXG4gICAgY29uc3RydWN0b3IocHJvdGVjdGVkIF9sb2c6IExvZ2dlclNlcnZpY2UsXG4gICAgICAgICAgICAgICAgQE9wdGlvbmFsKCkgcHJvdGVjdGVkIF9jYXRlZ29yeUZhY3Rvcnk6IENhdGVnb3J5RmFjdG9yeSxcbiAgICAgICAgICAgICAgICBASW5qZWN0KE5BRV9CQVNFX0ZJTFRFUikgYmFzZUZpbHRlcjogQmFzZUZpbHRlcikge1xuICAgICAgICBpZiAoYmFzZUZpbHRlci5maWx0ZXIgaW5zdGFuY2VvZiBGaWx0ZXIpIHtcbiAgICAgICAgICAgIHRoaXMuX2Jhc2VGaWx0ZXIgPSBiYXNlRmlsdGVyLmZpbHRlci5jbG9uZSgpO1xuICAgICAgICB9IGVsc2UgaWYgKGJhc2VGaWx0ZXIuZmlsdGVyIGluc3RhbmNlb2YgT2JzZXJ2YWJsZSkge1xuICAgICAgICAgICAgdGhpcy5fYmFzZUZpbHRlciA9IG5ldyBTaW1wbGVGaWx0ZXIoJycsIGJhc2VGaWx0ZXIuZmlsdGVyVHlwZSwge3Byb2Nlc3M6IHtpZGVudGlmaWVyOiAnX19FTVBUWV9fJ319KTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcignVW5zdXBwb3J0ZWQgQmFzZUZpbHRlciBpbnB1dCEgWW91IG11c3QgcHJvdmlkZSB0aGUgTkFFX0JBU0VfRklMVEVSIGluamVjdGlvbiB0b2tlbiB3aXRoIHByb3BlciB2YWx1ZXMhJyk7XG4gICAgICAgIH1cblxuICAgICAgICB0aGlzLl9wcmVkaWNhdGVRdWVyeUNoYW5nZWQkID0gbmV3IFN1YmplY3Q8dm9pZD4oKTtcbiAgICAgICAgdGhpcy5fcm9vdFByZWRpY2F0ZSA9IG5ldyBFZGl0YWJsZUNsYXVzZVByZWRpY2F0ZVdpdGhHZW5lcmF0b3JzKEJvb2xlYW5PcGVyYXRvci5BTkQsIHRoaXMuX3ByZWRpY2F0ZVF1ZXJ5Q2hhbmdlZCQsIHVuZGVmaW5lZCwgdHJ1ZSk7XG4gICAgICAgIHRoaXMuX2FjdGl2ZUZpbHRlciA9IG5ldyBCZWhhdmlvclN1YmplY3Q8RmlsdGVyPih0aGlzLl9iYXNlRmlsdGVyKTtcbiAgICAgICAgdGhpcy5fcHJlZGljYXRlUmVtb3ZlZCQgPSBuZXcgU3ViamVjdDxQcmVkaWNhdGVSZW1vdmFsRXZlbnQ+KCk7XG4gICAgICAgIHRoaXMuX2xvYWRpbmdGcm9tTWV0YWRhdGEkID0gbmV3IExvYWRpbmdFbWl0dGVyKCk7XG5cbiAgICAgICAgaWYgKGJhc2VGaWx0ZXIuZmlsdGVyIGluc3RhbmNlb2YgT2JzZXJ2YWJsZSkge1xuICAgICAgICAgICAgdGhpcy5zdWJGaWx0ZXIgPSBiYXNlRmlsdGVyLmZpbHRlci5zdWJzY3JpYmUoKGZpbHRlcikgPT4ge1xuICAgICAgICAgICAgICAgIHRoaXMuX2Jhc2VGaWx0ZXIgPSBmaWx0ZXIuY2xvbmUoKTtcbiAgICAgICAgICAgICAgICB0aGlzLnVwZGF0ZUFjdGl2ZUZpbHRlcigpO1xuICAgICAgICAgICAgfSk7XG4gICAgICAgIH1cblxuICAgICAgICB0aGlzLnByZWRpY2F0ZVF1ZXJ5Q2hhbmdlZCQuc3Vic2NyaWJlKCgpID0+IHtcbiAgICAgICAgICAgIHRoaXMudXBkYXRlQWN0aXZlRmlsdGVyKCk7XG4gICAgICAgIH0pO1xuICAgIH1cblxuICAgIG5nT25EZXN0cm95KCk6IHZvaWQge1xuICAgICAgICB0aGlzLl9wcmVkaWNhdGVSZW1vdmVkJC5jb21wbGV0ZSgpO1xuICAgICAgICB0aGlzLl9hY3RpdmVGaWx0ZXIuY29tcGxldGUoKTtcbiAgICAgICAgdGhpcy5fcHJlZGljYXRlUXVlcnlDaGFuZ2VkJC5jb21wbGV0ZSgpO1xuICAgICAgICBpZiAodGhpcy5zdWJGaWx0ZXIpIHtcbiAgICAgICAgICAgIHRoaXMuc3ViRmlsdGVyLnVuc3Vic2NyaWJlKCk7XG4gICAgICAgIH1cbiAgICAgICAgdGhpcy5fbG9hZGluZ0Zyb21NZXRhZGF0YSQuY29tcGxldGUoKTtcbiAgICAgICAgdGhpcy5fcm9vdFByZWRpY2F0ZS5kZXN0cm95KCk7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogQHJldHVybnMgdGhlIEZpbHRlciB0aGF0IGlzIGN1cnJlbnRseSBhcHBsaWVkIHRvIHRoZSB2aWV3XG4gICAgICovXG4gICAgcHVibGljIGdldCBhY3RpdmVGaWx0ZXIoKTogRmlsdGVyIHtcbiAgICAgICAgcmV0dXJuIHRoaXMuX2FjdGl2ZUZpbHRlci5nZXRWYWx1ZSgpO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIEByZXR1cm5zIGFuIGBPYnNlcnZhYmxlYCB0aGF0IHVwZGF0ZXMgZXZlcnkgdGltZSB0aGUgYWN0aXZlIEZpbHRlciBjaGFuZ2VzLlxuICAgICAqL1xuICAgIHB1YmxpYyBnZXQgYWN0aXZlRmlsdGVyJCgpOiBPYnNlcnZhYmxlPEZpbHRlcj4ge1xuICAgICAgICByZXR1cm4gdGhpcy5fYWN0aXZlRmlsdGVyLmFzT2JzZXJ2YWJsZSgpO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIEByZXR1cm5zIGB0cnVlYCBpZiBhIGZpbHRlciBvdGhlciB0aGFuIHRoZSBiYXNlIGZpbHRlciBpcyBjdXJyZW50bHkgYXBwbGllZC5cbiAgICAgKiBSZXR1cm5zIGBmYWxzZWAgaWYgb25seSB0aGUgYmFzZSBmaWx0ZXIgaXMgY3VycmVudGx5IGFwcGxpZWQuXG4gICAgICovXG4gICAgcHVibGljIGdldCBhZGRpdGlvbmFsRmlsdGVyc0FwcGxpZWQoKTogYm9vbGVhbiB7XG4gICAgICAgIHJldHVybiAhdGhpcy5fcm9vdFByZWRpY2F0ZS5xdWVyeS5pc0VtcHR5IHx8ICEhdGhpcy5fZnVsbFRleHRGaWx0ZXI7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogQHJldHVybnMgYHRydWVgIGlmIGFueSB2aXNpYmxlIHByZWRpY2F0ZXMgYXJlIGFwcGxpZWQuXG4gICAgICogUmV0dXJucyBgZmFsc2VgIGlmIHRoZXJlIGFyZSBubyBwcmVkaWNhdGVzLCBvciBpZiB0aGVyZSBhcmUgb25seSBoaWRkZW4gcHJlZGljYXRlcyBhcHBsaWVkXG4gICAgICovXG4gICAgcHVibGljIGdldCBoYXNWaXNpYmxlUHJlZGljYXRlcygpOiBib29sZWFuIHtcbiAgICAgICAgZm9yIChjb25zdCBwcmVkaWNhdGUgb2YgdGhpcy5fcm9vdFByZWRpY2F0ZS5nZXRQcmVkaWNhdGVNYXAoKS52YWx1ZXMoKSkge1xuICAgICAgICAgICAgaWYgKHByZWRpY2F0ZS5pc1Zpc2libGUpIHtcbiAgICAgICAgICAgICAgICByZXR1cm4gdHJ1ZTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gZmFsc2U7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogQHJldHVybnMgYSBjb3B5IG9mIHRoZSBiYXNlIGZpbHRlclxuICAgICAqL1xuICAgIHB1YmxpYyBnZXQgYmFzZUZpbHRlcigpOiBGaWx0ZXIge1xuICAgICAgICByZXR1cm4gdGhpcy5fYmFzZUZpbHRlci5jbG9uZSgpO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIEByZXR1cm5zIGFuIE9ic2VydmFibGUgdGhhdCBlbWl0cyB0aGUgaW5kZXggb2YgdGhlIHJlbW92ZWQgcHJlZGljYXRlIHdoZW5ldmVyIGEgcHJlZGljYXRlIGlzIHJlbW92ZWRcbiAgICAgKi9cbiAgICBwdWJsaWMgZ2V0IHByZWRpY2F0ZVJlbW92ZWQkKCk6IE9ic2VydmFibGU8UHJlZGljYXRlUmVtb3ZhbEV2ZW50PiB7XG4gICAgICAgIHJldHVybiB0aGlzLl9wcmVkaWNhdGVSZW1vdmVkJC5hc09ic2VydmFibGUoKTtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBAcmV0dXJucyB0aGUgcm9vdCBwcmVkaWNhdGUgb2YgdGhlIHNlYXJjaCBzZXJ2aWNlLCB0aGF0IGNhbiBiZSB1c2VkIHRvIGdlbmVyYXRlIHNlYXJjaCByZXF1ZXN0cyB3aXRoIGN1c3RvbSBxdWVyaWVzXG4gICAgICovXG4gICAgcHVibGljIGdldCByb290UHJlZGljYXRlKCk6IEVkaXRhYmxlQ2xhdXNlUHJlZGljYXRlV2l0aEdlbmVyYXRvcnMge1xuICAgICAgICByZXR1cm4gdGhpcy5fcm9vdFByZWRpY2F0ZTtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBAcmV0dXJucyB0aGUgdHlwZSBvZiB0aGUgZmlsdGVyIGhlbGQgaW4gdGhpcyBzZWFyY2ggc2VydmljZSBpbnN0YW5jZVxuICAgICAqL1xuICAgIHB1YmxpYyBnZXQgZmlsdGVyVHlwZSgpOiBGaWx0ZXJUeXBlIHtcbiAgICAgICAgcmV0dXJuIHRoaXMuYmFzZUZpbHRlci50eXBlO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIEByZXR1cm5zIHdoZXRoZXIgdGhlIHNlYXJjaCBzZXJ2aWNlIGlzIGN1cnJlbnRseSBsb2FkaW5nIGl0cyBzdGF0ZSBmcm9tIG1ldGFkYXRhIG9yIG5vdC5cbiAgICAgKlxuICAgICAqIFNlZSBbbG9hZEZyb21NZXRhZGF0YSgpXXtAbGluayBTZWFyY2hTZXJ2aWNlI2xvYWRGcm9tTWV0YWRhdGF9XG4gICAgICovXG4gICAgcHVibGljIGdldCBsb2FkaW5nRnJvbU1ldGFkYXRhKCk6IGJvb2xlYW4ge1xuICAgICAgICByZXR1cm4gdGhpcy5fbG9hZGluZ0Zyb21NZXRhZGF0YSQudmFsdWU7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogQHJldHVybnMgYW4gYE9ic2VydmFibGVgIHRoYXQgZW1pdHMgYHRydWVgIGlmIHRoZSBzZWFyY2ggc2VydmljZSBpcyBjdXJyZW50bHkgbG9hZGluZyBpdHMgc3RhdGUgZnJvbSBtZXRhZGF0YSxcbiAgICAgKiBlbWl0cyBgZmFsc2VgIG90aGVyd2lzZS5cbiAgICAgKlxuICAgICAqIFNlZSBbbG9hZEZyb21NZXRhZGF0YSgpXXtAbGluayBTZWFyY2hTZXJ2aWNlI2xvYWRGcm9tTWV0YWRhdGF9XG4gICAgICovXG4gICAgcHVibGljIGdldCBsb2FkaW5nRnJvbU1ldGFkYXRhJCgpOiBPYnNlcnZhYmxlPGJvb2xlYW4+IHtcbiAgICAgICAgcmV0dXJuIHRoaXMuX2xvYWRpbmdGcm9tTWV0YWRhdGEkLmFzT2JzZXJ2YWJsZSgpO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIEByZXR1cm5zIGFuIE9ic2VydmFibGUgdGhhdCBlbWl0cyB3aGVuZXZlciB0aGUgcm9vdCBwcmVkaWNhdGVzIHF1ZXJ5IGNoYW5nZXNcbiAgICAgKi9cbiAgICBwcm90ZWN0ZWQgZ2V0IHByZWRpY2F0ZVF1ZXJ5Q2hhbmdlZCQoKTogT2JzZXJ2YWJsZTxRdWVyeT4ge1xuICAgICAgICByZXR1cm4gdGhpcy5fcHJlZGljYXRlUXVlcnlDaGFuZ2VkJC5hc09ic2VydmFibGUoKS5waXBlKFxuICAgICAgICAgICAgbWFwKCgpID0+IHRoaXMuX3Jvb3RQcmVkaWNhdGUucXVlcnkpLFxuICAgICAgICAgICAgZGlzdGluY3RVbnRpbENoYW5nZWQoKHByZXYsIGN1cnIpID0+IHByZXYgJiYgcHJldi5lcXVhbHMoY3VycikpXG4gICAgICAgICk7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogQWRkcyBhIHtAbGluayBQcmVkaWNhdGV9IHRvIHRoZSBQcmVkaWNhdGUgcm9vdCBhbmQgdXBkYXRlcyB0aGUgYWN0aXZlIEZpbHRlci5cbiAgICAgKlxuICAgICAqIFByZWRpY2F0ZXMgYWRkZWQgdGhpcyB3YXkgd2lsbCBub3QgYmUgdmlzaWJsZSBpbiB0aGUgc2VhcmNoIEdVSS5cbiAgICAgKiBJZiB5b3Ugd2FudCB0byBtYWtlIHN1cmUgeW91ciBwcmVkaWNhdGVzIGFyZSB2aXNpYmxlIChhbmQgZWRpdGFibGUpXG4gICAgICogdXNlIHRoZSBbYWRkR2VuZXJhdGVkTGVhZlByZWRpY2F0ZSgpXXtAbGluayBTZWFyY2hTZXJ2aWNlI2FkZEdlbmVyYXRlZExlYWZQcmVkaWNhdGV9IG1ldGhvZCBpbnN0ZWFkLlxuICAgICAqIEBwYXJhbSBuZXdQcmVkaWNhdGUgUHJlZGljYXRlIHRoYXQgc2hvdWxkIGJlIGFkZGVkIHRvIHRoZSBzZWFyY2ggcXVlcmllcy5cbiAgICAgKiBAcmV0dXJucyB0aGUgaW5kZXggb2YgdGhlIGFkZGVkIFByZWRpY2F0ZVxuICAgICAqL1xuICAgIHB1YmxpYyBhZGRQcmVkaWNhdGUobmV3UHJlZGljYXRlOiBQcmVkaWNhdGUpOiBudW1iZXIge1xuICAgICAgICByZXR1cm4gdGhpcy5fcm9vdFByZWRpY2F0ZS5hZGRQcmVkaWNhdGUobmV3UHJlZGljYXRlLCBmYWxzZSk7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogQWRkcyBhIG5ldyBoaWRkZW4gYnJhbmNoIG9mIHRoZSBwcmVkaWNhdGUgdHJlZSB3aXRoIGEgc2luZ3VsYXIgbGVhZiBub2RlIGNvbnRhaW5pbmcgdGhlIHByb3ZpZGVkIFF1ZXJ5LlxuICAgICAqXG4gICAgICogVGhpcyBjYW4gYmUgdXNlZCB0byBhZGQgcHJlZGljYXRlcyB0byB0aGUgc2VhcmNoIHRyZWUgKHRoaW5rIGhlYWRlciBzZWFyY2gpLFxuICAgICAqIHdoaWNoIGNhbiBiZSBtYWRlIHZpc2libGUgYW5kIGVkaXRhYmxlIGluIHRoZSBzZWFyY2ggR1VJIGxhdGVyLlxuICAgICAqIEBwYXJhbSBnZW5lcmF0b3IgdGhlIGdlbmVyYXRvciB0aGF0IGlzIGluIHN1Y2ggc3RhdGUsIHRoYXQgaXQgZ2VuZXJhdGVzIHRoZSBRdWVyeSwgdGhhdCBzaG91bGQgYmUgYWRkZWQgYXMgYnJhbmNoL2xlYWYuXG4gICAgICogSWYgdGhlIGdlbmVyYXRvciBkb2Vzbid0IGN1cnJlbnRseSBnZW5lcmF0ZSBhIHF1ZXJ5IGEgbm9kZSB3aXRoIGFuIGVtcHR5IHF1ZXJ5IHdpbGwgYmUgYWRkZWQuXG4gICAgICovXG4gICAgcHVibGljIGFkZEdlbmVyYXRlZExlYWZQcmVkaWNhdGUoZ2VuZXJhdG9yOiBDYXRlZ29yeTxhbnk+KTogbnVtYmVyIHtcbiAgICAgICAgY29uc3QgYnJhbmNoSWQgPSB0aGlzLl9yb290UHJlZGljYXRlLmFkZE5ld0NsYXVzZVByZWRpY2F0ZShCb29sZWFuT3BlcmF0b3IuT1IsIGZhbHNlKTtcbiAgICAgICAgY29uc3QgYnJhbmNoID0gKFxuICAgICAgICAgICAgdGhpcy5fcm9vdFByZWRpY2F0ZS5nZXRQcmVkaWNhdGVNYXAoKS5nZXQoYnJhbmNoSWQpLmdldFdyYXBwZWRQcmVkaWNhdGUoKSBhcyB1bmtub3duIGFzIEVkaXRhYmxlQ2xhdXNlUHJlZGljYXRlV2l0aEdlbmVyYXRvcnNcbiAgICAgICAgKTtcbiAgICAgICAgYnJhbmNoLmFkZE5ld1ByZWRpY2F0ZUZyb21HZW5lcmF0b3IoZ2VuZXJhdG9yKTtcbiAgICAgICAgcmV0dXJuIGJyYW5jaElkO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIFJlbW92ZXMgdGhlIHtAbGluayBQcmVkaWNhdGV9IG9iamVjdCBmcm9tIHRoZSBwcm92aWRlZCBpbmRleC4gSWYgdGhlIGluZGV4IGlzIGludmFsaWQgZG9lcyBub3RoaW5nLlxuICAgICAqIFVwZGF0ZXMgdGhlIHRoZSBhY3RpdmUgRmlsdGVyIGlmIHRoZSBQcmVkaWNhdGUgdHJlZSB3YXMgYWZmZWN0ZWQuXG4gICAgICogQHBhcmFtIGluZGV4IGluZGV4IG9mIHRoZSBQcmVkaWNhdGUgdGhhdCBzaG91bGQgYmUgcmVtb3ZlZFxuICAgICAqIEBwYXJhbSBjbGVhcklucHV0IHdoZXRoZXIgdGhlIGlucHV0LCB0aGF0IGNvcnJlc3BvbmRzIHRvIHRoZSBwcmVkaWNhdGUgc2hvdWxkIGJlIGNsZWFyZWRcbiAgICAgKi9cbiAgICBwdWJsaWMgcmVtb3ZlUHJlZGljYXRlKGluZGV4OiBudW1iZXIsIGNsZWFySW5wdXQgPSB0cnVlKTogdm9pZCB7XG4gICAgICAgIGlmICh0aGlzLl9yb290UHJlZGljYXRlLnJlbW92ZVByZWRpY2F0ZShpbmRleCkpIHtcbiAgICAgICAgICAgIHRoaXMuX3ByZWRpY2F0ZVJlbW92ZWQkLm5leHQoe2luZGV4LCBjbGVhcklucHV0fSk7XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBSZW1vdmVzIGFsbCB7QGxpbmsgUHJlZGljYXRlfSBvYmplY3RzIHRoYXQgY29udHJpYnV0ZSB0byB0aGUgc2VhcmNoLiBVcGRhdGVzIHRoZSBhY3RpdmUgRmlsdGVyIGlmIGl0IHdhcyBhZmZlY3RlZC5cbiAgICAgKlxuICAgICAqIEBwYXJhbSBjbGVhckhpZGRlbiB3aGV0aGVyIHRoZSBoaWRkZW4gcHJlZGljYXRlcyBzaG91bGQgYmUgY2xlYXJlZCBhcyB3ZWxsXG4gICAgICovXG4gICAgcHVibGljIGNsZWFyUHJlZGljYXRlcyhjbGVhckhpZGRlbiA9IGZhbHNlKTogdm9pZCB7XG4gICAgICAgIGlmICh0aGlzLl9yb290UHJlZGljYXRlLmdldFByZWRpY2F0ZU1hcCgpLnNpemUgPiAwKSB7XG4gICAgICAgICAgICBmb3IgKGNvbnN0IFtpZCwgcHJlZGljYXRlXSBvZiB0aGlzLl9yb290UHJlZGljYXRlLmdldFByZWRpY2F0ZU1hcCgpLmVudHJpZXMoKSkge1xuICAgICAgICAgICAgICAgIGlmIChjbGVhckhpZGRlbiB8fCBwcmVkaWNhdGUuaXNWaXNpYmxlKSB7XG4gICAgICAgICAgICAgICAgICAgIHRoaXMucmVtb3ZlUHJlZGljYXRlKGlkKTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICB0aGlzLnVwZGF0ZUFjdGl2ZUZpbHRlcigpO1xuICAgICAgICB9XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogQWRkcyBhIHtAbGluayBGaWx0ZXJ9IHdpdGggdGhlIFtmdWxsVGV4dF17QGxpbmsgQ2FzZVNlYXJjaFJlcXVlc3RCb2R5I2Z1bGxUZXh0fSBhdHRyaWJ1dGUgc2V0IHRvIHRoZSBwcm92aWRlZCB2YWx1ZS5cbiAgICAgKiBJZiBmdWxsIHRleHQgZmlsdGVyIGlzIGFscmVhZHkgc2V0LCBpdCB3aWxsIGJlIHJlcGxhY2VkLlxuICAgICAqIEBwYXJhbSBzZWFyY2hlZFN1YnN0cmluZyB2YWx1ZSB0aGF0IHNob3VsZCBiZSBzZWFyY2hlZCBvbiBhbGwgZnVsbCB0ZXh0IGZpZWxkc1xuICAgICAqL1xuICAgIHB1YmxpYyBzZXRGdWxsVGV4dEZpbHRlcihzZWFyY2hlZFN1YnN0cmluZzogc3RyaW5nKTogdm9pZCB7XG4gICAgICAgIGNvbnN0IHdoaXRlU3BhY2VkU3Vic3RyaW5nID0gc2VhcmNoZWRTdWJzdHJpbmc/LnJlcGxhY2UoLyAvZywgJ1xcXFwgJyk7XG4gICAgICAgIHRoaXMuX2Z1bGxUZXh0RmlsdGVyID0gbmV3IFNpbXBsZUZpbHRlcignJywgdGhpcy5fYmFzZUZpbHRlci50eXBlLCB7ZnVsbFRleHQ6IHdoaXRlU3BhY2VkU3Vic3RyaW5nfSk7XG4gICAgICAgIHRoaXMudXBkYXRlQWN0aXZlRmlsdGVyKCk7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogQ2xlYXJzIHRoZSBmdWxsIHRleHQgZmlsdGVyIChpZiBzZXQpLiBJZiB0aGUgZnVsbCB0ZXh0IGZpbHRlciBpcyBub3Qgc2V0LCBkb2VzIG5vdGhpbmcuXG4gICAgICovXG4gICAgcHVibGljIGNsZWFyRnVsbFRleHRGaWx0ZXIoKTogdm9pZCB7XG4gICAgICAgIGNvbnN0IHdhc0Z1bGx0ZXh0U2V0ID0gdGhpcy5fZnVsbFRleHRGaWx0ZXIgIT09IHVuZGVmaW5lZDtcbiAgICAgICAgdGhpcy5fZnVsbFRleHRGaWx0ZXIgPSB1bmRlZmluZWQ7XG4gICAgICAgIGlmICh3YXNGdWxsdGV4dFNldCkge1xuICAgICAgICAgICAgdGhpcy51cGRhdGVBY3RpdmVGaWx0ZXIoKTtcbiAgICAgICAgfVxuICAgIH1cblxuICAgIC8qKlxuICAgICAqIFNob3dzIHRoZSBwcmVkaWNhdGVzIHdpdGggdGhlIGdpdmVuIGlkcy4gU2tpcHMgaWRzIHRoYXQgZG9uJ3QgZXhpc3QuXG4gICAgICogQHBhcmFtIHByZWRpY2F0ZUlkcyB0aGUgaWRzIG9mIHRoZSBwcmVkaWNhdGVzIHRoYXQgc2hvdWxkIGJlIHNob3duLlxuICAgICAqL1xuICAgIHB1YmxpYyBzaG93KHByZWRpY2F0ZUlkczogQXJyYXk8bnVtYmVyPik6IHZvaWQge1xuICAgICAgICB0aGlzLl9yb290UHJlZGljYXRlLnNob3dQcmVkaWNhdGVzKHByZWRpY2F0ZUlkcyk7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogUmVhZHMgdGhlIGN1cnJlbnQgcXVlcnkgZnJvbSB0aGUgcHJlZGljYXRlIHRyZWUsIGNvbWJpbmVzIGl0IHdpdGggdGhlIGJhc2UgRmlsdGVyIGFuZCBmdWxsIHRleHQgRmlsdGVyIChpZiBzZXQpXG4gICAgICogYW5kIHVwZGF0ZXMgdGhlIGFjdGl2ZSBGaWx0ZXIuXG4gICAgICovXG4gICAgcHJvdGVjdGVkIHVwZGF0ZUFjdGl2ZUZpbHRlcigpOiB2b2lkIHtcbiAgICAgICAgbGV0IGFkZGl0aW9uYWxGaWx0ZXI6IEZpbHRlcjtcbiAgICAgICAgaWYgKCF0aGlzLl9yb290UHJlZGljYXRlLnF1ZXJ5LmlzRW1wdHkpIHtcbiAgICAgICAgICAgIGFkZGl0aW9uYWxGaWx0ZXIgPSBuZXcgU2ltcGxlRmlsdGVyKCcnLCB0aGlzLl9iYXNlRmlsdGVyLnR5cGUsIHtxdWVyeTogdGhpcy5fcm9vdFByZWRpY2F0ZS5xdWVyeS52YWx1ZX0pO1xuICAgICAgICB9XG4gICAgICAgIGlmICh0aGlzLl9mdWxsVGV4dEZpbHRlcikge1xuICAgICAgICAgICAgaWYgKGFkZGl0aW9uYWxGaWx0ZXIpIHtcbiAgICAgICAgICAgICAgICBhZGRpdGlvbmFsRmlsdGVyID0gYWRkaXRpb25hbEZpbHRlci5tZXJnZSh0aGlzLl9mdWxsVGV4dEZpbHRlciwgTWVyZ2VPcGVyYXRvci5BTkQpO1xuICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICBhZGRpdGlvbmFsRmlsdGVyID0gdGhpcy5fZnVsbFRleHRGaWx0ZXI7XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgICAgaWYgKGFkZGl0aW9uYWxGaWx0ZXIpIHtcbiAgICAgICAgICAgIHRoaXMuX2FjdGl2ZUZpbHRlci5uZXh0KHRoaXMuX2Jhc2VGaWx0ZXIubWVyZ2UoYWRkaXRpb25hbEZpbHRlciwgTWVyZ2VPcGVyYXRvci5BTkQpKTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIHRoaXMuX2FjdGl2ZUZpbHRlci5uZXh0KHRoaXMuX2Jhc2VGaWx0ZXIuY2xvbmUoKSk7XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBAcmV0dXJucyBgdW5kZWZpbmVkYCBpZiB0aGUgcHJlZGljYXRlIHRyZWUgY29udGFpbnMgbm8gY29tcGxldGUgcXVlcnkuXG4gICAgICogT3RoZXJ3aXNlIHJldHVybnMgdGhlIHNlcmlhbGl6ZWQgZm9ybSBvZiB0aGUgY29tcGxldGVkIHF1ZXJpZXMgaW4gdGhlIHByZWRpY2F0ZSB0cmVlLlxuICAgICAqL1xuICAgIHB1YmxpYyBjcmVhdGVQcmVkaWNhdGVNZXRhZGF0YSgpOiBQcmVkaWNhdGVUcmVlTWV0YWRhdGEgfCB1bmRlZmluZWQge1xuICAgICAgICByZXR1cm4gdGhpcy5fcm9vdFByZWRpY2F0ZS5jcmVhdGVHZW5lcmF0b3JNZXRhZGF0YSgpIGFzIFByZWRpY2F0ZVRyZWVNZXRhZGF0YTtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBSZXBsYWNlcyB0aGUgY3VycmVudCBwcmVkaWNhdGUgZmlsdGVyIGJ5IHRoZSBvbmUgY29ycmVzcG9uZGluZyB0byB0aGUgcHJvdmlkZWQgZ2VuZXJhdG9yIG1ldGFkYXRhLlxuICAgICAqXG4gICAgICogVGhlIHtAbGluayBDYXRlZ29yeUZhY3Rvcnl9IGluc3RhbmNlIG11c3QgYmUgcHJvdmlkZWQgZm9yIHRoaXMgc2VydmljZSBpZiB3ZSB3YW50IHRvIHVzZSB0aGlzIG1ldGhvZC4gTG9ncyBhbiBlcnJvciBhbmQgZG9lcyBub3RoaW5nLlxuICAgICAqXG4gICAgICogVGhlIGBmaWx0ZXJUeXBlYCBvZiB0aGlzIHNlYXJjaCBzZXJ2aWNlIG11c3QgbWF0Y2ggdGhlIGBmaWx0ZXJUeXBlYCBvZiB0aGUgcHJvdmlkZWQgbWV0YWRhdGEuIE90aGVyd2lzZSBhbiBlcnJvciBpcyB0aHJvd24uXG4gICAgICpcbiAgICAgKiBAcGFyYW0gbWV0YWRhdGEgdGhlIHNlcmlhbGl6ZWQgc3RhdGUgb2YgdGhlIHByZWRpY2F0ZSB0cmVlIHRoYXQgc2hvdWxkIGJlIHJlc3RvcmVkIHRvIHRoaXMgc2VhcmNoIHNlcnZpY2VcbiAgICAgKi9cbiAgICBwdWJsaWMgbG9hZEZyb21NZXRhZGF0YShtZXRhZGF0YTogRmlsdGVyTWV0YWRhdGEpIHtcbiAgICAgICAgaWYgKHRoaXMuX2NhdGVnb3J5RmFjdG9yeSA9PT0gbnVsbCkge1xuICAgICAgICAgICAgdGhpcy5fbG9nLmVycm9yKCdBIENhdGVnb3J5RmFjdG9yeSBpbnN0YW5jZSBtdXN0IGJlIHByb3ZpZGVkIGZvciB0aGUgU2VhcmNoU2VydmljZSdcbiAgICAgICAgICAgICAgICArICcgaWYgeW91IHdhbnQgdG8gcmVjb25zdHJ1Y3QgYSBwcmVkaWNhdGUgZmlsdGVyIGZyb20gc2F2ZWQgbWV0YWRhdGEnKTtcbiAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgfVxuXG4gICAgICAgIGlmIChtZXRhZGF0YS5maWx0ZXJUeXBlICE9PSB0aGlzLmZpbHRlclR5cGUpIHtcbiAgICAgICAgICAgIHRocm93IEVycm9yKGBUaGUgZmlsdGVyIHR5cGUgb2YgdGhlIHByb3ZpZGVkIG1ldGFkYXRhICgke21ldGFkYXRhLmZpbHRlclR5cGVcbiAgICAgICAgICAgIH0pIGRvZXMgbm90IG1hdGNoIHRoZSBmaWx0ZXIgdHlwZSBvZiB0aGUgc2VhcmNoIHNlcnZpY2UgKCR7dGhpcy5maWx0ZXJUeXBlfSkhYCk7XG4gICAgICAgIH1cblxuICAgICAgICB0aGlzLmNsZWFyUHJlZGljYXRlcyh0cnVlKTtcbiAgICAgICAgdGhpcy5fbG9hZGluZ0Zyb21NZXRhZGF0YSQub24oKTtcblxuICAgICAgICBjb25zdCBnZW5lcmF0b3JPYnNlcnZhYmxlcyA9IFtdO1xuICAgICAgICBpZiAoQXJyYXkuaXNBcnJheShtZXRhZGF0YS5wcmVkaWNhdGVNZXRhZGF0YSkpIHtcbiAgICAgICAgICAgIGZvciAoY29uc3QgY2xhdXNlIG9mIG1ldGFkYXRhLnByZWRpY2F0ZU1ldGFkYXRhKSB7XG4gICAgICAgICAgICAgICAgY29uc3QgYnJhbmNoSWQgPSB0aGlzLl9yb290UHJlZGljYXRlLmFkZE5ld0NsYXVzZVByZWRpY2F0ZShCb29sZWFuT3BlcmF0b3IuT1IpO1xuICAgICAgICAgICAgICAgIGNvbnN0IGJyYW5jaFByZWRpY2F0ZSA9IChcbiAgICAgICAgICAgICAgICAgICAgdGhpcy5fcm9vdFByZWRpY2F0ZS5nZXRQcmVkaWNhdGVNYXAoKS5nZXQoYnJhbmNoSWQpXG4gICAgICAgICAgICAgICAgICAgICAgICAuZ2V0V3JhcHBlZFByZWRpY2F0ZSgpIGFzIHVua25vd24gYXMgRWRpdGFibGVDbGF1c2VQcmVkaWNhdGVXaXRoR2VuZXJhdG9yc1xuICAgICAgICAgICAgICAgICk7XG4gICAgICAgICAgICAgICAgZm9yIChjb25zdCBwcmVkaWNhdGUgb2YgY2xhdXNlKSB7XG4gICAgICAgICAgICAgICAgICAgIGNvbnN0IGxvY2FsQnJhbmNoUmVmZXJlbmNlID0gYnJhbmNoUHJlZGljYXRlO1xuICAgICAgICAgICAgICAgICAgICBnZW5lcmF0b3JPYnNlcnZhYmxlcy5wdXNoKFxuICAgICAgICAgICAgICAgICAgICAgICAgdGhpcy5fY2F0ZWdvcnlGYWN0b3J5LmdldEZyb21NZXRhZGF0YShwcmVkaWNhdGUpLnBpcGUodGFwKGdlbmVyYXRvciA9PiB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgbG9jYWxCcmFuY2hSZWZlcmVuY2UuYWRkTmV3UHJlZGljYXRlRnJvbUdlbmVyYXRvcihnZW5lcmF0b3IpO1xuICAgICAgICAgICAgICAgICAgICAgICAgfSkpXG4gICAgICAgICAgICAgICAgICAgICk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfVxuICAgICAgICB9XG5cbiAgICAgICAgZm9ya0pvaW4oZ2VuZXJhdG9yT2JzZXJ2YWJsZXMpLnN1YnNjcmliZSgoKSA9PiB7XG4gICAgICAgICAgICB0aGlzLl9sb2FkaW5nRnJvbU1ldGFkYXRhJC5vZmYoKTtcbiAgICAgICAgICAgIHRoaXMudXBkYXRlQWN0aXZlRmlsdGVyKCk7XG4gICAgICAgIH0pO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIEByZXR1cm5zIGFuIEFycmF5IG9mIGZpbHRlciB0ZXh0IHNlZ21lbnRzIHRoYXQgY29ycmVzcG9uZCB0byB0aGUgY3VycmVudGx5IGRpc3BsYXllZCBjb21wbGV0ZWQgcHJlZGljYXRlc1xuICAgICAqL1xuICAgIHB1YmxpYyBjcmVhdGVGaWx0ZXJUZXh0U2VnbWVudHMoKTogQXJyYXk8RmlsdGVyVGV4dFNlZ21lbnQ+IHtcbiAgICAgICAgcmV0dXJuIHRoaXMuX3Jvb3RQcmVkaWNhdGUuY3JlYXRlRmlsdGVyVGV4dFNlZ21lbnRzKCk7XG4gICAgfVxufVxuIl19