UNPKG

ngx-dynamic-hooks

Version:

Automatically insert live Angular components into a dynamic string of content (based on their selector or any pattern of your choice) and render the result in the DOM.

290 lines 49.8 kB
import { Injectable, reflectComponentType } from '@angular/core'; import { Observable } from 'rxjs'; import * as i0 from "@angular/core"; import * as i1 from "../utils/deepComparer"; import * as i2 from "../utils/logger"; /** * The service responsible for updating dynamically created components */ export class ComponentUpdater { constructor(deepComparer, logger) { this.deepComparer = deepComparer; this.logger = logger; } /** * Invoked when the inputs/outputs should be checked for updates * * @param hookIndex - The current hookIndex * @param context - The new context object * @param options - The current ParseOptions * @param triggerOnDynamicChanges - Whether to trigger the OnDynamicChanges method of dynamically loaded components */ refresh(hookIndex, context, options, triggerOnDynamicChanges) { // Update bindings for all loaded hooks for (const [hookId, hook] of Object.entries(hookIndex)) { this.updateBindings(hook, context, options); } // Also: If context has changed by reference, call OnDynamicChanges() for all created components. if (triggerOnDynamicChanges) { for (const hook of Object.values(hookIndex)) { if (!hook.componentRef) { return; } if (typeof hook.componentRef.instance['onDynamicChanges'] === 'function') { hook.componentRef.instance['onDynamicChanges']({ context }); } } } } /** * Creates or updates bindings for a hook with a loaded component * * @param hook - THe hook to update * @param context - The context object * @param options - The current ParseOptions */ updateBindings(hook, context, options) { if (!hook.componentRef) { return; } // Update bindings hook.bindings = hook.parser.getBindings(hook.id, hook.value, context, options); this.updateComponentWithNewInputs(hook, options); this.updateComponentWithNewOutputs(hook, context, options); // Snapshot bindings for comparison next time hook.previousBindings = { inputs: this.savePreviousBindings(hook, 'inputs', options.compareInputsByValue, options.compareByValueDepth), outputs: this.savePreviousBindings(hook, 'outputs', options.compareOutputsByValue, options.compareByValueDepth) }; } /** * Creates a list of all previous bindings along with their stringified values * * @param hook - The hook to check * @param type - The type of bindings that should be saved * @param saveStringified - Whether to save the stringified value in addition to the reference * @param stringifyDepth - How many levels deep to stringify the previous bindings */ savePreviousBindings(hook, type, saveStringified, stringifyDepth) { const result = {}; if (hook.bindings.hasOwnProperty(type)) { for (const [bindingName, bindingValue] of Object.entries(hook.bindings[type])) { result[bindingName] = { reference: bindingValue, stringified: saveStringified ? this.deepComparer.detailedStringify(bindingValue, stringifyDepth) : null // To compare by value }; } } return result; } // Updating bindings // ---------------------------------------------------------------------------------------------------------------- /** * Processes a hook object and updates the inputs of a dynamic component where required * * @param hook - The hook in question * @param options - The current ParseOptions */ updateComponentWithNewInputs(hook, options) { const component = hook.componentRef.instance; // Find out which inputs have changed const changedInputs = this.getChangedBindings(hook, 'inputs', options); // Check if inputs exists on component const existingInputs = []; const compMeta = reflectComponentType(hook.componentRef.componentType); for (const [inputName, inputValue] of Object.entries(changedInputs)) { // Some naming tolerance: Input name can be case-insensitive and in dash-case. // Look for more literal matches first (transformed dash-case + case-insensitive has lowest priority) const metaKey = options.ignoreInputAliases ? 'propName' : 'templateName'; const inputEntry = compMeta.inputs.find(inputObject => inputName === inputObject[metaKey]) || compMeta.inputs.find(inputObject => inputName.toLowerCase() === inputObject[metaKey].toLowerCase()) || compMeta.inputs.find(inputObject => inputName.replace(/-/g, '') === inputObject[metaKey]) || compMeta.inputs.find(inputObject => inputName.replace(/-/g, '').toLowerCase() === inputObject[metaKey].toLowerCase()); // If actual input was found, add it if (inputEntry) { existingInputs.push({ propName: inputEntry.propName, templateName: inputEntry.templateName, value: inputValue }); // If not, but accepts any property as input, add it anyway } else if (options.acceptInputsForAnyProperty) { // If property exists (in a case-agnostic way), use it. Otherwise create literal new property. let foundInputProp = Object.getOwnPropertyNames(component).find(propName => inputName === propName) || Object.getOwnPropertyNames(component).find(propName => inputName.toLowerCase() === propName.toLowerCase()); const finalInputProp = foundInputProp || inputName; // Even this setting has limits. Don't allow setting fundamental JavaScript object properties. if (!['__proto__', 'prototype', 'constructor'].includes(finalInputProp)) { existingInputs.push({ propName: finalInputProp, templateName: null, value: inputValue }); } else { this.logger.error(['Tried to overwrite a __proto__, prototype or constructor property with input "' + finalInputProp + '" for hook "' + hook.componentRef.componentType.name + '". This is not allowed.'], options); continue; } } } // Set inputs in component for (const { propName, templateName, value } of existingInputs) { if (templateName) { hook.componentRef?.setInput(templateName, value); // Official method to set inputs. Sets property, triggers OnChanges and marks for OnPush. Also works with new signal inputs. } else if (propName) { hook.componentRef.instance[propName] = value; // Resort to manual setting only if prop isn't a declared input (may happen with "acceptInputsForAnyProperty") } } // Important: Still need to trigger cd, even with componentRef.setInput if (existingInputs.length) { hook.componentRef?.changeDetectorRef.detectChanges(); } } /** * Processes a hook object and (re)subscribes the outputs of a dynamic component where required * * @param hook - The hook in question * @param context - The current context object * @param options - The current ParseOptions */ updateComponentWithNewOutputs(hook, context, options) { const component = hook.componentRef.instance; // Find out which outputs have changed const changedOutputs = this.getChangedBindings(hook, 'outputs', options); // Check if outputs exist on component const existingOutputs = []; const compMeta = reflectComponentType(hook.componentRef.componentType); for (const [outputName, outputCallback] of Object.entries(changedOutputs)) { const metaKey = options.ignoreOutputAliases ? 'propName' : 'templateName'; const outputEntry = compMeta.outputs.find(outputObject => outputName === outputObject[metaKey]) || compMeta.outputs.find(outputObject => outputName.toLowerCase() === outputObject[metaKey].toLowerCase()) || compMeta.outputs.find(outputObject => outputName.replace(/-/g, '') === outputObject[metaKey]) || compMeta.outputs.find(outputObject => outputName.replace(/-/g, '').toLowerCase() === outputObject[metaKey].toLowerCase()); if (outputEntry) { existingOutputs.push({ propName: outputEntry.propName, templateName: outputEntry.templateName, value: outputCallback }); } else if (options.acceptOutputsForAnyObservable) { // If observable exists (in a case-agnostic way), use it let foundOutputProp = Object.getOwnPropertyNames(component).find(propName => component[propName] instanceof Observable && outputName === propName) || Object.getOwnPropertyNames(component).find(propName => component[propName] instanceof Observable && outputName.toLowerCase() === propName.toLowerCase()); if (foundOutputProp) { existingOutputs.push({ propName: foundOutputProp, templateName: null, value: outputCallback }); } } } // (Re)subscribe to outputs, store subscription in Hook for (const { propName, templateName, value } of existingOutputs) { if (hook.outputSubscriptions[propName]) { hook.outputSubscriptions[propName].unsubscribe(); } hook.outputSubscriptions[propName] = hook.componentRef.instance[propName].subscribe((event) => { value(event, context); }); } } /** * Compares the current with the previous bindings and returns those that have changed * * @param hook - The hook in question * @param type - What kind of binding to check * @param options - The current ParseOptions */ getChangedBindings(hook, type, options) { const changedBindings = {}; if (hook.bindings.hasOwnProperty(type)) { for (const [key, binding] of Object.entries(hook.bindings[type])) { // If binding did not exist in previous hook data, binding is considered changed if (!hook.previousBindings || !hook.previousBindings[type].hasOwnProperty(key)) { changedBindings[key] = binding; continue; } // Compare old with new // a) By reference if (type === 'inputs' ? !options.compareInputsByValue : !options.compareOutputsByValue) { if (binding !== hook.previousBindings[type][key].reference) { changedBindings[key] = binding; } // b) By value } else { const stringifiedBinding = this.deepComparer.detailedStringify(binding, options.compareByValueDepth); const canBeComparedByValue = this.checkDetailedStringifyResultPair(key, hook.componentRef.componentType.name, options, hook.previousBindings[type][key].stringified, stringifiedBinding); if (canBeComparedByValue) { if (stringifiedBinding.result !== hook.previousBindings[type][key].stringified.result) { changedBindings[key] = binding; } } else { if (binding !== hook.previousBindings[type][key].reference) { changedBindings[key] = binding; } } } } } return changedBindings; } /** * Checks whether two detailedStringifiedResults can be compared and throws lots of errors and warnings if not * * @param bindingName - The binding in question * @param componentName - The component in question * @param options - The current ParseOptions * @param oldResult - The detailedStringifiedResult for the old value * @param newResult - The detailedStringifiedResult for the new value */ checkDetailedStringifyResultPair(bindingName, componentName, options, oldResult, newResult) { // Stringify successful? if (oldResult.result === null && newResult.result === null) { this.logger.warn(['Could stringify neither new nor old value for hook binding "' + bindingName + '" for component "' + componentName + '" to compare by value. Defaulting to comparison by reference instead.'], options); return false; } if (oldResult.result === null) { this.logger.warn(['Could not stringify old value for hook binding "' + bindingName + '" for component "' + componentName + '" to compare by value. Defaulting to comparison by reference instead.'], options); return false; } if (newResult.result === null) { this.logger.warn(['Could not stringify new value for hook binding "' + bindingName + '" for component "' + componentName + '" to compare by value. Defaulting to comparison by reference instead.'], options); return false; } // Max depth reached? if (oldResult.depthReachedCount > 0 && newResult.depthReachedCount > 0) { this.logger.warn([ 'Maximum compareByValueDepth of ' + options.compareByValueDepth + ' reached ' + newResult.depthReachedCount + ' time(s) for new value and ' + oldResult.depthReachedCount + ' time(s) for old value while comparing binding "' + bindingName + '" for component "' + componentName + '.\n', 'If this impacts performance, consider simplifying this binding, reducing comparison depth or setting compareInputsByValue/compareOutputsByValue to false.' ], options); } else if (oldResult.depthReachedCount > 0) { this.logger.warn([ 'Maximum compareByValueDepth of ' + options.compareByValueDepth + ' reached ' + oldResult.depthReachedCount + ' time(s) for old value while comparing binding "' + bindingName + '" for component "' + componentName + '.\n', 'If this impacts performance, consider simplifying this binding, reducing comparison depth or setting compareInputsByValue/compareOutputsByValue to false.', ], options); } else if (newResult.depthReachedCount > 0) { this.logger.warn([ 'Maximum compareByValueDepth of ' + options.compareByValueDepth + ' reached ' + newResult.depthReachedCount + ' time(s) for new value while comparing binding "' + bindingName + '" for component "' + componentName + '.\n', 'If this impacts performance, consider simplifying this binding, reducing comparison depth or setting compareInputsByValue/compareOutputsByValue to false.', ], options); } return true; } static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: ComponentUpdater, deps: [{ token: i1.DeepComparer }, { token: i2.Logger }], target: i0.ɵɵFactoryTarget.Injectable }); } static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: ComponentUpdater, providedIn: 'root' }); } } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: ComponentUpdater, decorators: [{ type: Injectable, args: [{ providedIn: 'root' }] }], ctorParameters: () => [{ type: i1.DeepComparer }, { type: i2.Logger }] }); //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY29tcG9uZW50VXBkYXRlci5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uLy4uLy4uL3Byb2plY3RzL25neC1keW5hbWljLWhvb2tzL3NyYy9saWIvc2VydmljZXMvY29yZS9jb21wb25lbnRVcGRhdGVyLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sRUFBRSxVQUFVLEVBQUUsb0JBQW9CLEVBQW9CLE1BQU0sZUFBZSxDQUFDO0FBQ25GLE9BQU8sRUFBRSxVQUFVLEVBQUUsTUFBTSxNQUFNLENBQUM7Ozs7QUFPbEM7O0dBRUc7QUFJSCxNQUFNLE9BQU8sZ0JBQWdCO0lBRTNCLFlBQW9CLFlBQTBCLEVBQVUsTUFBYztRQUFsRCxpQkFBWSxHQUFaLFlBQVksQ0FBYztRQUFVLFdBQU0sR0FBTixNQUFNLENBQVE7SUFDdEUsQ0FBQztJQUVEOzs7Ozs7O09BT0c7SUFDSCxPQUFPLENBQUMsU0FBb0IsRUFBRSxPQUFZLEVBQUUsT0FBcUIsRUFBRSx1QkFBZ0M7UUFFakcsdUNBQXVDO1FBQ3ZDLEtBQUssTUFBTSxDQUFDLE1BQU0sRUFBRSxJQUFJLENBQUMsSUFBSSxNQUFNLENBQUMsT0FBTyxDQUFDLFNBQVMsQ0FBQyxFQUFFLENBQUM7WUFDdkQsSUFBSSxDQUFDLGNBQWMsQ0FBQyxJQUFJLEVBQUUsT0FBTyxFQUFFLE9BQU8sQ0FBQyxDQUFDO1FBQzlDLENBQUM7UUFFRCxpR0FBaUc7UUFDakcsSUFBSSx1QkFBdUIsRUFBRSxDQUFDO1lBQzVCLEtBQUssTUFBTSxJQUFJLElBQUksTUFBTSxDQUFDLE1BQU0sQ0FBQyxTQUFTLENBQUMsRUFBRSxDQUFDO2dCQUM1QyxJQUFJLENBQUMsSUFBSSxDQUFDLFlBQVksRUFBRSxDQUFDO29CQUN2QixPQUFPO2dCQUNULENBQUM7Z0JBRUQsSUFBSSxPQUFPLElBQUksQ0FBQyxZQUFZLENBQUMsUUFBUSxDQUFDLGtCQUFrQixDQUFDLEtBQUssVUFBVSxFQUFFLENBQUM7b0JBQ3pF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QWlDLEdBQUcsT0FBTyxDQUFDLG1CQUFtQixHQUFHLFdBQVcsR0FBRyxTQUFTLENBQUMsaUJBQWlCLEdBQUcsNkJBQTZCLEdBQUcsU0FBUyxDQUFDLGlCQUFpQixHQUFHLGtEQUFrRCxHQUFHLFdBQVcsR0FBRyxtQkFBbUIsR0FBRyxhQUFhLEdBQUcsS0FBSztnQkFDMVIsMkpBQTJKO2FBQzVKLEVBQUUsT0FBTyxDQUFDLENBQUM7UUFDZCxDQUFDO2FBQU0sSUFBSSxTQUFTLENBQUMsaUJBQWlCLEdBQUcsQ0FBQyxFQUFFLENBQUM7WUFDM0MsSUFBSSxDQUFDLE1BQU0sQ0FBQyxJQUFJLENBQUM7Z0JBQ2YsaUNBQWlDLEdBQUcsT0FBTyxDQUFDLG1CQUFtQixHQUFHLFdBQVcsR0FBRyxTQUFTLENBQUMsaUJBQWlCLEdBQUcsa0RBQWtELEdBQUcsV0FBVyxHQUFHLG1CQUFtQixHQUFHLGFBQWEsR0FBRyxLQUFLO2dCQUM1TiwySkFBMko7YUFDNUosRUFBRSxPQUFPLENBQUMsQ0FBQztRQUNkLENBQUM7YUFBTSxJQUFJLFNBQVMsQ0FBQyxpQkFBaUIsR0FBRyxDQUFDLEVBQUUsQ0FBQztZQUMzQyxJQUFJLENBQUMsTUFBTSxDQUFDLElBQUksQ0FBQztnQkFDZixpQ0FBaUMsR0FBRyxPQUFPLENBQUMsbUJBQW1CLEdBQUcsV0FBVyxHQUFHLFNBQVMsQ0FBQyxpQkFBaUIsR0FBRyxrREFBa0QsR0FBRyxXQUFXLEdBQUcsbUJBQW1CLEdBQUcsYUFBYSxHQUFHLEtBQUs7Z0JBQzVOLDJKQUEySjthQUM1SixFQUFFLE9BQU8sQ0FBQyxDQUFDO1FBQ2QsQ0FBQztRQUVELE9BQU8sSUFBSSxDQUFDO0lBQ2QsQ0FBQzsrR0FyVFUsZ0JBQWdCO21IQUFoQixnQkFBZ0IsY0FGZixNQUFNOzs0RkFFUCxnQkFBZ0I7a0JBSDVCLFVBQVU7bUJBQUM7b0JBQ1YsVUFBVSxFQUFFLE1BQU07aUJBQ25CIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgSW5qZWN0YWJsZSwgcmVmbGVjdENvbXBvbmVudFR5cGUsIENoYW5nZURldGVjdG9yUmVmfSBmcm9tICdAYW5ndWxhci9jb3JlJztcbmltcG9ydCB7IE9ic2VydmFibGUgfSBmcm9tICdyeGpzJztcblxuaW1wb3J0IHsgSG9vaywgSG9va0luZGV4LCBQcmV2aW91c0hvb2tCaW5kaW5nIH0gZnJvbSAnLi4vLi4vaW50ZXJmYWNlc1B1YmxpYyc7XG5pbXBvcnQgeyBQYXJzZU9wdGlvbnMgfSBmcm9tICcuLi8uLi9zZXJ2aWNlcy9zZXR0aW5ncy9vcHRpb25zJztcbmltcG9ydCB7IERlZXBDb21wYXJlciwgRGV0YWlsZWRTdHJpbmdpZnlSZXN1bHQgfSBmcm9tICcuLi91dGlscy9kZWVwQ29tcGFyZXInO1xuaW1wb3J0IHsgTG9nZ2VyIH0gZnJvbSAnLi4vdXRpbHMvbG9nZ2VyJztcblxuLyoqXG4gKiBUaGUgc2VydmljZSByZXNwb25zaWJsZSBmb3IgdXBkYXRpbmcgZHluYW1pY2FsbHkgY3JlYXRlZCBjb21wb25lbnRzXG4gKi9cbkBJbmplY3RhYmxlKHtcbiAgcHJvdmlkZWRJbjogJ3Jvb3QnXG59KVxuZXhwb3J0IGNsYXNzIENvbXBvbmVudFVwZGF0ZXIge1xuXG4gIGNvbnN0cnVjdG9yKHByaXZhdGUgZGVlcENvbXBhcmVyOiBEZWVwQ29tcGFyZXIsIHByaXZhdGUgbG9nZ2VyOiBMb2dnZXIpIHtcbiAgfVxuXG4gIC8qKlxuICAgKiBJbnZva2VkIHdoZW4gdGhlIGlucHV0cy9vdXRwdXRzIHNob3VsZCBiZSBjaGVja2VkIGZvciB1cGRhdGVzXG4gICAqXG4gICAqIEBwYXJhbSBob29rSW5kZXggLSBUaGUgY3VycmVudCBob29rSW5kZXhcbiAgICogQHBhcmFtIGNvbnRleHQgLSBUaGUgbmV3IGNvbnRleHQgb2JqZWN0XG4gICAqIEBwYXJhbSBvcHRpb25zIC0gVGhlIGN1cnJlbnQgUGFyc2VPcHRpb25zXG4gICAqIEBwYXJhbSB0cmlnZ2VyT25EeW5hbWljQ2hhbmdlcyAtIFdoZXRoZXIgdG8gdHJpZ2dlciB0aGUgT25EeW5hbWljQ2hhbmdlcyBtZXRob2Qgb2YgZHluYW1pY2FsbHkgbG9hZGVkIGNvbXBvbmVudHNcbiAgICovXG4gIHJlZnJlc2goaG9va0luZGV4OiBIb29rSW5kZXgsIGNvbnRleHQ6IGFueSwgb3B0aW9uczogUGFyc2VPcHRpb25zLCB0cmlnZ2VyT25EeW5hbWljQ2hhbmdlczogYm9vbGVhbik6IHZvaWQge1xuXG4gICAgLy8gVXBkYXRlIGJpbmRpbmdzIGZvciBhbGwgbG9hZGVkIGhvb2tzXG4gICAgZm9yIChjb25zdCBbaG9va0lkLCBob29rXSBvZiBPYmplY3QuZW50cmllcyhob29rSW5kZXgpKSB7XG4gICAgICB0aGlzLnVwZGF0ZUJpbmRpbmdzKGhvb2ssIGNvbnRleHQsIG9wdGlvbnMpO1xuICAgIH1cblxuICAgIC8vIEFsc286IElmIGNvbnRleHQgaGFzIGNoYW5nZWQgYnkgcmVmZXJlbmNlLCBjYWxsIE9uRHluYW1pY0NoYW5nZXMoKSBmb3IgYWxsIGNyZWF0ZWQgY29tcG9uZW50cy5cbiAgICBpZiAodHJpZ2dlck9uRHluYW1pY0NoYW5nZXMpIHtcbiAgICAgIGZvciAoY29uc3QgaG9vayBvZiBPYmplY3QudmFsdWVzKGhvb2tJbmRleCkpIHtcbiAgICAgICAgaWYgKCFob29rLmNvbXBvbmVudFJlZikgeyBcbiAgICAgICAgICByZXR1cm47IFxuICAgICAgICB9XG5cbiAgICAgICAgaWYgKHR5cGVvZiBob29rLmNvbXBvbmVudFJlZi5pbnN0YW5jZVsnb25EeW5hbWljQ2hhbmdlcyddID09PSAnZnVuY3Rpb24nKSB7XG4gICAgICAgICAgaG9vay5jb21wb25lbnRSZWYuaW5zdGFuY2VbJ29uRHluYW1pY0NoYW5nZXMnXSh7Y29udGV4dH0pO1xuICAgICAgICB9XG4gICAgICB9XG4gICAgfVxuICB9XG5cbiAgLyoqXG4gICAqIENyZWF0ZXMgb3IgdXBkYXRlcyBiaW5kaW5ncyBmb3IgYSBob29rIHdpdGggYSBsb2FkZWQgY29tcG9uZW50XG4gICAqIFxuICAgKiBAcGFyYW0gaG9vayAtIFRIZSBob29rIHRvIHVwZGF0ZVxuICAgKiBAcGFyYW0gY29udGV4dCAtIFRoZSBjb250ZXh0IG9iamVjdFxuICAgKiBAcGFyYW0gb3B0aW9ucyAtIFRoZSBjdXJyZW50IFBhcnNlT3B0aW9uc1xuICAgKi9cbiAgdXBkYXRlQmluZGluZ3MoaG9vazogSG9vaywgY29udGV4dDogYW55LCBvcHRpb25zOiBQYXJzZU9wdGlvbnMpIHtcbiAgICBpZiAoIWhvb2suY29tcG9uZW50UmVmKSB7IFxuICAgICAgcmV0dXJuOyBcbiAgICB9XG5cbiAgICAvLyBVcGRhdGUgYmluZGluZ3NcbiAgICBob29rLmJpbmRpbmdzID0gaG9vay5wYXJzZXIuZ2V0QmluZGluZ3MoaG9vay5pZCwgaG9vay52YWx1ZSwgY29udGV4dCwgb3B0aW9ucyk7XG4gICAgdGhpcy51cGRhdGVDb21wb25lbnRXaXRoTmV3SW5wdXRzKGhvb2ssIG9wdGlvbnMpO1xuICAgIHRoaXMudXBkYXRlQ29tcG9uZW50V2l0aE5ld091dHB1dHMoaG9vaywgY29udGV4dCwgb3B0aW9ucyk7XG5cbiAgICAvLyBTbmFwc2hvdCBiaW5kaW5ncyBmb3IgY29tcGFyaXNvbiBuZXh0IHRpbWVcbiAgICBob29rLnByZXZpb3VzQmluZGluZ3MgPSB7XG4gICAgICBpbnB1dHM6IHRoaXMuc2F2ZVByZXZpb3VzQmluZGluZ3MoaG9vaywgJ2lucHV0cycsIG9wdGlvbnMuY29tcGFyZUlucHV0c0J5VmFsdWUhLCBvcHRpb25zLmNvbXBhcmVCeVZhbHVlRGVwdGghKSxcbiAgICAgIG91dHB1dHM6IHRoaXMuc2F2ZVByZXZpb3VzQmluZGluZ3MoaG9vaywgJ291dHB1dHMnLCBvcHRpb25zLmNvbXBhcmVPdXRwdXRzQnlWYWx1ZSEsIG9wdGlvbnMuY29tcGFyZUJ5VmFsdWVEZXB0aCEpXG4gICAgfTtcbiAgfVxuXG4gIC8qKlxuICAgKiBDcmVhdGVzIGEgbGlzdCBvZiBhbGwgcHJldmlvdXMgYmluZGluZ3MgYWxvbmcgd2l0aCB0aGVpciBzdHJpbmdpZmllZCB2YWx1ZXNcbiAgICpcbiAgICogQHBhcmFtIGhvb2sgLSBUaGUgaG9vayB0byBjaGVja1xuICAgKiBAcGFyYW0gdHlwZSAtIFRoZSB0eXBlIG9mIGJpbmRpbmdzIHRoYXQgc2hvdWxkIGJlIHNhdmVkXG4gICAqIEBwYXJhbSBzYXZlU3RyaW5naWZpZWQgLSBXaGV0aGVyIHRvIHNhdmUgdGhlIHN0cmluZ2lmaWVkIHZhbHVlIGluIGFkZGl0aW9uIHRvIHRoZSByZWZlcmVuY2VcbiAgICogQHBhcmFtIHN0cmluZ2lmeURlcHRoIC0gSG93IG1hbnkgbGV2ZWxzIGRlZXAgdG8gc3RyaW5naWZ5IHRoZSBwcmV2aW91cyBiaW5kaW5nc1xuICAgKi9cbiAgc2F2ZVByZXZpb3VzQmluZGluZ3MoaG9vazogSG9vaywgdHlwZTogJ2lucHV0cyd8J291dHB1dHMnLCBzYXZlU3RyaW5naWZpZWQ6IGJvb2xlYW4sIHN0cmluZ2lmeURlcHRoOiBudW1iZXIpOiB7W2tleTogc3RyaW5nXTogUHJldmlvdXNIb29rQmluZGluZ30ge1xuICAgIGNvbnN0IHJlc3VsdDoge1trZXk6IHN0cmluZ106IFByZXZpb3VzSG9va0JpbmRpbmd9ID0ge307XG4gICAgaWYgKGhvb2suYmluZGluZ3MhLmhhc093blByb3BlcnR5KHR5cGUpKSB7XG4gICAgICBmb3IgKGNvbnN0IFtiaW5kaW5nTmFtZSwgYmluZGluZ1ZhbHVlXSBvZiBPYmplY3QuZW50cmllcyhob29rLmJpbmRpbmdzIVt0eXBlXSBhcyBhbnkpKSB7XG4gICAgICAgIHJlc3VsdFtiaW5kaW5nTmFtZV0gPSB7XG4gICAgICAgICAgcmVmZXJlbmNlOiBiaW5kaW5nVmFsdWUsXG4gICAgICAgICAgc3RyaW5naWZpZWQ6IHNhdmVTdHJpbmdpZmllZCA/IHRoaXMuZGVlcENvbXBhcmVyLmRldGFpbGVkU3RyaW5naWZ5KGJpbmRpbmdWYWx1ZSwgc3RyaW5naWZ5RGVwdGgpIDogbnVsbCAvLyBUbyBjb21wYXJlIGJ5IHZhbHVlXG4gICAgICAgIH07XG4gICAgICB9XG4gICAgfVxuICAgIHJldHVybiByZXN1bHQ7XG4gIH1cblxuICAvLyBVcGRhdGluZyBiaW5kaW5nc1xuICAvLyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXG5cbiAgLyoqXG4gICAqIFByb2Nlc3NlcyBhIGhvb2sgb2JqZWN0IGFuZCB1cGRhdGVzIHRoZSBpbnB1dHMgb2YgYSBkeW5hbWljIGNvbXBvbmVudCB3aGVyZSByZXF1aXJlZFxuICAgKlxuICAgKiBAcGFyYW0gaG9vayAtIFRoZSBob29rIGluIHF1ZXN0aW9uXG4gICAqIEBwYXJhbSBvcHRpb25zIC0gVGhlIGN1cnJlbnQgUGFyc2VPcHRpb25zXG4gICAqL1xuICB1cGRhdGVDb21wb25lbnRXaXRoTmV3SW5wdXRzKGhvb2s6IEhvb2ssIG9wdGlvbnM6IFBhcnNlT3B0aW9ucyk6IHZvaWQge1xuICAgIGNvbnN0IGNvbXBvbmVudCA9IGhvb2suY29tcG9uZW50UmVmIS5pbnN0YW5jZTtcblxuICAgIC8vIEZpbmQgb3V0IHdoaWNoIGlucHV0cyBoYXZlIGNoYW5nZWRcbiAgICBjb25zdCBjaGFuZ2VkSW5wdXRzID0gdGhpcy5nZXRDaGFuZ2VkQmluZGluZ3MoaG9vaywgJ2lucHV0cycsIG9wdGlvbnMpO1xuXG4gICAgLy8gQ2hlY2sgaWYgaW5wdXRzIGV4aXN0cyBvbiBjb21wb25lbnRcbiAgICBjb25zdCBleGlzdGluZ0lucHV0czoge1xuICAgICAgcHJvcE5hbWU6IHN0cmluZyxcbiAgICAgIHRlbXBsYXRlTmFtZTogc3RyaW5nfG51bGwsXG4gICAgICB2YWx1ZTogYW55XG4gICAgfVtdID0gW107XG5cbiAgICBjb25zdCBjb21wTWV0YSA9IHJlZmxlY3RDb21wb25lbnRUeXBlKGhvb2suY29tcG9uZW50UmVmIS5jb21wb25lbnRUeXBlKSE7XG5cbiAgICBmb3IgKGNvbnN0IFtpbnB1dE5hbWUsIGlucHV0VmFsdWVdIG9mIE9iamVjdC5lbnRyaWVzKGNoYW5nZWRJbnB1dHMpKSB7XG4gICAgICAvLyBTb21lIG5hbWluZyB0b2xlcmFuY2U6IElucHV0IG5hbWUgY2FuIGJlIGNhc2UtaW5zZW5zaXRpdmUgYW5kIGluIGRhc2gtY2FzZS5cbiAgICAgIC8vIExvb2sgZm9yIG1vcmUgbGl0ZXJhbCBtYXRjaGVzIGZpcnN0ICh0cmFuc2Zvcm1lZCBkYXNoLWNhc2UgKyBjYXNlLWluc2Vuc2l0aXZlIGhhcyBsb3dlc3QgcHJpb3JpdHkpXG4gICAgICBjb25zdCBtZXRhS2V5ID0gb3B0aW9ucy5pZ25vcmVJbnB1dEFsaWFzZXMgPyAncHJvcE5hbWUnIDogJ3RlbXBsYXRlTmFtZSc7XG4gICAgICBjb25zdCBpbnB1dEVudHJ5ID0gXG4gICAgICAgIGNvbXBNZXRhLmlucHV0cy5maW5kKGlucHV0T2JqZWN0ID0+IGlucHV0TmFtZSA9PT0gaW5wdXRPYmplY3RbbWV0YUtleV0pIHx8XG4gICAgICAgIGNvbXBNZXRhLmlucHV0cy5maW5kKGlucHV0T2JqZWN0ID0+IGlucHV0TmFtZS50b0xvd2VyQ2FzZSgpID09PSBpbnB1dE9iamVjdFttZXRhS2V5XS50b0xvd2VyQ2FzZSgpKSB8fFxuICAgICAgICBjb21wTWV0YS5pbnB1dHMuZmluZChpbnB1dE9iamVjdCA9PiBpbnB1dE5hbWUucmVwbGFjZSgvLS9nLCAnJykgPT09IGlucHV0T2JqZWN0W21ldGFLZXldKSB8fFxuICAgICAgICBjb21wTWV0YS5pbnB1dHMuZmluZChpbnB1dE9iamVjdCA9PiBpbnB1dE5hbWUucmVwbGFjZSgvLS9nLCAnJykudG9Mb3dlckNhc2UoKSA9PT0gaW5wdXRPYmplY3RbbWV0YUtleV0udG9Mb3dlckNhc2UoKSlcblxuICAgICAgLy8gSWYgYWN0dWFsIGlucHV0IHdhcyBmb3VuZCwgYWRkIGl0XG4gICAgICBpZiAoaW5wdXRFbnRyeSkge1xuICAgICAgICBleGlzdGluZ0lucHV0cy5wdXNoKHtcbiAgICAgICAgICBwcm9wTmFtZTogaW5wdXRFbnRyeS5wcm9wTmFtZSxcbiAgICAgICAgICB0ZW1wbGF0ZU5hbWU6IGlucHV0RW50cnkudGVtcGxhdGVOYW1lLFxuICAgICAgICAgIHZhbHVlOiBpbnB1dFZhbHVlXG4gICAgICAgIH0pO1xuXG4gICAgICAvLyBJZiBub3QsIGJ1dCBhY2NlcHRzIGFueSBwcm9wZXJ0eSBhcyBpbnB1dCwgYWRkIGl0IGFueXdheVxuICAgICAgfSBlbHNlIGlmIChvcHRpb25zLmFjY2VwdElucHV0c0ZvckFueVByb3BlcnR5KSB7XG4gICAgICAgIC8vIElmIHByb3BlcnR5IGV4aXN0cyAoaW4gYSBjYXNlLWFnbm9zdGljIHdheSksIHVzZSBpdC4gT3RoZXJ3aXNlIGNyZWF0ZSBsaXRlcmFsIG5ldyBwcm9wZXJ0eS5cbiAgICAgICAgbGV0IGZvdW5kSW5wdXRQcm9wID0gXG4gICAgICAgICAgT2JqZWN0LmdldE93blByb3BlcnR5TmFtZXMoY29tcG9uZW50KS5maW5kKHByb3BOYW1lID0+IGlucHV0TmFtZSA9PT0gcHJvcE5hbWUpIHx8XG4gICAgICAgICAgT2JqZWN0LmdldE93blByb3BlcnR5TmFtZXMoY29tcG9uZW50KS5maW5kKHByb3BOYW1lID0+IGlucHV0TmFtZS50b0xvd2VyQ2FzZSgpID09PSBwcm9wTmFtZS50b0xvd2VyQ2FzZSgpKTtcblxuICAgICAgICBjb25zdCBmaW5hbElucHV0UHJvcCA9IGZvdW5kSW5wdXRQcm9wIHx8IGlucHV0TmFtZTtcblxuICAgICAgICAvLyBFdmVuIHRoaXMgc2V0dGluZyBoYXMgbGltaXRzLiBEb24ndCBhbGxvdyBzZXR0aW5nIGZ1bmRhbWVudGFsIEphdmFTY3JpcHQgb2JqZWN0IHByb3BlcnRpZXMuXG4gICAgICAgIGlmICghWydfX3Byb3RvX18nLCAncHJvdG90eXBlJywgJ2NvbnN0cnVjdG9yJ10uaW5jbHVkZXMoZmluYWxJbnB1dFByb3ApKSB7XG4gICAgICAgICAgZXhpc3RpbmdJbnB1dHMucHVzaCh7XG4gICAgICAgICAgICBwcm9wTmFtZTogZmluYWxJbnB1dFByb3AsXG4gICAgICAgICAgICB0ZW1wbGF0ZU5hbWU6IG51bGwsXG4gICAgICAgICAgICB2YWx1ZTogaW5wdXRWYWx1ZVxuICAgICAgICAgIH0pO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgIHRoaXMubG9nZ2VyLmVycm9yKFsnVHJpZWQgdG8gb3ZlcndyaXRlIGEgX19wcm90b19fLCBwcm90b3R5cGUgb3IgY29uc3RydWN0b3IgcHJvcGVydHkgd2l0aCBpbnB1dCBcIicgKyBmaW5hbElucHV0UHJvcCArICdcIiBmb3IgaG9vayBcIicgKyBob29rLmNvbXBvbmVudFJlZiEuY29tcG9uZW50VHlwZS5uYW1lICsgJ1wiLiBUaGlzIGlzIG5vdCBhbGxvd2VkLiddLCBvcHRpb25zKTtcbiAgICAgICAgICBjb250aW51ZTtcbiAgICAgICAgfVxuICAgICAgfVxuICAgIH1cblxuICAgIC8vIFNldCBpbnB1dHMgaW4gY29tcG9uZW50XG4gICAgZm9yIChjb25zdCB7cHJvcE5hbWUsIHRlbXBsYXRlTmFtZSwgdmFsdWV9IG9mIGV4aXN0aW5nSW5wdXRzKSB7XG4gICAgICBpZiAodGVtcGxhdGVOYW1lKSB7XG4gICAgICAgIGhvb2suY29tcG9uZW50UmVmPy5zZXRJbnB1dCh0ZW1wbGF0ZU5hbWUsIHZhbHVlKTsgICAgICAgICAgICAgLy8gT2ZmaWNpYWwgbWV0aG9kIHRvIHNldCBpbnB1dHMuIFNldHMgcHJvcGVydHksIHRyaWdnZXJzIE9uQ2hhbmdlcyBhbmQgbWFya3MgZm9yIE9uUHVzaC4gQWxzbyB3b3JrcyB3aXRoIG5ldyBzaWduYWwgaW5wdXRzLlxuICAgICAgfSBlbHNlIGlmIChwcm9wTmFtZSkge1xuICAgICAgICBob29rLmNvbXBvbmVudFJlZiEuaW5zdGFuY2VbcHJvcE5hbWVdID0gdmFsdWU7ICAgICAgICAgICAgICAgIC8vIFJlc29ydCB0byBtYW51YWwgc2V0dGluZyBvbmx5IGlmIHByb3AgaXNuJ3QgYSBkZWNsYXJlZCBpbnB1dCAobWF5IGhhcHBlbiB3aXRoIFwiYWNjZXB0SW5wdXRzRm9yQW55UHJvcGVydHlcIilcbiAgICAgIH1cbiAgICB9XG5cbiAgICAvLyBJbXBvcnRhbnQ6IFN0aWxsIG5lZWQgdG8gdHJpZ2dlciBjZCwgZXZlbiB3aXRoIGNvbXBvbmVudFJlZi5zZXRJbnB1dFxuICAgIGlmIChleGlzdGluZ0lucHV0cy5sZW5ndGgpIHtcbiAgICAgIGhvb2suY29tcG9uZW50UmVmPy5jaGFuZ2VEZXRlY3RvclJlZi5kZXRlY3RDaGFuZ2VzKCk7XG4gICAgfVxuICB9XG5cbiAgLyoqXG4gICAqIFByb2Nlc3NlcyBhIGhvb2sgb2JqZWN0IGFuZCAocmUpc3Vic2NyaWJlcyB0aGUgb3V0cHV0cyBvZiBhIGR5bmFtaWMgY29tcG9uZW50IHdoZXJlIHJlcXVpcmVkXG4gICAqXG4gICAqIEBwYXJhbSBob29rIC0gVGhlIGhvb2sgaW4gcXVlc3Rpb25cbiAgICogQHBhcmFtIGNvbnRleHQgLSBUaGUgY3VycmVudCBjb250ZXh0IG9iamVjdFxuICAgKiBAcGFyYW0gb3B0aW9ucyAtIFRoZSBjdXJyZW50IFBhcnNlT3B0aW9uc1xuICAgKi9cbiAgdXBkYXRlQ29tcG9uZW50V2l0aE5ld091dHB1dHMoaG9vazogSG9vaywgY29udGV4dDogYW55LCBvcHRpb25zOiBQYXJzZU9wdGlvbnMpOiB2b2lkIHtcbiAgICBjb25zdCBjb21wb25lbnQgPSBob29rLmNvbXBvbmVudFJlZiEuaW5zdGFuY2U7XG5cbiAgICAvLyBGaW5kIG91dCB3aGljaCBvdXRwdXRzIGhhdmUgY2hhbmdlZFxuICAgIGNvbnN0IGNoYW5nZWRPdXRwdXRzOiB7W2tleTogc3RyaW5nXTogKGU6IGFueSwgYzogYW55KSA9PiBhbnl9ID0gdGhpcy5nZXRDaGFuZ2VkQmluZGluZ3MoaG9vaywgJ291dHB1dHMnLCBvcHRpb25zKTtcblxuICAgIC8vIENoZWNrIGlmIG91dHB1dHMgZXhpc3Qgb24gY29tcG9uZW50XG4gICAgY29uc3QgZXhpc3RpbmdPdXRwdXRzOiB7XG4gICAgICBwcm9wTmFtZTogc3RyaW5nLFxuICAgICAgdGVtcGxhdGVOYW1lOiBzdHJpbmd8bnVsbCxcbiAgICAgIHZhbHVlOiAoZTogYW55LCBjOiBhbnkpID0+IGFueVxuICAgIH1bXSA9IFtdO1xuXG4gICAgY29uc3QgY29tcE1ldGEgPSByZWZsZWN0Q29tcG9uZW50VHlwZShob29rLmNvbXBvbmVudFJlZiEuY29tcG9uZW50VHlwZSkhO1xuXG4gICAgZm9yIChjb25zdCBbb3V0cHV0TmFtZSwgb3V0cHV0Q2FsbGJhY2tdIG9mIE9iamVjdC5lbnRyaWVzKGNoYW5nZWRPdXRwdXRzKSkge1xuICAgICAgY29uc3QgbWV0YUtleSA9IG9wdGlvbnMuaWdub3JlT3V0cHV0QWxpYXNlcyA/ICdwcm9wTmFtZScgOiAndGVtcGxhdGVOYW1lJztcbiAgICAgIGNvbnN0IG91dHB1dEVudHJ5ID0gXG4gICAgICAgIGNvbXBNZXRhLm91dHB1dHMuZmluZChvdXRwdXRPYmplY3QgPT4gb3V0cHV0TmFtZSA9PT0gb3V0cHV0T2JqZWN0W21ldGFLZXldKSB8fFxuICAgICAgICBjb21wTWV0YS5vdXRwdXRzLmZpbmQob3V0cHV0T2JqZWN0ID0+IG91dHB1dE5hbWUudG9Mb3dlckNhc2UoKSA9PT0gb3V0cHV0T2JqZWN0W21ldGFLZXldLnRvTG93ZXJDYXNlKCkpIHx8XG4gICAgICAgIGNvbXBNZXRhLm91dHB1dHMuZmluZChvdXRwdXRPYmplY3QgPT4gb3V0cHV0TmFtZS5yZXBsYWNlKC8tL2csICcnKSA9PT0gb3V0cHV0T2JqZWN0W21ldGFLZXldKSB8fFxuICAgICAgICBjb21wTWV0YS5vdXRwdXRzLmZpbmQob3V0cHV0T2JqZWN0ID0+IG91dHB1dE5hbWUucmVwbGFjZSgvLS9nLCAnJykudG9Mb3dlckNhc2UoKSA9PT0gb3V0cHV0T2JqZWN0W21ldGFLZXldLnRvTG93ZXJDYXNlKCkpXG5cbiAgICAgIGlmIChvdXRwdXRFbnRyeSkge1xuICAgICAgICBleGlzdGluZ091dHB1dHMucHVzaCh7XG4gICAgICAgICAgcHJvcE5hbWU6IG91dHB1dEVudHJ5LnByb3BOYW1lLFxuICAgICAgICAgIHRlbXBsYXRlTmFtZTogb3V0cHV0RW50cnkudGVtcGxhdGVOYW1lLFxuICAgICAgICAgIHZhbHVlOiBvdXRwdXRDYWxsYmFja1xuICAgICAgICB9KTtcbiAgICAgIFxuICAgICAgfSBlbHNlIGlmIChvcHRpb25zLmFjY2VwdE91dHB1dHNGb3JBbnlPYnNlcnZhYmxlKSB7XG4gICAgICAgIC8vIElmIG9ic2VydmFibGUgZXhpc3RzIChpbiBhIGNhc2UtYWdub3N0aWMgd2F5KSwgdXNlIGl0XG4gICAgICAgIGxldCBmb3VuZE91dHB1dFByb3AgPSBcbiAgICAgICAgICBPYmplY3QuZ2V0T3duUHJvcGVydHlOYW1lcyhjb21wb25lbnQpLmZpbmQocHJvcE5hbWUgPT4gY29tcG9uZW50W3Byb3BOYW1lXSBpbnN0YW5jZW9mIE9ic2VydmFibGUgJiYgb3V0cHV0TmFtZSA9PT0gcHJvcE5hbWUpIHx8XG4gICAgICAgICAgT2JqZWN0LmdldE93blByb3BlcnR5TmFtZXMoY29tcG9uZW50KS5maW5kKHByb3BOYW1lID0+IGNvbXBvbmVudFtwcm9wTmFtZV0gaW5zdGFuY2VvZiBPYnNlcnZhYmxlICYmIG91dHB1dE5hbWUudG9Mb3dlckNhc2UoKSA9PT0gcHJvcE5hbWUudG9Mb3dlckNhc2UoKSk7XG4gICAgICBcbiAgICAgICAgaWYgKGZvdW5kT3V0cHV0UHJvcCkge1xuICAgICAgICAgIGV4aXN0aW5nT3V0cHV0cy5wdXNoKHtcbiAgICAgICAgICAgIHByb3BOYW1lOiBmb3VuZE91dHB1dFByb3AsXG4gICAgICAgICAgICB0ZW1wbGF0ZU5hbWU6IG51bGwsXG4gICAgICAgICAgICB2YWx1ZTogb3V0cHV0Q2FsbGJhY2tcbiAgICAgICAgICB9KTtcbiAgICAgICAgfVxuICAgICAgfVxuICAgIH0gIFxuXG4gICAgLy8gKFJlKXN1YnNjcmliZSB0byBvdXRwdXRzLCBzdG9yZSBzdWJzY3JpcHRpb24gaW4gSG9va1xuICAgIGZvciAoY29uc3Qge3Byb3BOYW1lLCB0ZW1wbGF0ZU5hbWUsIHZhbHVlfSBvZiBleGlzdGluZ091dHB1dHMpIHtcbiAgICAgIGlmIChob29rLm91dHB1dFN1YnNjcmlwdGlvbnNbcHJvcE5hbWVdKSB7IGhvb2sub3V0cHV0U3Vic2NyaXB0aW9uc1twcm9wTmFtZV0udW5zdWJzY3JpYmUoKTsgfVxuICAgICAgaG9vay5vdXRwdXRTdWJzY3JpcHRpb25zW3Byb3BOYW1lXSA9IGhvb2suY29tcG9uZW50UmVmIS5pbnN0YW5jZVtwcm9wTmFtZV0uc3Vic2NyaWJlKChldmVudDogYW55KSA9PiB7XG4gICAgICAgIHZhbHVlKGV2ZW50LCBjb250ZXh0KTtcbiAgICAgIH0pO1xuICAgIH1cbiAgfVxuXG4gIC8qKlxuICAgKiBDb21wYXJlcyB0aGUgY3VycmVudCB3aXRoIHRoZSBwcmV2aW91cyBiaW5kaW5ncyBhbmQgcmV0dXJucyB0aG9zZSB0aGF0IGhhdmUgY2hhbmdlZFxuICAgKlxuICAgKiBAcGFyYW0gaG9vayAtIFRoZSBob29rIGluIHF1ZXN0aW9uXG4gICAqIEBwYXJhbSB0eXBlIC0gV2hhdCBraW5kIG9mIGJpbmRpbmcgdG8gY2hlY2tcbiAgICogQHBhcmFtIG9wdGlvbnMgLSBUaGUgY3VycmVudCBQYXJzZU9wdGlvbnNcbiAgICovXG4gIGdldENoYW5nZWRCaW5kaW5ncyhob29rOiBIb29rLCB0eXBlOiAnaW5wdXRzJ3wnb3V0cHV0cycsIG9wdGlvbnM6IFBhcnNlT3B0aW9ucyk6IHtba2V5OiBzdHJpbmddOiBhbnl9IHtcbiAgICBjb25zdCBjaGFuZ2VkQmluZGluZ3M6IHtba2V5OiBzdHJpbmddOiBhbnl9ID0ge307XG4gICAgaWYgKGhvb2suYmluZGluZ3MhLmhhc093blByb3BlcnR5KHR5cGUpKSB7XG4gICAgICBmb3IgKGNvbnN0IFtrZXksIGJpbmRpbmddIG9mIE9iamVjdC5lbnRyaWVzKGhvb2suYmluZGluZ3MhW3R5cGVdIGFzIGFueSkpIHtcblxuICAgICAgICAvLyBJZiBiaW5kaW5nIGRpZCBub3QgZXhpc3QgaW4gcHJldmlvdXMgaG9vayBkYXRhLCBiaW5kaW5nIGlzIGNvbnNpZGVyZWQgY2hhbmdlZFxuICAgICAgICBpZiAoIWhvb2sucHJldmlvdXNCaW5kaW5ncyB8fCAhaG9vay5wcmV2aW91c0JpbmRpbmdzW3R5cGVdLmhhc093blByb3BlcnR5KGtleSkpIHtcbiAgICAgICAgICBjaGFuZ2VkQmluZGluZ3Nba2V5XSA9IGJpbmRpbmc7XG4gICAgICAgICAgY29udGludWU7XG4gICAgICAgIH1cblxuICAgICAgICAvLyBDb21wYXJlIG9sZCB3aXRoIG5ld1xuICAgICAgICAvLyBhKSBCeSByZWZlcmVuY2VcbiAgICAgICAgaWYgKHR5cGUgPT09ICdpbnB1dHMnID8gIW9wdGlvbnMuY29tcGFyZUlucHV0c0J5VmFsdWUgOiAhb3B0aW9ucy5jb21wYXJlT3V0cHV0c0J5VmFsdWUpIHtcbiAgICAgICAgICBpZiAoYmluZGluZyAhPT0gaG9vay5wcmV2aW91c0JpbmRpbmdzW3R5cGVdW2tleV0ucmVmZXJlbmNlKSB7XG4gICAgICAgICAgICBjaGFuZ2VkQmluZGluZ3Nba2V5XSA9IGJpbmRpbmc7XG4gICAgICAgICAgfVxuICAgICAgICAvLyBiKSBCeSB2YWx1ZVxuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgIGNvbnN0IHN0cmluZ2lmaWVkQmluZGluZyA9IHRoaXMuZGVlcENvbXBhcmVyLmRldGFpbGVkU3RyaW5naWZ5KGJpbmRpbmcsIG9wdGlvbnMuY29tcGFyZUJ5VmFsdWVEZXB0aCk7XG4gICAgICAgICAgY29uc3QgY2FuQmVDb21wYXJlZEJ5VmFsdWUgPSB0aGlzLmNoZWNrRGV0YWlsZWRTdHJpbmdpZnlSZXN1bHRQYWlyKGtleSwgaG9vay5jb21wb25lbnRSZWYhLmNvbXBvbmVudFR5cGUubmFtZSwgb3B0aW9ucywgaG9vay5wcmV2aW91c0JpbmRpbmdzW3R5cGVdW2tleV0uc3RyaW5naWZpZWQhLCBzdHJpbmdpZmllZEJpbmRpbmcpO1xuXG4gICAgICAgICAgaWYgKGNhbkJlQ29tcGFyZWRCeVZhbHVlKSB7XG4gICAgICAgICAgICBpZiAoc3RyaW5naWZpZWRCaW5kaW5nLnJlc3VsdCAhPT0gaG9vay5wcmV2aW91c0JpbmRpbmdzW3R5cGVdW2tleV0uc3RyaW5naWZpZWQhLnJlc3VsdCkge1xuICAgICAgICAgICAgICBjaGFuZ2VkQmluZGluZ3Nba2V5XSA9IGJpbmRpbmc7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIGlmIChiaW5kaW5nICE9PSBob29rLnByZXZpb3VzQmluZGluZ3NbdHlwZV1ba2V5XS5yZWZlcmVuY2UpIHtcbiAgICAgICAgICAgICAgY2hhbmdlZEJpbmRpbmdzW2tleV0gPSBiaW5kaW5nO1xuICAgICAgICAgICAgfVxuICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgfVxuICAgIH1cblxuICAgIHJldHVybiBjaGFuZ2VkQmluZGluZ3M7XG4gIH1cblxuICAvKipcbiAgICogQ2hlY2tzIHdoZXRoZXIgdHdvIGRldGFpbGVkU3RyaW5naWZpZWRSZXN1bHRzIGNhbiBiZSBjb21wYXJlZCBhbmQgdGhyb3dzIGxvdHMgb2YgZXJyb3JzIGFuZCB3YXJuaW5ncyBpZiBub3RcbiAgICpcbiAgICogQHBhcmFtIGJpbmRpbmdOYW1lIC0gVGhlIGJpbmRpbmcgaW4gcXVlc3Rpb25cbiAgICogQHBhcmFtIGNvbXBvbmVudE5hbWUgLSBUaGUgY29tcG9uZW50IGluIHF1ZXN0aW9uXG4gICAqIEBwYXJhbSBvcHRpb25zIC0gVGhlIGN1cnJlbnQgUGFyc2VPcHRpb25zXG4gICAqIEBwYXJhbSBvbGRSZXN1bHQgLSBUaGUgZGV0YWlsZWRTdHJpbmdpZmllZFJlc3VsdCBmb3IgdGhlIG9sZCB2YWx1ZVxuICAgKiBAcGFyYW0gbmV3UmVzdWx0IC0gVGhlIGRldGFpbGVkU3RyaW5naWZpZWRSZXN1bHQgZm9yIHRoZSBuZXcgdmFsdWVcbiAgICovXG4gIGNoZWNrRGV0YWlsZWRTdHJpbmdpZnlSZXN1bHRQYWlyKGJpbmRpbmdOYW1lOiBzdHJpbmcsIGNvbXBvbmVudE5hbWU6IHN0cmluZywgb3B0aW9uczogUGFyc2VPcHRpb25zLCBvbGRSZXN1bHQ6IERldGFpbGVkU3RyaW5naWZ5UmVzdWx0LCBuZXdSZXN1bHQ6IERldGFpbGVkU3RyaW5naWZ5UmVzdWx0KTogYm9vbGVhbiB7XG4gICAgLy8gU3RyaW5naWZ5IHN1Y2Nlc3NmdWw/XG4gICAgaWYgKG9sZFJlc3VsdC5yZXN1bHQgPT09IG51bGwgJiYgbmV3UmVzdWx0LnJlc3VsdCA9PT0gbnVsbCkge1xuICAgICAgdGhpcy5sb2dnZXIud2FybihbJ0NvdWxkIHN0cmluZ2lmeSBuZWl0aGVyIG5ldyBub3Igb2xkIHZhbHVlIGZvciBob29rIGJpbmRpbmcgXCInICsgYmluZGluZ05hbWUgKyAnXCIgZm9yIGNvbXBvbmVudCBcIicgKyBjb21wb25lbnROYW1lICsgJ1wiIHRvIGNvbXBhcmUgYnkgdmFsdWUuIERlZmF1bHRpbmcgdG8gY29tcGFyaXNvbiBieSByZWZlcmVuY2UgaW5zdGVhZC4nXSwgb3B0aW9ucyk7XG4gICAgICByZXR1cm4gZmFsc2U7XG4gICAgfVxuICAgIGlmIChvbGRSZXN1bHQucmVzdWx0ID09PSBudWxsKSB7XG4gICAgICB0aGlzLmxvZ2dlci53YXJuKFsnQ291bGQgbm90IHN0cmluZ2lmeSBvbGQgdmFsdWUgZm9yIGhvb2sgYmluZGluZyBcIicgKyBiaW5kaW5nTmFtZSArICdcIiBmb3IgY29tcG9uZW50IFwiJyArIGNvbXBvbmVudE5hbWUgKyAnXCIgdG8gY29tcGFyZSBieSB2YWx1ZS4gRGVmYXVsdGluZyB0byBjb21wYXJpc29uIGJ5IHJlZmVyZW5jZSBpbnN0ZWFkLiddLCBvcHRpb25zKTtcbiAgICAgIHJldHVybiBmYWxzZTtcbiAgICB9XG4gICAgaWYgKG5ld1Jlc3VsdC5yZXN1bHQgPT09IG51bGwpIHtcbiAgICAgIHRoaXMubG9nZ2VyLndhcm4oWydDb3VsZCBub3Qgc3RyaW5naWZ5IG5ldyB2YWx1ZSBmb3IgaG9vayBiaW5kaW5nIFwiJyArIGJpbmRpbmdOYW1lICsgJ1wiIGZvciBjb21wb25lbnQgXCInICsgY29tcG9uZW50TmFtZSArICdcIiB0byBjb21wYXJlIGJ5IHZhbHVlLiBEZWZhdWx0aW5nIHRvIGNvbXBhcmlzb24gYnkgcmVmZXJlbmNlIGluc3RlYWQuJ10sIG9wdGlvbnMpO1xuICAgICAgcmV0dXJuIGZhbHNlO1xuICAgIH1cblxuICAgIC8vIE1heCBkZXB0aCByZWFjaGVkP1xuICAgIGlmIChvbGRSZXN1bHQuZGVwdGhSZWFjaGVkQ291bnQgPiAwICYmIG5ld1Jlc3VsdC5kZXB0aFJlYWNoZWRDb3VudCA+IDApIHtcbiAgICAgIHRoaXMubG9nZ2VyLndhcm4oW1xuICAgICAgICAnTWF4aW11bSBjb21wYXJlQnlWYWx1ZURlcHRoIG9mICcgKyBvcHRpb25zLmNvbXBhcmVCeVZhbHVlRGVwdGggKyAnIHJlYWNoZWQgJyArIG5ld1Jlc3VsdC5kZXB0aFJlYWNoZWRDb3VudCArICcgdGltZShzKSBmb3IgbmV3IHZhbHVlIGFuZCAnICsgb2xkUmVzdWx0LmRlcHRoUmVhY2hlZENvdW50ICsgJyB0aW1lKHMpIGZvciBvbGQgdmFsdWUgd2hpbGUgY29tcGFyaW5nIGJpbmRpbmcgXCInICsgYmluZGluZ05hbWUgKyAnXCIgZm9yIGNvbXBvbmVudCBcIicgKyBjb21wb25lbnROYW1lICsgJy5cXG4nLFxuICAgICAgICAnSWYgdGhpcyBpbXBhY3RzIHBlcmZvcm1hbmNlLCBjb25zaWRlciBzaW1wbGlmeWluZyB0aGlzIGJpbmRpbmcsIHJlZHVjaW5nIGNvbXBhcmlzb24gZGVwdGggb3Igc2V0dGluZyBjb21wYXJlSW5wdXRzQnlWYWx1ZS9jb21wYXJlT3V0cHV0c0J5VmFsdWUgdG8gZmFsc2UuJ1xuICAgICAgXSwgb3B0aW9ucyk7XG4gICAgfSBlbHNlIGlmIChvbGRSZXN1bHQuZGVwdGhSZWFjaGVkQ291bnQgPiAwKSB7XG4gICAgICB0aGlzLmxvZ2dlci53YXJuKFtcbiAgICAgICAgJ01heGltdW0gY29tcGFyZUJ5VmFsdWVEZXB0aCBvZiAnICsgb3B0aW9ucy5jb21wYXJlQnlWYWx1ZURlcHRoICsgJyByZWFjaGVkICcgKyBvbGRSZXN1bHQuZGVwdGhSZWFjaGVkQ291bnQgKyAnIHRpbWUocykgZm9yIG9sZCB2YWx1ZSB3aGlsZSBjb21wYXJpbmcgYmluZGluZyBcIicgKyBiaW5kaW5nTmFtZSArICdcIiBmb3IgY29tcG9uZW50IFwiJyArIGNvbXBvbmVudE5hbWUgKyAnLlxcbicsXG4gICAgICAgICdJZiB0aGlzIGltcGFjdHMgcGVyZm9ybWFuY2UsIGNvbnNpZGVyIHNpbXBsaWZ5aW5nIHRoaXMgYmluZGluZywgcmVkdWNpbmcgY29tcGFyaXNvbiBkZXB0aCBvciBzZXR0aW5nIGNvbXBhcmVJbnB1dHNCeVZhbHVlL2NvbXBhcmVPdXRwdXRzQnlWYWx1ZSB0byBmYWxzZS4nLFxuICAgICAgXSwgb3B0aW9ucyk7XG4gICAgfSBlbHNlIGlmIChuZXdSZXN1bHQuZGVwdGhSZWFjaGVkQ291bnQgPiAwKSB7XG4gICAgICB0aGlzLmxvZ2dlci53YXJuKFtcbiAgICAgICAgJ01heGltdW0gY29tcGFyZUJ5VmFsdWVEZXB0aCBvZiAnICsgb3B0aW9ucy5jb21wYXJlQnlWYWx1ZURlcHRoICsgJyByZWFjaGVkICcgKyBuZXdSZXN1bHQuZGVwdGhSZWFjaGVkQ291bnQgKyAnIHRpbWUocykgZm9yIG5ldyB2YWx1ZSB3aGlsZSBjb21wYXJpbmcgYmluZGluZyBcIicgKyBiaW5kaW5nTmFtZSArICdcIiBmb3IgY29tcG9uZW50IFwiJyArIGNvbXBvbmVudE5hbWUgKyAnLlxcbicsXG4gICAgICAgICdJZiB0aGlzIGltcGFjdHMgcGVyZm9ybWFuY2UsIGNvbnNpZGVyIHNpbXBsaWZ5aW5nIHRoaXMgYmluZGluZywgcmVkdWNpbmcgY29tcGFyaXNvbiBkZXB0aCBvciBzZXR0aW5nIGNvbXBhcmVJbnB1dHNCeVZhbHVlL2NvbXBhcmVPdXRwdXRzQnlWYWx1ZSB0byBmYWxzZS4nLFxuICAgICAgXSwgb3B0aW9ucyk7XG4gICAgfVxuXG4gICAgcmV0dXJuIHRydWU7XG4gIH1cbn1cbiJdfQ==