@angular/core
Version:
Angular - the core framework
452 lines • 83.3 kB
JavaScript
/**
* @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