@angular/compiler
Version:
Angular - the compiler library
831 lines • 143 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 { rendererTypeName, tokenReference, viewClassName } from '../compile_metadata';
import { BindingForm, convertActionBinding, convertPropertyBinding, convertPropertyBindingBuiltins, EventHandlerVars } from '../compiler_util/expression_converter';
import { ChangeDetectionStrategy } from '../core';
import { Identifiers } from '../identifiers';
import { LifecycleHooks } from '../lifecycle_reflector';
import { isNgContainer } from '../ml_parser/tags';
import * as o from '../output/output_ast';
import { convertValueToOutputAst } from '../output/value_util';
import { ElementAst, EmbeddedTemplateAst, NgContentAst, templateVisitAll } from '../template_parser/template_ast';
import { componentFactoryResolverProviderDef, depDef, lifecycleHookToNodeFlag, providerDef } from './provider_compiler';
const CLASS_ATTR = 'class';
const STYLE_ATTR = 'style';
const IMPLICIT_TEMPLATE_VAR = '$implicit';
export class ViewCompileResult {
constructor(viewClassVar, rendererTypeVar) {
this.viewClassVar = viewClassVar;
this.rendererTypeVar = rendererTypeVar;
}
}
export class ViewCompiler {
constructor(_reflector) {
this._reflector = _reflector;
}
compileComponent(outputCtx, component, template, styles, usedPipes) {
let embeddedViewCount = 0;
let renderComponentVarName = undefined;
if (!component.isHost) {
const template = component.template;
const customRenderData = [];
if (template.animations && template.animations.length) {
customRenderData.push(new o.LiteralMapEntry('animation', convertValueToOutputAst(outputCtx, template.animations), true));
}
const renderComponentVar = o.variable(rendererTypeName(component.type.reference));
renderComponentVarName = renderComponentVar.name;
outputCtx.statements.push(renderComponentVar
.set(o.importExpr(Identifiers.createRendererType2).callFn([new o.LiteralMapExpr([
new o.LiteralMapEntry('encapsulation', o.literal(template.encapsulation), false),
new o.LiteralMapEntry('styles', styles, false),
new o.LiteralMapEntry('data', new o.LiteralMapExpr(customRenderData), false)
])]))
.toDeclStmt(o.importType(Identifiers.RendererType2), [o.StmtModifier.Final, o.StmtModifier.Exported]));
}
const viewBuilderFactory = (parent) => {
const embeddedViewIndex = embeddedViewCount++;
return new ViewBuilder(this._reflector, outputCtx, parent, component, embeddedViewIndex, usedPipes, viewBuilderFactory);
};
const visitor = viewBuilderFactory(null);
visitor.visitAll([], template);
outputCtx.statements.push(...visitor.build());
return new ViewCompileResult(visitor.viewName, renderComponentVarName);
}
}
const LOG_VAR = o.variable('_l');
const VIEW_VAR = o.variable('_v');
const CHECK_VAR = o.variable('_ck');
const COMP_VAR = o.variable('_co');
const EVENT_NAME_VAR = o.variable('en');
const ALLOW_DEFAULT_VAR = o.variable(`ad`);
class ViewBuilder {
constructor(reflector, outputCtx, parent, component, embeddedViewIndex, usedPipes, viewBuilderFactory) {
this.reflector = reflector;
this.outputCtx = outputCtx;
this.parent = parent;
this.component = component;
this.embeddedViewIndex = embeddedViewIndex;
this.usedPipes = usedPipes;
this.viewBuilderFactory = viewBuilderFactory;
this.nodes = [];
this.purePipeNodeIndices = Object.create(null);
// Need Object.create so that we don't have builtin values...
this.refNodeIndices = Object.create(null);
this.variables = [];
this.children = [];
// TODO(tbosch): The old view compiler used to use an `any` type
// for the context in any embedded view. We keep this behaivor for now
// to be able to introduce the new view compiler without too many errors.
this.compType = this.embeddedViewIndex > 0 ?
o.DYNAMIC_TYPE :
o.expressionType(outputCtx.importExpr(this.component.type.reference));
this.viewName = viewClassName(this.component.type.reference, this.embeddedViewIndex);
}
visitAll(variables, astNodes) {
this.variables = variables;
// create the pipes for the pure pipes immediately, so that we know their indices.
if (!this.parent) {
this.usedPipes.forEach((pipe) => {
if (pipe.pure) {
this.purePipeNodeIndices[pipe.name] = this._createPipe(null, pipe);
}
});
}
if (!this.parent) {
this.component.viewQueries.forEach((query, queryIndex) => {
// Note: queries start with id 1 so we can use the number in a Bloom filter!
const queryId = queryIndex + 1;
const bindingType = query.first ? 0 /* First */ : 1 /* All */;
const flags = 134217728 /* TypeViewQuery */ | calcQueryFlags(query);
this.nodes.push(() => ({
sourceSpan: null,
nodeFlags: flags,
nodeDef: o.importExpr(Identifiers.queryDef).callFn([
o.literal(flags), o.literal(queryId),
new o.LiteralMapExpr([new o.LiteralMapEntry(query.propertyName, o.literal(bindingType), false)])
])
}));
});
}
templateVisitAll(this, astNodes);
if (this.parent && (astNodes.length === 0 || needsAdditionalRootNode(astNodes))) {
// if the view is an embedded view, then we need to add an additional root node in some cases
this.nodes.push(() => ({
sourceSpan: null,
nodeFlags: 1 /* TypeElement */,
nodeDef: o.importExpr(Identifiers.anchorDef).callFn([
o.literal(0 /* None */), o.NULL_EXPR, o.NULL_EXPR, o.literal(0)
])
}));
}
}
build(targetStatements = []) {
this.children.forEach((child) => child.build(targetStatements));
const { updateRendererStmts, updateDirectivesStmts, nodeDefExprs } = this._createNodeExpressions();
const updateRendererFn = this._createUpdateFn(updateRendererStmts);
const updateDirectivesFn = this._createUpdateFn(updateDirectivesStmts);
let viewFlags = 0 /* None */;
if (!this.parent && this.component.changeDetection === ChangeDetectionStrategy.OnPush) {
viewFlags |= 2 /* OnPush */;
}
const viewFactory = new o.DeclareFunctionStmt(this.viewName, [new o.FnParam(LOG_VAR.name)], [new o.ReturnStatement(o.importExpr(Identifiers.viewDef).callFn([
o.literal(viewFlags),
o.literalArr(nodeDefExprs),
updateDirectivesFn,
updateRendererFn,
]))], o.importType(Identifiers.ViewDefinition), this.embeddedViewIndex === 0 ? [o.StmtModifier.Exported] : []);
targetStatements.push(viewFactory);
return targetStatements;
}
_createUpdateFn(updateStmts) {
let updateFn;
if (updateStmts.length > 0) {
const preStmts = [];
if (!this.component.isHost && o.findReadVarNames(updateStmts).has(COMP_VAR.name)) {
preStmts.push(COMP_VAR.set(VIEW_VAR.prop('component')).toDeclStmt(this.compType));
}
updateFn = o.fn([
new o.FnParam(CHECK_VAR.name, o.INFERRED_TYPE),
new o.FnParam(VIEW_VAR.name, o.INFERRED_TYPE)
], [...preStmts, ...updateStmts], o.INFERRED_TYPE);
}
else {
updateFn = o.NULL_EXPR;
}
return updateFn;
}
visitNgContent(ast, context) {
// ngContentDef(ngContentIndex: number, index: number): NodeDef;
this.nodes.push(() => ({
sourceSpan: ast.sourceSpan,
nodeFlags: 8 /* TypeNgContent */,
nodeDef: o.importExpr(Identifiers.ngContentDef)
.callFn([o.literal(ast.ngContentIndex), o.literal(ast.index)])
}));
}
visitText(ast, context) {
// Static text nodes have no check function
const checkIndex = -1;
this.nodes.push(() => ({
sourceSpan: ast.sourceSpan,
nodeFlags: 2 /* TypeText */,
nodeDef: o.importExpr(Identifiers.textDef).callFn([
o.literal(checkIndex),
o.literal(ast.ngContentIndex),
o.literalArr([o.literal(ast.value)]),
])
}));
}
visitBoundText(ast, context) {
const nodeIndex = this.nodes.length;
// reserve the space in the nodeDefs array
this.nodes.push(null);
const astWithSource = ast.value;
const inter = astWithSource.ast;
const updateRendererExpressions = inter.expressions.map((expr, bindingIndex) => this._preprocessUpdateExpression({ nodeIndex, bindingIndex, sourceSpan: ast.sourceSpan, context: COMP_VAR, value: expr }));
// Check index is the same as the node index during compilation
// They might only differ at runtime
const checkIndex = nodeIndex;
this.nodes[nodeIndex] = () => ({
sourceSpan: ast.sourceSpan,
nodeFlags: 2 /* TypeText */,
nodeDef: o.importExpr(Identifiers.textDef).callFn([
o.literal(checkIndex),
o.literal(ast.ngContentIndex),
o.literalArr(inter.strings.map(s => o.literal(s))),
]),
updateRenderer: updateRendererExpressions
});
}
visitEmbeddedTemplate(ast, context) {
const nodeIndex = this.nodes.length;
// reserve the space in the nodeDefs array
this.nodes.push(null);
const { flags, queryMatchesExpr, hostEvents } = this._visitElementOrTemplate(nodeIndex, ast);
const childVisitor = this.viewBuilderFactory(this);
this.children.push(childVisitor);
childVisitor.visitAll(ast.variables, ast.children);
const childCount = this.nodes.length - nodeIndex - 1;
// anchorDef(
// flags: NodeFlags, matchedQueries: [string, QueryValueType][], ngContentIndex: number,
// childCount: number, handleEventFn?: ElementHandleEventFn, templateFactory?:
// ViewDefinitionFactory): NodeDef;
this.nodes[nodeIndex] = () => ({
sourceSpan: ast.sourceSpan,
nodeFlags: 1 /* TypeElement */ | flags,
nodeDef: o.importExpr(Identifiers.anchorDef).callFn([
o.literal(flags),
queryMatchesExpr,
o.literal(ast.ngContentIndex),
o.literal(childCount),
this._createElementHandleEventFn(nodeIndex, hostEvents),
o.variable(childVisitor.viewName),
])
});
}
visitElement(ast, context) {
const nodeIndex = this.nodes.length;
// reserve the space in the nodeDefs array so we can add children
this.nodes.push(null);
// Using a null element name creates an anchor.
const elName = isNgContainer(ast.name) ? null : ast.name;
const { flags, usedEvents, queryMatchesExpr, hostBindings: dirHostBindings, hostEvents } = this._visitElementOrTemplate(nodeIndex, ast);
let inputDefs = [];
let updateRendererExpressions = [];
let outputDefs = [];
if (elName) {
const hostBindings = ast.inputs
.map((inputAst) => ({
context: COMP_VAR,
inputAst,
dirAst: null,
}))
.concat(dirHostBindings);
if (hostBindings.length) {
updateRendererExpressions =
hostBindings.map((hostBinding, bindingIndex) => this._preprocessUpdateExpression({
context: hostBinding.context,
nodeIndex,
bindingIndex,
sourceSpan: hostBinding.inputAst.sourceSpan,
value: hostBinding.inputAst.value
}));
inputDefs = hostBindings.map(hostBinding => elementBindingDef(hostBinding.inputAst, hostBinding.dirAst));
}
outputDefs = usedEvents.map(([target, eventName]) => o.literalArr([o.literal(target), o.literal(eventName)]));
}
templateVisitAll(this, ast.children);
const childCount = this.nodes.length - nodeIndex - 1;
const compAst = ast.directives.find(dirAst => dirAst.directive.isComponent);
let compRendererType = o.NULL_EXPR;
let compView = o.NULL_EXPR;
if (compAst) {
compView = this.outputCtx.importExpr(compAst.directive.componentViewType);
compRendererType = this.outputCtx.importExpr(compAst.directive.rendererType);
}
// Check index is the same as the node index during compilation
// They might only differ at runtime
const checkIndex = nodeIndex;
this.nodes[nodeIndex] = () => ({
sourceSpan: ast.sourceSpan,
nodeFlags: 1 /* TypeElement */ | flags,
nodeDef: o.importExpr(Identifiers.elementDef).callFn([
o.literal(checkIndex),
o.literal(flags),
queryMatchesExpr,
o.literal(ast.ngContentIndex),
o.literal(childCount),
o.literal(elName),
elName ? fixedAttrsDef(ast) : o.NULL_EXPR,
inputDefs.length ? o.literalArr(inputDefs) : o.NULL_EXPR,
outputDefs.length ? o.literalArr(outputDefs) : o.NULL_EXPR,
this._createElementHandleEventFn(nodeIndex, hostEvents),
compView,
compRendererType,
]),
updateRenderer: updateRendererExpressions
});
}
_visitElementOrTemplate(nodeIndex, ast) {
let flags = 0 /* None */;
if (ast.hasViewContainer) {
flags |= 16777216 /* EmbeddedViews */;
}
const usedEvents = new Map();
ast.outputs.forEach((event) => {
const { name, target } = elementEventNameAndTarget(event, null);
usedEvents.set(elementEventFullName(target, name), [target, name]);
});
ast.directives.forEach((dirAst) => {
dirAst.hostEvents.forEach((event) => {
const { name, target } = elementEventNameAndTarget(event, dirAst);
usedEvents.set(elementEventFullName(target, name), [target, name]);
});
});
const hostBindings = [];
const hostEvents = [];
this._visitComponentFactoryResolverProvider(ast.directives);
ast.providers.forEach(providerAst => {
let dirAst = undefined;
ast.directives.forEach(localDirAst => {
if (localDirAst.directive.type.reference === tokenReference(providerAst.token)) {
dirAst = localDirAst;
}
});
if (dirAst) {
const { hostBindings: dirHostBindings, hostEvents: dirHostEvents } = this._visitDirective(providerAst, dirAst, ast.references, ast.queryMatches, usedEvents);
hostBindings.push(...dirHostBindings);
hostEvents.push(...dirHostEvents);
}
else {
this._visitProvider(providerAst, ast.queryMatches);
}
});
let queryMatchExprs = [];
ast.queryMatches.forEach((match) => {
let valueType = undefined;
if (tokenReference(match.value) ===
this.reflector.resolveExternalReference(Identifiers.ElementRef)) {
valueType = 0 /* ElementRef */;
}
else if (tokenReference(match.value) ===
this.reflector.resolveExternalReference(Identifiers.ViewContainerRef)) {
valueType = 3 /* ViewContainerRef */;
}
else if (tokenReference(match.value) ===
this.reflector.resolveExternalReference(Identifiers.TemplateRef)) {
valueType = 2 /* TemplateRef */;
}
if (valueType != null) {
queryMatchExprs.push(o.literalArr([o.literal(match.queryId), o.literal(valueType)]));
}
});
ast.references.forEach((ref) => {
let valueType = undefined;
if (!ref.value) {
valueType = 1 /* RenderElement */;
}
else if (tokenReference(ref.value) ===
this.reflector.resolveExternalReference(Identifiers.TemplateRef)) {
valueType = 2 /* TemplateRef */;
}
if (valueType != null) {
this.refNodeIndices[ref.name] = nodeIndex;
queryMatchExprs.push(o.literalArr([o.literal(ref.name), o.literal(valueType)]));
}
});
ast.outputs.forEach((outputAst) => {
hostEvents.push({ context: COMP_VAR, eventAst: outputAst, dirAst: null });
});
return {
flags,
usedEvents: Array.from(usedEvents.values()),
queryMatchesExpr: queryMatchExprs.length ? o.literalArr(queryMatchExprs) : o.NULL_EXPR,
hostBindings,
hostEvents: hostEvents
};
}
_visitDirective(providerAst, dirAst, refs, queryMatches, usedEvents) {
const nodeIndex = this.nodes.length;
// reserve the space in the nodeDefs array so we can add children
this.nodes.push(null);
dirAst.directive.queries.forEach((query, queryIndex) => {
const queryId = dirAst.contentQueryStartId + queryIndex;
const flags = 67108864 /* TypeContentQuery */ | calcQueryFlags(query);
const bindingType = query.first ? 0 /* First */ : 1 /* All */;
this.nodes.push(() => ({
sourceSpan: dirAst.sourceSpan,
nodeFlags: flags,
nodeDef: o.importExpr(Identifiers.queryDef).callFn([
o.literal(flags), o.literal(queryId),
new o.LiteralMapExpr([new o.LiteralMapEntry(query.propertyName, o.literal(bindingType), false)])
]),
}));
});
// Note: the operation below might also create new nodeDefs,
// but we don't want them to be a child of a directive,
// as they might be a provider/pipe on their own.
// I.e. we only allow queries as children of directives nodes.
const childCount = this.nodes.length - nodeIndex - 1;
let { flags, queryMatchExprs, providerExpr, depsExpr } = this._visitProviderOrDirective(providerAst, queryMatches);
refs.forEach((ref) => {
if (ref.value && tokenReference(ref.value) === tokenReference(providerAst.token)) {
this.refNodeIndices[ref.name] = nodeIndex;
queryMatchExprs.push(o.literalArr([o.literal(ref.name), o.literal(4 /* Provider */)]));
}
});
if (dirAst.directive.isComponent) {
flags |= 32768 /* Component */;
}
const inputDefs = dirAst.inputs.map((inputAst, inputIndex) => {
const mapValue = o.literalArr([o.literal(inputIndex), o.literal(inputAst.directiveName)]);
// Note: it's important to not quote the key so that we can capture renames by minifiers!
return new o.LiteralMapEntry(inputAst.directiveName, mapValue, false);
});
const outputDefs = [];
const dirMeta = dirAst.directive;
Object.keys(dirMeta.outputs).forEach((propName) => {
const eventName = dirMeta.outputs[propName];
if (usedEvents.has(eventName)) {
// Note: it's important to not quote the key so that we can capture renames by minifiers!
outputDefs.push(new o.LiteralMapEntry(propName, o.literal(eventName), false));
}
});
let updateDirectiveExpressions = [];
if (dirAst.inputs.length || (flags & (262144 /* DoCheck */ | 65536 /* OnInit */)) > 0) {
updateDirectiveExpressions =
dirAst.inputs.map((input, bindingIndex) => this._preprocessUpdateExpression({
nodeIndex,
bindingIndex,
sourceSpan: input.sourceSpan,
context: COMP_VAR,
value: input.value
}));
}
const dirContextExpr = o.importExpr(Identifiers.nodeValue).callFn([VIEW_VAR, o.literal(nodeIndex)]);
const hostBindings = dirAst.hostProperties.map((inputAst) => ({
context: dirContextExpr,
dirAst,
inputAst,
}));
const hostEvents = dirAst.hostEvents.map((hostEventAst) => ({
context: dirContextExpr,
eventAst: hostEventAst,
dirAst,
}));
// Check index is the same as the node index during compilation
// They might only differ at runtime
const checkIndex = nodeIndex;
this.nodes[nodeIndex] = () => ({
sourceSpan: dirAst.sourceSpan,
nodeFlags: 16384 /* TypeDirective */ | flags,
nodeDef: o.importExpr(Identifiers.directiveDef).callFn([
o.literal(checkIndex),
o.literal(flags),
queryMatchExprs.length ? o.literalArr(queryMatchExprs) : o.NULL_EXPR,
o.literal(childCount),
providerExpr,
depsExpr,
inputDefs.length ? new o.LiteralMapExpr(inputDefs) : o.NULL_EXPR,
outputDefs.length ? new o.LiteralMapExpr(outputDefs) : o.NULL_EXPR,
]),
updateDirectives: updateDirectiveExpressions,
directive: dirAst.directive.type,
});
return { hostBindings, hostEvents };
}
_visitProvider(providerAst, queryMatches) {
this._addProviderNode(this._visitProviderOrDirective(providerAst, queryMatches));
}
_visitComponentFactoryResolverProvider(directives) {
const componentDirMeta = directives.find(dirAst => dirAst.directive.isComponent);
if (componentDirMeta && componentDirMeta.directive.entryComponents.length) {
const { providerExpr, depsExpr, flags, tokenExpr } = componentFactoryResolverProviderDef(this.reflector, this.outputCtx, 8192 /* PrivateProvider */, componentDirMeta.directive.entryComponents);
this._addProviderNode({
providerExpr,
depsExpr,
flags,
tokenExpr,
queryMatchExprs: [],
sourceSpan: componentDirMeta.sourceSpan
});
}
}
_addProviderNode(data) {
// providerDef(
// flags: NodeFlags, matchedQueries: [string, QueryValueType][], token:any,
// value: any, deps: ([DepFlags, any] | any)[]): NodeDef;
this.nodes.push(() => ({
sourceSpan: data.sourceSpan,
nodeFlags: data.flags,
nodeDef: o.importExpr(Identifiers.providerDef).callFn([
o.literal(data.flags),
data.queryMatchExprs.length ? o.literalArr(data.queryMatchExprs) : o.NULL_EXPR,
data.tokenExpr, data.providerExpr, data.depsExpr
])
}));
}
_visitProviderOrDirective(providerAst, queryMatches) {
let flags = 0 /* None */;
let queryMatchExprs = [];
queryMatches.forEach((match) => {
if (tokenReference(match.value) === tokenReference(providerAst.token)) {
queryMatchExprs.push(o.literalArr([o.literal(match.queryId), o.literal(4 /* Provider */)]));
}
});
const { providerExpr, depsExpr, flags: providerFlags, tokenExpr } = providerDef(this.outputCtx, providerAst);
return {
flags: flags | providerFlags,
queryMatchExprs,
providerExpr,
depsExpr,
tokenExpr,
sourceSpan: providerAst.sourceSpan
};
}
getLocal(name) {
if (name == EventHandlerVars.event.name) {
return EventHandlerVars.event;
}
let currViewExpr = VIEW_VAR;
for (let currBuilder = this; currBuilder; currBuilder = currBuilder.parent,
currViewExpr = currViewExpr.prop('parent').cast(o.DYNAMIC_TYPE)) {
// check references
const refNodeIndex = currBuilder.refNodeIndices[name];
if (refNodeIndex != null) {
return o.importExpr(Identifiers.nodeValue).callFn([currViewExpr, o.literal(refNodeIndex)]);
}
// check variables
const varAst = currBuilder.variables.find((varAst) => varAst.name === name);
if (varAst) {
const varValue = varAst.value || IMPLICIT_TEMPLATE_VAR;
return currViewExpr.prop('context').prop(varValue);
}
}
return null;
}
notifyImplicitReceiverUse() {
// Not needed in ViewEngine as ViewEngine walks through the generated
// expressions to figure out if the implicit receiver is used and needs
// to be generated as part of the pre-update statements.
}
maybeRestoreView() {
// Not necessary in ViewEngine, because view restoration is an Ivy concept.
}
_createLiteralArrayConverter(sourceSpan, argCount) {
if (argCount === 0) {
const valueExpr = o.importExpr(Identifiers.EMPTY_ARRAY);
return () => valueExpr;
}
const checkIndex = this.nodes.length;
this.nodes.push(() => ({
sourceSpan,
nodeFlags: 32 /* TypePureArray */,
nodeDef: o.importExpr(Identifiers.pureArrayDef).callFn([
o.literal(checkIndex),
o.literal(argCount),
])
}));
return (args) => callCheckStmt(checkIndex, args);
}
_createLiteralMapConverter(sourceSpan, keys) {
if (keys.length === 0) {
const valueExpr = o.importExpr(Identifiers.EMPTY_MAP);
return () => valueExpr;
}
const map = o.literalMap(keys.map((e, i) => ({ ...e, value: o.literal(i) })));
const checkIndex = this.nodes.length;
this.nodes.push(() => ({
sourceSpan,
nodeFlags: 64 /* TypePureObject */,
nodeDef: o.importExpr(Identifiers.pureObjectDef).callFn([
o.literal(checkIndex),
map,
])
}));
return (args) => callCheckStmt(checkIndex, args);
}
_createPipeConverter(expression, name, argCount) {
const pipe = this.usedPipes.find((pipeSummary) => pipeSummary.name === name);
if (pipe.pure) {
const checkIndex = this.nodes.length;
this.nodes.push(() => ({
sourceSpan: expression.sourceSpan,
nodeFlags: 128 /* TypePurePipe */,
nodeDef: o.importExpr(Identifiers.purePipeDef).callFn([
o.literal(checkIndex),
o.literal(argCount),
])
}));
// find underlying pipe in the component view
let compViewExpr = VIEW_VAR;
let compBuilder = this;
while (compBuilder.parent) {
compBuilder = compBuilder.parent;
compViewExpr = compViewExpr.prop('parent').cast(o.DYNAMIC_TYPE);
}
const pipeNodeIndex = compBuilder.purePipeNodeIndices[name];
const pipeValueExpr = o.importExpr(Identifiers.nodeValue).callFn([compViewExpr, o.literal(pipeNodeIndex)]);
return (args) => callCheckStmt(checkIndex, [pipeValueExpr].concat(args));
}
else {
const nodeIndex = this._createPipe(expression.sourceSpan, pipe);
const nodeValueExpr = o.importExpr(Identifiers.nodeValue).callFn([VIEW_VAR, o.literal(nodeIndex)]);
return (args) => nodeValueExpr.prop('transform').callFn(args);
}
}
_createPipe(sourceSpan, pipe) {
const nodeIndex = this.nodes.length;
let flags = 0 /* None */;
pipe.type.lifecycleHooks.forEach((lifecycleHook) => {
// for pipes, we only support ngOnDestroy
if (lifecycleHook === LifecycleHooks.OnDestroy) {
flags |= lifecycleHookToNodeFlag(lifecycleHook);
}
});
const depExprs = pipe.type.diDeps.map((diDep) => depDef(this.outputCtx, diDep));
// function pipeDef(
// flags: NodeFlags, ctor: any, deps: ([DepFlags, any] | any)[]): NodeDef
this.nodes.push(() => ({
sourceSpan,
nodeFlags: 16 /* TypePipe */,
nodeDef: o.importExpr(Identifiers.pipeDef).callFn([
o.literal(flags), this.outputCtx.importExpr(pipe.type.reference), o.literalArr(depExprs)
])
}));
return nodeIndex;
}
/**
* For the AST in `UpdateExpression.value`:
* - create nodes for pipes, literal arrays and, literal maps,
* - update the AST to replace pipes, literal arrays and, literal maps with calls to check fn.
*
* WARNING: This might create new nodeDefs (for pipes and literal arrays and literal maps)!
*/
_preprocessUpdateExpression(expression) {
return {
nodeIndex: expression.nodeIndex,
bindingIndex: expression.bindingIndex,
sourceSpan: expression.sourceSpan,
context: expression.context,
value: convertPropertyBindingBuiltins({
createLiteralArrayConverter: (argCount) => this._createLiteralArrayConverter(expression.sourceSpan, argCount),
createLiteralMapConverter: (keys) => this._createLiteralMapConverter(expression.sourceSpan, keys),
createPipeConverter: (name, argCount) => this._createPipeConverter(expression, name, argCount)
}, expression.value)
};
}
_createNodeExpressions() {
const self = this;
let updateBindingCount = 0;
const updateRendererStmts = [];
const updateDirectivesStmts = [];
const nodeDefExprs = this.nodes.map((factory, nodeIndex) => {
const { nodeDef, nodeFlags, updateDirectives, updateRenderer, sourceSpan } = factory();
if (updateRenderer) {
updateRendererStmts.push(...createUpdateStatements(nodeIndex, sourceSpan, updateRenderer, false));
}
if (updateDirectives) {
updateDirectivesStmts.push(...createUpdateStatements(nodeIndex, sourceSpan, updateDirectives, (nodeFlags & (262144 /* DoCheck */ | 65536 /* OnInit */)) > 0));
}
// We use a comma expression to call the log function before
// the nodeDef function, but still use the result of the nodeDef function
// as the value.
// Note: We only add the logger to elements / text nodes,
// so we don't generate too much code.
const logWithNodeDef = nodeFlags & 3 /* CatRenderNode */ ?
new o.CommaExpr([LOG_VAR.callFn([]).callFn([]), nodeDef]) :
nodeDef;
return o.applySourceSpanToExpressionIfNeeded(logWithNodeDef, sourceSpan);
});
return { updateRendererStmts, updateDirectivesStmts, nodeDefExprs };
function createUpdateStatements(nodeIndex, sourceSpan, expressions, allowEmptyExprs) {
const updateStmts = [];
const exprs = expressions.map(({ sourceSpan, context, value }) => {
const bindingId = `${updateBindingCount++}`;
const nameResolver = context === COMP_VAR ? self : null;
const { stmts, currValExpr } = convertPropertyBinding(nameResolver, context, value, bindingId, BindingForm.General);
updateStmts.push(...stmts.map((stmt) => o.applySourceSpanToStatementIfNeeded(stmt, sourceSpan)));
return o.applySourceSpanToExpressionIfNeeded(currValExpr, sourceSpan);
});
if (expressions.length || allowEmptyExprs) {
updateStmts.push(o.applySourceSpanToStatementIfNeeded(callCheckStmt(nodeIndex, exprs).toStmt(), sourceSpan));
}
return updateStmts;
}
}
_createElementHandleEventFn(nodeIndex, handlers) {
const handleEventStmts = [];
let handleEventBindingCount = 0;
handlers.forEach(({ context, eventAst, dirAst }) => {
const bindingId = `${handleEventBindingCount++}`;
const nameResolver = context === COMP_VAR ? this : null;
const { stmts, allowDefault } = convertActionBinding(nameResolver, context, eventAst.handler, bindingId);
const trueStmts = stmts;
if (allowDefault) {
trueStmts.push(ALLOW_DEFAULT_VAR.set(allowDefault.and(ALLOW_DEFAULT_VAR)).toStmt());
}
const { target: eventTarget, name: eventName } = elementEventNameAndTarget(eventAst, dirAst);
const fullEventName = elementEventFullName(eventTarget, eventName);
handleEventStmts.push(o.applySourceSpanToStatementIfNeeded(new o.IfStmt(o.literal(fullEventName).identical(EVENT_NAME_VAR), trueStmts), eventAst.sourceSpan));
});
let handleEventFn;
if (handleEventStmts.length > 0) {
const preStmts = [ALLOW_DEFAULT_VAR.set(o.literal(true)).toDeclStmt(o.BOOL_TYPE)];
if (!this.component.isHost && o.findReadVarNames(handleEventStmts).has(COMP_VAR.name)) {
preStmts.push(COMP_VAR.set(VIEW_VAR.prop('component')).toDeclStmt(this.compType));
}
handleEventFn = o.fn([
new o.FnParam(VIEW_VAR.name, o.INFERRED_TYPE),
new o.FnParam(EVENT_NAME_VAR.name, o.INFERRED_TYPE),
new o.FnParam(EventHandlerVars.event.name, o.INFERRED_TYPE)
], [...preStmts, ...handleEventStmts, new o.ReturnStatement(ALLOW_DEFAULT_VAR)], o.INFERRED_TYPE);
}
else {
handleEventFn = o.NULL_EXPR;
}
return handleEventFn;
}
visitDirective(ast, context) { }
visitDirectiveProperty(ast, context) { }
visitReference(ast, context) { }
visitVariable(ast, context) { }
visitEvent(ast, context) { }
visitElementProperty(ast, context) { }
visitAttr(ast, context) { }
}
function needsAdditionalRootNode(astNodes) {
const lastAstNode = astNodes[astNodes.length - 1];
if (lastAstNode instanceof EmbeddedTemplateAst) {
return lastAstNode.hasViewContainer;
}
if (lastAstNode instanceof ElementAst) {
if (isNgContainer(lastAstNode.name) && lastAstNode.children.length) {
return needsAdditionalRootNode(lastAstNode.children);
}
return lastAstNode.hasViewContainer;
}
return lastAstNode instanceof NgContentAst;
}
function elementBindingDef(inputAst, dirAst) {
const inputType = inputAst.type;
switch (inputType) {
case 1 /* Attribute */:
return o.literalArr([
o.literal(1 /* TypeElementAttribute */), o.literal(inputAst.name),
o.literal(inputAst.securityContext)
]);
case 0 /* Property */:
return o.literalArr([
o.literal(8 /* TypeProperty */), o.literal(inputAst.name),
o.literal(inputAst.securityContext)
]);
case 4 /* Animation */:
const bindingType = 8 /* TypeProperty */ |
(dirAst && dirAst.directive.isComponent ? 32 /* SyntheticHostProperty */ :
16 /* SyntheticProperty */);
return o.literalArr([
o.literal(bindingType), o.literal('@' + inputAst.name), o.literal(inputAst.securityContext)
]);
case 2 /* Class */:
return o.literalArr([o.literal(2 /* TypeElementClass */), o.literal(inputAst.name), o.NULL_EXPR]);
case 3 /* Style */:
return o.literalArr([
o.literal(4 /* TypeElementStyle */), o.literal(inputAst.name), o.literal(inputAst.unit)
]);
default:
// This default case is not needed by TypeScript compiler, as the switch is exhaustive.
// However Closure Compiler does not understand that and reports an error in typed mode.
// The `throw new Error` below works around the problem, and the unexpected: never variable
// makes sure tsc still checks this code is unreachable.
const unexpected = inputType;
throw new Error(`unexpected ${unexpected}`);
}
}
function fixedAttrsDef(elementAst) {
const mapResult = Object.create(null);
elementAst.attrs.forEach(attrAst => {
mapResult[attrAst.name] = attrAst.value;
});
elementAst.directives.forEach(dirAst => {
Object.keys(dirAst.directive.hostAttributes).forEach(name => {
const value = dirAst.directive.hostAttributes[name];
const prevValue = mapResult[name];
mapResult[name] = prevValue != null ? mergeAttributeValue(name, prevValue, value) : value;
});
});
// Note: We need to sort to get a defined output order
// for tests and for caching generated artifacts...
return o.literalArr(Object.keys(mapResult).sort().map((attrName) => o.literalArr([o.literal(attrName), o.literal(mapResult[attrName])])));
}
function mergeAttributeValue(attrName, attrValue1, attrValue2) {
if (attrName == CLASS_ATTR || attrName == STYLE_ATTR) {
return `${attrValue1} ${attrValue2}`;
}
else {
return attrValue2;
}
}
function callCheckStmt(nodeIndex, exprs) {
if (exprs.length > 10) {
return CHECK_VAR.callFn([VIEW_VAR, o.literal(nodeIndex), o.literal(1 /* Dynamic */), o.literalArr(exprs)]);
}
else {
return CHECK_VAR.callFn([VIEW_VAR, o.literal(nodeIndex), o.literal(0 /* Inline */), ...exprs]);
}
}
function elementEventNameAndTarget(eventAst, dirAst) {
if (eventAst.isAnimation) {
return {
name: `@${eventAst.name}.${eventAst.phase}`,
target: dirAst && dirAst.directive.isComponent ? 'component' : null
};
}
else {
return eventAst;
}
}
function calcQueryFlags(query) {
let flags = 0 /* None */;
// Note: We only make queries static that query for a single item and the user specifically
// set the to be static. This is because of backwards compatibility with the old view compiler...
if (query.first && query.static) {
flags |= 268435456 /* StaticQuery */;
}
else {
flags |= 536870912 /* DynamicQuery */;
}
if (query.emitDistinctChangesOnly) {
flags |= -2147483648 /* EmitDistinctChangesOnly */;
}
return flags;
}
export function elementEventFullName(target, name) {
return target ? `${target}:${name}` : name;
}
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidmlld19jb21waWxlci5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uLy4uLy4uLy4uL3BhY2thZ2VzL2NvbXBpbGVyL3NyYy92aWV3X2NvbXBpbGVyL3ZpZXdfY29tcGlsZXIudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUE7Ozs7OztHQU1HO0FBRUgsT0FBTyxFQUFxRSxnQkFBZ0IsRUFBRSxjQUFjLEVBQUUsYUFBYSxFQUFDLE1BQU0scUJBQXFCLENBQUM7QUFFeEosT0FBTyxFQUFDLFdBQVcsRUFBb0Isb0JBQW9CLEVBQUUsc0JBQXNCLEVBQUUsOEJBQThCLEVBQUUsZ0JBQWdCLEVBQWdCLE1BQU0sdUNBQXVDLENBQUM7QUFFbk0sT0FBTyxFQUE2Qix1QkFBdUIsRUFBeUQsTUFBTSxTQUFTLENBQUM7QUFFcEksT0FBTyxFQUFDLFdBQVcsRUFBQyxNQUFNLGdCQUFnQixDQUFDO0FBQzNDLE9BQU8sRUFBQyxjQUFjLEVBQUMsTUFBTSx3QkFBd0IsQ0FBQztBQUN0RCxPQUFPLEVBQUMsYUFBYSxFQUFDLE1BQU0sbUJBQW1CLENBQUM7QUFDaEQsT0FBTyxLQUFLLENBQUMsTUFBTSxzQkFBc0IsQ0FBQztBQUMxQyxPQUFPLEVBQUMsdUJBQXVCLEVBQUMsTUFBTSxzQkFBc0IsQ0FBQztBQUU3RCxPQUFPLEVBQXlHLFVBQVUsRUFBRSxtQkFBbUIsRUFBRSxZQUFZLEVBQStGLGdCQUFnQixFQUF1QixNQUFNLGlDQUFpQyxDQUFDO0FBRTNVLE9BQU8sRUFBQyxtQ0FBbUMsRUFBRSxNQUFNLEVBQUUsdUJBQXVCLEVBQUUsV0FBVyxFQUFDLE1BQU0scUJBQXFCLENBQUM7QUFFdEgsTUFBTSxVQUFVLEdBQUcsT0FBTyxDQUFDO0FBQzNCLE1BQU0sVUFBVSxHQUFHLE9BQU8sQ0FBQztBQUMzQixNQUFNLHFCQUFxQixHQUFHLFdBQVcsQ0FBQztBQUUxQyxNQUFNLE9BQU8saUJBQWlCO0lBQzVCLFlBQW1CLFlBQW9CLEVBQVMsZUFBdUI7UUFBcEQsaUJBQVksR0FBWixZQUFZLENBQVE7UUFBUyxvQkFBZSxHQUFmLGVBQWUsQ0FBUTtJQUFHLENBQUM7Q0FDNUU7QUFFRCxNQUFNLE9BQU8sWUFBWTtJQUN2QixZQUFvQixVQUE0QjtRQUE1QixlQUFVLEdBQVYsVUFBVSxDQUFrQjtJQUFHLENBQUM7SUFFcEQsZ0JBQWdCLENBQ1osU0FBd0IsRUFBRSxTQUFtQyxFQUFFLFFBQXVCLEVBQ3RGLE1BQW9CLEVBQUUsU0FBK0I7UUFDdkQsSUFBSSxpQkFBaUIsR0FBRyxDQUFDLENBQUM7UUFFMUIsSUFBSSxzQkFBc0IsR0FBVyxTQUFVLENBQUM7UUFDaEQsSUFBSSxDQUFDLFNBQVMsQ0FBQyxNQUFNLEVBQUU7WUFDckIsTUFBTSxRQUFRLEdBQUcsU0FBUyxDQUFDLFFBQVUsQ0FBQztZQUN0QyxNQUFNLGdCQUFnQixHQUF3QixFQUFFLENBQUM7WUFDakQsSUFBSSxRQUFRLENBQUMsVUFBVSxJQUFJLFFBQVEsQ0FBQyxVQUFVLENBQUMsTUFBTSxFQUFFO2dCQUNyRCxnQkFBZ0IsQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLENBQUMsZUFBZSxDQUN2QyxXQUFXLEVBQUUsdUJBQXVCLENBQUMsU0FBUyxFQUFFLFFBQVEsQ0FBQyxVQUFVLENBQUMsRUFBRSxJQUFJLENBQUMsQ0FBQyxDQUFDO2FBQ2xGO1lBRUQsTUFBTSxrQkFBa0IsR0FBRyxDQUFDLENBQUMsUUFBUSxDQUFDLGdCQUFnQixDQUFDLFNBQVMsQ0FBQyxJQUFJLENBQUMsU0FBUyxDQUFDLENBQUMsQ0FBQztZQUNsRixzQkFBc0IsR0FBRyxrQkFBa0IsQ0FBQyxJQUFLLENBQUM7WUFDbEQsU0FBUyxDQUFDLFVBQVUsQ0FBQyxJQUFJLENBQ3JCLGtCQUFrQjtpQkFDYixHQUFHLENBQUMsQ0FBQyxDQUFDLFVBQVUsQ0FBQyxXQUFXLENBQUMsbUJBQW1CLENBQUMsQ0FBQyxNQUFNLENBQUMsQ0FBQyxJQUFJLENBQUMsQ0FBQyxjQUFjLENBQUM7b0JBQzlFLElBQUksQ0FBQyxDQUFDLGVBQWUsQ0FBQyxlQUFlLEVBQUUsQ0FBQyxDQUFDLE9BQU8sQ0FBQyxRQUFRLENBQUMsYUFBYSxDQUFDLEVBQUUsS0FBSyxDQUFDO29CQUNoRixJQUFJLENBQUMsQ0FBQyxlQUFlLENBQUMsUUFBUSxFQUFFLE1BQU0sRUFBRSxLQUFLLENBQUM7b0JBQzlDLElBQUksQ0FBQyxDQUFDLGVBQWUsQ0FBQyxNQUFNLEVBQUUsSUFBSSxDQUFDLENBQUMsY0FBYyxDQUFDLGdCQUFnQixDQUFDLEVBQUUsS0FBSyxDQUFDO2lCQUM3RSxDQUFDLENBQUMsQ0FBQyxDQUFDO2lCQUNKLFVBQVUsQ0FDUCxDQUFDLENBQUMsVUFBVSxDQUFDLFdBQVcsQ0FBQyxhQUFhLENBQUMsRUFDdkMsQ0FBQyxDQUFDLENBQUMsWUFBWSxDQUFDLEtBQUssRUFBRSxDQUFDLENBQUMsWUFBWSxDQUFDLFFBQVEsQ0FBQyxDQUFDLENBQUMsQ0FBQztTQUMvRDtRQUVELE1BQU0sa0JBQWtCLEdBQUcsQ0FBQyxNQUF3QixFQUFlLEVBQUU7WUFDbkUsTUFBTSxpQkFBaUIsR0FBRyxpQkFBaUIsRUFBRSxDQUFDO1lBQzlDLE9BQU8sSUFBSSxXQUFXLENBQ2xCLElBQUksQ0FBQyxVQUFVLEVBQUUsU0FBUyxFQUFFLE1BQU0sRUFBRSxTQUFTLEVBQUUsaUJBQWlCLEVBQUUsU0FBUyxFQUMzRSxrQkFBa0IsQ0FBQyxDQUFDO1FBQzFCLENBQUMsQ0FBQztRQUVGLE1BQU0sT0FBTyxHQUFHLGtCQUFrQixDQUFDLElBQUksQ0FBQyxDQUFDO1FBQ3pDLE9BQU8sQ0FBQyxRQUFRLENBQUMsRUFBRSxFQUFFLFFBQVEsQ0FBQyxDQUFDO1FBRS9CLFNBQVMsQ0FBQyxVQUFVLENBQUMsSUFBSSxDQUFDLEdBQUcsT0FBTyxDQUFDLEtBQUssRUFBRSxDQUFDLENBQUM7UUFFOUMsT0FBTyxJQUFJLGlCQUFpQixDQUFDLE9BQU8sQ0FBQyxRQUFRLEVBQUUsc0JBQXNCLENBQUMsQ0FBQztJQUN6RSxDQUFDO0NBQ0Y7QUFjRCxNQUFNLE9BQU8sR0FBRyxDQUFDLENBQUMsUUFBUSxDQUFDLElBQUksQ0FBQyxDQUFDO0FBQ2pDLE1BQU0sUUFBUSxHQUFHLENBQUMsQ0FBQyxRQUFRLENBQUMsSUFBSSxDQUFDLENBQUM7QUFDbEMsTUFBTSxTQUFTLEdBQUcsQ0FBQyxDQUFDLFFBQVEsQ0FBQyxLQUFLLENBQUMsQ0FBQztBQUNwQyxNQUFNLFFBQVEsR0FBRyxDQUFDLENBQUMsUUFBUSxDQUFDLEtBQUssQ0FBQyxDQUFDO0FBQ25DLE1BQU0sY0FBYyxHQUFHLENBQUMsQ0FBQyxRQUFRLENBQUMsSUFBSSxDQUFDLENBQUM7QUFDeEMsTUFBTSxpQkFBaUIsR0FBRyxDQUFDLENBQUMsUUFBUSxDQUFDLElBQUksQ0FBQyxDQUFDO0FBRTNDLE1BQU0sV0FBVztJQWlCZixZQUNZLFNBQTJCLEVBQVUsU0FBd0IsRUFDN0QsTUFBd0IsRUFBVSxTQUFtQyxFQUNyRSxpQkFBeUIsRUFBVSxTQUErQixFQUNsRSxrQkFBc0M7UUFIdEMsY0FBUyxHQUFULFNBQVMsQ0FBa0I7UUFBVSxjQUFTLEdBQVQsU0FBUyxDQUFlO1FBQzdELFdBQU0sR0FBTixNQUFNLENBQWtCO1FBQVUsY0FBUyxHQUFULFNBQVMsQ0FBMEI7UUFDckUsc0JBQWlCLEdBQWpCLGlCQUFpQixDQUFRO1FBQVUsY0FBUyxHQUFULFNBQVMsQ0FBc0I7UUFDbEUsdUJBQWtCLEdBQWxCLGtCQUFrQixDQUFvQjtRQW5CMUMsVUFBSyxHQU1OLEVBQUUsQ0FBQztRQUNGLHdCQUFtQixHQUFpQyxNQUFNLENBQUMsTUFBTSxDQUFDLElBQUksQ0FBQyxDQUFDO1FBQ2hGLDZEQUE2RDtRQUNyRCxtQkFBYyxHQUFnQyxNQUFNLENBQUMsTUFBTSxDQUFDLElBQUksQ0FBQyxDQUFDO1FBQ2xFLGNBQVMsR0FBa0IsRUFBRSxDQUFDO1FBQzlCLGFBQVEsR0FBa0IsRUFBRSxDQUFDO1FBU25DLGdFQUFnRTtRQUNoRSxzRUFBc0U7UUFDdEUseUVBQXlFO1FBQ3pFLElBQUksQ0FBQyxRQUFRLEdBQUcsSUFBSSxDQUFDLGlCQUFpQixHQUFHLENBQUMsQ0FBQyxDQUFDO1lBQ3hDLENBQUMsQ0FBQyxZQUFZLENBQUMsQ0FBQztZQUNoQixDQUFDLENBQUMsY0FBYyxDQUFDLFNBQVMsQ0FBQyxVQUFVLENBQUMsSUFBSSxDQUFDLFNBQVMsQ0FBQyxJQUFJLENBQUMsU0FBUyxDQUFDLENBQUUsQ0FBQztRQUMzRSxJQUFJLENBQUMsUUFBUSxHQUFHLGFBQWEsQ0FBQyxJQUFJLENBQUMsU0FBUyxDQUFDLElBQUksQ0FBQyxTQUFTLEVBQUUsSUFBSSxDQUFDLGlCQUFpQixDQUFDLENBQUM7SUFDdkYsQ0FBQztJQUVELFFBQVEsQ0FBQyxTQUF3QixFQUFFLFFBQXVCO1FBQ3hELElBQUksQ0FBQyxTQUFTLEdBQUcsU0FBUyxDQUFDO1FBQzNCLGtGQUFrRjtRQUNsRixJQUFJLENBQUMsSUFBSSxDQUFDLE1BQU0sRUFBRTtZQUNoQixJQUFJLENBQUMsU0FBUyxDQUFDLE9BQU8sQ0FBQyxDQUFDLElBQUksRUFBRSxFQUFFO2dCQUM5QixJQUFJLElBQUksQ0FBQyxJQUFJLEVBQUU7b0JBQ2IsSUFBSSxDQUFDLG1CQUFtQixDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsR0FBRyxJQUFJLENBQUMsV0FBVyxDQUFDLElBQUksRUFBRSxJQUFJLENBQUMsQ0FBQztpQkFDcEU7WUFDSCxDQUFDLENBQUMsQ0FBQztTQUNKO1FBRUQsSUFBSSxDQUFDLElBQUksQ0FBQyxNQUFNLEVBQUU7WUFDaEIsSUFBSSxDQUFDLFNBQVMsQ0FBQyxXQUFXLENBQUMsT0FBTyxDQUFDLENBQUMsS0FBSyxFQUFFLFVBQVUsRUFBRSxFQUFFO2dCQUN2RCw0RUFBNEU7Z0JBQzVFLE1BQU0sT0FBTyxHQUFHLFVBQVUsR0FBRyxDQUFDLENBQUM7Z0JBQy9CLE1BQU0sV0FBVyxHQUFHLEtBQUssQ0FBQyxLQUFLLENBQUMsQ0FBQyxlQUF3QixDQUFDLFlBQXFCLENBQUM7Z0JBQ2hGLE1BQU0sS0FBSyxHQUFHLGdDQUEwQixjQUFjLENBQUMsS0FBSyxDQUFDLENBQUM7Z0JBQzlELElBQUksQ0FBQyxLQUFLLENBQUMsSUFBSSxDQUFDLEdBQUcsRUFBRSxDQUFDLENBQUM7b0JBQ0wsVUFBVSxFQUFFLElBQUk7b0JBQ2hCLFNBQVMsRUFBRSxLQUFLO29CQUNoQixPQUFPLEVBQUUsQ0FBQyxDQUFDLFVBQVUsQ0FBQyxXQUFXLENBQUMsUUFBUSxDQUFDLENBQUMsTUFBTSxDQUFDO3dCQUNqRCxDQUFDLENBQUMsT0FBTyxDQUFDLEtBQUssQ0FBQyxFQUFFLENBQUMsQ0FBQyxPQUFPLENBQUMsT0FBTyxDQUFDO3dCQUNwQyxJQUFJLENBQUMsQ0FBQyxjQUFjLENBQUMsQ0FBQyxJQUFJLENBQUMsQ0FBQyxlQUFlLENBQ3ZDLEtBQUssQ0FBQyxZQUFZLEVBQUUsQ0FBQyxDQUFDLE9BQU8sQ0FBQyxXQUFXLENBQUMsRUFBRSxLQUFLLENBQUMsQ0FBQyxDQUFDO3FCQUN6RCxDQUFDO2lCQUNILENBQUMsQ0FBQyxDQUFDO1lBQ3RCLENBQUMsQ0FBQyxDQUFDO1NBQ0o7UUFDRCxnQkFBZ0IsQ0FBQyxJQUFJLEVBQUUsUUFBUSxDQUFDLENBQUM7UUFDakMsSUFBSSxJQUFJLENBQUMsTUFBTSxJQUFJLENBQUMsUUFBUSxDQUFDLE1BQU0sS0FBSyxDQUFDLElBQUksdUJBQXVCLENBQUMsUUFBUSxDQUFDLENBQUMsRUFBRTtZQUMvRSw2RkFBNkY7WUFDN0YsSUFBSSxDQUFDLEtBQUssQ0FBQyxJQUFJLENBQUMsR0FBRyxFQUFFLENBQUMsQ0FBQztnQkFDTCxVQUFVLEVBQUUsSUFBSTtnQkFDaEIsU0FBUyxxQkFBdUI7Z0JBQ2hDLE9BQU8sRUFBRSxDQUFDLENBQUMsVUFBVSxDQUFDLFdBQVcsQ0FBQyxTQUFTLENBQUMsQ0FBQyxNQUFNLENBQUM7b0JBQ2xELENBQUMsQ0FBQyxPQUFPLGNBQWdCLEVBQUUsQ0FBQyxDQUFDLFNBQVMsRUFBRSxDQUFDLENBQUMsU0FBUyxFQUFFLENBQUMsQ0FBQyxPQUFPLENBQUMsQ0FBQyxDQUFDO2lCQUNsRSxDQUFDO2FBQ0gsQ0FBQyxDQUFDLENBQUM7U0FDckI7SUFDSCxDQUFDO0lBRUQsS0FBSyxDQUFDLG1CQUFrQyxFQUFFO1FBQ3hDLElBQUksQ0FBQyxRQUFRLENBQUMsT0FBTyxDQUFDLENBQUMsS0FBSyxFQUFFLEVBQUUsQ0FBQyxLQUFLLENBQUMsS0FBSyxDQUFDLGdCQUFnQixDQUFDLENBQUMsQ0FBQztRQUVoRSxNQUFNLEVBQUMsbUJBQW1CLEVBQUUscUJBQXFCLEVBQUUsWUFBWSxFQUFDLEdBQzVELElBQUksQ0FBQyxzQkFBc0IsRUFBRSxDQUFDO1FBRWxDLE1BQU0sZ0JBQWdCLEdBQUcsSUFBSSxDQUFDLGVBQWUsQ0FBQyxtQkFBbUIsQ0FBQyxDQUFDO1FBQ25FLE1BQU0sa0JBQWtCLEdBQUcsSUFBSSxDQUFDLGVBQWUsQ0FBQyxxQkFBcUIsQ0FBQyxDQUFDO1FBR3ZFLElBQUksU0FBUyxlQUFpQixDQUFDO1FBQy9CLElBQUksQ0FBQyxJQUFJLENBQUMsTUFBTSxJQUFJLElBQUksQ0FBQyxTQUFTLENBQUMsZUFBZSxLQUFLLHVCQUF1QixDQUFDLE1BQU0sRUFBRTtZQUNyRixTQUFTLGtCQUFvQixDQUFDO1NBQy9CO1FBQ0QsTUFBTSxXQUFXLEdBQUcsSUFBSSxDQUFDLENBQUMsbUJBQW1CLENBQ3pDLElBQUksQ0FBQyxRQUFRLEVBQUUsQ0FBQyxJQUFJLENBQUMsQ0FBQyxPQUFPLENBQUMsT0FBTyxDQUFDLElBQUssQ0FBQyxDQUFDLEVBQzdDLENBQUMsSUFBSSxDQUFDLENBQUMsZUFBZSxDQUFDLENBQUMsQ0FBQyxVQUFVLENBQUMsV0FBVyxDQUFDLE9BQU8sQ0FBQyxDQUFDLE1BQU0sQ0FBQztnQkFDOUQsQ0FBQyxDQUFDLE9BQU8sQ0FBQyxTQUFTLENBQUM7Z0JBQ3BCLENBQUMsQ0FBQyxVQUFVLENBQUMsWUFBWSxDQUFDO2dCQUMxQixrQkFBa0I7Z0JBQ2xCLGdCQUFnQjthQUNqQixDQUFDLENBQUMsQ0FBQyxFQUNKLENBQUMsQ0FBQyxVQUFVLENBQUMsV0FBVyxDQUFDLGNBQWMsQ0FBQyxFQUN4QyxJQUFJLENBQUMsaUJBQWlCLEtBQUssQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxZQUFZLENBQUMsUUFBUSxDQUFDLENBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxDQUFDO1FBRW5FLGdCQUFnQixDQUFDLElBQUksQ0FBQyxXQUFXLENBQUMsQ0FBQztRQUNuQyxPQUFPLGdCQUFnQixDQUFDO0lBQzFCLENBQUM7SUFFTyxlQUFlLENBQUMsV0FBMEI7UUFDaEQsSUFBSSxRQUFzQixDQUFDO1FBQzNCLElBQUksV0FBVyxDQUFDLE1BQU0sR0FBRyxDQUFDLEVBQUU7WUFDMUIsTUFBTSxRQUFRLEdBQWtCLEVBQUUsQ0FBQztZQUNuQyxJQUFJLENBQUMsSUFBSSxDQUFDLFNBQVMsQ0FBQyxNQUFNLElBQUksQ0FBQyxDQUFDLGdCQUFnQixDQUFDLFdBQVcsQ0FBQyxDQUFDLEdBQUcsQ0FBQyxRQUFRLENBQUMsSUFBSyxDQUFDLEVBQUU7Z0JBQ2pGLFFBQVEsQ0FBQyxJQUFJLENBQUMsUUFBUSxDQUFDLEdBQUcsQ0FBQyxRQUFRLENBQUMsSUFBSSxDQUFDLFdBQVcsQ0FBQyxDQUFDLENBQUMsVUFBVSxDQUFDLElBQUksQ0FBQyxRQUFRLENBQUMsQ0FBQyxDQUFDO2FBQ25GO1lBQ0QsUUFBUSxHQUFHLENBQUMsQ0FBQyxFQUFFLENBQ1g7Z0JBQ0UsSUFBSSxDQUFDLENBQUMsT0FBTyxDQUFDLFNBQVMsQ0FBQyxJQUFLLEVBQUUsQ0FBQyxDQUFDLGFBQWEsQ0FBQztnQkFDL0MsSUFBSSxDQUFDLENBQUMsT0FBTyxDQUFDLFFBQVEsQ0FBQyxJQUFLLEVBQUUsQ0FBQyxDQUFDLGFBQWEsQ0FBQzthQUMvQyxFQUNELENBQUMsR0FBRyxRQUFRLEVBQUUsR0FBRyxXQUFXLENBQUMsRUFBRSxDQUFDLENBQUMsYUFBYSxDQUFDLENBQUM7U0FDckQ7YUFBTTtZQUNMLFFBQVEsR0FBRyxDQUFDLENBQUMsU0FBUyxDQUFDO1NBQ3hCO1FBQ0QsT0FBTyxRQUFRLENBQUM7SUFDbEIsQ0FBQztJQUVELGNBQWMsQ0FBQyxHQUFpQixFQUFFLE9BQVk7UUFDNUMsZ0VBQWdFO1FBQ2hFLElBQUksQ0FBQyxLQUFLLENBQUMsSUFBSSxDQUFDLEdBQUcsRUFBRSxDQUFDLENBQUM7WUFDTCxVQUFVLEVBQUUsR0FBRyxDQUFDLFVBQVU7WUFDMUIsU0FBUyx1QkFBeUI7WUFDbEMsT0FBTyxFQUFFLENBQUMsQ0FBQyxVQUFVLENBQUMsV0FBVyxDQUFDLFlBQVksQ0FBQztpQkFDakMsTUFBTSxDQUFDLENBQUMsQ0FBQyxDQUFDLE9BQU8sQ0FBQyxHQUFHLENBQUMsY0FBYyxDQUFDLEVBQUUsQ0FBQyxDQUFDLE9BQU8sQ0FBQyxHQUFHLENBQUMsS0FBSyxDQUFDLENBQUMsQ0FBQztTQUM1RSxDQUFDLENBQUMsQ0FBQztJQUN0QixDQUFDO0lBRUQsU0FBUyxDQUFDLEdBQVksRUFBRSxPQUFZO1FBQ2xDLDJDQUEyQztRQUMzQyxNQUFNLFVBQVUsR0FBRyxDQUFDLENBQUMsQ0FBQztRQUN0QixJQUFJLENBQUMsS0FBSyxDQUFDLElBQUksQ0FBQyxHQUFHLEVBQUUsQ0FBQyxDQUFDO1lBQ0wsVUFBVSxFQUFFLEdBQUcsQ0FBQyxVQUFVO1lBQzFCLFNBQVMsa0JBQW9CO1lBQzdCLE9BQU8sRUFBRSxDQUFDLENBQUMsVUFBVSxDQUFDLFdBQVcsQ0FBQyxPQUFPLENBQUMsQ0FBQyxNQUFNLENBQUM7Z0JBQ2hELENBQUMsQ0FBQyxPQUFPLENBQUMsVUFBVSxDQUFDO2dCQUNyQixDQUFDLENBQUMsT0FBTyxDQUFDLEdBQUcsQ0FBQyxjQUFjLENBQUM7Z0JBQzdCLENBQUMsQ0FBQyxVQUFVLENBQUMsQ0FBQyxDQUFDLENBQUMsT0FBTyxDQUFDLEdBQUcsQ0FBQyxLQUFLLENBQUMsQ0FBQyxDQUFDO2FBQ3JDLENBQUM7U0FDSCxDQUFDLENBQUMsQ0F