UNPKG

@angular/core

Version:

Angular - the core framework

452 lines • 83.3 kB
/** * @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 { EnvironmentInjector } from '../di/r3_injector'; import { validateMatchingNode } from '../hydration/error_handling'; import { CONTAINERS } from '../hydration/interfaces'; import { isInSkipHydrationBlock } from '../hydration/skip_hydration'; import { getSegmentHead, isDisconnectedNode, markRNodeAsClaimedByHydration, } from '../hydration/utils'; import { findMatchingDehydratedView, locateDehydratedViewsInContainer } from '../hydration/views'; import { isType } from '../interface/type'; import { assertNodeInjector } from '../render3/assert'; import { ComponentFactory as R3ComponentFactory } from '../render3/component_ref'; import { getComponentDef } from '../render3/definition'; import { getParentInjectorLocation, NodeInjector } from '../render3/di'; import { addToViewTree, createLContainer } from '../render3/instructions/shared'; import { CONTAINER_HEADER_OFFSET, DEHYDRATED_VIEWS, NATIVE, VIEW_REFS, } from '../render3/interfaces/container'; import { isLContainer } from '../render3/interfaces/type_checks'; import { HEADER_OFFSET, HYDRATION, PARENT, RENDERER, T_HOST, TVIEW, } from '../render3/interfaces/view'; import { assertTNodeType } from '../render3/node_assert'; import { destroyLView, detachView, nativeInsertBefore, nativeNextSibling, nativeParentNode, } from '../render3/node_manipulation'; import { getCurrentTNode, getLView } from '../render3/state'; import { getParentInjectorIndex, getParentInjectorView, hasParentInjector, } from '../render3/util/injector_utils'; import { getNativeByTNode, unwrapRNode, viewAttachedToContainer } from '../render3/util/view_utils'; import { addLViewToLContainer, shouldAddViewToDom } from '../render3/view_manipulation'; import { ViewRef as R3ViewRef } from '../render3/view_ref'; import { addToArray, removeFromArray } from '../util/array_utils'; import { assertDefined, assertEqual, assertGreaterThan, assertLessThan, throwError, } from '../util/assert'; import { createElementRef } from './element_ref'; /** * Represents a container where one or more views can be attached to a component. * * Can contain *host views* (created by instantiating a * component with the `createComponent()` method), and *embedded views* * (created by instantiating a `TemplateRef` with the `createEmbeddedView()` method). * * A view container instance can contain other view containers, * creating a view hierarchy. * * @usageNotes * * The example below demonstrates how the `createComponent` function can be used * to create an instance of a ComponentRef dynamically and attach it to an ApplicationRef, * so that it gets included into change detection cycles. * * Note: the example uses standalone components, but the function can also be used for * non-standalone components (declared in an NgModule) as well. * * ```typescript * @Component({ * standalone: true, * selector: 'dynamic', * template: `<span>This is a content of a dynamic component.</span>`, * }) * class DynamicComponent { * vcr = inject(ViewContainerRef); * } * * @Component({ * standalone: true, * selector: 'app', * template: `<main>Hi! This is the main content.</main>`, * }) * class AppComponent { * vcr = inject(ViewContainerRef); * * ngAfterViewInit() { * const compRef = this.vcr.createComponent(DynamicComponent); * compRef.changeDetectorRef.detectChanges(); * } * } * ``` * * @see {@link ComponentRef} * @see {@link EmbeddedViewRef} * * @publicApi */ export class ViewContainerRef { /** * @internal * @nocollapse */ static { this.__NG_ELEMENT_ID__ = injectViewContainerRef; } } /** * Creates a ViewContainerRef and stores it on the injector. Or, if the ViewContainerRef * already exists, retrieves the existing ViewContainerRef. * * @returns The ViewContainerRef instance to use */ export function injectViewContainerRef() { const previousTNode = getCurrentTNode(); return createContainerRef(previousTNode, getLView()); } const VE_ViewContainerRef = ViewContainerRef; // TODO(alxhub): cleaning up this indirection triggers a subtle bug in Closure in g3. Once the fix // for that lands, this can be cleaned up. const R3ViewContainerRef = class ViewContainerRef extends VE_ViewContainerRef { constructor(_lContainer, _hostTNode, _hostLView) { super(); this._lContainer = _lContainer; this._hostTNode = _hostTNode; this._hostLView = _hostLView; } get element() { return createElementRef(this._hostTNode, this._hostLView); } get injector() { return new NodeInjector(this._hostTNode, this._hostLView); } /** @deprecated No replacement */ get parentInjector() { const parentLocation = getParentInjectorLocation(this._hostTNode, this._hostLView); if (hasParentInjector(parentLocation)) { const parentView = getParentInjectorView(parentLocation, this._hostLView); const injectorIndex = getParentInjectorIndex(parentLocation); ngDevMode && assertNodeInjector(parentView, injectorIndex); const parentTNode = parentView[TVIEW].data[injectorIndex + 8 /* NodeInjectorOffset.TNODE */]; return new NodeInjector(parentTNode, parentView); } else { return new NodeInjector(null, this._hostLView); } } clear() { while (this.length > 0) { this.remove(this.length - 1); } } get(index) { const viewRefs = getViewRefs(this._lContainer); return (viewRefs !== null && viewRefs[index]) || null; } get length() { return this._lContainer.length - CONTAINER_HEADER_OFFSET; } createEmbeddedView(templateRef, context, indexOrOptions) { let index; let injector; if (typeof indexOrOptions === 'number') { index = indexOrOptions; } else if (indexOrOptions != null) { index = indexOrOptions.index; injector = indexOrOptions.injector; } const dehydratedView = findMatchingDehydratedView(this._lContainer, templateRef.ssrId); const viewRef = templateRef.createEmbeddedViewImpl(context || {}, injector, dehydratedView); this.insertImpl(viewRef, index, shouldAddViewToDom(this._hostTNode, dehydratedView)); return viewRef; } createComponent(componentFactoryOrType, indexOrOptions, injector, projectableNodes, environmentInjector) { const isComponentFactory = componentFactoryOrType && !isType(componentFactoryOrType); let index; // This function supports 2 signatures and we need to handle options correctly for both: // 1. When first argument is a Component type. This signature also requires extra // options to be provided as object (more ergonomic option). // 2. First argument is a Component factory. In this case extra options are represented as // positional arguments. This signature is less ergonomic and will be deprecated. if (isComponentFactory) { if (ngDevMode) { assertEqual(typeof indexOrOptions !== 'object', true, 'It looks like Component factory was provided as the first argument ' + 'and an options object as the second argument. This combination of arguments ' + 'is incompatible. You can either change the first argument to provide Component ' + 'type or change the second argument to be a number (representing an index at ' + "which to insert the new component's host view into this container)"); } index = indexOrOptions; } else { if (ngDevMode) { assertDefined(getComponentDef(componentFactoryOrType), `Provided Component class doesn't contain Component definition. ` + `Please check whether provided class has @Component decorator.`); assertEqual(typeof indexOrOptions !== 'number', true, 'It looks like Component type was provided as the first argument ' + "and a number (representing an index at which to insert the new component's " + 'host view into this container as the second argument. This combination of arguments ' + 'is incompatible. Please use an object as the second argument instead.'); } const options = (indexOrOptions || {}); if (ngDevMode && options.environmentInjector && options.ngModuleRef) { throwError(`Cannot pass both environmentInjector and ngModuleRef options to createComponent().`); } index = options.index; injector = options.injector; projectableNodes = options.projectableNodes; environmentInjector = options.environmentInjector || options.ngModuleRef; } const componentFactory = isComponentFactory ? componentFactoryOrType : new R3ComponentFactory(getComponentDef(componentFactoryOrType)); const contextInjector = injector || this.parentInjector; // If an `NgModuleRef` is not provided explicitly, try retrieving it from the DI tree. if (!environmentInjector && componentFactory.ngModule == null) { // For the `ComponentFactory` case, entering this logic is very unlikely, since we expect that // an instance of a `ComponentFactory`, resolved via `ComponentFactoryResolver` would have an // `ngModule` field. This is possible in some test scenarios and potentially in some JIT-based // use-cases. For the `ComponentFactory` case we preserve backwards-compatibility and try // using a provided injector first, then fall back to the parent injector of this // `ViewContainerRef` instance. // // For the factory-less case, it's critical to establish a connection with the module // injector tree (by retrieving an instance of an `NgModuleRef` and accessing its injector), // so that a component can use DI tokens provided in MgModules. For this reason, we can not // rely on the provided injector, since it might be detached from the DI tree (for example, if // it was created via `Injector.create` without specifying a parent injector, or if an // injector is retrieved from an `NgModuleRef` created via `createNgModule` using an // NgModule outside of a module tree). Instead, we always use `ViewContainerRef`'s parent // injector, which is normally connected to the DI tree, which includes module injector // subtree. const _injector = isComponentFactory ? contextInjector : this.parentInjector; // DO NOT REFACTOR. The code here used to have a `injector.get(NgModuleRef, null) || // undefined` expression which seems to cause internal google apps to fail. This is documented // in the following internal bug issue: go/b/142967802 const result = _injector.get(EnvironmentInjector, null); if (result) { environmentInjector = result; } } const componentDef = getComponentDef(componentFactory.componentType ?? {}); const dehydratedView = findMatchingDehydratedView(this._lContainer, componentDef?.id ?? null); const rNode = dehydratedView?.firstChild ?? null; const componentRef = componentFactory.create(contextInjector, projectableNodes, rNode, environmentInjector); this.insertImpl(componentRef.hostView, index, shouldAddViewToDom(this._hostTNode, dehydratedView)); return componentRef; } insert(viewRef, index) { return this.insertImpl(viewRef, index, true); } insertImpl(viewRef, index, addToDOM) { const lView = viewRef._lView; if (ngDevMode && viewRef.destroyed) { throw new Error('Cannot insert a destroyed View in a ViewContainer!'); } if (viewAttachedToContainer(lView)) { // If view is already attached, detach it first so we clean up references appropriately. const prevIdx = this.indexOf(viewRef); // A view might be attached either to this or a different container. The `prevIdx` for // those cases will be: // equal to -1 for views attached to this ViewContainerRef // >= 0 for views attached to a different ViewContainerRef if (prevIdx !== -1) { this.detach(prevIdx); } else { const prevLContainer = lView[PARENT]; ngDevMode && assertEqual(isLContainer(prevLContainer), true, 'An attached view should have its PARENT point to a container.'); // We need to re-create a R3ViewContainerRef instance since those are not stored on // LView (nor anywhere else). const prevVCRef = new R3ViewContainerRef(prevLContainer, prevLContainer[T_HOST], prevLContainer[PARENT]); prevVCRef.detach(prevVCRef.indexOf(viewRef)); } } // Logical operation of adding `LView` to `LContainer` const adjustedIdx = this._adjustIndex(index); const lContainer = this._lContainer; addLViewToLContainer(lContainer, lView, adjustedIdx, addToDOM); viewRef.attachToViewContainerRef(); addToArray(getOrCreateViewRefs(lContainer), adjustedIdx, viewRef); return viewRef; } move(viewRef, newIndex) { if (ngDevMode && viewRef.destroyed) { throw new Error('Cannot move a destroyed View in a ViewContainer!'); } return this.insert(viewRef, newIndex); } indexOf(viewRef) { const viewRefsArr = getViewRefs(this._lContainer); return viewRefsArr !== null ? viewRefsArr.indexOf(viewRef) : -1; } remove(index) { const adjustedIdx = this._adjustIndex(index, -1); const detachedView = detachView(this._lContainer, adjustedIdx); if (detachedView) { // Before destroying the view, remove it from the container's array of `ViewRef`s. // This ensures the view container length is updated before calling // `destroyLView`, which could recursively call view container methods that // rely on an accurate container length. // (e.g. a method on this view container being called by a child directive's OnDestroy // lifecycle hook) removeFromArray(getOrCreateViewRefs(this._lContainer), adjustedIdx); destroyLView(detachedView[TVIEW], detachedView); } } detach(index) { const adjustedIdx = this._adjustIndex(index, -1); const view = detachView(this._lContainer, adjustedIdx); const wasDetached = view && removeFromArray(getOrCreateViewRefs(this._lContainer), adjustedIdx) != null; return wasDetached ? new R3ViewRef(view) : null; } _adjustIndex(index, shift = 0) { if (index == null) { return this.length + shift; } if (ngDevMode) { assertGreaterThan(index, -1, `ViewRef index must be positive, got ${index}`); // +1 because it's legal to insert at the end. assertLessThan(index, this.length + 1 + shift, 'index'); } return index; } }; function getViewRefs(lContainer) { return lContainer[VIEW_REFS]; } function getOrCreateViewRefs(lContainer) { return (lContainer[VIEW_REFS] || (lContainer[VIEW_REFS] = [])); } /** * Creates a ViewContainerRef and stores it on the injector. * * @param hostTNode The node that is requesting a ViewContainerRef * @param hostLView The view to which the node belongs * @returns The ViewContainerRef instance to use */ export function createContainerRef(hostTNode, hostLView) { ngDevMode && assertTNodeType(hostTNode, 12 /* TNodeType.AnyContainer */ | 3 /* TNodeType.AnyRNode */); let lContainer; const slotValue = hostLView[hostTNode.index]; if (isLContainer(slotValue)) { // If the host is a container, we don't need to create a new LContainer lContainer = slotValue; } else { // An LContainer anchor can not be `null`, but we set it here temporarily // and update to the actual value later in this function (see // `_locateOrCreateAnchorNode`). lContainer = createLContainer(slotValue, hostLView, null, hostTNode); hostLView[hostTNode.index] = lContainer; addToViewTree(hostLView, lContainer); } _locateOrCreateAnchorNode(lContainer, hostLView, hostTNode, slotValue); return new R3ViewContainerRef(lContainer, hostTNode, hostLView); } /** * Creates and inserts a comment node that acts as an anchor for a view container. * * If the host is a regular element, we have to insert a comment node manually which will * be used as an anchor when inserting elements. In this specific case we use low-level DOM * manipulation to insert it. */ function insertAnchorNode(hostLView, hostTNode) { const renderer = hostLView[RENDERER]; ngDevMode && ngDevMode.rendererCreateComment++; const commentNode = renderer.createComment(ngDevMode ? 'container' : ''); const hostNative = getNativeByTNode(hostTNode, hostLView); const parentOfHostNative = nativeParentNode(renderer, hostNative); nativeInsertBefore(renderer, parentOfHostNative, commentNode, nativeNextSibling(renderer, hostNative), false); return commentNode; } let _locateOrCreateAnchorNode = createAnchorNode; let _populateDehydratedViewsInLContainer = () => false; // noop by default /** * Looks up dehydrated views that belong to a given LContainer and populates * this information into the `LContainer[DEHYDRATED_VIEWS]` slot. When running * in client-only mode, this function is a noop. * * @param lContainer LContainer that should be populated. * @param tNode Corresponding TNode. * @param hostLView LView that hosts LContainer. * @returns a boolean flag that indicates whether a populating operation * was successful. The operation might be unsuccessful in case is has completed * previously, we are rendering in client-only mode or this content is located * in a skip hydration section. */ export function populateDehydratedViewsInLContainer(lContainer, tNode, hostLView) { return _populateDehydratedViewsInLContainer(lContainer, tNode, hostLView); } /** * Regular creation mode: an anchor is created and * assigned to the `lContainer[NATIVE]` slot. */ function createAnchorNode(lContainer, hostLView, hostTNode, slotValue) { // We already have a native element (anchor) set, return. if (lContainer[NATIVE]) return; let commentNode; // If the host is an element container, the native host element is guaranteed to be a // comment and we can reuse that comment as anchor element for the new LContainer. // The comment node in question is already part of the DOM structure so we don't need to append // it again. if (hostTNode.type & 8 /* TNodeType.ElementContainer */) { commentNode = unwrapRNode(slotValue); } else { commentNode = insertAnchorNode(hostLView, hostTNode); } lContainer[NATIVE] = commentNode; } /** * Hydration logic that looks up all dehydrated views in this container * and puts them into `lContainer[DEHYDRATED_VIEWS]` slot. * * @returns a boolean flag that indicates whether a populating operation * was successful. The operation might be unsuccessful in case is has completed * previously, we are rendering in client-only mode or this content is located * in a skip hydration section. */ function populateDehydratedViewsInLContainerImpl(lContainer, tNode, hostLView) { // We already have a native element (anchor) set and the process // of finding dehydrated views happened (so the `lContainer[DEHYDRATED_VIEWS]` // is not null), exit early. if (lContainer[NATIVE] && lContainer[DEHYDRATED_VIEWS]) { return true; } const hydrationInfo = hostLView[HYDRATION]; const noOffsetIndex = tNode.index - HEADER_OFFSET; const isNodeCreationMode = !hydrationInfo || isInSkipHydrationBlock(tNode) || isDisconnectedNode(hydrationInfo, noOffsetIndex); // Regular creation mode. if (isNodeCreationMode) { return false; } // Hydration mode, looking up an anchor node and dehydrated views in DOM. const currentRNode = getSegmentHead(hydrationInfo, noOffsetIndex); const serializedViews = hydrationInfo.data[CONTAINERS]?.[noOffsetIndex]; ngDevMode && assertDefined(serializedViews, 'Unexpected state: no hydration info available for a given TNode, ' + 'which represents a view container.'); const [commentNode, dehydratedViews] = locateDehydratedViewsInContainer(currentRNode, serializedViews); if (ngDevMode) { validateMatchingNode(commentNode, Node.COMMENT_NODE, null, hostLView, tNode, true); // Do not throw in case this node is already claimed (thus `false` as a second // argument). If this container is created based on an `<ng-template>`, the comment // node would be already claimed from the `template` instruction. If an element acts // as an anchor (e.g. <div #vcRef>), a separate comment node would be created/located, // so we need to claim it here. markRNodeAsClaimedByHydration(commentNode, false); } lContainer[NATIVE] = commentNode; lContainer[DEHYDRATED_VIEWS] = dehydratedViews; return true; } function locateOrCreateAnchorNode(lContainer, hostLView, hostTNode, slotValue) { if (!_populateDehydratedViewsInLContainer(lContainer, hostTNode, hostLView)) { // Populating dehydrated views operation returned `false`, which indicates // that the logic was running in client-only mode, this an anchor comment // node should be created for this container. createAnchorNode(lContainer, hostLView, hostTNode, slotValue); } } export function enableLocateOrCreateContainerRefImpl() { _locateOrCreateAnchorNode = locateOrCreateAnchorNode; _populateDehydratedViewsInLContainer = populateDehydratedViewsInLContainerImpl; } //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidmlld19jb250YWluZXJfcmVmLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vLi4vLi4vLi4vcGFja2FnZXMvY29yZS9zcmMvbGlua2VyL3ZpZXdfY29udGFpbmVyX3JlZi50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQTs7Ozs7O0dBTUc7QUFHSCxPQUFPLEVBQUMsbUJBQW1CLEVBQUMsTUFBTSxtQkFBbUIsQ0FBQztBQUN0RCxPQUFPLEVBQUMsb0JBQW9CLEVBQUMsTUFBTSw2QkFBNkIsQ0FBQztBQUNqRSxPQUFPLEVBQUMsVUFBVSxFQUFDLE1BQU0seUJBQXlCLENBQUM7QUFDbkQsT0FBTyxFQUE4QixzQkFBc0IsRUFBQyxNQUFNLDZCQUE2QixDQUFDO0FBQ2hHLE9BQU8sRUFDTCxjQUFjLEVBQ2Qsa0JBQWtCLEVBQ2xCLDZCQUE2QixHQUM5QixNQUFNLG9CQUFvQixDQUFDO0FBQzVCLE9BQU8sRUFBQywwQkFBMEIsRUFBRSxnQ0FBZ0MsRUFBQyxNQUFNLG9CQUFvQixDQUFDO0FBQ2hHLE9BQU8sRUFBQyxNQUFNLEVBQU8sTUFBTSxtQkFBbUIsQ0FBQztBQUMvQyxPQUFPLEVBQUMsa0JBQWtCLEVBQUMsTUFBTSxtQkFBbUIsQ0FBQztBQUNyRCxPQUFPLEVBQUMsZ0JBQWdCLElBQUksa0JBQWtCLEVBQUMsTUFBTSwwQkFBMEIsQ0FBQztBQUNoRixPQUFPLEVBQUMsZUFBZSxFQUFDLE1BQU0sdUJBQXVCLENBQUM7QUFDdEQsT0FBTyxFQUFDLHlCQUF5QixFQUFFLFlBQVksRUFBQyxNQUFNLGVBQWUsQ0FBQztBQUN0RSxPQUFPLEVBQUMsYUFBYSxFQUFFLGdCQUFnQixFQUFDLE1BQU0sZ0NBQWdDLENBQUM7QUFDL0UsT0FBTyxFQUNMLHVCQUF1QixFQUN2QixnQkFBZ0IsRUFFaEIsTUFBTSxFQUNOLFNBQVMsR0FDVixNQUFNLGlDQUFpQyxDQUFDO0FBV3pDLE9BQU8sRUFBQyxZQUFZLEVBQUMsTUFBTSxtQ0FBbUMsQ0FB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QjtRQUMvQiw2QkFBNkIsQ0FBQyxXQUFXLEVBQUUsS0FBSyxDQUFDLENBQUM7SUFDcEQsQ0FBQztJQUVELFVBQVUsQ0FBQyxNQUFNLENBQUMsR0FBRyxXQUF1QixDQUFDO0lBQzdDLFVBQVUsQ0FBQyxnQkFBZ0IsQ0FBQyxHQUFHLGVBQWUsQ0FBQztJQUUvQyxPQUFPLElBQUksQ0FBQztBQUNkLENBQUM7QUFFRCxTQUFTLHdCQUF3QixDQUMvQixVQUFzQixFQUN0QixTQUFnQixFQUNoQixTQUFnQixFQUNoQixTQUFjO0lBRWQsSUFBSSxDQUFDLG9DQUFvQyxDQUFDLFVBQVUsRUFBRSxTQUFTLEVBQUUsU0FBUyxDQUFDLEVBQUUsQ0FBQztRQUM1RSwwRUFBMEU7UUFDMUUseUVBQXlFO1FBQ3pFLDZDQUE2QztRQUM3QyxnQkFBZ0IsQ0FBQyxVQUFVLEVBQUUsU0FBUyxFQUFFLFNBQVMsRUFBRSxTQUFTLENBQUMsQ0FBQztJQUNoRSxDQUFDO0FBQ0gsQ0FBQztBQUVELE1BQU0sVUFBVSxvQ0FBb0M7SUFDbEQseUJBQXlCLEdBQUcsd0JBQXdCLENBQUM7SUFDckQsb0NBQW9DLEdBQUcsdUNBQXVDLENBQUM7QUFDakYsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbIi8qKlxuICogQGxpY2Vuc2VcbiAqIENvcHlyaWdodCBHb29nbGUgTExDIEFsbCBSaWdodHMgUmVzZXJ2ZWQuXG4gKlxuICogVXNlIG9mIHRoaXMgc291cmNlIGNvZGUgaXMgZ292ZXJuZWQgYnkgYW4gTUlULXN0eWxlIGxpY2Vuc2UgdGhhdCBjYW4gYmVcbiAqIGZvdW5kIGluIHRoZSBMSUNFTlNFIGZpbGUgYXQgaHR0cHM6Ly9hbmd1bGFyLmlvL2xpY2Vuc2VcbiAqL1xuXG5pbXBvcnQge0luamVjdG9yfSBmcm9tICcuLi9kaS9pbmplY3Rvcic7XG5pbXBvcnQge0Vudmlyb25tZW50SW5qZWN0b3J9IGZyb20gJy4uL2RpL3IzX2luamVjdG9yJztcbmltcG9ydCB7dmFsaWRhdGVNYXRjaGluZ05vZGV9IGZyb20gJy4uL2h5ZHJhdGlvbi9lcnJvcl9oYW5kbGluZyc7XG5pbXBvcnQge0NPTlRBSU5FUlN9IGZyb20gJy4uL2h5ZHJhdGlvbi9pbnRlcmZhY2VzJztcbmltcG9ydCB7aGFzSW5Ta2lwSHlkcmF0aW9uQmxvY2tGbGFnLCBpc0luU2tpcEh5ZHJhdGlvbkJsb2NrfSBmcm9tICcuLi9oeWRyYXRpb24vc2tpcF9oeWRyYXRpb24nO1xuaW1wb3J0IHtcbiAgZ2V0U2VnbWVudEhlYWQsXG4gIGlzRGlzY29ubmVjdGVkTm9kZSxcbiAgbWFya1JOb2RlQXNDbGFpbWVkQnlIeWRyYXRpb24sXG59IGZyb20gJy4uL2h5ZHJhdGlvbi91dGlscyc7XG5pbXBvcnQge2ZpbmRNYXRjaGluZ0RlaHlkcmF0ZWRWaWV3LCBsb2NhdGVEZWh5ZHJhdGVkVmlld3NJbkNvbnRhaW5lcn0gZnJvbSAnLi4vaHlkcmF0aW9uL3ZpZXdzJztcbmltcG9ydCB7aXNUeXBlLCBUeXBlfSBmcm9tICcuLi9pbnRlcmZhY2UvdHlwZSc7XG5pbXBvcnQge2Fzc2VydE5vZGVJbmplY3Rvcn0gZnJvbSAnLi4vcmVuZGVyMy9hc3NlcnQnO1xuaW1wb3J0IHtDb21wb25lbnRGYWN0b3J5IGFzIFIzQ29tcG9uZW50RmFjdG9yeX0gZnJvbSAnLi4vcmVuZGVyMy9jb21wb25lbnRfcmVmJztcbmltcG9ydCB7Z2V0Q29tcG9uZW50RGVmfSBmcm9tICcuLi9yZW5kZXIzL2RlZmluaXRpb24nO1xuaW1wb3J0IHtnZXRQYXJlbnRJbmplY3RvckxvY2F0aW9uLCBOb2RlSW5qZWN0b3J9IGZyb20gJy4uL3JlbmRlcjMvZGknO1xuaW1wb3J0IHthZGRUb1ZpZXdUcmVlLCBjcmVhdGVMQ29udGFpbmVyfSBmcm9tICcuLi9yZW5kZXIzL2luc3RydWN0aW9ucy9zaGFyZWQnO1xuaW1wb3J0IHtcbiAgQ09OVEFJTkVSX0hFQURFUl9PRkZTRVQsXG4gIERFSFlEUkFURURfVklFV1MsXG4gIExDb250YWluZXIsXG4gIE5BVElWRSxcbiAgVklFV19SRUZTLFxufSBmcm9tICcuLi9yZW5kZXIzL2ludGVyZmFjZXMvY29udGFpbmVyJztcbmltcG9ydCB7Tm9kZUluamVjdG9yT2Zmc2V0fSBmcm9tICcuLi9yZW5kZXIzL2ludGVyZmFjZXMvaW5qZWN0b3InO1xuaW1wb3J0IHtcbiAgVENvbnRhaW5lck5vZGUsXG4gIFREaXJlY3RpdmVIb3N0Tm9kZSxcbiAgVEVsZW1lbnRDb250YWluZXJOb2RlLFxuICBURWxlbWVudE5vZGUsXG4gIFROb2RlLFxuICBUTm9kZVR5cGUsXG59IGZyb20gJy4uL3JlbmRlcjMvaW50ZXJmYWNlcy9ub2RlJztcbmltcG9ydCB7UkNvbW1lbnQsIFJOb2RlfSBmcm9tICcuLi9yZW5kZXIzL2ludGVyZmFjZXMvcmVuZGVyZXJfZG9tJztcbmltcG9ydCB7aXNMQ29udGFpbmVyfSBmcm9tICcuLi9yZW5kZXIzL2ludGVyZmFjZXMvdHlwZV9jaGVja3MnO1xuaW1wb3J0IHtcbiAgSEVBREVSX09GRlNFVCxcbiAgSFlEUkFUSU9OLFxuICBMVmlldyxcbiAgUEFSRU5ULFxuICBSRU5ERVJFUixcbiAgVF9IT1NULFxuICBUVklFVyxcbn0gZnJvbSAnLi4vcmVuZGVyMy9pbnRlcmZhY2VzL3ZpZXcnO1xuaW1wb3J0IHthc3NlcnRUTm9kZVR5cGV9IGZyb20gJy4uL3JlbmRlcjMvbm9kZV9hc3NlcnQnO1xuaW1wb3J0IHtcbiAgZGVzdHJveUxWaWV3LFxuICBkZXRhY2hWaWV3LFxuICBuYXRpdmVJbnNlcnRCZWZvcmUsXG4gIG5hdGl2ZU5leHRTaWJsaW5nLFxuICBuYXRpdmVQYXJlbnROb2RlLFxufSBmcm9tICcuLi9yZW5kZXIzL25vZGVfbWFuaXB1bGF0aW9uJztcbmltcG9ydCB7Z2V0Q3VycmVudFROb2RlLCBnZXRMVmlld30gZnJvbSAnLi4vcmVuZGVyMy9zdGF0ZSc7XG5pbXBvcnQge1xuICBnZXRQYXJlbnRJbmplY3RvckluZGV4LFxuICBnZXRQYXJlbnRJbmplY3RvclZpZXcsXG4gIGhhc1BhcmVudEluamVjdG9yLFxufSBmcm9tICcuLi9yZW5kZXIzL3V0aWwvaW5qZWN0b3JfdXRpbHMnO1xuaW1wb3J0IHtnZXROYXRpdmVCeVROb2RlLCB1bndyYXBSTm9kZSwgdmlld0F0dGFjaGVkVG9Db250YWluZXJ9IGZyb20gJy4uL3JlbmRlcjMvdXRpbC92aWV3X3V0aWxzJztcbmltcG9ydCB7YWRkTFZpZXdUb0xDb250YWluZXIsIHNob3VsZEFkZFZpZXdUb0RvbX0gZnJvbSAnLi4vcmVuZGVyMy92aWV3X21hbmlwdWxhdGlvbic7XG5pbXBvcnQge1ZpZXdSZWYgYXMgUjNWaWV3UmVmfSBmcm9tICcuLi9yZW5kZXIzL3ZpZXdfcmVmJztcbmltcG9ydCB7YWRkVG9BcnJheSwgcmVtb3ZlRnJvbUFycmF5fSBmcm9tICcuLi91dGlsL2FycmF5X3V0aWxzJztcbmltcG9ydCB7XG4gIGFzc2VydERlZmluZWQsXG4gIGFzc2VydEVxdWFsLFxuICBhc3NlcnRHcmVhdGVyVGhhbixcbiAgYXNzZXJ0TGVzc1RoYW4sXG4gIHRocm93RXJyb3IsXG59IGZyb20gJy4uL3V0aWwvYXNzZXJ0JztcblxuaW1wb3J0IHtDb21wb25lbnRGYWN0b3J5LCBDb21wb25lbnRSZWZ9IGZyb20gJy4vY29tcG9uZW50X2ZhY3RvcnknO1xuaW1wb3J0IHtjcmVhdGVFbGVtZW50UmVmLCBFbGVtZW50UmVmfSBmcm9tICcuL2VsZW1lbnRfcmVmJztcbmltcG9ydCB7TmdNb2R1bGVSZWZ9IGZyb20gJy4vbmdfbW9kdWxlX2ZhY3RvcnknO1xuaW1wb3J0IHtUZW1wbGF0ZVJlZn0gZnJvbSAnLi90ZW1wbGF0ZV9yZWYnO1xuaW1wb3J0IHtFbWJlZGRlZFZpZXdSZWYsIFZpZXdSZWZ9IGZyb20gJy4vdmlld19yZWYnO1xuXG4vKipcbiAqIFJlcHJlc2VudHMgYSBjb250YWluZXIgd2hlcmUgb25lIG9yIG1vcmUgdmlld3MgY2FuIGJlIGF0dGFjaGVkIHRvIGEgY29tcG9uZW50LlxuICpcbiAqIENhbiBjb250YWluICpob3N0IHZpZXdzKiAoY3JlYXRlZCBieSBpbnN0YW50aWF0aW5nIGFcbiAqIGNvbXBvbmVudCB3aXRoIHRoZSBgY3JlYXRlQ29tcG9uZW50KClgIG1ldGhvZCksIGFuZCAqZW1iZWRkZWQgdmlld3MqXG4gKiAoY3JlYXRlZCBieSBpbnN0YW50aWF0aW5nIGEgYFRlbXBsYXRlUmVmYCB3aXRoIHRoZSBgY3JlYXRlRW1iZWRkZWRWaWV3KClgIG1ldGhvZCkuXG4gKlxuICogQSB2aWV3IGNvbnRhaW5lciBpbnN0YW5jZSBjYW4gY29udGFpbiBvdGhlciB2aWV3IGNvbnRhaW5lcnMsXG4gKiBjcmVhdGluZyBhIHZpZXcgaGllcmFyY2h5LlxuICpcbiAqIEB1c2FnZU5vdGVzXG4gKlxuICogVGhlIGV4YW1wbGUgYmVsb3cgZGVtb25zdHJhdGVzIGhvdyB0aGUgYGNyZWF0ZUNvbXBvbmVudGAgZnVuY3Rpb24gY2FuIGJlIHVzZWRcbiAqIHRvIGNyZWF0ZSBhbiBpbnN0YW5jZSBvZiBhIENvbXBvbmVudFJlZiBkeW5hbWljYWxseSBhbmQgYXR0YWNoIGl0IHRvIGFuIEFwcGxpY2F0aW9uUmVmLFxuICogc28gdGhhdCBpdCBnZXRzIGluY2x1ZGVkIGludG8gY2hhbmdlIGRldGVjdGlvbiBjeWNsZXMuXG4gKlxuICogTm90ZTogdGhlIGV4YW1wbGUgdXNlcyBzdGFuZGFsb25lIGNvbXBvbmVudHMsIGJ1dCB0aGUgZnVuY3Rpb24gY2FuIGFsc28gYmUgdXNlZCBmb3JcbiAqIG5vbi1zdGFuZGFsb25lIGNvbXBvbmVudHMgKGRlY2xhcmVkIGluIGFuIE5nTW9kdWxlKSBhcyB3ZWxsLlxuICpcbiAqIGBgYHR5cGVzY3JpcHRcbiAqIEBDb21wb25lbnQoe1xuICogICBzdGFuZGFsb25lOiB0cnVlLFxuICogICBzZWxlY3RvcjogJ2R5bmFtaWMnLFxuICogICB0ZW1wbGF0ZTogYDxzcGFuPlRoaXMgaXMgYSBjb250ZW50IG9mIGEgZHluYW1pYyBjb21wb25lbnQuPC9zcGFuPmAsXG4gKiB9KVxuICogY2xhc3MgRHluYW1pY0NvbXBvbmVudCB7XG4gKiAgIHZjciA9IGluamVjdChWaWV3Q29udGFpbmVyUmVmKTtcbiAqIH1cbiAqXG4gKiBAQ29tcG9uZW50KHtcbiAqICAgc3RhbmRhbG9uZTogdHJ1ZSxcbiAqICAgc2VsZWN0b3I6ICdhcHAnLFxuICogICB0ZW1wbGF0ZTogYDxtYWluPkhpISBUaGlzIGlzIHRoZSBtYWluIGNvbnRlbnQuPC9tYWluPmAsXG4gKiB9KVxuICogY2xhc3MgQXBwQ29tcG9uZW50IHtcbiAqICAgdmNyID0gaW5qZWN0KFZpZXdDb250YWluZXJSZWYpO1xuICpcbiAqICAgbmdBZnRlclZpZXdJbml0KCkge1xuICogICAgIGNvbnN0IGNvbXBSZWYgPSB0aGlzLnZjci5jcmVhdGVDb21wb25lbnQoRHluYW1pY0NvbXBvbmVudCk7XG4gKiAgICAgY29tcFJlZi5jaGFuZ2VEZXRlY3RvclJlZi5kZXRlY3RDaGFuZ2VzKCk7XG4gKiAgIH1cbiAqIH1cbiAqIGBgYFxuICpcbiAqIEBzZWUge0BsaW5rIENvbXBvbmVudFJlZn1cbiAqIEBzZWUge0BsaW5rIEVtYmVkZGVkVmlld1JlZn1cbiAqXG4gKiBAcHVibGljQXBpXG4gKi9cbmV4cG9ydCBhYnN0cmFjdCBjbGFzcyBWaWV3Q29udGFpbmVyUmVmIHtcbiAgLyoqXG4gICAqIEFuY2hvciBlbGVtZW50IHRoYXQgc3BlY2lmaWVzIHRoZSBsb2NhdGlvbiBvZiB0aGlzIGNvbnRhaW5lciBpbiB0aGUgY29udGFpbmluZyB2aWV3LlxuICAgKiBFYWNoIHZpZXcgY29udGFpbmVyIGNhbiBoYXZlIG9ubHkgb25lIGFuY2hvciBlbGVtZW50LCBhbmQgZWFjaCBhbmNob3IgZWxlbWVudFxuICAgKiBjYW4gaGF2ZSBvbmx5IGEgc2luZ2xlIHZpZXcgY29udGFpbmVyLlxuICAgKlxuICAgKiBSb290IGVsZW1lbnRzIG9mIHZpZXdzIGF0dGFjaGVkIHRvIHRoaXMgY29udGFpbmVyIGJlY29tZSBzaWJsaW5ncyBvZiB0aGUgYW5jaG9yIGVsZW1lbnQgaW5cbiAgICogdGhlIHJlbmRlcmVkIHZpZXcuXG4gICAqXG4gICAqIEFjY2VzcyB0aGUgYFZpZXdDb250YWluZXJSZWZgIG9mIGFuIGVsZW1lbnQgYnkgcGxhY2luZyBhIGBEaXJlY3RpdmVgIGluamVjdGVkXG4gICAqIHdpdGggYFZpZXdDb250YWluZXJSZWZgIG9uIHRoZSBlbGVtZW50LCBvciB1c2UgYSBgVmlld0NoaWxkYCBxdWVyeS5cbiAgICpcbiAgICogPCEtLSBUT0RPOiByZW5hbWUgdG8gYW5jaG9yRWxlbWVudCAtLT5cbiAgICovXG4gIGFic3RyYWN0IGdldCBlbGVtZW50KCk6IEVsZW1lbnRSZWY7XG5cbiAgLyoqXG4gICAqIFRoZSBkZXBlbmRlbmN5IGluamVjdG9yIGZvciB0aGlzIHZpZXcgY29udGFpbmVyLlxuICAgKi9cbiAgYWJzdHJhY3QgZ2V0IGluamVjdG9yKCk6IEluamVjdG9yO1xuXG4gIC8qKiBAZGVwcmVjYXRlZCBObyByZXBsYWNlbWVudCAqL1xuICBhYnN0cmFjdCBnZXQgcGFyZW50SW5qZWN0b3IoKTogSW5qZWN0b3I7XG5cbiAgLyoqXG4gICAqIERlc3Ryb3lzIGFsbCB2aWV3cyBpbiB0aGlzIGNvbnRhaW5lci5cbiAgICovXG4gIGFic3RyYWN0IGNsZWFyKCk6IHZvaWQ7XG5cbiAgLyoqXG4gICAqIFJldHJpZXZlcyBhIHZpZXcgZnJvbSB0aGlzIGNvbnRhaW5lci5cbiAgICogQHBhcmFtIGluZGV4IFRoZSAwLWJhc2VkIGluZGV4IG9mIHRoZSB2aWV3IHRvIHJldHJpZXZlLlxuICAgKiBAcmV0dXJucyBUaGUgYFZpZXdSZWZgIGluc3RhbmNlLCBvciBudWxsIGlmIHRoZSBpbmRleCBpcyBvdXQgb2YgcmFuZ2UuXG4gICAqL1xuICBhYnN0cmFjdCBnZXQoaW5kZXg6IG51bWJlcik6IFZpZXdSZWYgfCBudWxsO1xuXG4gIC8qKlxuICAgKiBSZXBvcnRzIGhvdyBtYW55IHZpZXdzIGFyZSBjdXJyZW50bHkgYXR0YWNoZWQgdG8gdGhpcyBjb250YWluZXIuXG4gICAqIEByZXR1cm5zIFRoZSBudW1iZXIgb2Ygdmlld3MuXG4gICAqL1xuICBhYnN0cmFjdCBnZXQgbGVuZ3RoKCk6IG51bWJlcjtcblxuICAvKipcbiAgICogSW5zdGFudGlhdGVzIGFuIGVtYmVkZGVkIHZpZXcgYW5kIGluc2VydHMgaXRcbiAgICogaW50byB0aGlzIGNvbnRhaW5lci5cbiAgICogQHBhcmFtIHRlbXBsYXRlUmVmIFRoZSBIVE1MIHRlbXBsYXRlIHRoYXQgZGVmaW5lcyB0aGUgdmlldy5cbiAgICogQHBhcmFtIGNvbnRleHQgVGhlIGRhdGEtYmluZGluZyBjb250ZXh0IG9mIHRoZSBlbWJlZGRlZCB2aWV3LCBhcyBkZWNsYXJlZFxuICAgKiBpbiB0aGUgYDxuZy10ZW1wbGF0ZT5gIHVzYWdlLlxuICAgKiBAcGFyYW0gb3B0aW9ucyBFeHRyYSBjb25maWd1cmF0aW9uIGZvciB0aGUgY3JlYXRlZCB2aWV3LiBJbmNsdWRlczpcbiAgICogICogaW5kZXg6IFRoZSAwLWJhc2VkIGluZGV4IGF0IHdoaWNoIHRvIGluc2VydCB0aGUgbmV3IHZpZXcgaW50byB0aGlzIGNvbnRhaW5lci5cbiAgICogICAgICAgICAgIElmIG5vdCBzcGVjaWZpZWQsIGFwcGVuZHMgdGhlIG5ldyB2aWV3IGFzIHRoZSBsYXN0IGVudHJ5LlxuICAgKiAgKiBpbmplY3RvcjogSW5qZWN0b3IgdG8gYmUgdXNlZCB3aXRoaW4gdGhlIGVtYmVkZGVkIHZpZXcuXG4gICAqXG4gICAqIEByZXR1cm5zIFRoZSBgVmlld1JlZmAgaW5zdGFuY2UgZm9yIHRoZSBuZXdseSBjcmVhdGVkIHZpZXcuXG4gICAqL1xuICBhYnN0cmFjdCBjcmVhdGVFbWJlZGRlZFZpZXc8Qz4oXG4gICAgdGVtcGxhdGVSZWY6IFRlbXBsYXRlUmVmPEM+LFxuICAgIGNvbnRleHQ/OiBDLFxuICAgIG9wdGlvbnM/OiB7XG4gICAgICBpbmRleD86IG51bWJlcjtcbiAgICAgIGluamVjdG9yPzogSW5qZWN0b3I7XG4gICAgfSxcbiAgKTogRW1iZWRkZWRWaWV3UmVmPEM+O1xuXG4gIC8qKlxuICAgKiBJbnN0YW50aWF0ZXMgYW4gZW1iZWRkZWQgdmlldyBhbmQgaW5zZXJ0cyBpdFxuICAgKiBpbnRvIHRoaXMgY29udGFpbmVyLlxuICAgKiBAcGFyYW0gdGVtcGxhdGVSZWYgVGhlIEhUTUwgdGVtcGxhdGUgdGhhdCBkZWZpbmVzIHRoZSB2aWV3LlxuICAgKiBAcGFyYW0gY29udGV4dCBUaGUgZGF0YS1iaW5kaW5nIGNvbnRleHQgb2YgdGhlIGVtYmVkZGVkIHZpZXcsIGFzIGRlY2xhcmVkXG4gICAqIGluIHRoZSBgPG5nLXRlbXBsYXRlPmAgdXNhZ2UuXG4gICAqIEBwYXJhbSBpbmRleCBUaGUgMC1iYXNlZCBpbmRleCBhdCB3aGljaCB0byBpbnNlcnQgdGhlIG5ldyB2aWV3IGludG8gdGhpcyBjb250YWluZXIuXG4gICAqIElmIG5vdCBzcGVjaWZpZWQsIGFwcGVuZHMgdGhlIG5ldyB2aWV3IGFzIHRoZSBsYXN0IGVudHJ5LlxuICAgKlxuICAgKiBAcmV0dXJucyBUaGUgYFZpZXdSZWZgIGluc3RhbmNlIGZvciB0aGUgbmV3bHkgY3JlYXRlZCB2aWV3LlxuICAgKi9cbiAgYWJzdHJhY3QgY3JlYXRlRW1iZWRkZWRWaWV3PEM+KFxuICAgIHRlbXBsYXRlUmVmOiBUZW1wbGF0ZVJlZjxDPixcbiAgICBjb250ZXh0PzogQyxcbiAgICBpbmRleD86IG51bWJlcixcbiAgKTogRW1iZWRkZWRWaWV3UmVmPEM+O1xuXG4gIC8qKlxuICAgKiBJbnN0YW50aWF0ZXMgYSBzaW5nbGUgY29tcG9uZW50IGFuZCBpbnNlcnRzIGl0cyBob3N0IHZpZXcgaW50byB0aGlzIGNvbnRhaW5lci5cbiAgICpcbiAgICogQHBhcmFtIGNvbXBvbmVudFR5cGUgQ29tcG9uZW50IFR5cGUgdG8gdXNlLlxuICAgKiBAcGFyYW0gb3B0aW9ucyBBbiBvYmplY3QgdGhhdCBjb250YWlucyBleHRyYSBwYXJhbWV0ZXJzOlxuICAgKiAgKiBpbmRleDogdGhlIGluZGV4IGF0IHdoaWNoIHRvIGluc2VydCB0aGUgbmV3IGNvbXBvbmVudCdzIGhvc3QgdmlldyBpbnRvIHRoaXMgY29udGFpbmVyLlxuICAgKiAgICAgICAgICAgSWYgbm90IHNwZWNpZmllZCwgYXBwZW5kcyB0aGUgbmV3IHZpZXcgYXMgdGhlIGxhc3QgZW50cnkuXG4gICAqICAqIGluamVjdG9yOiB0aGUgaW5qZWN0b3IgdG8gdXNlIGFzIHRoZSBwYXJlbnQgZm9yIHRoZSBuZXcgY29tcG9uZW50LlxuICAgKiAgKiBuZ01vZHVsZVJlZjogYW4gTmdNb2R1bGVSZWYgb2YgdGhlIGNvbXBvbmVudCdzIE5nTW9kdWxlLCB5b3Ugc2hvdWxkIGFsbW9zdCBhbHdheXMgcHJvdmlkZVxuICAgKiAgICAgICAgICAgICAgICAgdGhpcyB0byBlbnN1cmUgdGhhdCBhbGwgZXhwZWN0ZWQgcHJvdmlkZXJzIGFyZSBhdmFpbGFibGUgZm9yIHRoZSBjb21wb25lbnRcbiAgICogICAgICAgICAgICAgICAgIGluc3RhbnRpYXRpb24uXG4gICAqICAqIGVudmlyb25tZW50SW5qZWN0b3I6IGFuIEVudmlyb25tZW50SW5qZWN0b3Igd2hpY2ggd2lsbCBwcm92aWRlIHRoZSBjb21wb25lbnQncyBlbnZpcm9ubWVudC5cbiAgICogICAgICAgICAgICAgICAgIHlvdSBzaG91bGQgYWxtb3N0IGFsd2F5cyBwcm92aWRlIHRoaXMgdG8gZW5zdXJlIHRoYXQgYWxsIGV4cGVjdGVkIHByb3ZpZGVyc1xuICAgKiAgICAgICAgICAgICAgICAgYXJlIGF2YWlsYWJsZSBmb3IgdGhlIGNvbXBvbmVudCBpbnN0YW50aWF0aW9uLiBUaGlzIG9wdGlvbiBpcyBpbnRlbmRlZCB0b1xuICAgKiAgICAgICAgICAgICAgICAgcmVwbGFjZSB0aGUgYG5nTW9kdWxlUmVmYCBwYXJhbWV0ZXIuXG4gICAqICAqIHByb2plY3RhYmxlTm9kZXM6IGxpc3Qgb2YgRE9NIG5vZGVzIHRoYXQgc2hvd