/** * @license * Copyright Google LLC All Rights Reserved. * * Use of this source code is governed by an MIT-style license that can be * found in the LICENSE file at https://angular.io/license */ import { convertToBitFlags } from '../di/injector_compatibility'; import { EnvironmentInjector } from '../di/r3_injector'; import { RuntimeError } from '../errors'; import { retrieveHydrationInfo } from '../hydration/utils'; import { ComponentFactory as AbstractComponentFactory, ComponentRef as AbstractComponentRef } from '../linker/component_factory'; import { ComponentFactoryResolver as AbstractComponentFactoryResolver } from '../linker/component_factory_resolver'; import { createElementRef } from '../linker/element_ref'; import { RendererFactory2 } from '../render/api'; import { Sanitizer } from '../sanitization/sanitizer'; import { assertDefined, assertGreaterThan, assertIndexInRange } from '../util/assert'; import { VERSION } from '../version'; import { NOT_FOUND_CHECK_ONLY_ELEMENT_INJECTOR } from '../view/provider_flags'; import { AfterRenderEventManager } from './after_render_hooks'; import { assertComponentType } from './assert'; import { attachPatchData } from './context_discovery'; import { getComponentDef } from './definition'; import { getNodeInjectable, NodeInjector } from './di'; import { registerPostOrderHooks } from './hooks'; import { reportUnknownPropertyError } from './instructions/element_validation'; import { markViewDirty } from './instructions/mark_view_dirty'; import { renderView } from './instructions/render'; import { addToViewTree, createLView, createTView, executeContentQueries, getOrCreateComponentTView, getOrCreateTNode, initializeDirectives, invokeDirectivesHostBindings, locateHostElement, markAsComponentHost, setInputsForProperty } from './instructions/shared'; import { CONTEXT, HEADER_OFFSET, INJECTOR, TVIEW } from './interfaces/view'; import { MATH_ML_NAMESPACE, SVG_NAMESPACE } from './namespaces'; import { createElementNode, setupStaticAttributes, writeDirectClass } from './node_manipulation'; import { extractAttrsAndClassesFromSelector, stringifyCSSSelectorList } from './node_selector_matcher'; import { EffectManager } from './reactivity/effect'; import { enterView, getCurrentTNode, getLView, leaveView } from './state'; import { computeStaticStyling } from './styling/static_styling'; import { mergeHostAttrs, setUpAttributes } from './util/attrs_utils'; import { stringifyForError } from './util/stringify_utils'; import { getComponentLViewByIndex, getNativeByTNode, getTNode } from './util/view_utils'; import { RootViewRef } from './view_ref'; export class ComponentFactoryResolver extends AbstractComponentFactoryResolver { /** * @param ngModule The NgModuleRef to which all resolved factories are bound. */ constructor(ngModule) { super(); this.ngModule = ngModule; } resolveComponentFactory(component) { ngDevMode && assertComponentType(component); const componentDef = getComponentDef(component); return new ComponentFactory(componentDef, this.ngModule); } } function toRefArray(map) { const array = []; for (let nonMinified in map) { if (map.hasOwnProperty(nonMinified)) { const minified = map[nonMinified]; array.push({ propName: minified, templateName: nonMinified }); } } return array; } function getNamespace(elementName) { const name = elementName.toLowerCase(); return name === 'svg' ? SVG_NAMESPACE : (name === 'math' ? MATH_ML_NAMESPACE : null); } /** * Injector that looks up a value using a specific injector, before falling back to the module * injector. Used primarily when creating components or embedded views dynamically. */ export class ChainedInjector { constructor(injector, parentInjector) { this.injector = injector; this.parentInjector = parentInjector; } get(token, notFoundValue, flags) { flags = convertToBitFlags(flags); const value = this.injector.get(token, NOT_FOUND_CHECK_ONLY_ELEMENT_INJECTOR, flags); if (value !== NOT_FOUND_CHECK_ONLY_ELEMENT_INJECTOR || notFoundValue === NOT_FOUND_CHECK_ONLY_ELEMENT_INJECTOR) { // Return the value from the root element injector when // - it provides it // (value !== NOT_FOUND_CHECK_ONLY_ELEMENT_INJECTOR) // - the module injector should not be checked // (notFoundValue === NOT_FOUND_CHECK_ONLY_ELEMENT_INJECTOR) return value; } return this.parentInjector.get(token, notFoundValue, flags); } } /** * ComponentFactory interface implementation. */ export class ComponentFactory extends AbstractComponentFactory { get inputs() { const componentDef = this.componentDef; const inputTransforms = componentDef.inputTransforms; const refArray = toRefArray(componentDef.inputs); if (inputTransforms !== null) { for (const input of refArray) { if (inputTransforms.hasOwnProperty(input.propName)) { input.transform = inputTransforms[input.propName]; } } } return refArray; } get outputs() { return toRefArray(this.componentDef.outputs); } /** * @param componentDef The component definition. * @param ngModule The NgModuleRef to which the factory is bound. */ constructor(componentDef, ngModule) { super(); this.componentDef = componentDef; this.ngModule = ngModule; this.componentType = componentDef.type; this.selector = stringifyCSSSelectorList(componentDef.selectors); this.ngContentSelectors = componentDef.ngContentSelectors ? componentDef.ngContentSelectors : []; this.isBoundToModule = !!ngModule; } create(injector, projectableNodes, rootSelectorOrNode, environmentInjector) { environmentInjector = environmentInjector || this.ngModule; let realEnvironmentInjector = environmentInjector instanceof EnvironmentInjector ? environmentInjector : environmentInjector?.injector; if (realEnvironmentInjector && this.componentDef.getStandaloneInjector !== null) { realEnvironmentInjector = this.componentDef.getStandaloneInjector(realEnvironmentInjector) || realEnvironmentInjector; } const rootViewInjector = realEnvironmentInjector ? new ChainedInjector(injector, realEnvironmentInjector) : injector; const rendererFactory = rootViewInjector.get(RendererFactory2, null); if (rendererFactory === null) { throw new RuntimeError(407 /* RuntimeErrorCode.RENDERER_NOT_FOUND */, ngDevMode && 'Angular was not able to inject a renderer (RendererFactory2). ' + 'Likely this is due to a broken DI hierarchy. ' + 'Make sure that any injector used to create this component has a correct parent.'); } const sanitizer = rootViewInjector.get(Sanitizer, null); const effectManager = rootViewInjector.get(EffectManager, null); const afterRenderEventManager = rootViewInjector.get(AfterRenderEventManager, null); const environment = { rendererFactory, sanitizer, effectManager, afterRenderEventManager, }; const hostRenderer = rendererFactory.createRenderer(null, this.componentDef); // Determine a tag name used for creating host elements when this component is created // dynamically. Default to 'div' if this component did not specify any tag name in its selector. const elementName = this.componentDef.selectors[0][0] || 'div'; const hostRNode = rootSelectorOrNode ? locateHostElement(hostRenderer, rootSelectorOrNode, this.componentDef.encapsulation, rootViewInjector) : createElementNode(hostRenderer, elementName, getNamespace(elementName)); // Signal components use the granular "RefreshView" for change detection const signalFlags = (4096 /* LViewFlags.SignalView */ | 512 /* LViewFlags.IsRoot */); // Non-signal components use the traditional "CheckAlways or OnPush/Dirty" change detection const nonSignalFlags = this.componentDef.onPush ? 64 /* LViewFlags.Dirty */ | 512 /* LViewFlags.IsRoot */ : 16 /* LViewFlags.CheckAlways */ | 512 /* LViewFlags.IsRoot */; const rootFlags = this.componentDef.signals ? signalFlags : nonSignalFlags; let hydrationInfo = null; if (hostRNode !== null) { hydrationInfo = retrieveHydrationInfo(hostRNode, rootViewInjector, true /* isRootView */); } // Create the root view. Uses empty TView and ContentTemplate. const rootTView = createTView(0 /* TViewType.Root */, null, null, 1, 0, null, null, null, null, null, null); const rootLView = createLView(null, rootTView, null, rootFlags, null, null, environment, hostRenderer, rootViewInjector, null, hydrationInfo); // rootView is the parent when bootstrapping // TODO(misko): it looks like we are entering view here but we don't really need to as // `renderView` does that. However as the code is written it is needed because // `createRootComponentView` and `createRootComponent` both read global state. Fixing those // issues would allow us to drop this. enterView(rootLView); let component; let tElementNode; try { const rootComponentDef = this.componentDef; let rootDirectives; let hostDirectiveDefs = null; if (rootComponentDef.findHostDirectiveDefs) { rootDirectives = []; hostDirectiveDefs = new Map(); rootComponentDef.findHostDirectiveDefs(rootComponentDef, rootDirectives, hostDirectiveDefs); rootDirectives.push(rootComponentDef); } else { rootDirectives = [rootComponentDef]; } const hostTNode = createRootComponentTNode(rootLView, hostRNode); const componentView = createRootComponentView(hostTNode, hostRNode, rootComponentDef, rootDirectives, rootLView, environment, hostRenderer); tElementNode = getTNode(rootTView, HEADER_OFFSET); // TODO(crisbeto): in practice `hostRNode` should always be defined, but there are some tests // where the renderer is mocked out and `undefined` is returned. We should update the tests so // that this check can be removed. if (hostRNode) { setRootNodeAttributes(hostRenderer, rootComponentDef, hostRNode, rootSelectorOrNode); } if (projectableNodes !== undefined) { projectNodes(tElementNode, this.ngContentSelectors, projectableNodes); } // TODO: should LifecycleHooksFeature and other host features be generated by the compiler and // executed here? // Angular 5 reference: https://stackblitz.com/edit/lifecycle-hooks-vcref component = createRootComponent(componentView, rootComponentDef, rootDirectives, hostDirectiveDefs, rootLView, [LifecycleHooksFeature]); renderView(rootTView, rootLView, null); } finally { leaveView(); } return new ComponentRef(this.componentType, component, createElementRef(tElementNode, rootLView), rootLView, tElementNode); } } /** * Represents an instance of a Component created via a {@link ComponentFactory}. * * `ComponentRef` provides access to the Component Instance as well other objects related to this * Component Instance and allows you to destroy the Component Instance via the {@link #destroy} * method. * */ export class ComponentRef extends AbstractComponentRef { constructor(componentType, instance, location, _rootLView, _tNode) { super(); this.location = location; this._rootLView = _rootLView; this._tNode = _tNode; this.previousInputValues = null; this.instance = instance; this.hostView = this.changeDetectorRef = new RootViewRef(_rootLView); this.componentType = componentType; } setInput(name, value) { const inputData = this._tNode.inputs; let dataValue; if (inputData !== null && (dataValue = inputData[name])) { this.previousInputValues ??= new Map(); // Do not set the input if it is the same as the last value // This behavior matches `bindingUpdated` when binding inputs in templates. if (this.previousInputValues.has(name) && Object.is(this.previousInputValues.get(name), value)) { return; } const lView = this._rootLView; setInputsForProperty(lView[TVIEW], lView, dataValue, name, value); this.previousInputValues.set(name, value); const childComponentLView = getComponentLViewByIndex(this._tNode.index, lView); markViewDirty(childComponentLView); } else { if (ngDevMode) { const cmpNameForError = stringifyForError(this.componentType); let message = `Can't set value of the '${name}' input on the '${cmpNameForError}' component. `; message += `Make sure that the '${name}' property is annotated with @Input() or a mapped @Input('${name}') exists.`; reportUnknownPropertyError(message); } } } get injector() { return new NodeInjector(this._tNode, this._rootLView); } destroy() { this.hostView.destroy(); } onDestroy(callback) { this.hostView.onDestroy(callback); } } /** Creates a TNode that can be used to instantiate a root component. */ function createRootComponentTNode(lView, rNode) { const tView = lView[TVIEW]; const index = HEADER_OFFSET; ngDevMode && assertIndexInRange(lView, index); lView[index] = rNode; // '#host' is added here as we don't know the real host DOM name (we don't want to read it) and at // the same time we want to communicate the debug `TNode` that this is a special `TNode` // representing a host element. return getOrCreateTNode(tView, index, 2 /* TNodeType.Element */, '#host', null); } /** * Creates the root component view and the root component node. * * @param hostRNode Render host element. * @param rootComponentDef ComponentDef * @param rootView The parent view where the host node is stored * @param rendererFactory Factory to be used for creating child renderers. * @param hostRenderer The current renderer * @param sanitizer The sanitizer, if provided * * @returns Component view created */ function createRootComponentView(tNode, hostRNode, rootComponentDef, rootDirectives, rootView, environment, hostRenderer) { const tView = rootView[TVIEW]; applyRootComponentStyling(rootDirectives, tNode, hostRNode, hostRenderer); // Hydration info is on the host element and needs to be retrieved // and passed to the component LView. let hydrationInfo = null; if (hostRNode !== null) { hydrationInfo = retrieveHydrationInfo(hostRNode, rootView[INJECTOR]); } const viewRenderer = environment.rendererFactory.createRenderer(hostRNode, rootComponentDef); let lViewFlags = 16 /* LViewFlags.CheckAlways */; if (rootComponentDef.signals) { lViewFlags = 4096 /* LViewFlags.SignalView */; } else if (rootComponentDef.onPush) { lViewFlags = 64 /* LViewFlags.Dirty */; } const componentView = createLView(rootView, getOrCreateComponentTView(rootComponentDef), null, lViewFlags, rootView[tNode.index], tNode, environment, viewRenderer, null, null, hydrationInfo); if (tView.firstCreatePass) { markAsComponentHost(tView, tNode, rootDirectives.length - 1); } addToViewTree(rootView, componentView); // Store component view at node index, with node as the HOST return rootView[tNode.index] = componentView; } /** Sets up the styling information on a root component. */ function applyRootComponentStyling(rootDirectives, tNode, rNode, hostRenderer) { for (const def of rootDirectives) { tNode.mergedAttrs = mergeHostAttrs(tNode.mergedAttrs, def.hostAttrs); } if (tNode.mergedAttrs !== null) { computeStaticStyling(tNode, tNode.mergedAttrs, true); if (rNode !== null) { setupStaticAttributes(hostRenderer, rNode, tNode); } } } /** * Creates a root component and sets it up with features and host bindings.Shared by * renderComponent() and ViewContainerRef.createComponent(). */ function createRootComponent(componentView, rootComponentDef, rootDirectives, hostDirectiveDefs, rootLView, hostFeatures) { const rootTNode = getCurrentTNode(); ngDevMode && assertDefined(rootTNode, 'tNode should have been already created'); const tView = rootLView[TVIEW]; const native = getNativeByTNode(rootTNode, rootLView); initializeDirectives(tView, rootLView, rootTNode, rootDirectives, null, hostDirectiveDefs); for (let i = 0; i < rootDirectives.length; i++) { const directiveIndex = rootTNode.directiveStart + i; const directiveInstance = getNodeInjectable(rootLView, tView, directiveIndex, rootTNode); attachPatchData(directiveInstance, rootLView); } invokeDirectivesHostBindings(tView, rootLView, rootTNode); if (native) { attachPatchData(native, rootLView); } // We're guaranteed for the `componentOffset` to be positive here // since a root component always matches a component def. ngDevMode && assertGreaterThan(rootTNode.componentOffset, -1, 'componentOffset must be great than -1'); const component = getNodeInjectable(rootLView, tView, rootTNode.directiveStart + rootTNode.componentOffset, rootTNode); componentView[CONTEXT] = rootLView[CONTEXT] = component; if (hostFeatures !== null) { for (const feature of hostFeatures) { feature(component, rootComponentDef); } } // We want to generate an empty QueryList for root content queries for backwards // compatibility with ViewEngine. executeContentQueries(tView, rootTNode, componentView); return component; } /** Sets the static attributes on a root component. */ function setRootNodeAttributes(hostRenderer, componentDef, hostRNode, rootSelectorOrNode) { if (rootSelectorOrNode) { setUpAttributes(hostRenderer, hostRNode, ['ng-version', VERSION.full]); } else { // If host element is created as a part of this function call (i.e. `rootSelectorOrNode` // is not defined), also apply attributes and classes extracted from component selector. // Extract attributes and classes from the first selector only to match VE behavior. const { attrs, classes } = extractAttrsAndClassesFromSelector(componentDef.selectors[0]); if (attrs) { setUpAttributes(hostRenderer, hostRNode, attrs); } if (classes && classes.length > 0) { writeDirectClass(hostRenderer, hostRNode, classes.join(' ')); } } } /** Projects the `projectableNodes` that were specified when creating a root component. */ function projectNodes(tNode, ngContentSelectors, projectableNodes) { const projection = tNode.projection = []; for (let i = 0; i < ngContentSelectors.length; i++) { const nodesforSlot = projectableNodes[i]; // Projectable nodes can be passed as array of arrays or an array of iterables (ngUpgrade // case). Here we do normalize passed data structure to be an array of arrays to avoid // complex checks down the line. // We also normalize the length of the passed in projectable nodes (to match the number of // slots defined by a component). projection.push(nodesforSlot != null ? Array.from(nodesforSlot) : null); } } /** * Used to enable lifecycle hooks on the root component. * * Include this feature when calling `renderComponent` if the root component * you are rendering has lifecycle hooks defined. Otherwise, the hooks won't * be called properly. * * Example: * * ``` * renderComponent(AppComponent, {hostFeatures: [LifecycleHooksFeature]}); * ``` */ export function LifecycleHooksFeature() { const tNode = getCurrentTNode(); ngDevMode && assertDefined(tNode, 'TNode is required'); registerPostOrderHooks(getLView()[TVIEW], tNode); } //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY29tcG9uZW50X3JlZi5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uLy4uLy4uLy4uL3BhY2thZ2VzL2NvcmUvc3JjL3JlbmRlcjMvY29tcG9uZW50X3JlZi50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQTs7Ozs7O0dBTUc7QUFJSCxPQUFPLEVBQUMsaUJBQWlCLEVBQUMsTUFBTSw4QkFBOEIsQ0FBQztBQUcvRCxPQUFPLEVBQUMsbUJBQW1CLEVBQUMsTUFBTSxtQkFBbUIsQ0FBQztBQUN0RCxPQUFPLEVBQUMsWUFBWSxFQUFtQixNQUFNLFdBQVcsQ0FBQztBQUV6RCxPQUFPLEVBQUMscUJBQXFCLEVBQUMsTUFBTSxvQkFBb0IsQ0FBQztBQUV6RCxPQUFPLEVBQUMsZ0JBQWdCLElBQUksd0JBQXdCLEVBQUUsWUFBWSxJQUFJLG9CQUFvQixFQUFDLE1BQU0sNkJBQTZCLENBQUM7QUFDL0gsT0FBTyxFQUFDLHdCQUF3QixJQUFJLGdDQUFnQyxFQUFDLE1BQU0sc0NBQXNDLENBQUM7QUFDbEgsT0FBTyxFQUFDLGdCQUFnQixFQUFhLE1BQU0sdUJBQXVCLENBQUM7QUFFbkUsT0FBTyxFQUFZLGdCQUFnQixFQUFDLE1BQU0sZUFBZSxDQUFDO0FBQzFELE9BQU8sRUFBQyxTQUFTLEVBQUMsTUFBTSwyQkFBMkIsQ0FBQztBQUNwRCxPQUFPLEVBQUMsYUFBYSxFQUFFLGlCQUFpQixFQUFFLGtCQUFrQixFQUFDLE1BQU0sZ0JBQWdCLENBQUM7QUFDcEYsT0FBTyxFQUFDLE9BQU8sRUFBQyxNQUFNLFlBQVksQ0FBQztBQUNuQyxPQUFPLEVBQUMscUNBQXFDLEVBQUMsTUFBTSx3QkFBd0IsQ0FBQztBQUU3RSxPQUFPLEVBQUMsdUJBQXVCLEVBQUMsTUFBTSxzQkFBc0IsQ0FBQztBQUM3RCxPQUFPLEVBQUMsbUJBQW1CLEVBQUMsTUFBTSxVQUFVLENBQUM7QUFDN0MsT0FBTyxFQUFDLGVBQWUsRUFBQyxNQUFNLHFCQUFxQixDQUFDO0FB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ZVxuICogQ29weXJpZ2h0IEdvb2dsZSBMTEMgQWxsIFJpZ2h0cyBSZXNlcnZlZC5cbiAqXG4gKiBVc2Ugb2YgdGhpcyBzb3VyY2UgY29kZSBpcyBnb3Zlcm5lZCBieSBhbiBNSVQtc3R5bGUgbGljZW5zZSB0aGF0IGNhbiBiZVxuICogZm91bmQgaW4gdGhlIExJQ0VOU0UgZmlsZSBhdCBodHRwczovL2FuZ3VsYXIuaW8vbGljZW5zZVxuICovXG5cbmltcG9ydCB7Q2hhbmdlRGV0ZWN0b3JSZWZ9IGZyb20gJy4uL2NoYW5nZV9kZXRlY3Rpb24vY2hhbmdlX2RldGVjdG9yX3JlZic7XG5pbXBvcnQge0luamVjdG9yfSBmcm9tICcuLi9kaS9pbmplY3Rvcic7XG5pbXBvcnQge2NvbnZlcnRUb0JpdEZsYWdzfSBmcm9tICcuLi9kaS9pbmplY3Rvcl9jb21wYXRpYmlsaXR5JztcbmltcG9ydCB7SW5qZWN0RmxhZ3MsIEluamVjdE9wdGlvbnN9IGZyb20gJy4uL2RpL2ludGVyZmFjZS9pbmplY3Rvcic7XG5pbXBvcnQge1Byb3ZpZGVyVG9rZW59IGZyb20gJy4uL2RpL3Byb3ZpZGVyX3Rva2VuJztcbmltcG9ydCB7RW52aXJvbm1lbnRJbmplY3Rvcn0gZnJvbSAnLi4vZGkvcjNfaW5qZWN0b3InO1xuaW1wb3J0IHtSdW50aW1lRXJyb3IsIFJ1bnRpbWVFcnJvckNvZGV9IGZyb20gJy4uL2Vycm9ycyc7XG5pbXBvcnQge0RlaHlkcmF0ZWRWaWV3fSBmcm9tICcuLi9oeWRyYXRpb24vaW50ZXJmYWNlcyc7XG5pbXBvcnQge3JldHJpZXZlSHlkcmF0aW9uSW5mb30gZnJvbSAnLi4vaHlkcmF0aW9uL3V0aWxzJztcbmltcG9ydCB7VHlwZX0gZnJvbSAnLi4vaW50ZXJmYWNlL3R5cGUnO1xuaW1wb3J0IHtDb21wb25lbnRGYWN0b3J5IGFzIEFic3RyYWN0Q29tcG9uZW50RmFjdG9yeSwgQ29tcG9uZW50UmVmIGFzIEFic3RyYWN0Q29tcG9uZW50UmVmfSBmcm9tICcuLi9saW5rZXIvY29tcG9uZW50X2ZhY3RvcnknO1xuaW1wb3J0IHtDb21wb25lbnRGYWN0b3J5UmVzb2x2ZXIgYXMgQWJzdHJhY3RDb21wb25lbnRGYWN0b3J5UmVzb2x2ZXJ9IGZyb20gJy4uL2xpbmtlci9jb21wb25lbnRfZmFjdG9yeV9yZXNvbHZlcic7XG5pbXBvcnQge2NyZWF0ZUVsZW1lbnRSZWYsIEVsZW1lbnRSZWZ9IGZyb20gJy4uL2xpbmtlci9lbGVtZW50X3JlZic7XG5pbXBvcnQge05nTW9kdWxlUmVmfSBmcm9tICcuLi9saW5rZXIvbmdfbW9kdWxlX2ZhY3RvcnknO1xuaW1wb3J0IHtSZW5kZXJlcjIsIFJlbmRlcmVyRmFjdG9yeTJ9IGZyb20gJy4uL3JlbmRlci9hcGknO1xuaW1wb3J0IHtTYW5pdGl6ZXJ9IGZyb20gJy4uL3Nhbml0aXphdGlvbi9zYW5pdGl6ZXInO1xuaW1wb3J0IHthc3NlcnREZWZpbmVkLCBhc3NlcnRHcmVhdGVyVGhhbiwgYXNzZXJ0SW5kZXhJblJhbmdlfSBmcm9tICcuLi91dGlsL2Fzc2VydCc7XG5pbXBvcnQge1ZFUlNJT059IGZyb20gJy4uL3ZlcnNpb24nO1xuaW1wb3J0IHtOT1RfRk9VTkRfQ0hFQ0tfT05MWV9FTEVNRU5UX0lOSkVDVE9SfSBmcm9tICcuLi92aWV3L3Byb3ZpZGVyX2ZsYWdzJztcblxuaW1wb3J0IHtBZnRlclJlbmRlckV2ZW50TWFuYWdlcn0gZnJvbSAnLi9hZnRlcl9yZW5kZXJfaG9va3MnO1xuaW1wb3J0IHthc3NlcnRDb21wb25lbnRUeXBlfSBmcm9tICcuL2Fzc2VydCc7XG5pbXBvcnQge2F0dGFjaFBhdGNoRGF0YX0gZnJvbSAnLi9jb250ZXh0X2Rpc2NvdmVyeSc7XG5pbXBvcnQge2dldENvbXBvbmVudERlZn0gZnJvbSAnLi9kZWZpbml0aW9uJztcbmltcG9ydCB7Z2V0Tm9kZUluamVjdGFibGUsIE5vZGVJbmplY3Rvcn0gZnJvbSAnLi9kaSc7XG5pbXBvcnQge3JlZ2lzdGVyUG9zdE9yZGVySG9va3N9IGZyb20gJy4vaG9va3MnO1xuaW1wb3J0IHtyZXBvcnRVbmtub3duUHJvcGVydHlFcnJvcn0gZnJvbSAnLi9pbnN0cnVjdGlvbnMvZWxlbWVudF92YWxpZGF0aW9uJztcbmltcG9ydCB7bWFya1ZpZXdEaXJ0eX0gZnJvbSAnLi9pbnN0cnVjdGlvbnMvbWFya192aWV3X2RpcnR5JztcbmltcG9ydCB7cmVuZGVyVmlld30gZnJvbSAnLi9pbnN0cnVjdGlvbnMvcmVuZGVyJztcbmltcG9ydCB7YWRkVG9WaWV3VHJlZSwgY3JlYXRlTFZpZXcsIGNyZWF0ZVRWaWV3LCBleGVjdXRlQ29udGVudFF1ZXJpZXMsIGdldE9yQ3JlYXRlQ29tcG9uZW50VFZpZXcsIGdldE9yQ3JlYXRlVE5vZGUsIGluaXRpYWxpemVEaXJlY3RpdmVzLCBpbnZva2VEaXJlY3RpdmVzSG9zdEJpbmRpbmdzLCBsb2NhdGVIb3N0RWxlbWVudCwgbWFya0FzQ29tcG9uZW50SG9zdCwgc2V0SW5wdXRzRm9yUHJvcGVydHl9IGZyb20gJy4vaW5zdHJ1Y3Rpb25zL3NoYXJlZCc7XG5pbXBvcnQge0NvbXBvbmVudERlZiwgRGlyZWN0aXZlRGVmLCBIb3N0RGlyZWN0aXZlRGVmc30gZnJvbSAnLi9pbnRlcmZhY2VzL2RlZmluaXRpb24nO1xuaW1wb3J0IHtQcm9wZXJ0eUFsaWFzVmFsdWUsIFRDb250YWluZXJOb2RlLCBURWxlbWVudENvbnRhaW5lck5vZGUsIFRFbGVtZW50Tm9kZSwgVE5vZGUsIFROb2RlVHlwZX0gZnJvbSAnLi9pbnRlcmZhY2VzL25vZGUnO1xuaW1wb3J0IHtSZW5kZXJlcn0gZnJvbSAnLi9pbnRlcmZhY2VzL3JlbmRlcmVyJztcbmltcG9ydCB7UkVsZW1lbnQsIFJOb2RlfSBmcm9tICcuL2ludGVyZmFjZXMvcmVuZGVyZXJfZG9tJztcbmltcG9ydCB7Q09OVEVYVCwgSEVBREVSX09GRlNFVCwgSU5KRUNUT1IsIExWaWV3LCBMVmlld0Vudmlyb25tZW50LCBMVmlld0ZsYWdzLCBUVklFVywgVFZpZXdUeXBlfSBmcm9tICcuL2ludGVyZmFjZXMvdmlldyc7XG5pbXBvcnQge01BVEhfTUxfTkFNRVNQQUNFLCBTVkdfTkFNRVNQQUNFfSBmcm9tICcuL25hbWVzcGFjZXMnO1xuaW1wb3J0IHtjcmVhdGVFbGVtZW50Tm9kZSwgc2V0dXBTdGF0aWNBdHRyaWJ1dGVzLCB3cml0ZURpcmVjdENsYXNzfSBmcm9tICcuL25vZGVfbWFuaXB1bGF0aW9uJztcbmltcG9ydCB7ZXh0cmFjdEF0dHJzQW5kQ2xhc3Nlc0Zyb21TZWxlY3Rvciwgc3RyaW5naWZ5Q1NTU2VsZWN0b3JMaXN0fSBmcm9tICcuL25vZGVfc2VsZWN0b3JfbWF0Y2hlcic7XG5pbXBvcnQge0VmZmVjdE1hbmFnZXJ9IGZyb20gJy4vcmVhY3Rpdml0eS9lZmZlY3QnO1xuaW1wb3J0IHtlbnRlclZpZXcsIGdldEN1cnJlbnRUTm9kZSwgZ2V0TFZpZXcsIGxlYXZlVmlld30gZnJvbSAnLi9zdGF0ZSc7XG5pbXBvcnQge2NvbXB1dGVTdGF0aWNTdHlsaW5nfSBmcm9tICcuL3N0eWxpbmcvc3RhdGljX3N0eWxpbmcnO1xuaW1wb3J0IHttZXJnZUhvc3RBdHRycywgc2V0VXBBdHRyaWJ1dGVzfSBmcm9tICcuL3V0aWwvYXR0cnNfdXRpbHMnO1xuaW1wb3J0IHtzdHJpbmdpZnlGb3JFcnJvcn0gZnJvbSAnLi91dGlsL3N0cmluZ2lmeV91dGlscyc7XG5pbXBvcnQge2dldENvbXBvbmVudExWaWV3QnlJbmRleCwgZ2V0TmF0aXZlQnlUTm9kZSwgZ2V0VE5vZGV9IGZyb20gJy4vdXRpbC92aWV3X3V0aWxzJztcbmltcG9ydCB7Um9vdFZpZXdSZWYsIFZpZXdSZWZ9IGZyb20gJy4vdmlld19yZWYnO1xuXG5leHBvcnQgY2xhc3MgQ29tcG9uZW50RmFjdG9yeVJlc29sdmVyIGV4dGVuZHMgQWJzdHJhY3RDb21wb25lbnRGYWN0b3J5UmVzb2x2ZXIge1xuICAvKipcbiAgICogQHBhcmFtIG5nTW9kdWxlIFRoZSBOZ01vZHVsZVJlZiB0byB3aGljaCBhbGwgcmVzb2x2ZWQgZmFjdG9yaWVzIGFyZSBib3VuZC5cbiAgICovXG4gIGNvbnN0cnVjdG9yKHByaXZhdGUgbmdNb2R1bGU/OiBOZ01vZHVsZVJlZjxhbnk+KSB7XG4gICAgc3VwZXIoKTtcbiAgfVxuXG4gIG92ZXJyaWRlIHJlc29sdmVDb21wb25lbnRGYWN0b3J5PFQ+KGNvbXBvbmVudDogVHlwZTxUPik6IEFic3RyYWN0Q29tcG9uZW50RmFjdG9yeTxUPiB7XG4gICAgbmdEZXZNb2RlICYmIGFzc2VydENvbXBvbmVudFR5cGUoY29tcG9uZW50KTtcbiAgICBjb25zdCBjb21wb25lbnREZWYgPSBnZXRDb21wb25lbnREZWYoY29tcG9uZW50KSE7XG4gICAgcmV0dXJuIG5ldyBDb21wb25lbnRGYWN0b3J5KGNvbXBvbmVudERlZiwgdGhpcy5uZ01vZHVsZSk7XG4gIH1cbn1cblxuZnVuY3Rpb24gdG9SZWZBcnJheShtYXA6IHtba2V5OiBzdHJpbmddOiBzdHJpbmd9KToge3Byb3BOYW1lOiBzdHJpbmc7IHRlbXBsYXRlTmFtZTogc3RyaW5nO31bXSB7XG4gIGNvbnN0IGFycmF5OiB7cHJvcE5hbWU6IHN0cmluZzsgdGVtcGxhdGVOYW1lOiBzdHJpbmc7fVtdID0gW107XG4gIGZvciAobGV0IG5vbk1pbmlmaWVkIGluIG1hcCkge1xuICAgIGlmIChtYXAuaGFzT3duUHJvcGVydHkobm9uTWluaWZpZWQpKSB7XG4gICAgICBjb25zdCBtaW5pZmllZCA9IG1hcFtub25NaW5pZmllZF07XG4gICAgICBhcnJheS5wdXNoKHtwcm9wTmFtZTogbWluaWZpZWQsIHRlbXBsYXRlTmFtZTogbm9uTWluaWZpZWR9KTtcbiAgICB9XG4gIH1cbiAgcmV0dXJuIGFycmF5O1xufVxuXG5mdW5jdGlvbiBnZXROYW1lc3BhY2UoZWxlbWVudE5hbWU6IHN0cmluZyk6IHN0cmluZ3xudWxsIHtcbiAgY29uc3QgbmFtZSA9IGVsZW1lbnROYW1lLnRvTG93ZXJDYXNlKCk7XG4gIHJldHVybiBuYW1lID09PSAnc3ZnJyA/IFNWR19OQU1FU1BBQ0UgOiAobmFtZSA9PT0gJ21hdGgnID8gTUFUSF9NTF9OQU1FU1BBQ0UgOiBudWxsKTtcbn1cblxuLyoqXG4gKiBJbmplY3RvciB0aGF0IGxvb2tzIHVwIGEgdmFsdWUgdXNpbmcgYSBzcGVjaWZpYyBpbmplY3RvciwgYmVmb3JlIGZhbGxpbmcgYmFjayB0byB0aGUgbW9kdWxlXG4gKiBpbmplY3Rvci4gVXNlZCBwcmltYXJpbHkgd2hlbiBjcmVhdGluZyBjb21wb25lbnRzIG9yIGVtYmVkZGVkIHZpZXdzIGR5bmFtaWNhbGx5LlxuICovXG5leHBvcnQgY2xhc3MgQ2hhaW5lZEluamVjdG9yIGltcGxlbWVudHMgSW5qZWN0b3Ige1xuICBjb25zdHJ1Y3RvcihwdWJsaWMgaW5qZWN0b3I6IEluamVjdG9yLCBwdWJsaWMgcGFyZW50SW5qZWN0b3I6IEluamVjdG9yKSB7fVxuXG4gIGdldDxUPih0b2tlbjogUHJvdmlkZXJUb2tlbjxUPiwgbm90Rm91bmRWYWx1ZT86IFQsIGZsYWdzPzogSW5qZWN0RmxhZ3N8SW5qZWN0T3B0aW9ucyk6IFQge1xuICAgIGZsYWdzID0gY29udmVydFRvQml0RmxhZ3MoZmxhZ3MpO1xuICAgIGNvbnN0IHZhbHVlID0gdGhpcy5pbmplY3Rvci5nZXQ8VHx0eXBlb2YgTk9UX0ZPVU5EX0NIRUNLX09OTFlfRUxFTUVOVF9JTkpFQ1RPUj4oXG4gICAgICAgIHRva2VuLCBOT1RfRk9VTkRfQ0hFQ0tfT05MWV9FTEVNRU5UX0lOSkVDVE9SLCBmbGFncyk7XG5cbiAgICBpZiAodmFsdWUgIT09IE5PVF9GT1VORF9DSEVDS19PTkxZX0VMRU1FTlRfSU5KRUNUT1IgfHxcbiAgICAgICAgbm90Rm91bmRWYWx1ZSA9PT0gKE5PVF9GT1VORF9DSEVDS19PTkxZX0VMRU1FTlRfSU5KRUNUT1IgYXMgdW5rbm93biBhcyBUKSkge1xuICAgICAgLy8gUmV0dXJuIHRoZSB2YWx1ZSBmcm9tIHRoZSByb290IGVsZW1lbnQgaW5qZWN0b3Igd2hlblxuICAgICAgLy8gLSBpdCBwcm92aWRlcyBpdFxuICAgICAgLy8gICAodmFsdWUgIT09IE5PVF9GT1VORF9DSEVDS19PTkxZX0VMRU1FTlRfSU5KRUNUT1IpXG4gICAgICAvLyAtIHRoZSBtb2R1bGUgaW5qZWN0b3Igc2hvdWxkIG5vdCBiZSBjaGVja2VkXG4gICAgICAvLyAgIChub3RGb3VuZFZhbHVlID09PSBOT1RfRk9VTkRfQ0hFQ0tfT05MWV9FTEVNRU5UX0lOSkVDVE9SKVxuICAgICAgcmV0dXJuIHZhbHVlIGFzIFQ7XG4gICAgfVxuXG4gICAgcmV0dXJuIHRoaXMucGFyZW50SW5qZWN0b3IuZ2V0KHRva2VuLCBub3RGb3VuZFZhbHVlLCBmbGFncyk7XG4gIH1cbn1cblxuLyoqXG4gKiBDb21wb25lbnRGYWN0b3J5IGludGVyZmFjZSBpbXBsZW1lbnRhdGlvbi5cbiAqL1xuZXhwb3J0IGNsYXNzIENvbXBvbmVudEZhY3Rvcnk8VD4gZXh0ZW5kcyBBYnN0cmFjdENvbXBvbmVudEZhY3Rvcnk8VD4ge1xuICBvdmVycmlkZSBzZWxlY3Rvcjogc3RyaW5nO1xuICBvdmVycmlkZSBjb21wb25lbnRUeXBlOiBUeXBlPGFueT47XG4gIG92ZXJyaWRlIG5nQ29udGVudFNlbGVjdG9yczogc3RyaW5nW107XG4gIGlzQm91bmRUb01vZHVsZTogYm9vbGVhbjtcblxuICBvdmVycmlkZSBnZXQgaW5wdXRzKCk6IHtcbiAgICBwcm9wTmFtZTogc3RyaW5nLFxuICAgIHRlbXBsYXRlTmFtZTogc3RyaW5nLFxuICAgIHRyYW5zZm9ybT86ICh2YWx1ZTogYW55KSA9PiBhbnksXG4gIH1bXSB7XG4gICAgY29uc3QgY29tcG9uZW50RGVmID0gdGhpcy5jb21wb25lbnREZWY7XG4gICAgY29uc3QgaW5wdXRUcmFuc2Zvcm1zID0gY29tcG9uZW50RGVmLmlucHV0VHJhbnNmb3JtcztcbiAgICBjb25zdCByZWZBcnJheSA9IHRvUmVmQXJyYXkoY29tcG9uZW50RGVmLmlucHV0cykgYXMge1xuICAgICAgcHJvcE5hbWU6IHN0cmluZyxcbiAgICAgIHRlbXBsYXRlTmFtZTogc3RyaW5nLFxuICAgICAgdHJhbnNmb3JtPzogKHZhbHVlOiBhbnkpID0+IGFueSxcbiAgICB9W107XG5cbiAgICBpZiAoaW5wdXRUcmFuc2Zvcm1zICE9PSBudWxsKSB7XG4gICAgICBmb3IgKGNvbnN0IGlucHV0IG9mIHJlZkFycmF5KSB7XG4gICAgICAgIGlmIChpbnB1dFRyYW5zZm9ybXMuaGFzT3duUHJvcGVydHkoaW5wdXQucHJvcE5hbWUpKSB7XG4gICAgICAgICAgaW5wdXQudHJhbnNmb3JtID0gaW5wdXRUcmFuc2Zvcm1zW2lucHV0LnByb3BOYW1lXTtcbiAgICAgICAgfVxuICAgICAgfVxuICAgIH1cblxuICAgIHJldHVybiByZWZBcnJheTtcbiAgfVxuXG4gIG92ZXJyaWRlIGdldCBvdXRwdXRzKCk6IHtwcm9wTmFtZTogc3RyaW5nOyB0ZW1wbGF0ZU5hbWU6IHN0cmluZzt9W10ge1xuICAgIHJldHVybiB0b1JlZkFycmF5KHRoaXMuY29tcG9uZW50RGVmLm91dHB1dHMpO1xuICB9XG5cbiAgLyoqXG4gICAqIEBwYXJhbSBjb21wb25lbnREZWYgVGhlIGNvbXBvbmVudCBkZWZpbml0aW9uLlxuICAgKiBAcGFyYW0gbmdNb2R1bGUgVGhlIE5nTW9kdWxlUmVmIHRvIHdoaWNoIHRoZSBmYWN0b3J5IGlzIGJvdW5kLlxuICAgKi9cbiAgY29uc3RydWN0b3IocHJpdmF0ZSBjb21wb25lbnREZWY6IENvbXBvbmVudERlZjxhbnk+LCBwcml2YXRlIG5nTW9kdWxlPzogTmdNb2R1bGVSZWY8YW55Pikge1xuICAgIHN1cGVyKCk7XG4gICAgdGhpcy5jb21wb25lbnRUeXBlID0gY29tcG9uZW50RGVmLnR5cGU7XG4gICAgdGhpcy5zZWxlY3RvciA9IHN0cmluZ2lmeUNTU1NlbGVjdG9yTGlzdChjb21wb25lbnREZWYuc2VsZWN0b3JzKTtcbiAgICB0aGlzLm5nQ29udGVudFNlbGVjdG9ycyA9XG4gICAgICAgIGNvbXBvbmVudERlZi5uZ0NvbnRlbnRTZWxlY3RvcnMgPyBjb21wb25lbnREZWYubmdDb250ZW50U2VsZWN0b3JzIDogW107XG4gICAgdGhpcy5pc0JvdW5kVG9Nb2R1bGUgPSAhIW5nTW9kdWxlO1xuICB9XG5cbiAgb3ZlcnJpZGUgY3JlYXRlKFxuICAgICAgaW5qZWN0b3I6IEluamVjdG9yLCBwcm9qZWN0YWJsZU5vZGVzPzogYW55W11bXXx1bmRlZmluZWQsIHJvb3RTZWxlY3Rvck9yTm9kZT86IGFueSxcbiAgICAgIGVudmlyb25tZW50SW5qZWN0b3I/OiBOZ01vZHVsZVJlZjxhbnk+fEVudmlyb25tZW50SW5qZWN0b3J8XG4gICAgICB1bmRlZmluZWQpOiBBYnN0cmFjdENvbXBvbmVudFJlZjxUPiB7XG4gICAgZW52aXJvbm1lbnRJbmplY3RvciA9IGVudmlyb25tZW50SW5qZWN0b3IgfHwgdGhpcy5uZ01vZHVsZTtcblxuICAgIGxldCByZWFsRW52aXJvbm1lbnRJbmplY3RvciA9IGVudmlyb25tZW50SW5qZWN0b3IgaW5zdGFuY2VvZiBFbnZpcm9ubWVudEluamVjdG9yID9cbiAgICAgICAgZW52aXJvbm1lbnRJbmplY3RvciA6XG4gICAgICAgIGVudmlyb25tZW50SW5qZWN0b3I/LmluamVjdG9yO1xuXG4gICAgaWYgKHJlYWxFbnZpcm9ubWVudEluamVjdG9yICYmIHRoaXMuY29tcG9uZW50RGVmLmdldFN0YW5kYWxvbmVJbmplY3RvciAhPT0gbnVsbCkge1xuICAgICAgcmVhbEVudmlyb25tZW50SW5qZWN0b3IgPSB0aGlzLmNvbXBvbmVudERlZi5nZXRTdGFuZGFsb25lSW5qZWN0b3IocmVhbEVudmlyb25tZW50SW5qZWN0b3IpIHx8XG4gICAgICAgICAgcmVhbEVudmlyb25tZW50SW5qZWN0b3I7XG4gICAgfVxuXG4gICAgY29uc3Qgcm9vdFZpZXdJbmplY3RvciA9XG4gICAgICAgIHJlYWxFbnZpcm9ubWVudEluamVjdG9yID8gbmV3IENoYWluZWRJbmplY3RvcihpbmplY3RvciwgcmVhbEVudmlyb25tZW50SW5qZWN0b3IpIDogaW5qZWN0b3I7XG5cbiAgICBjb25zdCByZW5kZXJlckZhY3RvcnkgPSByb290Vmlld0luamVjdG9yLmdldChSZW5kZXJlckZhY3RvcnkyLCBudWxsKTtcbiAgICBpZiAocmVuZGVyZXJGYWN0b3J5ID09PSBudWxsKSB7XG4gICAgICB0aHJvdyBuZXcgUnVudGltZUVycm9yKFxuICAgICAgICAgIFJ1bnRpbWVFcnJvckNvZGUuUkVOREVSRVJfTk9UX0ZPVU5ELFxuICAgICAgICAgIG5nRGV2TW9kZSAmJlxuICAgICAgICAgICAgICAnQW5ndWxhciB3YXMgbm90IGFibGUgdG8gaW5qZWN0IGEgcmVuZGVyZXIgKFJlbmRlcmVyRmFjdG9yeTIpLiAnICtcbiAgICAgICAgICAgICAgICAgICdMaWtlbHkgdGhpcyBpcyBkdWUgdG8gYSBicm9rZW4gREkgaGllcmFyY2h5LiAnICtcbiAgICAgICAgICAgICAgICAgICdNYWtlIHN1cmUgdGhhdCBhbnkgaW5qZWN0b3IgdXNlZCB0byBjcmVhdGUgdGhpcyBjb21wb25lbnQgaGFzIGEgY29ycmVjdCBwYXJlbnQuJyk7XG4gICAgfVxuICAgIGNvbnN0IHNhbml0aXplciA9IHJvb3RWaWV3SW5qZWN0b3IuZ2V0KFNhbml0aXplciwgbnVsbCk7XG5cbiAgICBjb25zdCBlZmZlY3RNYW5hZ2VyID0gcm9vdFZpZXdJbmplY3Rvci5nZXQoRWZmZWN0TWFuYWdlciwgbnVsbCk7XG5cbiAgICBjb25zdCBhZnRlclJlbmRlckV2ZW50TWFuYWdlciA9IHJvb3RWaWV3SW5qZWN0b3IuZ2V0KEFmdGVyUmVuZGVyRXZlbnRNYW5hZ2VyLCBudWxsKTtcblxuICAgIGNvbnN0IGVudmlyb25tZW50OiBMVmlld0Vudmlyb25tZW50ID0ge1xuICAgICAgcmVuZGVyZXJGYWN0b3J5LFxuICAgICAgc2FuaXRpemVyLFxuICAgICAgZWZmZWN0TWFuYWdlcixcbiAgICAgIGFmdGVyUmVuZGVyRXZlbnRNYW5hZ2VyLFxuICAgIH07XG5cbiAgICBjb25zdCBob3N0UmVuZGVyZXIgPSByZW5kZXJlckZhY3RvcnkuY3JlYXRlUmVuZGVyZXIobnVsbCwgdGhpcy5jb21wb25lbnREZWYpO1xuICAgIC8vIERldGVybWluZSBhIHRhZyBuYW1lIHVzZWQgZm9yIGNyZWF0aW5nIGhvc3QgZWxlbWVudHMgd2hlbiB0aGlzIGNvbXBvbmVudCBpcyBjcmVhdGVkXG4gICAgLy8gZHluYW1pY2FsbHkuIERlZmF1bHQgdG8gJ2RpdicgaWYgdGhpcyBjb21wb25lbnQgZGlkIG5vdCBzcGVjaWZ5IGFueSB0YWcgbmFtZSBpbiBpdHMgc2VsZWN0b3IuXG4gICAgY29uc3QgZWxlbWVudE5hbWUgPSB0aGlzLmNvbXBvbmVudERlZi5zZWxlY3RvcnNbMF1bMF0gYXMgc3RyaW5nIHx8ICdkaXYnO1xuICAgIGNvbnN0IGhvc3RSTm9kZSA9IHJvb3RTZWxlY3Rvck9yTm9kZSA/XG4gICAgICAgIGxvY2F0ZUhvc3RFbGVtZW50KFxuICAgICAgICAgICAgaG9zdFJlbmRlcmVyLCByb290U2VsZWN0b3JPck5vZGUsIHRoaXMuY29tcG9uZW50RGVmLmVuY2Fwc3VsYXRpb24sIHJvb3RWaWV3SW5qZWN0b3IpIDpcbiAgICAgICAgY3JlYXRlRWxlbWVudE5vZGUoaG9zdFJlbmRlcmVyLCBlbGVtZW50TmFtZSwgZ2V0TmFtZXNwYWNlKGVsZW1lbnROYW1lKSk7XG5cbiAgICAvLyBTaWduYWwgY29tcG9uZW50cyB1c2UgdGhlIGdyYW51bGFyIFwiUmVmcmVzaFZpZXdcIiAgZm9yIGNoYW5nZSBkZXRlY3Rpb25cbiAgICBjb25zdCBzaWduYWxGbGFncyA9IChMVmlld0ZsYWdzLlNpZ25hbFZpZXcgfCBMVmlld0ZsYWdzLklzUm9vdCk7XG4gICAgLy8gTm9uLXNpZ25hbCBjb21wb25lbnRzIHVzZSB0aGUgdHJhZGl0aW9uYWwgXCJDaGVja0Fsd2F5cyBvciBPblB1c2gvRGlydHlcIiBjaGFuZ2UgZGV0ZWN0aW9uXG4gICAgY29uc3Qgbm9uU2lnbmFsRmxhZ3MgPSB0aGlzLmNvbXBvbmVudERlZi5vblB1c2ggPyBMVmlld0ZsYWdzLkRpcnR5IHwgTFZpZXdGbGFncy5Jc1Jvb3QgOlxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgTFZpZXdGbGFncy5DaGVja0Fsd2F5cyB8IExWaWV3RmxhZ3MuSXNSb290O1xuICAgIGNvbnN0IHJvb3RGbGFncyA9IHRoaXMuY29tcG9uZW50RGVmLnNpZ25hbHMgPyBzaWduYWxGbGFncyA6IG5vblNpZ25hbEZsYWdzO1xuXG4gICAgbGV0IGh5ZHJhdGlvbkluZm86IERlaHlkcmF0ZWRWaWV3fG51bGwgPSBudWxsO1xuICAgIGlmIChob3N0Uk5vZGUgIT09IG51bGwpIHtcbiAgICAgIGh5ZHJhdGlvbkluZm8gPSByZXRyaWV2ZUh5ZHJhdGlvbkluZm8oaG9zdFJOb2RlLCByb290Vmlld0luamVjdG9yLCB0cnVlIC8qIGlzUm9vdFZpZXcgKi8pO1xuICAgIH1cblxuICAgIC8vIENyZWF0ZSB0aGUgcm9vdCB2aWV3LiBVc2VzIGVtcHR5IFRWaWV3IGFuZCBDb250ZW50VGVtcGxhdGUuXG4gICAgY29uc3Qgcm9vdFRWaWV3ID1cbiAgICAgICAgY3JlYXRlVFZpZXcoVFZpZXdUeXBlLlJvb3QsIG51bGwsIG51bGwsIDEsIDAsIG51bGwsIG51bGwsIG51bGwsIG51bGwsIG51bGwsIG51bGwpO1xuICAgIGNvbnN0IHJvb3RMVmlldyA9IGNyZWF0ZUxWaWV3KFxuICAgICAgICBudWxsLCByb290VFZpZXcsIG51bGwsIHJvb3RGbGFncywgbnVsbCwgbnVsbCwgZW52aXJvbm1lbnQsIGhvc3RSZW5kZXJlciwgcm9vdFZpZXdJbmplY3RvcixcbiAgICAgICAgbnVsbCwgaHlkcmF0aW9uSW5mbyk7XG5cbiAgICAvLyByb290VmlldyBpcyB0aGUgcGFyZW50IHdoZW4gYm9vdHN0cmFwcGluZ1xuICAgIC8vIFRPRE8obWlza28pOiBpdCBsb29rcyBsaWtlIHdlIGFyZSBlbnRlcmluZyB2aWV3IGhlcmUgYnV0IHdlIGRvbid0IHJlYWxseSBuZWVkIHRvIGFzXG4gICAgLy8gYHJlbmRlclZpZXdgIGRvZXMgdGhhdC4gSG93ZXZlciBhcyB0aGUgY29kZSBpcyB3cml0dGVuIGl0IGlzIG5lZWRlZCBiZWNhdXNlXG4gICAgLy8gYGNyZWF0ZVJvb3RDb21wb25lbnRWaWV3YCBhbmQgYGNyZWF0ZVJvb3RDb21wb25lbnRgIGJvdGggcmVhZCBnbG9iYWwgc3RhdGUuIEZpeGluZyB0aG9zZVxuICAgIC8vIGlzc3VlcyB3b3VsZCBhbGxvdyB1cyB0byBkcm9wIHRoaXMuXG4gICAgZW50ZXJWaWV3KHJvb3RMVmlldyk7XG5cbiAgICBsZXQgY29tcG9uZW50OiBUO1xuICAgIGxldCB0RWxlbWVudE5vZGU6IFRFbGVtZW50Tm9kZTtcblxuICAgIHRyeSB7XG4gICAgICBjb25zdCByb290Q29tcG9uZW50RGVmID0gdGhpcy5jb21wb25lbnREZWY7XG4gICAgICBsZXQgcm9vdERpcmVjdGl2ZXM6IERpcmVjdGl2ZURlZjx1bmtub3duPltdO1xuICAgICAgbGV0IGhvc3REaXJlY3RpdmVEZWZzOiBIb3N0RGlyZWN0aXZlRGVmc3xudWxsID0gbnVsbDtcblxuICAgICAgaWYgKHJvb3RDb21wb25lbnREZWYuZmluZEhvc3REaXJlY3RpdmVEZWZzKSB7XG4gICAgICAgIHJvb3REaXJlY3RpdmVzID0gW107XG4gICAgICAgIGhvc3REaXJlY3RpdmVEZWZzID0gbmV3IE1hcCgpO1xuICAgICAgICByb290Q29tcG9uZW50RGVmLmZpbmRIb3N0RGlyZWN0aXZlRGVmcyhyb290Q29tcG9uZW50RGVmLCByb290RGlyZWN0aXZlcywgaG9zdERpcmVjdGl2ZURlZnMpO1xuICAgICAgICByb290RGlyZWN0aXZlcy5wdXNoKHJvb3RDb21wb25lbnREZWYpO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgcm9vdERpcmVjdGl2ZXMgPSBbcm9vdENvbXBvbmVudERlZl07XG4gICAgICB9XG5cbiAgICAgIGNvbnN0IGhvc3RUTm9kZSA9IGNyZWF0ZVJvb3RDb21wb25lbnRUTm9kZShyb290TFZpZXcsIGhvc3RSTm9kZSk7XG4gICAgICBjb25zdCBjb21wb25lbnRWaWV3ID0gY3JlYXRlUm9vdENvbXBvbmVudFZpZXcoXG4gICAgICAgICAgaG9zdFROb2RlLCBob3N0Uk5vZGUsIHJvb3RDb21wb25lbnREZWYsIHJvb3REaXJlY3RpdmVzLCByb290TFZpZXcsIGVudmlyb25tZW50LFxuICAgICAgICAgIGhvc3RSZW5kZXJlcik7XG5cbiAgICAgIHRFbGVtZW50Tm9kZSA9IGdldFROb2RlKHJvb3RUVmlldywgSEVBREVSX09GRlNFVCkgYXMgVEVsZW1lbnROb2RlO1xuXG4gICAgICAvLyBUT0RPKGNyaXNiZXRvKTogaW4gcHJhY3RpY2UgYGhvc3RSTm9kZWAgc2hvdWxkIGFsd2F5cyBiZSBkZWZpbmVkLCBidXQgdGhlcmUgYXJlIHNvbWUgdGVzdHNcbiAgICAgIC8vIHdoZXJlIHRoZSByZW5kZXJlciBpcyBtb2NrZWQgb3V0IGFuZCBgdW5kZWZpbmVkYCBpcyByZXR1cm5lZC4gV2Ugc2hvdWxkIHVwZGF0ZSB0aGUgdGVzdHMgc29cbiAgICAgIC8vIHRoYXQgdGhpcyBjaGVjayBjYW4gYmUgcmVtb3ZlZC5cbiAgICAgIGlmIChob3N0Uk5vZGUpIHtcbiAgICAgICAgc2V0Um9vdE5vZGVBdHRyaWJ1dGVzKGhvc3RSZW5kZXJlciwgcm9vdENvbXBvbmVudERlZiwgaG9zdFJOb2RlLCByb290U2VsZWN0b3JPck5vZGUpO1xuICAgICAgfVxuXG4gICAgICBpZiAocHJvamVjdGFibGVOb2RlcyAhPT0gdW5kZWZpbmVkKSB7XG4gICAgICAgIHByb2plY3ROb2Rlcyh0RWxlbWVudE5vZGUsIHRoaXMubmdDb250ZW50U2VsZWN0b3JzLCBwcm9qZWN0YWJsZU5vZGVzKTtcbiAgICAgIH1cblxuICAgICAgLy8gVE9ETzogc2hvdWxkIExpZmVjeWNsZUhvb2tzRmVhdHVyZSBhbmQgb3RoZXIgaG9zdCBmZWF0dXJlcyBiZSBnZW5lcmF0ZWQgYnkgdGhlIGNvbXBpbGVyIGFuZFxuICAgICAgLy8gZXhlY3V0ZWQgaGVyZT9cbiAgICAgIC8vIEFuZ3VsYXIgNSByZWZlcmVuY2U6IGh0dHBzOi8vc3RhY2tibGl0ei5jb20vZWRpdC9saWZlY3ljbGUtaG9va3MtdmNyZWZcbiAgICAgIGNvbXBvbmVudCA9IGNyZWF0ZVJvb3RDb21wb25lbnQoXG4gICAgICAgICAgY29tcG9uZW50Vmlldywgcm9vdENvbXBvbmVudERlZiwgcm9vdERpcmVjdGl2ZXMsIGhvc3REaXJlY3RpdmVEZWZzLCByb290TFZpZXcsXG4gICAgICAgICAgW0xpZmVjeWNsZUhvb2tzRmVhdHVyZV0pO1xuICAgICAgcmVuZGVyVmlldyhyb290VFZpZXcsIHJvb3RMVmlldywgbnVsbCk7XG4gICAgfSBmaW5hbGx5IHtcbiAgICAgIGxlYXZlVmlldygpO1xuICAgIH1cblxuICAgIHJldHVybiBuZXcgQ29tcG9uZW50UmVmKFxuICAgICAgICB0aGlzLmNvbXBvbmVudFR5cGUsIGNvbXBvbmVudCwgY3JlYXRlRWxlbWVudFJlZih0RWxlbWVudE5vZGUsIHJvb3RMVmlldyksIHJvb3RMVmlldyxcbiAgICAgICAgdEVsZW1lbnROb2RlKTtcbiAgfVxufVxuXG4vKipcbiAqIFJlcHJlc2VudHMgYW4gaW5zdGFuY2Ugb2YgYSBDb21wb25lbnQgY3JlYXRlZCB2aWEgYSB7QGxpbmsgQ29tcG9uZW50RmFjdG9yeX0uXG4gKlxuICogYENvbXBvbmVudFJlZmAgcHJvdmlkZXMgYWNjZXNzIHRvIHRoZSBDb21wb25lbnQgSW5zdGFuY2UgYXMgd2VsbCBvdGhlciBvYmplY3RzIHJlbGF0ZWQgdG8gdGhpc1xuICogQ29tcG9uZW50IEluc3RhbmNlIGFuZCBhbGxvd3MgeW91IHRvIGRlc3Ryb3kgdGhlIENvbXBvbmVudCBJbnN0YW5jZSB2aWEgdGhlIHtAbGluayAjZGVzdHJveX1cbiAqIG1ldGhvZC5cbiAqXG4gKi9cbmV4cG9ydCBjbGFzcyBDb21wb25lbnRSZWY8VD4gZXh0ZW5kcyBBYnN0cmFjdENvbXBvbmVudFJlZjxUPiB7XG4gIG92ZXJyaWRlIGluc3RhbmNlOiBUO1xuICBvdmVycmlkZSBob3N0VmlldzogVmlld1JlZjxUPjtcbiAgb3ZlcnJpZGUgY2hhbmdlRGV0ZWN0b3JSZWY6IENoYW5nZURldGVjdG9yUmVmO1xuICBvdmVycmlkZSBjb21wb25lbnRUeXBlOiBUeXBlPFQ+O1xuICBwcml2YXRlIHByZXZpb3VzSW5wdXRWYWx1ZXM6IE1hcDxzdHJpbmcsIHVua25vd24+fG51bGwgPSBudWxsO1xuXG4gIGNvbnN0cnVjdG9yKFxuICAgICAgY29tcG9uZW50VHlwZTogVHlwZTxUPiwgaW5zdGFuY2U6IFQsIHB1YmxpYyBsb2NhdGlvbjogRWxlbWVudFJlZiwgcHJpdmF0ZSBfcm9vdExWaWV3OiBMVmlldyxcbiAgICAgIHByaXZhdGUgX3ROb2RlOiBURWxlbWVudE5vZGV8VENvbnRhaW5lck5vZGV8VEVsZW1lbnRDb250YWluZXJOb2RlKSB7XG4gICAgc3VwZXIoKTtcbiAgICB0aGlzLmluc3RhbmNlID0gaW5zdGFuY2U7XG4gICAgdGhpcy5ob3N0VmlldyA9IHRoaXMuY2hhbmdlRGV0ZWN0b3JSZWYgPSBuZXcgUm9vdFZpZXdSZWY8VD4oX3Jvb3RMVmlldyk7XG4gICAgdGhpcy5jb21wb25lbnRUeXBlID0gY29tcG9uZW50VHlwZTtcbiAgfVxuXG4gIG92ZXJyaWRlIHNldElucHV0KG5hbWU6IHN0cmluZywgdmFsdWU6IHVua25vd24pOiB2b2lkIHtcbiAgICBjb25zdCBpbnB1dERhdGEgPSB0aGlzLl90Tm9kZS5pbnB1dHM7XG4gICAgbGV0IGRhdGFWYWx1ZTogUHJvcGVydHlBbGlhc1ZhbHVlfHVuZGVmaW5lZDtcbiAgICBpZiAoaW5wdXREYXRhICE9PSBudWxsICYmIChkYXRhVmFsdWUgPSBpbnB1dERhdGFbbmFtZV0pKSB7XG4gICAgICB0aGlzLnByZXZpb3VzSW5wdXRWYWx1ZXMgPz89IG5ldyBNYXAoKTtcbiAgICAgIC8vIERvIG5vdCBzZXQgdGhlIGlucHV0IGlmIGl0IGlzIHRoZSBzYW1lIGFzIHRoZSBsYXN0IHZhbHVlXG4gICAgICAvLyBUaGlzIGJlaGF2aW9yIG1hdGNoZXMgYGJpbmRpbmdVcGRhdGVkYCB3aGVuIGJpbmRpbmcgaW5wdXRzIGluIHRlbXBsYXRlcy5cbiAgICAgIGlmICh0aGlzLnByZXZpb3VzSW5wdXRWYWx1ZXMuaGFzKG5hbWUpICYmXG4gICAgICAgICAgT2JqZWN0LmlzKHRoaXMucHJldmlvdXNJbnB1dFZhbHVlcy5nZXQobmFtZSksIHZhbHVlKSkge1xuICAgICAgICByZXR1cm47XG4gICAgICB9XG5cbiAgICAgIGNvbnN0IGxWaWV3ID0gdGhpcy5fcm9vdExWaWV3O1xuICAgICAgc2V0SW5wdXRzRm9yUHJvcGVydHkobFZpZXdbVFZJRVddLCBsVmlldywgZGF0YVZhbHVlLCBuYW1lLCB2YWx1ZSk7XG4gICAgICB0aGlzLnByZXZpb3VzSW5wdXRWYWx1ZXMuc2V0KG5hbWUsIHZhbHVlKTtcbiAgICAgIGNvbnN0IGNoaWxkQ29tcG9uZW50TFZpZXcgPSBnZXRDb21wb25lbnRMVmlld0J5SW5kZXgodGhpcy5fdE5vZGUuaW5kZXgsIGxWaWV3KTtcbiAgICAgIG1hcmtWaWV3RGlydHkoY2hpbGRDb21wb25lbnRMVmlldyk7XG4gICAgfSBlbHNlIHtcbiAgICAgIGlmIChuZ0Rldk1vZGUpIHtcbiAgICAgICAgY29uc3QgY21wTmFtZUZvckVycm9yID0gc3RyaW5naWZ5Rm9yRXJyb3IodGhpcy5jb21wb25lbnRUeXBlKTtcbiAgICAgICAgbGV0IG1lc3NhZ2UgPVxuICAgICAgICAgICAgYENhbid0IHNldCB2YWx1ZSBvZiB0aGUgJyR7bmFtZX0nIGlucHV0IG9uIHRoZSAnJHtjbXBOYW1lRm9yRXJyb3J9JyBjb21wb25lbnQuIGA7XG4gICAgICAgIG1lc3NhZ2UgKz0gYE1ha2Ugc3VyZSB0aGF0IHRoZSAnJHtcbiAgICAgICAgICAgIG5hbWV9JyBwcm9wZXJ0eSBpcyBhbm5vdGF0ZWQgd2l0aCBASW5wdXQoKSBvciBhIG1hcHBlZCBASW5wdXQoJyR7bmFtZX0nKSBleGlzdHMuYDtcbiAgICAgICAgcmVwb3J0VW5rbm93blByb3BlcnR5RXJyb3IobWVzc2FnZSk7XG4gICAgICB9XG4gICAgfVxuICB9XG5cbiAgb3ZlcnJpZGUgZ2V0IGluamVjdG9yKCk6IEluamVjdG9yIHtcbiAgICByZXR1cm4gbmV3IE5vZGVJbmplY3Rvcih0aGlzLl90Tm9kZSwgdGhpcy5fcm9vdExWaWV3KTtcbiAgfVxuXG4gIG92ZXJyaWRlIGRlc3Ryb3koKTogdm9pZCB7XG4gICAgdGhpcy5ob3N0Vmlldy5kZXN0cm95KCk7XG4gIH1cblxuICBvdmVycmlkZSBvbkRlc3Ryb3koY2FsbGJhY2s6ICgpID0+IHZvaWQpOiB2b2lkIHtcbiAgICB0aGlzLmhvc3RWaWV3Lm9uRGVzdHJveShjYWxsYmFjayk7XG4gIH1cbn1cblxuLyoqIFJlcHJlc2VudHMgYSBIb3N0RmVhdHVyZSBmdW5jdGlvbi4gKi9cbnR5cGUgSG9zdEZlYXR1cmUgPSAoPFQ+KGNvbXBvbmVudDogVCwgY29tcG9uZW50RGVmOiBDb21wb25lbnREZWY8VD4pID0+IHZvaWQpO1xuXG4vKiogQ3JlYXRlcyBhIFROb2RlIHRoYXQgY2FuIGJlIHVzZWQgdG8gaW5zdGFudGlhdGUgYSByb290IGNvbXBvbmVudC4gKi9cbmZ1bmN0aW9uIGNyZWF0ZVJvb3RDb21wb25lbnRUTm9kZShsVmlldzogTFZpZXcsIHJOb2RlOiBSTm9kZSk6IFRFbGVtZW50Tm9kZSB7XG4gIGNvbnN0IHRWaWV3ID0gbFZpZXdbVFZJRVddO1xuICBjb25zdCBpbmRleCA9IEhFQURFUl9PRkZTRVQ7XG4gIG5nRGV2TW9kZSAmJiBhc3NlcnRJbmRleEluUmFuZ2UobFZpZXcsIGluZGV4KTtcbiAgbFZpZXdbaW5kZXhdID0gck5vZGU7XG5cbiAgLy8gJyNob3N0JyBpcyBhZGRlZCBoZXJlIGFzIHdlIGRvbid0IGtub3cgdGhlIHJlYWwgaG9zdCBET00gbmFtZSAod2UgZG9uJ3Qgd2FudCB0byByZWFkIGl0KSBhbmQgYXRcbiAgLy8gdGhlIHNhbWUgdGltZSB3ZSB3YW50IHRvIGNvbW11bmljYXRlIHRoZSBkZWJ1ZyBgVE5vZGVgIHRoYXQgdGhpcyBpcyBhIHNwZWNpYWwgYFROb2RlYFxuICAvLyByZXByZXNlbnRpbmcgYSBob3N0IGVsZW1lbnQuXG4gIHJldHVybiBnZXRPckNyZWF0ZVROb2RlKHRWaWV3LCBpbmRleCwgVE5vZGVUeXBlLkVsZW1lbnQsICcjaG9zdCcsIG51bGwpO1xufVxuXG4vKipcbiAqIENyZWF0ZXMgdGhlIHJvb3QgY29tcG9uZW50IHZpZXcgYW5kIHRoZSByb290IGNvbXBvbmVudCBub2RlLlxuICpcbiAqIEBwYXJhbSBob3N0Uk5vZGUgUmVuZGVyIGhvc3QgZWxlbWVudC5cbiAqIEBwYXJhbSByb290Q29tcG9uZW50RGVmIENvbXBvbmVudERlZlxuICogQHBhcmFtIHJvb3RWaWV3IFRoZSBwYXJlbnQgdmlldyB3aGVyZSB0aGUgaG9zdCBub2RlIGlzIHN0b3JlZFxuICogQHBhcmFtIHJlbmRlcmVyRmFjdG9yeSBGYWN0b3J5IHRvIGJlIHVzZWQgZm9yIGNyZWF0aW5nIGNoaWxkIHJlbmRlcmVycy5cbiAqIEBwYXJhbSBob3N0UmVuZGVyZXIgVGhlIGN1cnJlbnQgcmVuZGVyZXJcbiAqIEBwYXJhbSBzYW5pdGl6ZXIgVGhlIHNhbml0aXplciwgaWYgcHJvdmlkZWRcbiAqXG4gKiBAcmV0dXJucyBDb21wb25lbnQgdmlldyBjcmVhdGVkXG4gKi9cbmZ1bmN0aW9uIGNyZWF0ZVJvb3RDb21wb25lbnRWaWV3KFxuICAgIHROb2RlOiBURWxlbWVudE5vZGUsIGhvc3RSTm9kZTogUkVsZW1lbnR8bnVsbCwgcm9vdENvbXBvbmVudERlZjogQ29tcG9uZW50RGVmPGFueT4sXG4gICAgcm9vdERpcmVjdGl2ZXM6IERpcmVjdGl2ZURlZjxhbnk+W10sIHJvb3RWaWV3OiBMVmlldywgZW52aXJvbm1lbnQ6IExWaWV3RW52aXJvbm1lbnQsXG4gICAgaG9zdFJlbmRlcmVyOiBSZW5kZXJlcik6IExWaWV3IHtcbiAgY29uc3QgdFZpZXcgPSByb290Vmlld1tUVklFV107XG4gIGFwcGx5Um9vdENvbXBvbmVudFN0eWxpbmcocm9vdERpcmVjdGl2ZXMsIHROb2RlLCBob3N0Uk5vZGUsIGhvc3RSZW5kZXJlcik7XG5cbiAgLy8gSHlkcmF0aW9uIGluZm8gaXMgb24gdGhlIGhvc3QgZWxlbWVudCBhbmQgbmVlZHMgdG8gYmUgcmV0cmlldmVkXG4gIC8vIGFuZCBwYXNzZWQgdG8gdGhlIGNvbXBvbmVudCBMVmlldy5cbiAgbGV0IGh5ZHJhdGlvbkluZm86IERlaHlkcmF0ZWRWaWV3fG51bGwgPSBudWxsO1xuICBpZiAoaG9zdFJOb2RlICE9PSBudWxsKSB7XG4gICAgaHlkcmF0aW9uSW5mbyA9IHJldHJpZXZlSHlkcmF0aW9uSW5mbyhob3N0Uk5vZGUsIHJvb3RWaWV3W0lOSkVDVE9SXSEpO1xuICB9XG4gIGNvbnN0IHZpZXdSZW5kZXJlciA9IGVudmlyb25tZW50LnJlbmRlcmVyRmFjdG9yeS5jcmVhdGVSZW5kZXJlcihob3N0Uk5vZGUsIHJvb3RDb21wb25lbnREZWYpO1xuICBsZXQgbFZpZXdGbGFncyA9IExWaWV3RmxhZ3MuQ2hlY2tBbHdheXM7XG4gIGlmIChyb290Q29tcG9uZW50RGVmLnNpZ25hbHMpIHtcbiAgICBsVmlld0ZsYWdzID0gTFZpZXdGbGFncy5TaWduYWxWaWV3O1xuICB9IGVsc2UgaWYgKHJvb3RDb21wb25lbnREZWYub25QdXNoKSB7XG4gICAgbFZpZXdGbGFncyA9IExWaWV3RmxhZ3MuRGlydHk7XG4gIH1cbiAgY29uc3QgY29tcG9uZW50VmlldyA9IGNyZWF0ZUxWaWV3KFxuICAgICAgcm9vdFZpZXcsIGdldE9yQ3JlYXRlQ29tcG9uZW50VFZpZXcocm9vdENvbXBvbmVudERlZiksIG51bGwsIGxWaWV3RmxhZ3MsXG4gICAgICByb290Vmlld1t0Tm9kZS5pbmRleF0sIHROb2RlLCBlbnZpcm9ubWVudCwgdmlld1JlbmRlcmVyLCBudWxsLCBudWxsLCBoeWRyYXRpb25JbmZvKTtcblxuICBpZiAodFZpZXcuZmlyc3RDcmVhdGVQYXNzKSB7XG4gICAgbWFya0FzQ29tcG9uZW50SG9zdCh0VmlldywgdE5vZGUsIHJvb3REaXJlY3RpdmVzLmxlbmd0aCAtIDEpO1xuICB9XG5cbiAgYWRkVG9WaWV3VHJlZShyb290VmlldywgY29tcG9uZW50Vmlldyk7XG5cbiAgLy8gU3RvcmUgY29tcG9uZW50IHZpZXcgYXQgbm9kZSBpbmRleCwgd2l0aCBub2RlIGFzIHRoZSBIT1NUXG4gIHJldHVybiByb290Vmlld1t0Tm9kZS5pbmRleF0gPSBjb21wb25lbnRWaWV3O1xufVxuXG4vKiogU2V0cyB1cCB0aGUgc3R5bGluZyBpbmZvcm1hdGlvbiBvbiBhIHJvb3QgY29tcG9uZW50LiAqL1xuZnVuY3Rpb24gYXBwbHlSb290Q29tcG9uZW50U3R5bGluZyhcbiAgICByb290RGlyZWN0aXZlczogRGlyZWN0aXZlRGVmPGFueT5bXSwgdE5vZGU6IFRFbGVtZW50Tm9kZSwgck5vZGU6IFJFbGVtZW50fG51bGwsXG4gICAgaG9zdFJlbmRlcmVyOiBSZW5kZXJlcik6IHZvaWQge1xuICBmb3IgKGNvbnN0IGRlZiBvZiByb290RGlyZWN0aXZlcykge1xuICAgIHROb2RlLm1lcmdlZEF0dHJzID0gbWVyZ2VIb3N0QXR0cnModE5vZGUubWVyZ2VkQXR0cnMsIGRlZi5ob3N0QXR0cnMpO1xuICB9XG5cbiAgaWYgKHROb2RlLm1lcmdlZEF0dHJzICE9PSBudWxsKSB7XG4gICAgY29tcHV0ZVN0YXRpY1N0eWxpbmcodE5vZGUsIHROb2RlLm1lcmdlZEF0dHJzLCB0cnVlKTtcblxuICAgIGlmIChyTm9kZSAhPT0gbnVsbCkge1xuICAgICAgc2V0dXBTdGF0aWNBdHRyaWJ1dGVzKGhvc3RSZW5kZXJlciwgck5vZGUsIHROb2RlKTtcbiAgICB9XG4gIH1cbn1cblxuLyoqXG4gKiBDcmVhdGVzIGEgcm9vdCBjb21wb25lbnQgYW5kIHNldHMgaXQgdXAgd2l0aCBmZWF0dXJlcyBhbmQgaG9zdCBiaW5kaW5ncy5TaGFyZWQgYnlcbiAqIHJlbmRlckNvbXBvbmVudCgpIGFuZCBWaWV3Q29udGFpbmVyUmVmLmNyZWF0ZUNvbXBvbmVudCgpLlxuICovXG5mdW5jdGlvbiBjcmVhdGVSb290Q29tcG9uZW50PFQ+KFxuICAgIGNvbXBvbmVudFZpZXc6IExWaWV3LCByb290Q29tcG9uZW50RGVmOiBDb21wb25lbnREZWY8VD4sIHJvb3REaXJlY3RpdmVzOiBEaXJlY3RpdmVEZWY8YW55PltdLFxuICAgIGhvc3REaXJlY3RpdmVEZWZzOiBIb3N0RGlyZWN0aXZlRGVmc3xudWxsLCByb290TFZpZXc6IExWaWV3LFxuICAgIGhvc3RGZWF0dXJlczogSG9zdEZlYXR1cmVbXXxudWxsKTogYW55IHtcbiAgY29uc3Qgcm9vdFROb2RlID0gZ2V0Q3VycmVudFROb2RlKCkgYXMgVEVsZW1lbnROb2RlO1xuICBuZ0Rldk1vZGUgJiYgYXNzZXJ0RGVmaW5lZChyb290VE5vZGUsICd0Tm9kZSBzaG91bGQgaGF2ZSBiZWVuIGFscmVhZHkgY3JlYXRlZCcpO1xuICBjb25zdCB0VmlldyA9IHJvb3RMVmlld1tUVklFV107XG4gIGNvbnN0IG5hdGl2ZSA9IGdldE5hdGl2ZUJ5VE5vZGUocm9vdFROb2RlLCByb290TFZpZXcpO1xuXG4gIGluaXRpYWxpemVEaXJlY3RpdmVzKHRWaWV3LCByb290TFZpZXcsIHJvb3RUTm9kZSwgcm9vdERpcmVjdGl2ZXMsIG51bGwsIGhvc3REaXJlY3RpdmVEZWZzKTtcblxuICBmb3IgKGxldCBpID0gMDsgaSA8IHJvb3REaXJlY3RpdmVzLmxlbmd0aDsgaSsrKSB7XG4gICAgY29uc3QgZGlyZWN0aXZlSW5kZXggPSByb290VE5vZGUuZGlyZWN0aXZlU3RhcnQgKyBpO1xuICAgIGNvbnN0IGRpcmVjdGl2ZUluc3RhbmNlID0gZ2V0Tm9kZUluamVjdGFibGUocm9vdExWaWV3LCB0VmlldywgZGlyZWN0aXZlSW5kZXgsIHJvb3RUTm9kZSk7XG4gICAgYXR0YWNoUGF0Y2hEYXRhKGRpcmVjdGl2ZUluc3RhbmNlLCByb290TFZpZXcpO1xuICB9XG5cbiAgaW52b2tlRGlyZWN0aXZlc0hvc3RCaW5kaW5ncyh0Vmlldywgcm9vdExWaWV3LCByb290VE5vZGUpO1xuXG4gIGlmIChuYXRpdmUpIHtcbiAgICBhdHRhY2hQYXRjaERhdGEobmF0aXZlLCByb290TFZpZXcpO1xuICB9XG5cbiAgLy8gV2UncmUgZ3VhcmFudGVlZCBmb3IgdGhlIGBjb21wb25lbnRPZmZzZXRgIHRvIGJlIHBvc2l0aXZlIGhlcmVcbiAgLy8gc2luY2UgYSByb290IGNvbXBvbmVudCBhbHdheXMgbWF0Y2hlcyBhIGNvbXBvbmVudCBkZWYuXG4gIG5nRGV2TW9kZSAmJlxuICAgICAgYXNzZXJ0R3JlYXRlclRoYW4ocm9vdFROb2RlLmNvbXBvbmVudE9mZnNldCwgLTEsICdjb21wb25lbnRPZmZzZXQgbXVzdCBiZSBncmVhdCB0aGFuIC0xJyk7XG4gIGNvbnN0IGNvbXBvbmVudCA9IGdldE5vZGVJbmplY3RhYmxlKFxuICAgICAgcm9vdExWaWV3LCB0Vmlldywgcm9vdFROb2RlLmRpcmVjdGl2ZVN0YXJ0ICsgcm9vdFROb2RlLmNvbXBvbmVudE9mZnNldCwgcm9vdFROb2RlKTtcbiAgY29tcG9uZW50Vmlld1tDT05URVhUXSA9IHJvb3RMVmlld1tDT05URVhUXSA9IGNvbXBvbmVudDtcblxuICBpZiAoaG9zdEZlYXR1cmVzICE9PSBudWxsKSB7XG4gICAgZm9yIChjb25zdCBmZWF0dXJlIG9mIGhvc3RGZWF0dXJlcykge1xuICAgICAgZmVhdHVyZShjb21wb25lbnQsIHJvb3RDb21wb25lbnREZWYpO1xuICAgIH1cbiAgfVxuXG4gIC8vIFdlIHdhbnQgdG8gZ2VuZXJhdGUgYW4gZW1wdHkgUXVlcnlMaXN0IGZvciByb290IGNvbnRlbnQgcXVlcmllcyBmb3IgYmFja3dhcmRzXG4gIC8vIGNvbXBhdGliaWxpdHkgd2l0aCBWaWV3RW5naW5lLlxuICBleGVjdXRlQ29udGVudFF1ZXJpZXModFZpZXcsIHJvb3RUTm9kZSwgY29tcG9uZW50Vmlldyk7XG5cbiAgcmV0dXJuIGNvbXBvbmVudDtcbn1cblxuLyoqIFNldHMgdGhlIHN0YXRpYyBhdHRyaWJ1dGVzIG9uIGEgcm9vdCBjb21wb25lbnQuICovXG5mdW5jdGlvbiBzZXRSb290Tm9kZUF0dHJpYnV0ZXMoXG4gICAgaG9zdFJlbmRlcmVyOiBSZW5kZXJlcjIsIGNvbXBvbmVudERlZjogQ29tcG9uZW50RGVmPHVua25vd24+LCBob3N0Uk5vZGU6IFJFbGVtZW50LFxuICAgIHJvb3RTZWxlY3Rvck9yTm9kZTogYW55KSB7XG4gIGlmIChyb290U2VsZWN0b3JPck5vZGUpIHtcbiAgICBzZXRVcEF0dHJpYnV0ZXMoaG9zdFJlbmRlcmVyLCBob3N0Uk5vZGUsIFsnbmctdmVyc2lvbicsIFZFUlNJT04uZnVsbF0pO1xuICB9IGVsc2Uge1xuICAgIC8vIElmIGhvc3QgZWxlbWVudCBpcyBjcmVhdGVkIGFzIGEgcGFydCBvZiB0aGlzIGZ1bmN0aW9uIGNhbGwgKGkuZS4gYHJvb3RTZWxlY3Rvck9yTm9kZWBcbiAgICAvLyBpcyBub3QgZGVmaW5lZCksIGFsc28gYXBwbHkgYXR0cmlidXRlcyBhbmQgY2xhc3NlcyBleHRyYWN0ZWQgZnJvbSBjb21wb25lbnQgc2VsZWN0b3IuXG4gICAgLy8gRXh0cmFjdCBhdHRyaWJ1dGVzIGFuZCBjbGFzc2VzIGZyb20gdGhlIGZpcnN0IHNlbGVjdG9yIG9ubHkgdG8gbWF0Y2ggVkUgYmVoYXZpb3IuXG4gICAgY29uc3Qge2F0dHJzLCBjbGFzc2VzfSA9IGV4dHJhY3RBdHRyc0FuZENsYXNzZXNGcm9tU2VsZWN0b3IoY29tcG9uZW50RGVmLnNlbGVjdG9yc1swXSk7XG4gICAgaWYgKGF0dHJzKSB7XG4gICAgICBzZXRVcEF0dHJpYnV0ZXMoaG9zdFJlbmRlcmVyLCBob3N0Uk5vZGUsIGF0dHJzKTtcbiAgICB9XG4gICAgaWYgKGNsYXNzZXMgJiYgY2xhc3Nlcy5sZW5ndGggPiAwKSB7XG4gICAgICB3cml0ZURpcmVjdENsYXNzKGhvc3RSZW5kZXJlciwgaG9zdFJOb2RlLCBjbGFzc2VzLmpvaW4oJyAnKSk7XG4gICAgfVxuICB9XG59XG5cbi8qKiBQcm9qZWN0cyB0aGUgYHByb2plY3RhYmxlTm9kZXNgIHRoYXQgd2VyZSBzcGVjaWZpZWQgd2hlbiBjcmVhdGluZyBhIHJvb3QgY29tcG9uZW50LiAqL1xuZnVuY3Rpb24gcHJvamVjdE5vZGVzKFxuICAgIHROb2RlOiBURWxlbWVudE5vZGUsIG5nQ29udGVudFNlbGVjdG9yczogc3RyaW5nW10sIHByb2plY3RhYmxlTm9kZXM6IGFueVtdW10pIHtcbiAgY29uc3QgcHJvamVjdGlvbjogKFROb2RlfFJOb2RlW118bnVsbClbXSA9IHROb2RlLnByb2plY3Rpb24gPSBbXTtcbiAgZm9yIChsZXQgaSA9IDA7IGkgPCBuZ0NvbnRlbnRTZWxlY3RvcnMubGVuZ3RoOyBpKyspIHtcbiAgICBjb25zdCBub2Rlc2ZvclNsb3QgPSBwcm9qZWN0YWJsZU5vZGVzW2ldO1xuICAgIC8vIFByb2plY3RhYmxlIG5vZGVzIGNhbiBiZSBwYXNzZWQgYXMgYXJyYXkgb2YgYXJyYXlzIG9yIGFuIGFycmF5IG9mIGl0ZXJhYmxlcyAobmdVcGdyYWRlXG4gICAgLy8gY2FzZSkuIEhlcmUgd2UgZG8gbm9ybWFsaXplIHBhc3NlZCBkYXRhIHN0cnVjdHVyZSB0byBiZSBhbiBhcnJheSBvZiBhcnJheXMgdG8gYXZvaWRcbiAgICAvLyBjb21wbGV4IGNoZWNrcyBkb3duIHRoZSBsaW5lLlxuICAgIC8vIFdlIGFsc28gbm9ybWFsaXplIHRoZSBsZW5ndGggb2YgdGhlIHBhc3NlZCBpbiBwcm9qZWN0YWJsZSBub2RlcyAodG8gbWF0Y2ggdGhlIG51bWJlciBvZlxuICAgIC8vIDxuZy1jb250YWluZXI+IHNsb3RzIGRlZmluZWQgYnkgYSBjb21wb25lbnQpLlxuICAgIHByb2plY3Rpb24ucHVzaChub2Rlc2ZvclNsb3QgIT0gbnVsbCA/IEFycmF5LmZyb20obm9kZXNmb3JTbG90KSA6IG51bGwpO1xuICB9XG59XG5cbi8qKlxuICogVXNlZCB0byBlbmFibGUgbGlmZWN5Y2xlIGhvb2tzIG9uIHRoZSByb290IGNvbXBvbmVudC5cbiAqXG4gKiBJbmNsdWRlIHRoaXMgZmVhdHVyZSB3aGVuIGNhbGxpbmcgYHJlbmRlckNvbXBvbmVudGAgaWYgdGhlIHJvb3QgY29tcG9uZW50XG4gKiB5b3UgYXJlIHJlbmRlcmluZyBoYXMgbGlmZWN5Y2xlIGhvb2tzIGRlZmluZWQuIE90aGVyd2lzZSwgdGhlIGhvb2tzIHdvbid0XG4gKiBiZSBjYWxsZWQgcHJvcGVybHkuXG4gKlxuICogRXhhbXBsZTpcbiAqXG4gKiBgYGBcbiAqIHJlbmRlckNvbXBvbmVudChBcHBDb21wb25lbnQsIHtob3N0RmVhdHVyZXM6IFtMaWZlY3ljbGVIb29rc0ZlYXR1cmVdfSk7XG4gKiBgYGBcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIExpZmVjeWNsZUhvb2tzRmVhdHVyZSgpOiB2b2lkIHtcbiAgY29uc3QgdE5vZGUgPSBnZXRDdXJyZW50VE5vZGUoKSE7XG4gIG5nRGV2TW9kZSAmJiBhc3NlcnREZWZpbmVkKHROb2RlLCAnVE5vZGUgaXMgcmVxdWlyZWQnKTtcbiAgcmVnaXN0ZXJQb3N0T3JkZXJIb29rcyhnZXRMVmlldygpW1RWSUVXXSwgdE5vZGUpO1xufVxuIl19