UNPKG

@angular/core

Version:

Angular - the core framework

642 lines 95.4 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 '../../util/ng_dev_mode'; import '../../util/ng_i18n_closure_mode'; import { XSS_SECURITY_URL } from '../../error_details_base_url'; import { getTemplateContent, URI_ATTRS, VALID_ATTRS, VALID_ELEMENTS } from '../../sanitization/html_sanitizer'; import { getInertBodyHelper } from '../../sanitization/inert_body'; import { _sanitizeUrl } from '../../sanitization/url_sanitizer'; import { assertDefined, assertEqual, assertGreaterThanOrEqual, assertOneOf, assertString } from '../../util/assert'; import { loadIcuContainerVisitor } from '../instructions/i18n_icu_container_visitor'; import { allocExpando, createTNodeAtIndex } from '../instructions/shared'; import { getDocument } from '../interfaces/document'; import { ELEMENT_MARKER, I18nCreateOpCode, ICU_MARKER } from '../interfaces/i18n'; import { HEADER_OFFSET } from '../interfaces/view'; import { getCurrentParentTNode, getCurrentTNode, setCurrentTNode } from '../state'; import { i18nCreateOpCodesToString, i18nRemoveOpCodesToString, i18nUpdateOpCodesToString, icuCreateOpCodesToString } from './i18n_debug'; import { addTNodeAndUpdateInsertBeforeIndex } from './i18n_insert_before_index'; import { ensureIcuContainerVisitorLoaded } from './i18n_tree_shaking'; import { createTNodePlaceholder, icuCreateOpCode, setTIcu, setTNodeInsertBeforeIndex } from './i18n_util'; const BINDING_REGEXP = /�(\d+):?\d*�/gi; const ICU_REGEXP = /({\s*�\d+:?\d*�\s*,\s*\S{6}\s*,[\s\S]*})/gi; const NESTED_ICU = /�(\d+)�/; const ICU_BLOCK_REGEXP = /^\s*(�\d+:?\d*�)\s*,\s*(select|plural)\s*,/; const MARKER = `�`; const SUBTEMPLATE_REGEXP = /�\/?\*(\d+:\d+)�/gi; const PH_REGEXP = /�(\/?[#*]\d+):?\d*�/gi; /** * Angular Dart introduced &ngsp; as a placeholder for non-removable space, see: * https://github.com/dart-lang/angular/blob/0bb611387d29d65b5af7f9d2515ab571fd3fbee4/_tests/test/compiler/preserve_whitespace_test.dart#L25-L32 * In Angular Dart &ngsp; is converted to the 0xE500 PUA (Private Use Areas) unicode character * and later on replaced by a space. We are re-implementing the same idea here, since translations * might contain this special character. */ const NGSP_UNICODE_REGEXP = /\uE500/g; function replaceNgsp(value) { return value.replace(NGSP_UNICODE_REGEXP, ' '); } /** * Patch a `debug` property getter on top of the existing object. * * NOTE: always call this method with `ngDevMode && attachDebugObject(...)` * * @param obj Object to patch * @param debugGetter Getter returning a value to patch */ function attachDebugGetter(obj, debugGetter) { if (ngDevMode) { Object.defineProperty(obj, 'debug', { get: debugGetter, enumerable: false }); } else { throw new Error('This method should be guarded with `ngDevMode` so that it can be tree shaken in production!'); } } /** * Create dynamic nodes from i18n translation block. * * - Text nodes are created synchronously * - TNodes are linked into tree lazily * * @param tView Current `TView` * @parentTNodeIndex index to the parent TNode of this i18n block * @param lView Current `LView` * @param index Index of `ɵɵi18nStart` instruction. * @param message Message to translate. * @param subTemplateIndex Index into the sub template of message translation. (ie in case of * `ngIf`) (-1 otherwise) */ export function i18nStartFirstCreatePass(tView, parentTNodeIndex, lView, index, message, subTemplateIndex) { const rootTNode = getCurrentParentTNode(); const createOpCodes = []; const updateOpCodes = []; const existingTNodeStack = [[]]; if (ngDevMode) { attachDebugGetter(createOpCodes, i18nCreateOpCodesToString); attachDebugGetter(updateOpCodes, i18nUpdateOpCodesToString); } message = getTranslationForTemplate(message, subTemplateIndex); const msgParts = replaceNgsp(message).split(PH_REGEXP); for (let i = 0; i < msgParts.length; i++) { let value = msgParts[i]; if ((i & 1) === 0) { // Even indexes are text (including bindings & ICU expressions) const parts = i18nParseTextIntoPartsAndICU(value); for (let j = 0; j < parts.length; j++) { let part = parts[j]; if ((j & 1) === 0) { // `j` is odd therefore `part` is string const text = part; ngDevMode && assertString(text, 'Parsed ICU part should be string'); if (text !== '') { i18nStartFirstCreatePassProcessTextNode(tView, rootTNode, existingTNodeStack[0], createOpCodes, updateOpCodes, lView, text); } } else { // `j` is Even therefor `part` is an `ICUExpression` const icuExpression = part; // Verify that ICU expression has the right shape. Translations might contain invalid // constructions (while original messages were correct), so ICU parsing at runtime may // not succeed (thus `icuExpression` remains a string). // Note: we intentionally retain the error here by not using `ngDevMode`, because // the value can change based on the locale and users aren't guaranteed to hit // an invalid string while they're developing. if (typeof icuExpression !== 'object') { throw new Error(`Unable to parse ICU expression in "${message}" message.`); } const icuContainerTNode = createTNodeAndAddOpCode(tView, rootTNode, existingTNodeStack[0], lView, createOpCodes, ngDevMode ? `ICU ${index}:${icuExpression.mainBinding}` : '', true); const icuNodeIndex = icuContainerTNode.index; ngDevMode && assertGreaterThanOrEqual(icuNodeIndex, HEADER_OFFSET, 'Index must be in absolute LView offset'); icuStart(tView, lView, updateOpCodes, parentTNodeIndex, icuExpression, icuNodeIndex); } } } else { // Odd indexes are placeholders (elements and sub-templates) // At this point value is something like: '/#1:2' (originally coming from '�/#1:2�') const isClosing = value.charCodeAt(0) === 47 /* CharCode.SLASH */; const type = value.charCodeAt(isClosing ? 1 : 0); ngDevMode && assertOneOf(type, 42 /* CharCode.STAR */, 35 /* CharCode.HASH */); const index = HEADER_OFFSET + Number.parseInt(value.substring((isClosing ? 2 : 1))); if (isClosing) { existingTNodeStack.shift(); setCurrentTNode(getCurrentParentTNode(), false); } else { const tNode = createTNodePlaceholder(tView, existingTNodeStack[0], index); existingTNodeStack.unshift([]); setCurrentTNode(tNode, true); } } } tView.data[index] = { create: createOpCodes, update: updateOpCodes, }; } /** * Allocate space in i18n Range add create OpCode instruction to create a text or comment node. * * @param tView Current `TView` needed to allocate space in i18n range. * @param rootTNode Root `TNode` of the i18n block. This node determines if the new TNode will be * added as part of the `i18nStart` instruction or as part of the `TNode.insertBeforeIndex`. * @param existingTNodes internal state for `addTNodeAndUpdateInsertBeforeIndex`. * @param lView Current `LView` needed to allocate space in i18n range. * @param createOpCodes Array storing `I18nCreateOpCodes` where new opCodes will be added. * @param text Text to be added when the `Text` or `Comment` node will be created. * @param isICU true if a `Comment` node for ICU (instead of `Text`) node should be created. */ function createTNodeAndAddOpCode(tView, rootTNode, existingTNodes, lView, createOpCodes, text, isICU) { const i18nNodeIdx = allocExpando(tView, lView, 1, null); let opCode = i18nNodeIdx << I18nCreateOpCode.SHIFT; let parentTNode = getCurrentParentTNode(); if (rootTNode === parentTNode) { // FIXME(misko): A null `parentTNode` should represent when we fall of the `LView` boundary. // (there is no parent), but in some circumstances (because we are inconsistent about how we set // `previousOrParentTNode`) it could point to `rootTNode` So this is a work around. parentTNode = null; } if (parentTNode === null) { // If we don't have a parent that means that we can eagerly add nodes. // If we have a parent than these nodes can't be added now (as the parent has not been created // yet) and instead the `parentTNode` is responsible for adding it. See // `TNode.insertBeforeIndex` opCode |= I18nCreateOpCode.APPEND_EAGERLY; } if (isICU) { opCode |= I18nCreateOpCode.COMMENT; ensureIcuContainerVisitorLoaded(loadIcuContainerVisitor); } createOpCodes.push(opCode, text === null ? '' : text); // We store `{{?}}` so that when looking at debug `TNodeType.template` we can see where the // bindings are. const tNode = createTNodeAtIndex(tView, i18nNodeIdx, isICU ? 32 /* TNodeType.Icu */ : 1 /* TNodeType.Text */, text === null ? (ngDevMode ? '{{?}}' : '') : text, null); addTNodeAndUpdateInsertBeforeIndex(existingTNodes, tNode); const tNodeIdx = tNode.index; setCurrentTNode(tNode, false /* Text nodes are self closing */); if (parentTNode !== null && rootTNode !== parentTNode) { // We are a child of deeper node (rather than a direct child of `i18nStart` instruction.) // We have to make sure to add ourselves to the parent. setTNodeInsertBeforeIndex(parentTNode, tNodeIdx); } return tNode; } /** * Processes text node in i18n block. * * Text nodes can have: * - Create instruction in `createOpCodes` for creating the text node. * - Allocate spec for text node in i18n range of `LView` * - If contains binding: * - bindings => allocate space in i18n range of `LView` to store the binding value. * - populate `updateOpCodes` with update instructions. * * @param tView Current `TView` * @param rootTNode Root `TNode` of the i18n block. This node determines if the new TNode will * be added as part of the `i18nStart` instruction or as part of the * `TNode.insertBeforeIndex`. * @param existingTNodes internal state for `addTNodeAndUpdateInsertBeforeIndex`. * @param createOpCodes Location where the creation OpCodes will be stored. * @param lView Current `LView` * @param text The translated text (which may contain binding) */ function i18nStartFirstCreatePassProcessTextNode(tView, rootTNode, existingTNodes, createOpCodes, updateOpCodes, lView, text) { const hasBinding = text.match(BINDING_REGEXP); const tNode = createTNodeAndAddOpCode(tView, rootTNode, existingTNodes, lView, createOpCodes, hasBinding ? null : text, false); if (hasBinding) { generateBindingUpdateOpCodes(updateOpCodes, text, tNode.index, null, 0, null); } } /** * See `i18nAttributes` above. */ export function i18nAttributesFirstPass(tView, index, values) { const previousElement = getCurrentTNode(); const previousElementIndex = previousElement.index; const updateOpCodes = []; if (ngDevMode) { attachDebugGetter(updateOpCodes, i18nUpdateOpCodesToString); } if (tView.firstCreatePass && tView.data[index] === null) { for (let i = 0; i < values.length; i += 2) { const attrName = values[i]; const message = values[i + 1]; if (message !== '') { // Check if attribute value contains an ICU and throw an error if that's the case. // ICUs in element attributes are not supported. // Note: we intentionally retain the error here by not using `ngDevMode`, because // the `value` can change based on the locale and users aren't guaranteed to hit // an invalid string while they're developing. if (ICU_REGEXP.test(message)) { throw new Error(`ICU expressions are not supported in attributes. Message: "${message}".`); } // i18n attributes that hit this code path are guaranteed to have bindings, because // the compiler treats static i18n attributes as regular attribute bindings. // Since this may not be the first i18n attribute on this element we need to pass in how // many previous bindings there have already been. generateBindingUpdateOpCodes(updateOpCodes, message, previousElementIndex, attrName, countBindings(updateOpCodes), null); } } tView.data[index] = updateOpCodes; } } /** * Generate the OpCodes to update the bindings of a string. * * @param updateOpCodes Place where the update opcodes will be stored. * @param str The string containing the bindings. * @param destinationNode Index of the destination node which will receive the binding. * @param attrName Name of the attribute, if the string belongs to an attribute. * @param sanitizeFn Sanitization function used to sanitize the string after update, if necessary. * @param bindingStart The lView index of the next expression that can be bound via an opCode. * @returns The mask value for these bindings */ function generateBindingUpdateOpCodes(updateOpCodes, str, destinationNode, attrName, bindingStart, sanitizeFn) { ngDevMode && assertGreaterThanOrEqual(destinationNode, HEADER_OFFSET, 'Index must be in absolute LView offset'); const maskIndex = updateOpCodes.length; // Location of mask const sizeIndex = maskIndex + 1; // location of size for skipping updateOpCodes.push(null, null); // Alloc space for mask and size const startIndex = maskIndex + 2; // location of first allocation. if (ngDevMode) { attachDebugGetter(updateOpCodes, i18nUpdateOpCodesToString); } const textParts = str.split(BINDING_REGEXP); let mask = 0; for (let j = 0; j < textParts.length; j++) { const textValue = textParts[j]; if (j & 1) { // Odd indexes are bindings const bindingIndex = bindingStart + parseInt(textValue, 10); updateOpCodes.push(-1 - bindingIndex); mask = mask | toMaskBit(bindingIndex); } else if (textValue !== '') { // Even indexes are text updateOpCodes.push(textValue); } } updateOpCodes.push(destinationNode << 2 /* I18nUpdateOpCode.SHIFT_REF */ | (attrName ? 1 /* I18nUpdateOpCode.Attr */ : 0 /* I18nUpdateOpCode.Text */)); if (attrName) { updateOpCodes.push(attrName, sanitizeFn); } updateOpCodes[maskIndex] = mask; updateOpCodes[sizeIndex] = updateOpCodes.length - startIndex; return mask; } /** * Count the number of bindings in the given `opCodes`. * * It could be possible to speed this up, by passing the number of bindings found back from * `generateBindingUpdateOpCodes()` to `i18nAttributesFirstPass()` but this would then require more * complexity in the code and/or transient objects to be created. * * Since this function is only called once when the template is instantiated, is trivial in the * first instance (since `opCodes` will be an empty array), and it is not common for elements to * contain multiple i18n bound attributes, it seems like this is a reasonable compromise. */ function countBindings(opCodes) { let count = 0; for (let i = 0; i < opCodes.length; i++) { const opCode = opCodes[i]; // Bindings are negative numbers. if (typeof opCode === 'number' && opCode < 0) { count++; } } return count; } /** * Convert binding index to mask bit. * * Each index represents a single bit on the bit-mask. Because bit-mask only has 32 bits, we make * the 32nd bit share all masks for all bindings higher than 32. Since it is extremely rare to * have more than 32 bindings this will be hit very rarely. The downside of hitting this corner * case is that we will execute binding code more often than necessary. (penalty of performance) */ function toMaskBit(bindingIndex) { return 1 << Math.min(bindingIndex, 31); } export function isRootTemplateMessage(subTemplateIndex) { return subTemplateIndex === -1; } /** * Removes everything inside the sub-templates of a message. */ function removeInnerTemplateTranslation(message) { let match; let res = ''; let index = 0; let inTemplate = false; let tagMatched; while ((match = SUBTEMPLATE_REGEXP.exec(message)) !== null) { if (!inTemplate) { res += message.substring(index, match.index + match[0].length); tagMatched = match[1]; inTemplate = true; } else { if (match[0] === `${MARKER}/*${tagMatched}${MARKER}`) { index = match.index; inTemplate = false; } } } ngDevMode && assertEqual(inTemplate, false, `Tag mismatch: unable to find the end of the sub-template in the translation "${message}"`); res += message.slice(index); return res; } /** * Extracts a part of a message and removes the rest. * * This method is used for extracting a part of the message associated with a template. A * translated message can span multiple templates. * * Example: * ``` * <div i18n>Translate <span *ngIf>me</span>!</div> * ``` * * @param message The message to crop * @param subTemplateIndex Index of the sub-template to extract. If undefined it returns the * external template and removes all sub-templates. */ export function getTranslationForTemplate(message, subTemplateIndex) { if (isRootTemplateMessage(subTemplateIndex)) { // We want the root template message, ignore all sub-templates return removeInnerTemplateTranslation(message); } else { // We want a specific sub-template const start = message.indexOf(`:${subTemplateIndex}${MARKER}`) + 2 + subTemplateIndex.toString().length; const end = message.search(new RegExp(`${MARKER}\\/\\*\\d+:${subTemplateIndex}${MARKER}`)); return removeInnerTemplateTranslation(message.substring(start, end)); } } /** * Generate the OpCodes for ICU expressions. * * @param icuExpression * @param index Index where the anchor is stored and an optional `TIcuContainerNode` * - `lView[anchorIdx]` points to a `Comment` node representing the anchor for the ICU. * - `tView.data[anchorIdx]` points to the `TIcuContainerNode` if ICU is root (`null` otherwise) */ export function icuStart(tView, lView, updateOpCodes, parentIdx, icuExpression, anchorIdx) { ngDevMode && assertDefined(icuExpression, 'ICU expression must be defined'); let bindingMask = 0; const tIcu = { type: icuExpression.type, currentCaseLViewIndex: allocExpando(tView, lView, 1, null), anchorIdx, cases: [], create: [], remove: [], update: [] }; addUpdateIcuSwitch(updateOpCodes, icuExpression, anchorIdx); setTIcu(tView, anchorIdx, tIcu); const values = icuExpression.values; for (let i = 0; i < values.length; i++) { // Each value is an array of strings & other ICU expressions const valueArr = values[i]; const nestedIcus = []; for (let j = 0; j < valueArr.length; j++) { const value = valueArr[j]; if (typeof value !== 'string') { // It is an nested ICU expression const icuIndex = nestedIcus.push(value) - 1; // Replace nested ICU expression by a comment node valueArr[j] = `<!--�${icuIndex}�-->`; } } bindingMask = parseIcuCase(tView, tIcu, lView, updateOpCodes, parentIdx, icuExpression.cases[i], valueArr.join(''), nestedIcus) | bindingMask; } if (bindingMask) { addUpdateIcuUpdate(updateOpCodes, bindingMask, anchorIdx); } } /** * Parses text containing an ICU expression and produces a JSON object for it. * Original code from closure library, modified for Angular. * * @param pattern Text containing an ICU expression that needs to be parsed. * */ export function parseICUBlock(pattern) { const cases = []; const values = []; let icuType = 1 /* IcuType.plural */; let mainBinding = 0; pattern = pattern.replace(ICU_BLOCK_REGEXP, function (str, binding, type) { if (type === 'select') { icuType = 0 /* IcuType.select */; } else { icuType = 1 /* IcuType.plural */; } mainBinding = parseInt(binding.slice(1), 10); return ''; }); const parts = i18nParseTextIntoPartsAndICU(pattern); // Looking for (key block)+ sequence. One of the keys has to be "other". for (let pos = 0; pos < parts.length;) { let key = parts[pos++].trim(); if (icuType === 1 /* IcuType.plural */) { // Key can be "=x", we just want "x" key = key.replace(/\s*(?:=)?(\w+)\s*/, '$1'); } if (key.length) { cases.push(key); } const blocks = i18nParseTextIntoPartsAndICU(parts[pos++]); if (cases.length > values.length) { values.push(blocks); } } // TODO(ocombe): support ICU expressions in attributes, see #21615 return { type: icuType, mainBinding: mainBinding, cases, values }; } /** * Breaks pattern into strings and top level {...} blocks. * Can be used to break a message into text and ICU expressions, or to break an ICU expression * into keys and cases. Original code from closure library, modified for Angular. * * @param pattern (sub)Pattern to be broken. * @returns An `Array<string|IcuExpression>` where: * - odd positions: `string` => text between ICU expressions * - even positions: `ICUExpression` => ICU expression parsed into `ICUExpression` record. */ export function i18nParseTextIntoPartsAndICU(pattern) { if (!pattern) { return []; } let prevPos = 0; const braceStack = []; const results = []; const braces = /[{}]/g; // lastIndex doesn't get set to 0 so we have to. braces.lastIndex = 0; let match; while (match = braces.exec(pattern)) { const pos = match.index; if (match[0] == '}') { braceStack.pop(); if (braceStack.length == 0) { // End of the block. const block = pattern.substring(prevPos, pos); if (ICU_BLOCK_REGEXP.test(block)) { results.push(parseICUBlock(block)); } else { results.push(block); } prevPos = pos + 1; } } else { if (braceStack.length == 0) { const substring = pattern.substring(prevPos, pos); results.push(substring); prevPos = pos + 1; } braceStack.push('{'); } } const substring = pattern.substring(prevPos); results.push(substring); return results; } /** * Parses a node, its children and its siblings, and generates the mutate & update OpCodes. * */ export function parseIcuCase(tView, tIcu, lView, updateOpCodes, parentIdx, caseName, unsafeCaseHtml, nestedIcus) { const create = []; const remove = []; const update = []; if (ngDevMode) { attachDebugGetter(create, icuCreateOpCodesToString); attachDebugGetter(remove, i18nRemoveOpCodesToString); attachDebugGetter(update, i18nUpdateOpCodesToString); } tIcu.cases.push(caseName); tIcu.create.push(create); tIcu.remove.push(remove); tIcu.update.push(update); const inertBodyHelper = getInertBodyHelper(getDocument()); const inertBodyElement = inertBodyHelper.getInertBodyElement(unsafeCaseHtml); ngDevMode && assertDefined(inertBodyElement, 'Unable to generate inert body element'); const inertRootNode = getTemplateContent(inertBodyElement) || inertBodyElement; if (inertRootNode) { return walkIcuTree(tView, tIcu, lView, updateOpCodes, create, remove, update, inertRootNode, parentIdx, nestedIcus, 0); } else { return 0; } } function walkIcuTree(tView, tIcu, lView, sharedUpdateOpCodes, create, remove, update, parentNode, parentIdx, nestedIcus, depth) { let bindingMask = 0; let currentNode = parentNode.firstChild; while (currentNode) { const newIndex = allocExpando(tView, lView, 1, null); switch (currentNode.nodeType) { case Node.ELEMENT_NODE: const element = currentNode; const tagName = element.tagName.toLowerCase(); if (VALID_ELEMENTS.hasOwnProperty(tagName)) { addCreateNodeAndAppend(create, ELEMENT_MARKER, tagName, parentIdx, newIndex); tView.data[newIndex] = tagName; const elAttrs = element.attributes; for (let i = 0; i < elAttrs.length; i++) { const attr = elAttrs.item(i); const lowerAttrName = attr.name.toLowerCase(); const hasBinding = !!attr.value.match(BINDING_REGEXP); // we assume the input string is safe, unless it's using a binding if (hasBinding) { if (VALID_ATTRS.hasOwnProperty(lowerAttrName)) { if (URI_ATTRS[lowerAttrName]) { generateBindingUpdateOpCodes(update, attr.value, newIndex, attr.name, 0, _sanitizeUrl); } else { generateBindingUpdateOpCodes(update, attr.value, newIndex, attr.name, 0, null); } } else { ngDevMode && console.warn(`WARNING: ignoring unsafe attribute value ` + `${lowerAttrName} on element ${tagName} ` + `(see ${XSS_SECURITY_URL})`); } } else { addCreateAttribute(create, newIndex, attr); } } // Parse the children of this node (if any) bindingMask = walkIcuTree(tView, tIcu, lView, sharedUpdateOpCodes, create, remove, update, currentNode, newIndex, nestedIcus, depth + 1) | bindingMask; addRemoveNode(remove, newIndex, depth); } break; case Node.TEXT_NODE: const value = currentNode.textContent || ''; const hasBinding = value.match(BINDING_REGEXP); addCreateNodeAndAppend(create, null, hasBinding ? '' : value, parentIdx, newIndex); addRemoveNode(remove, newIndex, depth); if (hasBinding) { bindingMask = generateBindingUpdateOpCodes(update, value, newIndex, null, 0, null) | bindingMask; } break; case Node.COMMENT_NODE: // Check if the comment node is a placeholder for a nested ICU const isNestedIcu = NESTED_ICU.exec(currentNode.textContent || ''); if (isNestedIcu) { const nestedIcuIndex = parseInt(isNestedIcu[1], 10); const icuExpression = nestedIcus[nestedIcuIndex]; // Create the comment node that will anchor the ICU expression addCreateNodeAndAppend(create, ICU_MARKER, ngDevMode ? `nested ICU ${nestedIcuIndex}` : '', parentIdx, newIndex); icuStart(tView, lView, sharedUpdateOpCodes, parentIdx, icuExpression, newIndex); addRemoveNestedIcu(remove, newIndex, depth); } break; } currentNode = currentNode.nextSibling; } return bindingMask; } function addRemoveNode(remove, index, depth) { if (depth === 0) { remove.push(index); } } function addRemoveNestedIcu(remove, index, depth) { if (depth === 0) { remove.push(~index); // remove ICU at `index` remove.push(index); // remove ICU comment at `index` } } function addUpdateIcuSwitch(update, icuExpression, index) { update.push(toMaskBit(icuExpression.mainBinding), 2, -1 - icuExpression.mainBinding, index << 2 /* I18nUpdateOpCode.SHIFT_REF */ | 2 /* I18nUpdateOpCode.IcuSwitch */); } function addUpdateIcuUpdate(update, bindingMask, index) { update.push(bindingMask, 1, index << 2 /* I18nUpdateOpCode.SHIFT_REF */ | 3 /* I18nUpdateOpCode.IcuUpdate */); } function addCreateNodeAndAppend(create, marker, text, appendToParentIdx, createAtIdx) { if (marker !== null) { create.push(marker); } create.push(text, createAtIdx, icuCreateOpCode(0 /* IcuCreateOpCode.AppendChild */, appendToParentIdx, createAtIdx)); } function addCreateAttribute(create, newIndex, attr) { create.push(newIndex << 1 /* IcuCreateOpCode.SHIFT_REF */ | 1 /* IcuCreateOpCode.Attr */, attr.name, attr.value); } //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaTE4bl9wYXJzZS5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uLy4uLy4uLy4uLy4uL3BhY2thZ2VzL2NvcmUvc3JjL3JlbmRlcjMvaTE4bi9pMThuX3BhcnNlLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBOzs7Ozs7R0FNRztBQUNILE9BQU8sd0JBQXdCLENBQUM7QUFDaEMsT0FBTyxpQ0FBaUMsQ0FBQztBQUV6QyxPQUFPLEVBQUMsZ0JBQWdCLEVBQUMsTUFBTSw4QkFBOEIsQ0FBQztBQUM5RCxPQUFPLEVBQUMsa0JBQWtCLEVBQUUsU0FBUyxFQUFFLFdBQVcsRUFBRSxjQUFjLEVBQUMsTUFBTSxtQ0FBbUMsQ0FBQztBQUM3RyxPQUFPLEVBQUMsa0JBQWtCLEVBQUMsTUFBTSwrQkFBK0IsQ0FBQztBQUNqRSxPQUFPLEVBQUMsWUFBWSxFQUFDLE1BQU0sa0NBQWtDLENBQUM7QUFDOUQsT0FBTyxFQUFDLGFBQWEsRUFBRSxXQUFXLEVBQUUsd0JBQXdCLEVBQUUsV0FBVyxFQUFFLFlBQVksRUFBQyxNQUFNLG1CQUFtQixDQUFDO0FBRWxILE9BQU8sRUFBQyx1QkFBdUIsRUFBQyxNQUFNLDRDQUE0QyxDQUFDO0FBQ25GLE9BQU8sRUFBQyxZQUFZLEVBQUUsa0JBQWtCLEVBQUMsTUFBTSx3QkFBd0IsQ0FBQztBQUN4RSxPQUFPLEVBQUMsV0FBVyxFQUFDLE1BQU0sd0JBQXdCLENBQUM7QUFDbkQsT0FBTyxFQUFDLGNBQWMsRUFBRSxnQkFBZ0IsRUFBNkUsVUFBVSxFQUF5RSxNQUFNLG9CQUFvQixDQUFDO0FBR25PLE9BQU8sRUFBQyxhQUFhLEVBQWUsTUFBTSxvQkFBb0IsQ0FBQztBQUMvRCxPQUFPLEVBQUMscUJBQXFCLEVBQUUsZUFBZSxFQUFFLGVBQWUsRUFBQyxNQUFNLFVBQVUsQ0FBQztBQUVqRixPQUFPLEVBQUMseUJBQXlCLEVBQUUseUJBQXlCLEVBQUUseUJBQXlCLEVBQUUsd0JBQXdCLEVBQUMsTUFBTSxjQUFjLENBQUM7QUFDdkksT0FBTyxFQUFDLGtDQUFrQyxFQUFDLE1BQU0sNEJBQTRCLENBQUM7QUFDOUUsT0FBTyxFQUFDLCtCQUErQixFQUFDLE1BQU0scUJBQXFCLENBQUM7QUFDcEUsT0FBTyxFQUFDLHNCQUFzQixFQUFFLGVBQWUsRUFBRSxPQUFPLEVBQUUseUJBQXlCLEVBQUMsTUFBTSxhQUFhLENBQUM7QUFJeEcsTUFBTSxjQUFjLEdBQUcsZ0JBQWdCLENBQUM7QUFDeEMsTUFBTSxVQUFVLEdBQUcsNENBQTRDLENBQUM7QUFDaEUsTUFBTSxVQUFVLEdBQUcsU0FBUyxDQUFDO0FBQzdCLE1BQU0sZ0JBQWdCLEdBQUcsNENBQTRDLENBQUM7QUFFdEUsTUFBTSxNQUFNLEdBQUcsR0FBRyxDQUFDO0FBQ25CLE1BQU0sa0JBQWtCLEdBQUcsb0JBQW9CLENBQUM7QUFDaEQsTUFBTSxTQUFTLEdBQUcsdUJBQXVCLENBQUM7QUFFMUM7Ozs7OztHQU1HO0FBQ0gsTUFBTSxtQkFBbUIsR0FBRyxTQUFTLENBQUM7QUFDdEMsU0FBUyxXQUFXLENBQUMsS0FBYTtJQUNoQyxPQUFPLEtBQUssQ0FBQyxPQUFPLENBQUMsbUJBQW1CLEVBQUUsR0FBRyxDQUFDLENBQUM7QUFDakQsQ0FBQztBQUVEOzs7Ozs7O0dBT0c7QUFDSCxTQUFTLGlCQUFpQixDQUFJLEdBQU0sRUFBRSxXQUE2QjtJQUNqRSxJQUFJLFNBQVMsRUFBRTtRQUNiLE1BQU0sQ0FBQyxjQUFjLENBQUMsR0FBRyxFQUFFLE9BQU8sRUFBRSxFQUFDLEdBQUcsRUFBRSxXQUFXLEVBQUUsVUFBVSxFQUFFLEtBQUssRUFBQyxDQUFDLENBQUM7S0FDNUU7U0FBTTtRQUNMLE1BQU0sSUFBSSxLQUFLLENBQ1gsNkZBQTZGLENBQUMsQ0FBQztLQUNwRztBQUNILENBQUM7QUFFRDs7Ozs7Ozs7Ozs7OztHQWFHO0FBQ0gsTUFBTSxVQUFVLHdCQUF3QixDQUNwQyxLQUFZLEVBQUUsZ0JBQXdCLEVBQUUsS0FBWSxFQUFFLEtBQWEsRUFBRSxPQUFlLEVBQ3BGLGdCQUF3QjtJQUMxQixNQUFNLFNBQVMsR0FBRyxxQkFBcUIsRUFBRSxDQUFDO0lBQzFDLE1BQU0sYUFBYSxHQUFzQixFQUFTLENBQUM7SUFDbkQsTUFBTSxhQUFhLEdBQXNCLEVBQVMsQ0FBQztJQUNuRCxNQUFNLGtCQUFrQixHQUFjLENBQUMsRUFBRSxDQUFDLENBQUM7SUFDM0MsSUFBSSxTQUFTLEVBQUU7UUFDYixpQkFBaUIsQ0FBQyxhQUFhLEVBQUUseUJBQXlCLENBQUMsQ0FBQztRQUM1RCxpQkFBaUIsQ0FBQyxhQUFhLEVBQUUseUJBQXlCLENBQUMsQ0FBQztLQUM3RDtJQUVELE9BQU8sR0FBRyx5QkFBeUIsQ0FBQyxPQUFPLEVBQUUsZ0JBQWdCLENBQUMsQ0FBQztJQUMvRCxNQUFNLFFBQVEsR0FBRyxXQUFXLENBQUMsT0FBTyxDQUFDLENBQUMsS0FBSyxDQUFDLFNBQVMsQ0FBQyxDQUFDO0lBQ3ZELEtBQUssSUFBSSxDQUFDLEdBQUcsQ0FBQyxFQUFFLENBQUMsR0FBRyxRQUFRLENBQUMsTUFBTSxFQUFFLENBQUMsRUFBRSxFQUFFO1FBQ3hDLElBQUksS0FBSyxHQUFHLFFBQVEsQ0FBQyxDQUFDLENBQUMsQ0FBQztRQUN4QixJQUFJLENBQUMsQ0FBQyxHQUFHLENBQUMsQ0FBQyxLQUFLLENBQUMsRUFBRTtZQUNqQiwrREFBK0Q7WUFDL0QsTUFBTSxLQUFLLEdBQUcsNEJBQTRCLENBQUMsS0FBSyxDQUFDLENBQUM7WUFDbEQsS0FBSyxJQUFJLENBQUMsR0FBRyxDQUFDLEVBQUUsQ0FBQyxHQUFHLEtBQUssQ0FBQyxNQUFNLEVBQUUsQ0FBQyxFQUFFLEVBQUU7Z0JBQ3JDLElBQUksSUFBSSxHQUFHLEtBQUssQ0FBQyxDQUFDLENBQUMsQ0FBQztnQkFDcEIsSUFBSSxDQUFDLENBQUMsR0FBRyxDQUFDLENBQUMsS0FBSyxDQUFDLEVBQUU7b0JBQ2pCLHdDQUF3QztvQkFDeEMsTUFBTSxJQUFJLEdBQUcsSUFBYyxDQUFDO29CQUM1QixTQUFTLElBQUksWUFBWSxDQUFDLElBQUksRUFBRSxrQ0FBa0MsQ0FBQyxDQUFDO29CQUNwRSxJQUFJLElBQUksS0FBSyxFQUFFLEVBQUU7d0JBQ2YsdUNBQXVDLENBQ25DLEtBQUssRUFBRSxTQUFTLEVBQUUsa0JBQWtCLENBQUMsQ0FBQyxDQUFDLEVBQUUsYUFBYSxFQUFFLGFBQWEsRUFBRSxLQUFLLEVBQUUsSUFBSSxDQUFDLENBQUM7cUJBQ3pGO2lCQUNGO3FCQUFNO29CQUNMLG9EQUFvRDtvQkFDcEQsTUFBTSxhQUFhLEdBQWtCLElBQXFCLENBQUM7b0JBQzNELHFGQUFxRjtvQkFDckYsc0ZBQXNGO29CQUN0Rix1REFBdUQ7b0JBQ3ZELGlGQUFpRjtvQkFDakYsOEVBQThFO29CQUM5RSw4Q0FBOEM7b0JBQzlDLElBQUksT0FBTyxhQUFhLEtBQUssUUFBUSxFQUFFO3dCQUNyQyxNQUFNLElBQUksS0FBSyxDQUFDLHNDQUFzQyxPQUFPLFlBQVksQ0FBQyxDQUFDO3FCQUM1RTtvQkFDRCxNQUFNLGlCQUFpQixHQUFHLHVCQUF1QixDQUM3QyxLQUFLLEVBQUUsU0FBUyxFQUFFLGtCQUFrQixDQUFDLENBQUMsQ0FBQyxFQUFFLEtBQUssRUFBRSxhQUFhLEVBQzdELFNBQVMsQ0FBQyxDQUFDLENBQUMsT0FBTyxLQUFLLElBQUksYUFBYSxDQUFDLFdBQVcsRUFBRSxDQUFDLENBQUMsQ0FBQyxFQUFFLEVBQUUsSUFBSSxDQUFDLENBQUM7b0JBQ3hFLE1BQU0sWUFBWSxHQUFHLGlCQUFpQixDQUFDLEtBQUssQ0FBQztvQkFDN0MsU0FBUzt3QkFDTCx3QkFBd0IsQ0FDcEIsWUFBWSxFQUFFLGFBQWEsRUFBRSx3Q0FBd0MsQ0FBQyxDQUFDO29CQUMvRSxRQUFRLENBQUMsS0FBSyxFQUFFLEtBQUssRUFBRSxhQUFhLEVBQUUsZ0JBQWdCLEVBQUUsYUFBYSxFQUFFLFlBQVksQ0FBQyxDQUFDO2lCQUN0RjthQUNGO1NBQ0Y7YUFBTTtZQUNMLDREQUE0RDtZQUM1RCxvRkFBb0Y7WUFDcEYsTUFBTSxTQUFTLEdBQUcsS0FBSyxDQUFDLFVBQVUsQ0FBQyxDQUFDLENBQUMsNEJBQW1CLENBQUM7WUFDekQsTUFBTSxJQUFJLEdBQUcsS0FBSyxDQUFDLFVBQVUsQ0FBQyxTQUFTLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUM7WUFDakQsU0FBUyxJQUFJLFdBQVcsQ0FBQyxJQUFJLGlEQUErQixDQUFDO1lBQzdELE1BQU0sS0FBSyxHQUFHLGFBQWEsR0FBRyxNQUFNLENBQUMsUUFBUSxDQUFDLEtBQUssQ0FBQyxTQUFTLENBQUMsQ0FBQyxTQUFTLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDO1lBQ3BGLElBQUksU0FBUyxFQUFFO2dCQUNiLGtCQUFrQixDQUFDLEtBQUssRUFBRSxDQUFDO2dCQUMzQixlQUFlLENBQUMscUJBQXFCLEVBQUcsRUFBRSxLQUFLLENBQUMsQ0FBQzthQUNsRDtpQkFBTTtnQkFDTCxNQUFNLEtBQUssR0FBRyxzQkFBc0IsQ0FBQyxLQUFLLEVBQUUsa0JBQWtCLENBQUMsQ0FBQyxDQUFDLEVBQUUsS0FBSyxDQUFDLENBQUM7Z0JBQzFFLGtCQUFrQixDQUFDLE9BQU8sQ0FBQyxFQUFFLENBQUMsQ0FBQztnQkFDL0IsZUFBZSxDQUFDLEtBQUssRUFBRSxJQUFJLENBQUMsQ0FBQzthQUM5QjtTQUNGO0tBQ0Y7SUFFRCxLQUFLLENBQUMsSUFBSSxDQUFDLEtBQUssQ0FBQyxHQUFVO1FBQ3pCLE1BQU0sRUFBRSxhQUFhO1FBQ3JCLE1BQU0sRUFBRSxhQUFhO0tBQ3RCLENBQUM7QUFDSixDQUFDO0FBRUQ7Ozs7Ozs7Ozs7O0dBV0c7QUFDSCxTQUFTLHVCQUF1QixDQUM1QixLQUFZLEVBQUUsU0FBcUIsRUFBRSxjQUF1QixFQUFFLEtBQVksRUFDMUUsYUFBZ0MsRUFBRSxJQUFpQixFQUFFLEtBQWM7SUFDckUsTUFBTSxXQUFXLEdBQUcsWUFBWSxDQUFDLEtBQUssRUFBRSxLQUFLLEVBQUUsQ0FBQyxFQUFFLElBQUksQ0FBQyxDQUFDO0lBQ3hELElBQUksTUFBTSxHQUFHLFdBQVcsSUFBSSxnQkFBZ0IsQ0FBQyxLQUFLLENBQUM7SUFDbkQsSUFBSSxXQUFXLEdBQUcscUJBQXFCLEVBQUUsQ0FBQztJQUUxQyxJQUFJLFNBQVMsS0FBSyxXQUFXLEVBQUU7UUFDN0IsNEZBQTRGO1FBQzVGLGdHQUFnRztRQUNoRyxtRkFBbUY7UUFDbkYsV0FBVyxHQUFHLElBQUksQ0FBQztLQUNwQjtJQUNELElBQUksV0FBVyxLQUFLLElBQUksRUFBRTtRQUN4QixzRUFBc0U7UUFDdEUsOEZBQThGO1FBQzlGLHVFQUF1RTtRQUN2RSw0QkFBNEI7UUFDNUIsTUFBTSxJQUFJLGdCQUFnQixDQUFDLGNBQWMsQ0FBQztLQUMzQztJQUNELElBQUksS0FBSyxFQUFFO1FBQ1QsTUFBTSxJQUFJLGdCQUFnQixDQUFDLE9BQU8sQ0FBQztRQUNuQywrQkFBK0IsQ0FBQyx1QkFBdUIsQ0FBQyxDQUFDO0tBQzFEO0lBQ0QsYUFBYSxDQUFDLElBQUksQ0FBQyxNQUFNLEVBQUUsSUFBSSxLQUFLLElBQUksQ0FBQyxDQUFDLENBQUMsRUFBRSxDQUFDLENBQUMsQ0FBQyxJQUFJLENBQUMsQ0FBQztJQUN0RCwyRkFBMkY7SUFDM0YsZ0JBQWdCO0lBQ2hCLE1BQU0sS0FBSyxHQUFHLGtCQUFrQixDQUM1QixLQUFLLEVBQUUsV0FBVyxFQUFFLEtBQUssQ0FBQyxDQUFDLHdCQUFlLENBQUMsdUJBQWUsRUFDMUQsSUFBSSxLQUFLLElBQUksQ0FBQyxDQUFDLENBQUMsQ0FBQyxTQUFTLENBQUMsQ0FBQyxDQUFDLE9BQU8sQ0FBQyxDQUFDLENBQUMsRUFBRSxDQUFDLENBQUMsQ0FBQyxDQUFDLElBQUksRUFBRSxJQUFJLENBQUMsQ0FBQztJQUM3RCxrQ0FBa0MsQ0FBQyxjQUFjLEVBQUUsS0FBSyxDQUFDLENBQUM7SUFDMUQsTUFBTSxRQUFRLEdBQUcsS0FBSyxDQUFDLEtBQUssQ0FBQztJQUM3QixlQUFlLENBQUMsS0FBSyxFQUFFLEtBQUssQ0FBQyxpQ0FBaUMsQ0FBQyxDQUFDO0lBQ2hFLElBQUksV0FBVyxLQUFLLElBQUksSUFBSSxTQUFTLEtBQUssV0FBVyxFQUFFO1FBQ3JELHlGQUF5RjtRQUN6Rix1REFBdUQ7UUFDdkQseUJBQXlCLENBQUMsV0FBVyxFQUFFLFFBQVEsQ0FBQyxDQUFDO0tBQ2xEO0lBQ0QsT0FBTyxLQUFLLENBQUM7QUFDZixDQUFDO0FBRUQ7Ozs7Ozs7Ozs7Ozs7Ozs7OztHQWtCRztBQUNILFNBQVMsdUNBQXVDLENBQzVDLEtBQVksRUFBRSxTQUFxQixFQUFFLGNBQXVCLEVBQUUsYUFBZ0MsRUFDOUYsYUFBZ0MsRUFBRSxLQUFZLEVBQUUsSUFBWTtJQUM5RCxNQUFNLFVBQVUsR0FBRyxJQUFJLENBQUMsS0FBSyxDQUFDLGNBQWMsQ0FBQyxDQUFDO0lBQzlDLE1BQU0sS0FBSyxHQUFHLHVCQUF1QixDQUNqQyxLQUFLLEVBQUUsU0FBUyxFQUFFLGNBQWMsRUFBRSxLQUFLLEVBQUUsYUFBYSxFQUFFLFVBQVUsQ0FBQyxDQUFDLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQyxJQUFJLEVBQUUsS0FBSyxDQUFDLENBQUM7SUFDN0YsSUFBSSxVQUFVLEVBQUU7UUFDZCw0QkFBNEIsQ0FBQyxhQUFhLEVBQUUsSUFBSSxFQUFFLEtBQUssQ0FBQyxLQUFLLEVBQUUsSUFBSSxFQUFFLENBQUMsRUFBRSxJQUFJLENBQUMsQ0FBQztLQUMvRTtBQUNILENBQUM7QUFFRDs7R0FFRztBQUNILE1BQU0sVUFBVSx1QkFBdUIsQ0FBQyxLQUFZLEVBQUUsS0FBYSxFQUFFLE1BQWdCO0lBQ25GLE1BQU0sZUFBZSxHQUFHLGVBQWUsRUFBRyxDQUFDO0lBQzNDLE1BQU0sb0JBQW9CLEdBQUcsZUFBZSxDQUFDLEtBQUssQ0FBQztJQUNuRCxNQUFNLGFBQWEsR0FBc0IsRUFBUyxDQUFDO0lBQ25ELElBQUksU0FBUyxFQUFFO1FBQ2IsaUJBQWlCLENBQUMsYUFBYSxFQUFFLHlCQUF5QixDQUFDLENBQUM7S0FDN0Q7SUFDRCxJQUFJLEtBQUssQ0FBQyxlQUFlLElBQUksS0FBSyxDQUFDLElBQUksQ0FBQyxLQUFLLENBQUMsS0FBSyxJQUFJLEVBQUU7UUFDdkQsS0FBSyxJQUFJLENBQUMsR0FBRyxDQUFDLEVBQUUsQ0FBQyxHQUFHLE1BQU0sQ0FBQyxNQUFNLEVBQUUsQ0FBQyxJQUFJLENBQUMsRUFBRTtZQUN6QyxNQUFNLFFBQVEsR0FBRyxNQUFNLENBQUMsQ0FBQyxDQUFDLENBQUM7WUFDM0IsTUFBTSxPQUFPLEdBQUcsTUFBTSxDQUFDLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQztZQUU5QixJQUFJLE9BQU8sS0FBSyxFQUFFLEVBQUU7Z0JBQ2xCLGtGQUFrRjtnQkFDbEYsZ0RBQWdEO2dCQUNoRCxpRkFBaUY7Z0JBQ2pGLGdGQUFnRjtnQkFDaEYsOENBQThDO2dCQUM5QyxJQUFJLFVBQVUsQ0FBQyxJQUFJLENBQUMsT0FBTyxDQUFDLEVBQUU7b0JBQzVCLE1BQU0sSUFBSSxLQUFLLENBQ1gsOERBQThELE9BQU8sSUFBSSxDQUFDLENBQUM7aUJBQ2hGO2dCQUVELG1GQUFtRjtnQkFDbkYsNEVBQTRFO2dCQUM1RSx3RkFBd0Y7Z0JBQ3hGLGtEQUFrRDtnQkFDbEQsNEJBQTRCLENBQ3hCLGFBQWEsRUFBRSxPQUFPLEVBQUUsb0JBQW9CLEVBQUUsUUFBUSxFQUFFLGFBQWEsQ0FBQyxhQUFhLENBQUMsRUFDcEYsSUFBSSxDQUFDLENBQUM7YUFDWDtTQUNGO1FBQ0QsS0FBSyxDQUFDLElBQUksQ0FBQyxLQUFLLENBQUMsR0FBRyxhQUFhLENBQUM7S0FDbkM7QUFDSCxDQUFDO0FBR0Q7Ozs7Ozs7Ozs7R0FVRztBQUNILFNBQVMsNEJBQTRCLENBQ2pDLGFBQWdDLEVBQUUsR0FBVyxFQUFFLGVBQXVCLEVBQUUsUUFBcUIsRUFDN0YsWUFBb0IsRUFBRSxVQUE0QjtJQUNwRCxTQUFTO1FBQ0wsd0JBQXdCLENBQ3BCLGVBQWUsRUFBRSxhQUFhLEVBQUUsd0NBQXdDLENBQUMsQ0FBQztJQUNsRixNQUFNLFNBQVMsR0FBRyxhQUFhLENBQUMsTUFBTSxDQUFDLENBQUUsbUJBQW1CO0lBQzVELE1BQU0sU0FBUyxHQUFHLFNBQVMsR0FBRyxDQUFDLENBQUMsQ0FBUyxnQ0FBZ0M7SUFDekUsYUFBYSxDQUFDLElBQUksQ0FBQyxJQUFJLEVBQUUsSUFBSSxDQUFDLENBQUMsQ0FBVSxnQ0FBZ0M7SUFDekUsTUFBTSxVQUFVLEdBQUcsU0FBUyxHQUFHLENBQUMsQ0FBQyxDQUFRLGdDQUFnQztJQUN6RSxJQUFJLFNBQVMsRUFBRTtRQUNiLGlCQUFpQixDQUFDLGFBQWEsRUFBRSx5QkFBeUIsQ0FBQyxDQUFDO0tBQzdEO0lBQ0QsTUFBTSxTQUFTLEdBQUcsR0FBRyxDQUFDLEtBQUssQ0FBQyxjQUFjLENBQUMsQ0FBQztJQUM1QyxJQUFJLElBQUksR0FBRyxDQUFDLENBQUM7SUFFYixLQUFLLElBQUksQ0FBQyxHQUFHLENBQUMsRUFBRSxDQUFDLEdBQUcsU0FBUyxDQUFDLE1BQU0sRUFBRSxDQUFDLEVBQUUsRUFBRTtRQUN6QyxNQUFNLFNBQVMsR0FBRyxTQUFTLENBQUMsQ0FBQyxDQUFDLENBQUM7UUFFL0IsSUFBSSxDQUFDLEdBQUcsQ0FBQyxFQUFFO1lBQ1QsMkJBQTJCO1lBQzNCLE1BQU0sWUFBWSxHQUFHLFlBQVksR0FBRyxRQUFRLENBQUMsU0FBUyxFQUFFLEVBQUUsQ0FBQyxDQUFDO1lBQzVELGFBQWEsQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFDLEdBQUcsWUFBWSxDQUFDLENBQUM7WUFDdEMsSUFBSSxHQUFHLElBQUksR0FBRyxTQUFTLENBQUMsWUFBWSxDQUFDLENBQUM7U0FDdkM7YUFBTSxJQUFJLFNBQVMsS0FBSyxFQUFFLEVBQUU7WUFDM0Isd0JBQXdCO1lBQ3hCLGFBQWEsQ0FBQyxJQUFJLENBQUMsU0FBUyxDQUFDLENBQUM7U0FDL0I7S0FDRjtJQUVELGFBQWEsQ0FBQyxJQUFJLENBQ2QsZUFBZSxzQ0FBOEI7UUFDN0MsQ0FBQyxRQUFRLENBQUMsQ0FBQywrQkFBdUIsQ0FBQyw4QkFBc0IsQ0FBQyxDQUFDLENBQUM7SUFDaEUsSUFBSSxRQUFRLEVBQUU7UUFDWixhQUFhLENBQUMsSUFBSSxDQUFDLFFBQVEsRUFBRSxVQUFVLENBQUMsQ0FBQztLQUMxQztJQUNELGFBQWEsQ0FBQyxTQUFTLENBQUMsR0FBRyxJQUFJLENBQUM7SUFDaEMsYUFBYSxDQUFDLFNBQVMsQ0FBQyxHQUFHLGFBQWEsQ0FBQyxNQUFNLEdBQUcsVUFBVSxDQUFDO0lBQzdELE9BQU8sSUFBSSxDQUFDO0FBQ2QsQ0FBQztBQUVEOzs7Ozs7Ozs7O0dBVUc7QUFDSCxTQUFTLGFBQWEsQ0FBQyxPQUEwQjtJQUMvQyxJQUFJLEtBQUssR0FBRyxDQUFDLENBQUM7SUFDZCxLQUFLLElBQUksQ0FBQyxHQUFHLENBQUMsRUFBRSxDQUFDLEdBQUcsT0FBTyxDQUFDLE1BQU0sRUFBRSxDQUFDLEVBQUUsRUFBRTtRQUN2QyxNQUFNLE1BQU0sR0FBRyxPQUFPLENBQUMsQ0FBQyxDQUFDLENBQUM7UUFDMUIsaUNBQWlDO1FBQ2pDLElBQUksT0FBTyxNQUFNLEtBQUssUUFBUSxJQUFJLE1BQU0sR0FBRyxDQUFDLEVBQUU7WUFDNUMsS0FBSyxFQUFFLENBQUM7U0FDVDtLQUNGO0lBQ0QsT0FBTyxLQUFLLENBQUM7QUFDZixDQUFDO0FBRUQ7Ozs7Ozs7R0FPRztBQUNILFNBQVMsU0FBUyxDQUFDLFlBQW9CO0lBQ3JDLE9BQU8sQ0FBQyxJQUFJLElBQUksQ0FBQyxHQUFHLENBQUMsWUFBWSxFQUFFLEVBQUUsQ0FBQyxDQUFDO0FBQ3pDLENBQUM7QUFFRCxNQUFNLFVBQVUscUJBQXFCLENBQUMsZ0JBQXdCO0lBQzVELE9BQU8sZ0JBQWdCLEtBQUssQ0FBQyxDQUFDLENBQUM7QUFDakMsQ0FBQztBQUdEOztHQUVHO0FBQ0gsU0FBUyw4QkFBOEIsQ0FBQyxPQUFlO0lBQ3JELElBQUksS0FBSyxDQUFDO0lBQ1YsSUFBSSxHQUFHLEdBQUcsRUFBRSxDQUFDO0lBQ2IsSUFBSSxLQUFLLEdBQUcsQ0FBQyxDQUFDO0lBQ2QsSUFBSSxVQUFVLEdBQUcsS0FBSyxDQUFDO0lBQ3ZCLElBQUksVUFBVSxDQUFDO0lBRWYsT0FBTyxDQUFDLEtBQUssR0FBRyxrQkFBa0IsQ0FBQyxJQUFJLENBQUMsT0FBTyxDQUFDLENBQUMsS0FBSyxJQUFJLEVBQUU7UUFDMUQsSUFBSSxDQUFDLFVBQVUsRUFBRTtZQUNmLEdBQUcsSUFBSSxPQUFPLENBQUMsU0FBUyxDQUFDLEtBQUssRUFBRSxLQUFLLENBQUMsS0FBSyxHQUFHLEtBQUssQ0FBQyxDQUFDLENBQUMsQ0FBQyxNQUFNLENBQUMsQ0FBQztZQUMvRCxVQUFVLEdBQUcsS0FBSyxDQUFDLENBQUMsQ0FBQyxDQUFDO1lBQ3RCLFVBQVUsR0FBRyxJQUFJLENBQUM7U0FDbkI7YUFBTTtZQUNMLElBQUksS0FBSyxDQUFDLENBQUMsQ0FBQyxLQUFLLEdBQUcsTUFBTSxLQUFLLFVBQVUsR0FBRyxNQUFNLEVBQUUsRUFBRTtnQkFDcEQsS0FBSyxHQUFHLEtBQUssQ0FBQyxLQUFLLENBQUM7Z0JBQ3BCLFVBQVUsR0FBRyxLQUFLLENBQUM7YUFDcEI7U0FDRjtLQUNGO0lBRUQsU0FBUztRQUNMLFdBQVcsQ0FDUCxVQUFVLEVBQUUsS0FBSyxFQUNqQixnRkFDSSxPQUFPLEdBQUcsQ0FBQyxDQUFDO0lBRXhCLEdBQUcsSUFBSSxPQUFPLENBQUMsS0FBSyxDQUFDLEtBQUssQ0FBQyxDQUFDO0lBQzVCLE9BQU8sR0FBRyxDQUFDO0FBQ2IsQ0FBQztBQUdEOzs7Ozs7Ozs7Ozs7OztHQWNHO0FBQ0gsTUFBTSxVQUFVLHlCQUF5QixDQUFDLE9BQWUsRUFBRSxnQkFBd0I7SUFDakYsSUFBSSxxQkFBcUIsQ0FBQyxnQkFBZ0IsQ0FBQyxFQUFFO1FBQzNDLDhEQUE4RDtRQUM5RCxPQUFPLDhCQUE4QixDQUFDLE9BQU8sQ0FBQyxDQUFDO0tBQ2hEO1NBQU07UUFDTCxrQ0FBa0M7UUFDbEMsTUFBTSxLQUFLLEdBQ1AsT0FBTyxDQUFDLE9BQU8sQ0FBQyxJQUFJLGdCQUFnQixHQUFHLE1BQU0sRUFBRSxDQUFDLEdBQUcsQ0FBQyxHQUFHLGdCQUFnQixDQUFDLFFBQVEsRUFBRSxDQUFDLE1BQU0sQ0FBQztRQUM5RixNQUFNLEdBQUcsR0FBRyxPQUFPLENBQUMsTUFBTSxDQUFDLElBQUksTUFBTSxDQUFDLEdBQUcsTUFBTSxjQUFjLGdCQUFnQixHQUFHLE1BQU0sRUFBRSxDQUFDLENBQUMsQ0FBQztRQUMzRixPQUFPLDhCQUE4QixDQUFDLE9BQU8sQ0FBQyxTQUFTLENBQUMsS0FBSyxFQUFFLEdBQUcsQ0FBQyxDQUFDLENBQUM7S0FDdEU7QUFDSCxDQUFDO0FBRUQ7Ozs7Ozs7R0FPRztBQUNILE1BQU0sVUFBVSxRQUFRLENBQ3BCLEtBQVksRUFBRSxLQUFZLEVBQUUsYUFBZ0MsRUFBRSxTQUFpQixFQUMvRSxhQUE0QixFQUFFLFNBQWlCO0lBQ2pELFNBQVMsSUFBSSxhQUFhLENBQUMsYUFBYSxFQUFFLGdDQUFnQyxDQUFDLENBQUM7SUFDNUUsSUFBSSxXQUFXLEdBQUcsQ0FBQyxDQUFDO0lBQ3BCLE1BQU0sSUFBSSxHQUFTO1FBQ2pCLElBQUksRUFBRSxhQUFhLENBQUMsSUFBSTtRQUN4QixxQkFBcUIsRUFBRSxZQUFZLENBQUMsS0FBSyxFQUFFLEtBQUssRUFBRSxDQUFDLEVBQUUsSUFBSSxDQUFDO1FBQzFELFNBQVM7UUFDVCxLQUFLLEVBQUUsRUFBRTtRQUNULE1BQU0sRUFBRSxFQUFFO1FBQ1YsTUFBTSxFQUFFLEVBQUU7UUFDVixNQUFNLEVBQUUsRUFBRTtLQUNYLENBQUM7SUFDRixrQkFBa0IsQ0FBQyxhQUFhLEVBQUUsYUFBYSxFQUFFLFNBQVMsQ0FBQyxDQUFDO0lBQzVELE9BQU8sQ0FBQyxLQUFLLEVBQUUsU0FBUyxFQUFFLElBQUksQ0FBQyxDQUFDO0lBQ2hDLE1BQU0sTUFBTSxHQUFHLGFBQWEsQ0FBQyxNQUFNLENBQUM7SUFDcEMsS0FBSyxJQUFJLENBQUMsR0FBRyxDQUFDLEVBQUUsQ0FBQyxHQUFHLE1BQU0sQ0FBQyxNQUFNLEVBQUUsQ0FBQyxFQUFFLEVBQUU7UUFDdEMsNERBQTREO1FBQzVELE1BQU0sUUFBUSxHQUFHLE1BQU0sQ0FBQyxDQUFDLENBQUMsQ0FBQztRQUMzQixNQUFNLFVBQVUsR0FBb0IsRUFBRSxDQUFDO1FBQ3ZDLEtBQUssSUFBSSxDQUFDLEdBQUcsQ0FBQyxFQUFFLENBQUMsR0FBRyxRQUFRLENBQUMsTUFBTSxFQUFFLENBQUMsRUFBRSxFQUFFO1lBQ3hDLE1BQU0sS0FBSyxHQUFHLFFBQVEsQ0FBQyxDQUFDLENBQUMsQ0FBQztZQUMxQixJQUFJLE9BQU8sS0FBSyxLQUFLLFFBQVEsRUFBRTtnQkFDN0IsaUNBQWlDO2dCQUNqQyxNQUFNLFFBQVEsR0FBRyxVQUFVLENBQUMsSUFBSSxDQUFDLEtBQXNCLENBQUMsR0FBRyxDQUFDLENBQUM7Z0JBQzdELGtEQUFrRDtnQkFDbEQsUUFBUSxDQUFDLENBQUMsQ0FBQyxHQUFHLFFBQVEsUUFBUSxNQUFNLENBQUM7YUFDdEM7U0FDRjtRQUNELFdBQVcsR0FBRyxZQUFZLENBQ1IsS0FBSyxFQUFFLElBQUksRUFBRSxLQUFLLEVBQUUsYUFBYSxFQUFFLFNBQVMsRUFBRSxhQUFhLENBQUMsS0FBSyxDQUFDLENBQUMsQ0FBQyxFQUNwRSxRQUFRLENBQUMsSUFBSSxDQUFDLEVBQUUsQ0FBQyxFQUFFLFVBQVUsQ0FBQztZQUM1QyxXQUFXLENBQUM7S0FDakI7SUFDRCxJQUFJLFdBQVcsRUFBRTtRQUNmLGtCQUFrQixDQUFDLGFBQWEsRUFBRSxXQUFXLEVBQUUsU0FBUyxDQUFDLENBQUM7S0FDM0Q7QUFDSCxDQUFDO0FBRUQ7Ozs7OztHQU1HO0FBQ0gsTUFBTSxVQUFVLGFBQWEsQ0FBQyxPQUFlO0lBQzNDLE1BQU0sS0FBSyxHQUFHLEVBQUUsQ0FBQztJQUNqQixNQUFNLE1BQU0sR0FBK0IsRUFBRSxDQUFDO0lBQzlDLElBQUksT0FBTyx5QkFBaUIsQ0FBQztJQUM3QixJQUFJLFdBQVcsR0FBRyxDQUFDLENBQUM7SUFDcEIsT0FBTyxHQUFHLE9BQU8sQ0FBQyxPQUFPLENBQUMsZ0JBQWdCLEVBQUUsVUFBUyxHQUFXLEVBQUUsT0FBZSxFQUFFLElBQVk7UUFDN0YsSUFBSSxJQUFJLEtBQUssUUFBUSxFQUFFO1lBQ3JCLE9BQU8seUJBQWlCLENBQUM7U0FDMUI7YUFBTTtZQUNMLE9BQU8seUJBQWlCLENBQUM7U0FDMUI7UUFDRCxXQUFXLEdBQUcsUUFBUSxDQUFDLE9BQU8sQ0FBQyxLQUFLLENBQUMsQ0FBQyxDQUFDLEVBQUUsRUFBRSxDQUFDLENBQUM7UUFDN0MsT0FBTyxFQUFFLENBQUM7SUFDWixDQUFDLENBQUMsQ0FBQztJQUVILE1BQU0sS0FBSyxHQUFHLDRCQUE0QixDQUFDLE9BQU8sQ0FBYSxDQUFDO0lBQ2hFLHdFQUF3RTtJQUN4RSxLQUFLLElBQUksR0FBRyxHQUFHLENBQUMsRUFBRSxHQUFHLEdBQUcsS0FBSyxDQUFDLE1BQU0sR0FBRztRQUNyQyxJQUFJLEdBQUcsR0FBRyxLQUFLLENBQUMsR0FBRyxFQUFFLENBQUMsQ0FBQyxJQUFJLEVBQUUsQ0FBQztRQUM5QixJQUFJLE9BQU8sMkJBQW1CLEVBQUU7WUFDOUIsb0NBQW9DO1lBQ3BDLEdBQUcsR0FBRyxHQUFHLENBQUMsT0FBTyxDQUFDLG1CQUFtQixFQUFFLElBQUksQ0FBQyxDQUFDO1NBQzlDO1FBQ0QsSUFBSSxHQUFHLENBQUMsTUFBTSxFQUFFO1lBQ2QsS0FBSyxDQUFDLElBQUksQ0FBQyxHQUFHLENBQUMsQ0FBQztTQUNqQjtRQUVELE1BQU0sTUFBTSxHQUFHLDRCQUE0QixDQUFDLEtBQUssQ0FBQyxHQUFHLEVBQUUsQ0FBQyxDQUFhLENBQUM7UUFDdEUsSUFBSSxLQUFLLENBQUMsTUFBTSxHQUFHLE1BQU0sQ0FBQyxNQUFNLEVBQUU7WUFDaEMsTUFBTSxDQUFDLElBQUksQ0FBQyxNQUFNLENBQUMsQ0FBQztTQUNyQjtLQUNGO0lBRUQsa0VBQWtFO0lBQ2xFLE9BQU8sRUFBQyxJQUFJLEVBQUUsT0FBTyxFQUFFLFdBQVcsRUFBRSxXQUFXLEVBQUUsS0FBSyxFQUFFLE1BQU0sRUFBQyxDQUFDO0FBQ2xFLENBQUM7QUFHRDs7Ozs7Ozs7O0dBU0c7QUFDSCxNQUFNLFVBQVUsNEJBQTRCLENBQUMsT0FBZTtJQUMxRCxJQUFJLENBQUMsT0FBTyxFQUFFO1FBQ1osT0FBTyxFQUFFLENBQUM7S0FDWDtJQUVELElBQUksT0FBTyxHQUFHLENBQUMsQ0FBQztJQUNoQixNQUFNLFVBQVUsR0FBRyxFQUFFLENBQUM7SUFDdEIsTUFBTSxPQUFPLEdBQTZCLEVBQUUsQ0FBQztJQUM3QyxNQUFNLE1BQU0sR0FBRyxPQUFPLENBQUM7SUFDdkIsZ0RBQWdEO0lBQ2hELE1BQU0sQ0FBQyxTQUFTLEdBQUcsQ0FBQyxDQUFDO0lBRXJCLElBQUksS0FBSyxDQUFDO0lBQ1YsT0FBTyxLQUFLLEdBQUcsTUFBTSxDQUFDLElBQUksQ0FBQyxPQUFPLENBQUMsRUFBRTtRQUNuQyxNQUFNLEdBQUcsR0FBRyxLQUFLLENBQUMsS0FBSyxDQUFDO1FBQ3hCLElBQUksS0FBSyxDQUFDLENBQUMsQ0FBQyxJQUFJLEdBQUcsRUFBRTtZQUNuQixVQUFVLENBQUMsR0FBRyxFQUFFLENBQUM7WUFFakIsSUFBSSxVQUFVLENBQUMsTUFBTSxJQUFJLENBQUMsRUFBRTtnQkFDMUIsb0JBQW9CO2dCQUNwQixNQUFNLEtBQUssR0FBRyxPQUFPLENBQUMsU0FBUyxDQUFDLE9BQU8sRUFBRSxHQUFHLENBQUMsQ0FBQztnQkFDOUMsSUFBSSxnQkFBZ0IsQ0FBQyxJQUFJLENBQUMsS0FBSyxDQUFDLEVBQUU7b0JBQ2hDLE9BQU8sQ0FBQyxJQUFJLENBQUMsYUFBYSxDQUFDLEtBQUssQ0FBQyxDQUFDLENBQUM7aUJBQ3BDO3FCQUFNO29CQUNMLE9BQU8sQ0FBQyxJQUFJLENBQUMsS0FBSyxDQUFDLENBQUM7aUJBQ3JCO2dCQUVELE9BQU8sR0FBRyxHQUFHLEdBQUcsQ0FBQyxDQUFDO2FBQ25CO1NBQ0Y7YUFBTTtZQUNMLElBQUksVUFBVSxDQUFDLE1BQU0sSUFBSSxDQUFDLEVBQUU7Z0JBQzFCLE1BQU0sU0FBUyxHQUFHLE9BQU8sQ0FBQyxTQUFTLENBQUMsT0FBTyxFQUFFLEdBQUcsQ0FBQyxDQUFDO2dCQUNsRCxPQUFPLENBQUMsSUFBSSxDQUFDLFNBQVMsQ0FBQyxDQUFDO2dCQUN4QixPQUFPLEdBQUcsR0FBRyxHQUFHLENBQUMsQ0FBQzthQUNuQjtZQUNELFVBQVUsQ0FBQyxJQUFJLENBQUMsR0FBRyxDQUFDLENBQUM7U0FDdEI7S0FDRjtJQUVELE1BQU0sU0FBUyxHQUFHLE9BQU8sQ0FBQyxTQUFTLENBQUMsT0FBTyxDQUFDLENBQUM7SUFDN0MsT0FBTyxDQUFDLElBQUksQ0FBQyxTQUFTLENBQUMsQ0FBQztJQUN4QixPQUFPLE9BQU8sQ0FBQztBQUNqQixDQUFDO0FBR0Q7OztHQUdHO0FBQ0gsTUFBTSxVQUFVLFlBQVksQ0FDeEIsS0FBWSxFQUFFLElBQVUsRUFBRSxLQUFZLEVBQUUsYUFBZ0MsRUFBRSxTQUFpQixFQUMzRixRQUFnQixFQUFFLGNBQXNCLEVBQUUsVUFBMkI7SUFDdkUsTUFBTSxNQUFNLEdBQXFCLEVBQVMsQ0FBQztJQUMzQyxNQUFNLE1BQU0sR0FBc0IsRUFBUyxDQUFDO0lBQzVDLE1BQU0sTUFBTSxHQUFzQixFQUFTLENBQUM7SUFDNUMsSUFBSSxTQUFTLEVBQUU7UUFDYixpQkFBaUIsQ0FBQyxNQUFNLEVBQUUsd0JBQXdCLENBQUMsQ0FBQztRQUNwRCxpQkFBaUIsQ0FBQyxNQUFNLEVBQUUseUJBQXlCLENBQUMsQ0FBQztRQUNyRCxpQkFBaUIsQ0FBQyxNQUFNLEVBQUUseUJBQXlCLENBQUMsQ0FBQztLQUN0RDtJQUNELElBQUksQ0FBQyxLQUFLLENBQUMsSUFBSSxDQUFDLFFBQVEsQ0FBQyxDQUFDO0lBQzFCLElBQUksQ0FBQyxNQUFNLENBQUMsSUFBSSxDQUFDLE1BQU0sQ0FBQyxDQUFDO0lBQ3pCLElBQUksQ0FBQyxNQUFNLENBQUMsSUFBSSxDQUFDLE1BQU0sQ0FBQyxDQUFDO0lBQ3pCLElBQUksQ0FBQyxNQUFNLENBQUMsSUFBSSxDQUFDLE1BQU0sQ0FBQyxDQUFDO0lBRXpCLE1BQU0sZUFBZSxHQUFHLGtCQUFrQixDQUFDLFdBQVcsRUFBRSxDQUFDLENBQUM7SUFDMUQsTUFBTSxnQkFBZ0IsR0FBRyxlQUFlLENBQUMsbUJBQW1CLENBQUMsY0FBYyxDQUFDLENBQUM7SUFDN0UsU0FBUyxJQUFJLGFBQWEsQ0FBQyxnQkFBZ0IsRUFBRSx1Q0FBdUMsQ0FBQyxDQUFDO0lBQ3RGLE1BQU0sYUFBYSxHQUFHLGtCQUFrQixDQUFDLGdCQUFpQixDQUFZLElBQUksZ0JBQWdCLENBQUM7SUFDM0YsSUFBSSxhQUFhLEVBQUU7UUFDakIsT0FBTyxXQUFXLENBQ2QsS0FBSyxFQUFFLElBQUksRUFBRSxLQUFLLEVBQUUsYUFBYSxFQUFFLE1BQU0sRUFBRSxNQUFNLEVBQUUsTUFBTSxFQUFFLGFBQWEsRUFBRSxTQUFTLEVBQ25GLFVBQVUsRUFBRSxDQUFDLENBQUMsQ0FBQztLQUNwQjtTQUFNO1FBQ0wsT0FBTyxDQUFDLENBQUM7S0FDVjtBQUNILENBQUM7QUFFRCxTQUFTLFdBQVcsQ0FDaEIsS0FBWSxFQUFFLElBQVUsRUFBRSxLQUFZLEVBQUUsbUJBQXNDLEVBQzlFLE1BQXdCLEVBQUUsTUFBeUIsRUFBRSxNQUF5QixFQUM5RSxVQUFtQixFQUFFLFNBQWlCLEVBQUUsVUFBMkIsRUFBRSxLQUFhO0lBQ3BGLElBQUksV0FBVyxHQUFHLENBQUMsQ0FBQztJQUNwQixJQUFJLFdBQVcsR0FBRyxVQUFVLENBQUMsVUFBVSxDQUFDO0lBQ3hDLE9BQU8sV0FBVyxFQUFFO1FBQ2xCLE1BQU0sUUFBUSxHQUFHLFlBQVksQ0FBQyxLQUFLLEVBQUUsS0FBSyxFQUFFLENBQUMsRUFBRSxJQUFJLENBQUMsQ0FBQztRQUNyRCxRQUFRLFdBQVcsQ0FBQyxRQUFRLEVBQUU7WUFDNUIsS0FBSyxJQUFJLENBQUMsWUFBWTtnQkFDcEIsTUFBTSxPQUFPLEdBQUcsV0FBc0IsQ0FBQztnQkFDdkMsTUFBTSxPQUFPLEdBQUcsT0FBTyxDQUFDLE9BQU8sQ0FBQyxXQUFXLEVB