UNPKG

@angular/core

Version:

Angular - the core framework

371 lines 44.9 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 { RuntimeError } from '../errors'; import { getDeclarationComponentDef } from '../render3/instructions/element_validation'; import { TVIEW } from '../render3/interfaces/view'; import { getParentRElement } from '../render3/node_manipulation'; const AT_THIS_LOCATION = '<-- AT THIS LOCATION'; /** * Retrieves a user friendly string for a given TNodeType for use in * friendly error messages * * @param tNodeType * @returns */ function getFriendlyStringFromTNodeType(tNodeType) { switch (tNodeType) { case 4 /* TNodeType.Container */: return 'view container'; case 2 /* TNodeType.Element */: return 'element'; case 8 /* TNodeType.ElementContainer */: return 'ng-container'; case 32 /* TNodeType.Icu */: return 'icu'; case 64 /* TNodeType.Placeholder */: return 'i18n'; case 16 /* TNodeType.Projection */: return 'projection'; case 1 /* TNodeType.Text */: return 'text'; default: // This should not happen as we cover all possible TNode types above. return '<unknown>'; } } /** * Validates that provided nodes match during the hydration process. */ export function validateMatchingNode(node, nodeType, tagName, lView, tNode, isViewContainerAnchor = false) { if (!node || (node.nodeType !== nodeType || (node.nodeType === Node.ELEMENT_NODE && node.tagName.toLowerCase() !== tagName?.toLowerCase()))) { const expectedNode = shortRNodeDescription(nodeType, tagName, null); let header = `During hydration Angular expected ${expectedNode} but `; const hostComponentDef = getDeclarationComponentDef(lView); const componentClassName = hostComponentDef?.type?.name; const expected = `Angular expected this DOM:\n\n${describeExpectedDom(lView, tNode, isViewContainerAnchor)}\n\n`; let actual = ''; if (!node) { // No node found during hydration. header += `the node was not found.\n\n`; } else { const actualNode = shortRNodeDescription(node.nodeType, node.tagName ?? null, node.textContent ?? null); header += `found ${actualNode}.\n\n`; actual = `Actual DOM is:\n\n${describeDomFromNode(node)}\n\n`; } const footer = getHydrationErrorFooter(componentClassName); const message = header + expected + actual + getHydrationAttributeNote() + footer; throw new RuntimeError(-500 /* RuntimeErrorCode.HYDRATION_NODE_MISMATCH */, message); } } /** * Validates that a given node has sibling nodes */ export function validateSiblingNodeExists(node) { validateNodeExists(node); if (!node.nextSibling) { const header = 'During hydration Angular expected more sibling nodes to be present.\n\n'; const actual = `Actual DOM is:\n\n${describeDomFromNode(node)}\n\n`; const footer = getHydrationErrorFooter(); const message = header + actual + footer; throw new RuntimeError(-501 /* RuntimeErrorCode.HYDRATION_MISSING_SIBLINGS */, message); } } /** * Validates that a node exists or throws */ export function validateNodeExists(node, lView = null, tNode = null) { if (!node) { const header = 'During hydration, Angular expected an element to be present at this location.\n\n'; let expected = ''; let footer = ''; if (lView !== null && tNode !== null) { expected = `${describeExpectedDom(lView, tNode, false)}\n\n`; footer = getHydrationErrorFooter(); } throw new RuntimeError(-502 /* RuntimeErrorCode.HYDRATION_MISSING_NODE */, header + expected + footer); } } /** * Builds the hydration error message when a node is not found * * @param lView the LView where the node exists * @param tNode the TNode */ export function nodeNotFoundError(lView, tNode) { const header = 'During serialization, Angular was unable to find an element in the DOM:\n\n'; const expected = `${describeExpectedDom(lView, tNode, false)}\n\n`; const footer = getHydrationErrorFooter(); throw new RuntimeError(-502 /* RuntimeErrorCode.HYDRATION_MISSING_NODE */, header + expected + footer); } /** * Builds a hydration error message when a node is not found at a path location * * @param host the Host Node * @param path the path to the node */ export function nodeNotFoundAtPathError(host, path) { const header = `During hydration Angular was unable to locate a node ` + `using the "${path}" path, starting from the ${describeRNode(host)} node.\n\n`; const footer = getHydrationErrorFooter(); throw new RuntimeError(-502 /* RuntimeErrorCode.HYDRATION_MISSING_NODE */, header + footer); } /** * Builds the hydration error message in the case that dom nodes are created outside of * the Angular context and are being used as projected nodes * * @param lView the LView * @param tNode the TNode * @returns an error */ export function unsupportedProjectionOfDomNodes(rNode) { const header = 'During serialization, Angular detected DOM nodes ' + 'that were created outside of Angular context and provided as projectable nodes ' + '(likely via `ViewContainerRef.createComponent` or `createComponent` APIs). ' + 'Hydration is not supported for such cases, consider refactoring the code to avoid ' + 'this pattern or using `ngSkipHydration` on the host element of the component.\n\n'; const actual = `${describeDomFromNode(rNode)}\n\n`; const message = header + actual + getHydrationAttributeNote(); return new RuntimeError(-503 /* RuntimeErrorCode.UNSUPPORTED_PROJECTION_DOM_NODES */, message); } /** * Builds the hydration error message in the case that ngSkipHydration was used on a * node that is not a component host element or host binding * * @param rNode the HTML Element * @returns an error */ export function invalidSkipHydrationHost(rNode) { const header = 'The `ngSkipHydration` flag is applied on a node ' + 'that doesn\'t act as a component host. Hydration can be ' + 'skipped only on per-component basis.\n\n'; const actual = `${describeDomFromNode(rNode)}\n\n`; const footer = 'Please move the `ngSkipHydration` attribute to the component host element.\n\n'; const message = header + actual + footer; return new RuntimeError(-504 /* RuntimeErrorCode.INVALID_SKIP_HYDRATION_HOST */, message); } // Stringification methods /** * Stringifies a given TNode's attributes * * @param tNode a provided TNode * @returns string */ function stringifyTNodeAttrs(tNode) { const results = []; if (tNode.attrs) { for (let i = 0; i < tNode.attrs.length;) { const attrName = tNode.attrs[i++]; // Once we reach the first flag, we know that the list of // attributes is over. if (typeof attrName == 'number') { break; } const attrValue = tNode.attrs[i++]; results.push(`${attrName}="${shorten(attrValue)}"`); } } return results.join(' '); } /** * The list of internal attributes that should be filtered out while * producing an error message. */ const internalAttrs = new Set(['ngh', 'ng-version', 'ng-server-context']); /** * Stringifies an HTML Element's attributes * * @param rNode an HTML Element * @returns string */ function stringifyRNodeAttrs(rNode) { const results = []; for (let i = 0; i < rNode.attributes.length; i++) { const attr = rNode.attributes[i]; if (internalAttrs.has(attr.name)) continue; results.push(`${attr.name}="${shorten(attr.value)}"`); } return results.join(' '); } // Methods for Describing the DOM /** * Converts a tNode to a helpful readable string value for use in error messages * * @param tNode a given TNode * @param innerContent the content of the node * @returns string */ function describeTNode(tNode, innerContent = '…') { switch (tNode.type) { case 1 /* TNodeType.Text */: const content = tNode.value ? `(${tNode.value})` : ''; return `#text${content}`; case 2 /* TNodeType.Element */: const attrs = stringifyTNodeAttrs(tNode); const tag = tNode.value.toLowerCase(); return `<${tag}${attrs ? ' ' + attrs : ''}>${innerContent}</${tag}>`; case 8 /* TNodeType.ElementContainer */: return '<!-- ng-container -->'; case 4 /* TNodeType.Container */: return '<!-- container -->'; default: const typeAsString = getFriendlyStringFromTNodeType(tNode.type); return `#node(${typeAsString})`; } } /** * Converts an RNode to a helpful readable string value for use in error messages * * @param rNode a given RNode * @param innerContent the content of the node * @returns string */ function describeRNode(rNode, innerContent = '…') { const node = rNode; switch (node.nodeType) { case Node.ELEMENT_NODE: const tag = node.tagName.toLowerCase(); const attrs = stringifyRNodeAttrs(node); return `<${tag}${attrs ? ' ' + attrs : ''}>${innerContent}</${tag}>`; case Node.TEXT_NODE: const content = node.textContent ? shorten(node.textContent) : ''; return `#text${content ? `(${content})` : ''}`; case Node.COMMENT_NODE: return `<!-- ${shorten(node.textContent ?? '')} -->`; default: return `#node(${node.nodeType})`; } } /** * Builds the string containing the expected DOM present given the LView and TNode * values for a readable error message * * @param lView the lView containing the DOM * @param tNode the tNode * @param isViewContainerAnchor boolean * @returns string */ function describeExpectedDom(lView, tNode, isViewContainerAnchor) { const spacer = ' '; let content = ''; if (tNode.prev) { content += spacer + '…\n'; content += spacer + describeTNode(tNode.prev) + '\n'; } else if (tNode.type && tNode.type & 12 /* TNodeType.AnyContainer */) { content += spacer + '…\n'; } if (isViewContainerAnchor) { content += spacer + describeTNode(tNode) + '\n'; content += spacer + `<!-- container --> ${AT_THIS_LOCATION}\n`; } else { content += spacer + describeTNode(tNode) + ` ${AT_THIS_LOCATION}\n`; } content += spacer + '…\n'; const parentRNode = tNode.type ? getParentRElement(lView[TVIEW], tNode, lView) : null; if (parentRNode) { content = describeRNode(parentRNode, '\n' + content); } return content; } /** * Builds the string containing the DOM present around a given RNode for a * readable error message * * @param node the RNode * @returns string */ function describeDomFromNode(node) { const spacer = ' '; let content = ''; const currentNode = node; if (currentNode.previousSibling) { content += spacer + '…\n'; content += spacer + describeRNode(currentNode.previousSibling) + '\n'; } content += spacer + describeRNode(currentNode) + ` ${AT_THIS_LOCATION}\n`; if (node.nextSibling) { content += spacer + '…\n'; } if (node.parentNode) { content = describeRNode(currentNode.parentNode, '\n' + content); } return content; } /** * Shortens the description of a given RNode by its type for readability * * @param nodeType the type of node * @param tagName the node tag name * @param textContent the text content in the node * @returns string */ function shortRNodeDescription(nodeType, tagName, textContent) { switch (nodeType) { case Node.ELEMENT_NODE: return `<${tagName.toLowerCase()}>`; case Node.TEXT_NODE: const content = textContent ? ` (with the "${shorten(textContent)}" content)` : ''; return `a text node${content}`; case Node.COMMENT_NODE: return 'a comment node'; default: return `#node(nodeType=${nodeType})`; } } /** * Builds the footer hydration error message * * @param componentClassName the name of the component class * @returns string */ function getHydrationErrorFooter(componentClassName) { const componentInfo = componentClassName ? `the "${componentClassName}"` : 'corresponding'; return `To fix this problem:\n` + ` * check ${componentInfo} component for hydration-related issues\n` + ` * check to see if your template has valid HTML structure\n` + ` * or skip hydration by adding the \`ngSkipHydration\` attribute ` + `to its host node in a template\n\n`; } /** * An attribute related note for hydration errors */ function getHydrationAttributeNote() { return 'Note: attributes are only displayed to better represent the DOM' + ' but have no effect on hydration mismatches.\n\n'; } // Node string utility functions /** * Strips all newlines out of a given string * * @param input a string to be cleared of new line characters * @returns */ function stripNewlines(input) { return input.replace(/\s+/gm, ''); } /** * Reduces a string down to a maximum length of characters with ellipsis for readability * * @param input a string input * @param maxLength a maximum length in characters * @returns string */ function shorten(input, maxLength = 50) { if (!input) { return ''; } input = stripNewlines(input); return input.length > maxLength ? `${input.substring(0, maxLength - 1)}…` : input; } //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZXJyb3JfaGFuZGxpbmcuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi8uLi8uLi9wYWNrYWdlcy9jb3JlL3NyYy9oeWRyYXRpb24vZXJyb3JfaGFuZGxpbmcudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUE7Ozs7OztHQU1HO0FBRUgsT0FBTyxFQUFDLFlBQVksRUFBbUIsTUFBTSxXQUFXLENBQUM7QUFDekQsT0FBTyxFQUFDLDBCQUEwQixFQUFDLE1BQU0sNENBQTRDLENBQUM7QUFHdEYsT0FBTyxFQUFRLEtBQUssRUFBQyxNQUFNLDRCQUE0QixDQUFDO0FBQ3hELE9BQU8sRUFBQyxpQkFBaUIsRUFBQyxNQUFNLDhCQUE4QixDQUFDO0FBRS9ELE1BQU0sZ0JBQWdCLEdBQUcsc0JBQXNCLENBQUM7QUFFaEQ7Ozs7OztHQU1HO0FBQ0gsU0FBUyw4QkFBOEIsQ0FBQyxTQUFvQjtJQUMxRCxRQUFRLFNBQVMsRUFBRSxDQUFDO1FBQ2xCO1lBQ0UsT0FBTyxnQkFBZ0IsQ0FBQztRQUMxQjtZQUNFLE9BQU8sU0FBUyxDQUFDO1FBQ25CO1lBQ0UsT0FBTyxjQUFjLENBQUM7UUFDeEI7WUFDRSxPQUFPLEtBQUssQ0FBQztRQUNmO1lBQ0UsT0FBTyxNQUFNLENBQUM7UUFDaEI7WUFDRSxPQUFPLFlBQVksQ0FBQztRQUN0QjtZQUNFLE9BQU8sTUFBTSxDQUFDO1FBQ2hCO1lBQ0UscUVBQXFFO1lBQ3JFLE9BQU8sV0FBVyxDQUFDO0lBQ3ZCLENBQUM7QUFDSCxDQUFDO0FBRUQ7O0dBRUc7QUFDSCxNQUFNLFVBQVUsb0JBQW9CLENBQ2hDLElBQVcsRUFBRSxRQUFnQixFQUFFLE9BQW9CLEVBQUUsS0FBWSxFQUFFLEtBQVksRUFDL0UscUJBQXFCLEdBQUcsS0FBSztJQUMvQixJQUFJLENBQUMsSUFBSTtRQUNMLENBQUUsSUFBYSxDQUFDLFFBQVEsS0FBSyxRQUFRO1lBQ3BDLENBQUUsSUFBYSxDQUFDLFFBQVEsS0FBSyxJQUFJLENB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QUssSUFBSSxDQUFDLFlBQVk7WUFDcEIsT0FBTyxnQkFBZ0IsQ0FBQztRQUMxQjtZQUNFLE9BQU8sa0JBQWtCLFFBQVEsR0FBRyxDQUFDO0lBQ3pDLENBQUM7QUFDSCxDQUFDO0FBR0Q7Ozs7O0dBS0c7QUFDSCxTQUFTLHVCQUF1QixDQUFDLGtCQUEyQjtJQUMxRCxNQUFNLGFBQWEsR0FBRyxrQkFBa0IsQ0FBQyxDQUFDLENBQUMsUUFBUSxrQkFBa0IsR0FBRyxDQUFDLENBQUMsQ0FBQyxlQUFlLENBQUM7SUFDM0YsT0FBTyx3QkFBd0I7UUFDM0IsYUFBYSxhQUFhLDJDQUEyQztRQUNyRSw4REFBOEQ7UUFDOUQsb0VBQW9FO1FBQ3BFLG9DQUFvQyxDQUFDO0FBQzNDLENBQUM7QUFFRDs7R0FFRztBQUNILFNBQVMseUJBQXlCO0lBQ2hDLE9BQU8saUVBQWlFO1FBQ3BFLGtEQUFrRCxDQUFDO0FBQ3pELENBQUM7QUFFRCxnQ0FBZ0M7QUFFaEM7Ozs7O0dBS0c7QUFDSCxTQUFTLGFBQWEsQ0FBQyxLQUFhO0lBQ2xDLE9BQU8sS0FBSyxDQUFDLE9BQU8sQ0FBQyxPQUFPLEVBQUUsRUFBRSxDQUFDLENBQUM7QUFDcEMsQ0FBQztBQUVEOzs7Ozs7R0FNRztBQUNILFNBQVMsT0FBTyxDQUFDLEtBQWtCLEVBQUUsU0FBUyxHQUFHLEVBQUU7SUFDakQsSUFBSSxDQUFDLEtBQUssRUFBRSxDQUFDO1FBQ1gsT0FBTyxFQUFFLENBQUM7SUFDWixDQUFDO0lBQ0QsS0FBSyxHQUFHLGFBQWEsQ0FBQyxLQUFLLENBQUMsQ0FBQztJQUM3QixPQUFPLEtBQUssQ0FBQyxNQUFNLEdBQUcsU0FBUyxDQUFDLENBQUMsQ0FBQyxHQUFHLEtBQUssQ0FBQyxTQUFTLENBQUMsQ0FBQyxFQUFFLFNBQVMsR0FBRyxDQUFDLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQyxLQUFLLENBQUM7QUFDcEYsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbIi8qKlxuICogQGxpY2Vuc2VcbiAqIENvcHlyaWdodCBHb29nbGUgTExDIEFsbCBSaWdodHMgUmVzZXJ2ZWQuXG4gKlxuICogVXNlIG9mIHRoaXMgc291cmNlIGNvZGUgaXMgZ292ZXJuZWQgYnkgYW4gTUlULXN0eWxlIGxpY2Vuc2UgdGhhdCBjYW4gYmVcbiAqIGZvdW5kIGluIHRoZSBMSUNFTlNFIGZpbGUgYXQgaHR0cHM6Ly9hbmd1bGFyLmlvL2xpY2Vuc2VcbiAqL1xuXG5pbXBvcnQge1J1bnRpbWVFcnJvciwgUnVudGltZUVycm9yQ29kZX0gZnJvbSAnLi4vZXJyb3JzJztcbmltcG9ydCB7Z2V0RGVjbGFyYXRpb25Db21wb25lbnREZWZ9IGZyb20gJy4uL3JlbmRlcjMvaW5zdHJ1Y3Rpb25zL2VsZW1lbnRfdmFsaWRhdGlvbic7XG5pbXBvcnQge1ROb2RlLCBUTm9kZVR5cGV9IGZyb20gJy4uL3JlbmRlcjMvaW50ZXJmYWNlcy9ub2RlJztcbmltcG9ydCB7Uk5vZGV9IGZyb20gJy4uL3JlbmRlcjMvaW50ZXJmYWNlcy9yZW5kZXJlcl9kb20nO1xuaW1wb3J0IHtMVmlldywgVFZJRVd9IGZyb20gJy4uL3JlbmRlcjMvaW50ZXJmYWNlcy92aWV3JztcbmltcG9ydCB7Z2V0UGFyZW50UkVsZW1lbnR9IGZyb20gJy4uL3JlbmRlcjMvbm9kZV9tYW5pcHVsYXRpb24nO1xuXG5jb25zdCBBVF9USElTX0xPQ0FUSU9OID0gJzwtLSBBVCBUSElTIExPQ0FUSU9OJztcblxuLyoqXG4gKiBSZXRyaWV2ZXMgYSB1c2VyIGZyaWVuZGx5IHN0cmluZyBmb3IgYSBnaXZlbiBUTm9kZVR5cGUgZm9yIHVzZSBpblxuICogZnJpZW5kbHkgZXJyb3IgbWVzc2FnZXNcbiAqXG4gKiBAcGFyYW0gdE5vZGVUeXBlXG4gKiBAcmV0dXJuc1xuICovXG5mdW5jdGlvbiBnZXRGcmllbmRseVN0cmluZ0Zyb21UTm9kZVR5cGUodE5vZGVUeXBlOiBUTm9kZVR5cGUpOiBzdHJpbmcge1xuICBzd2l0Y2ggKHROb2RlVHlwZSkge1xuICAgIGNhc2UgVE5vZGVUeXBlLkNvbnRhaW5lcjpcbiAgICAgIHJldHVybiAndmlldyBjb250YWluZXInO1xuICAgIGNhc2UgVE5vZGVUeXBlLkVsZW1lbnQ6XG4gICAgICByZXR1cm4gJ2VsZW1lbnQnO1xuICAgIGNhc2UgVE5vZGVUeXBlLkVsZW1lbnRDb250YWluZXI6XG4gICAgICByZXR1cm4gJ25nLWNvbnRhaW5lcic7XG4gICAgY2FzZSBUTm9kZVR5cGUuSWN1OlxuICAgICAgcmV0dXJuICdpY3UnO1xuICAgIGNhc2UgVE5vZGVUeXBlLlBsYWNlaG9sZGVyOlxuICAgICAgcmV0dXJuICdpMThuJztcbiAgICBjYXNlIFROb2RlVHlwZS5Qcm9qZWN0aW9uOlxuICAgICAgcmV0dXJuICdwcm9qZWN0aW9uJztcbiAgICBjYXNlIFROb2RlVHlwZS5UZXh0OlxuICAgICAgcmV0dXJuICd0ZXh0JztcbiAgICBkZWZhdWx0OlxuICAgICAgLy8gVGhpcyBzaG91bGQgbm90IGhhcHBlbiBhcyB3ZSBjb3ZlciBhbGwgcG9zc2libGUgVE5vZGUgdHlwZXMgYWJvdmUuXG4gICAgICByZXR1cm4gJzx1bmtub3duPic7XG4gIH1cbn1cblxuLyoqXG4gKiBWYWxpZGF0ZXMgdGhhdCBwcm92aWRlZCBub2RlcyBtYXRjaCBkdXJpbmcgdGhlIGh5ZHJhdGlvbiBwcm9jZXNzLlxuICovXG5leHBvcnQgZnVuY3Rpb24gdmFsaWRhdGVNYXRjaGluZ05vZGUoXG4gICAgbm9kZTogUk5vZGUsIG5vZGVUeXBlOiBudW1iZXIsIHRhZ05hbWU6IHN0cmluZ3xudWxsLCBsVmlldzogTFZpZXcsIHROb2RlOiBUTm9kZSxcbiAgICBpc1ZpZXdDb250YWluZXJBbmNob3IgPSBmYWxzZSk6IHZvaWQge1xuICBpZiAoIW5vZGUgfHxcbiAgICAgICgobm9kZSBhcyBOb2RlKS5ub2RlVHlwZSAhPT0gbm9kZVR5cGUgfHxcbiAgICAgICAoKG5vZGUgYXMgTm9kZSkubm9kZVR5cGUgPT09IE5vZGUuRUxFTUVOVF9OT0RFICYmXG4gICAgICAgIChub2RlIGFzIEhUTUxFbGVtZW50KS50YWdOYW1lLnRvTG93ZXJDYXNlKCkgIT09IHRhZ05hbWU/LnRvTG93ZXJDYXNlKCkpKSkge1xuICAgIGNvbnN0IGV4cGVjdGVkTm9kZSA9IHNob3J0Uk5vZGVEZXNjcmlwdGlvbihub2RlVHlwZSwgdGFnTmFtZSwgbnVsbCk7XG4gICAgbGV0IGhlYWRlciA9IGBEdXJpbmcgaHlkcmF0aW9uIEFuZ3VsYXIgZXhwZWN0ZWQgJHtleHBlY3RlZE5vZGV9IGJ1dCBgO1xuXG4gICAgY29uc3QgaG9zdENvbXBvbmVudERlZiA9IGdldERlY2xhcmF0aW9uQ29tcG9uZW50RGVmKGxWaWV3KTtcbiAgICBjb25zdCBjb21wb25lbnRDbGFzc05hbWUgPSBob3N0Q29tcG9uZW50RGVmPy50eXBlPy5uYW1lO1xuXG4gICAgY29uc3QgZXhwZWN0ZWQgPSBgQW5ndWxhciBleHBlY3RlZCB0aGlzIERPTTpcXG5cXG4ke1xuICAgICAgICBkZXNjcmliZUV4cGVjdGVkRG9tKGxWaWV3LCB0Tm9kZSwgaXNWaWV3Q29udGFpbmVyQW5jaG9yKX1cXG5cXG5gO1xuXG4gICAgbGV0IGFjdHVhbCA9ICcnO1xuXG4gICAgaWYgKCFub2RlKSB7XG4gICAgICAvLyBObyBub2RlIGZvdW5kIGR1cmluZyBoeWRyYXRpb24uXG4gICAgICBoZWFkZXIgKz0gYHRoZSBub2RlIHdhcyBub3QgZm91bmQuXFxuXFxuYDtcbiAgICB9IGVsc2Uge1xuICAgICAgY29uc3QgYWN0dWFsTm9kZSA9IHNob3J0Uk5vZGVEZXNjcmlwdGlvbihcbiAgICAgICAgICAobm9kZSBhcyBOb2RlKS5ub2RlVHlwZSwgKG5vZGUgYXMgSFRNTEVsZW1lbnQpLnRhZ05hbWUgPz8gbnVsbCxcbiAgICAgICAgICAobm9kZSBhcyBIVE1MRWxlbWVudCkudGV4dENvbnRlbnQgPz8gbnVsbCk7XG5cbiAgICAgIGhlYWRlciArPSBgZm91bmQgJHthY3R1YWxOb2RlfS5cXG5cXG5gO1xuICAgICAgYWN0dWFsID0gYEFjdHVhbCBET00gaXM6XFxuXFxuJHtkZXNjcmliZURvbUZyb21Ob2RlKG5vZGUpfVxcblxcbmA7XG4gICAgfVxuXG4gICAgY29uc3QgZm9vdGVyID0gZ2V0SHlkcmF0aW9uRXJyb3JGb290ZXIoY29tcG9uZW50Q2xhc3NOYW1lKTtcbiAgICBjb25zdCBtZXNzYWdlID0gaGVhZGVyICsgZXhwZWN0ZWQgKyBhY3R1YWwgKyBnZXRIeWRyYXRpb25BdHRyaWJ1dGVOb3RlKCkgKyBmb290ZXI7XG4gICAgdGhyb3cgbmV3IFJ1bnRpbWVFcnJvcihSdW50aW1lRXJyb3JDb2RlLkhZRFJBVElPTl9OT0RFX01JU01BVENILCBtZXNzYWdlKTtcbiAgfVxufVxuXG4vKipcbiAqIFZhbGlkYXRlcyB0aGF0IGEgZ2l2ZW4gbm9kZSBoYXMgc2libGluZyBub2Rlc1xuICovXG5leHBvcnQgZnVuY3Rpb24gdmFsaWRhdGVTaWJsaW5nTm9kZUV4aXN0cyhub2RlOiBSTm9kZXxudWxsKTogdm9pZCB7XG4gIHZhbGlkYXRlTm9kZUV4aXN0cyhub2RlKTtcbiAgaWYgKCFub2RlIS5uZXh0U2libGluZykge1xuICAgIGNvbnN0IGhlYWRlciA9ICdEdXJpbmcgaHlkcmF0aW9uIEFuZ3VsYXIgZXhwZWN0ZWQgbW9yZSBzaWJsaW5nIG5vZGVzIHRvIGJlIHByZXNlbnQuXFxuXFxuJztcbiAgICBjb25zdCBhY3R1YWwgPSBgQWN0dWFsIERPTSBpczpcXG5cXG4ke2Rlc2NyaWJlRG9tRnJvbU5vZGUobm9kZSEpfVxcblxcbmA7XG4gICAgY29uc3QgZm9vdGVyID0gZ2V0SHlkcmF0aW9uRXJyb3JGb290ZXIoKTtcblxuICAgIGNvbnN0IG1lc3NhZ2UgPSBoZWFkZXIgKyBhY3R1YWwgKyBmb290ZXI7XG4gICAgdGhyb3cgbmV3IFJ1bnRpbWVFcnJvcihSdW50aW1lRXJyb3JDb2RlLkhZRFJBVElPTl9NSVNTSU5HX1NJQkxJTkdTLCBtZXNzYWdlKTtcbiAgfVxufVxuXG4vKipcbiAqIFZhbGlkYXRlcyB0aGF0IGEgbm9kZSBleGlzdHMgb3IgdGhyb3dzXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiB2YWxpZGF0ZU5vZGVFeGlzdHMoXG4gICAgbm9kZTogUk5vZGV8bnVsbCwgbFZpZXc6IExWaWV3fG51bGwgPSBudWxsLCB0Tm9kZTogVE5vZGV8bnVsbCA9IG51bGwpOiB2b2lkIHtcbiAgaWYgKCFub2RlKSB7XG4gICAgY29uc3QgaGVhZGVyID1cbiAgICAgICAgJ0R1cmluZyBoeWRyYXRpb24sIEFuZ3VsYXIgZXhwZWN0ZWQgYW4gZWxlbWVudCB0byBiZSBwcmVzZW50IGF0IHRoaXMgbG9jYXRpb24uXFxuXFxuJztcbiAgICBsZXQgZXhwZWN0ZWQgPSAnJztcbiAgICBsZXQgZm9vdGVyID0gJyc7XG4gICAgaWYgKGxWaWV3ICE9PSBudWxsICYmIHROb2RlICE9PSBudWxsKSB7XG4gICAgICBleHBlY3RlZCA9IGAke2Rlc2NyaWJlRXhwZWN0ZWREb20obFZpZXcsIHROb2RlLCBmYWxzZSl9XFxuXFxuYDtcbiAgICAgIGZvb3RlciA9IGdldEh5ZHJhdGlvbkVycm9yRm9vdGVyKCk7XG4gICAgfVxuICAgIHRocm93IG5ldyBSdW50aW1lRXJyb3IoUnVudGltZUVycm9yQ29kZS5IWURSQVRJT05fTUlTU0lOR19OT0RFLCBoZWFkZXIgKyBleHBlY3RlZCArIGZvb3Rlcik7XG4gIH1cbn1cblxuLyoqXG4gKiBCdWlsZHMgdGhlIGh5ZHJhdGlvbiBlcnJvciBtZXNzYWdlIHdoZW4gYSBub2RlIGlzIG5vdCBmb3VuZFxuICpcbiAqIEBwYXJhbSBsVmlldyB0aGUgTFZpZXcgd2hlcmUgdGhlIG5vZGUgZXhpc3RzXG4gKiBAcGFyYW0gdE5vZGUgdGhlIFROb2RlXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBub2RlTm90Rm91bmRFcnJvcihsVmlldzogTFZpZXcsIHROb2RlOiBUTm9kZSk6IEVycm9yIHtcbiAgY29uc3QgaGVhZGVyID0gJ0R1cmluZyBzZXJpYWxpemF0aW9uLCBBbmd1bGFyIHdhcyB1bmFibGUgdG8gZmluZCBhbiBlbGVtZW50IGluIHRoZSBET006XFxuXFxuJztcbiAgY29uc3QgZXhwZWN0ZWQgPSBgJHtkZXNjcmliZUV4cGVjdGVkRG9tKGxWaWV3LCB0Tm9kZSwgZmFsc2UpfVxcblxcbmA7XG4gIGNvbnN0IGZvb3RlciA9IGdldEh5ZHJhdGlvbkVycm9yRm9vdGVyKCk7XG5cbiAgdGhyb3cgbmV3IFJ1bnRpbWVFcnJvcihSdW50aW1lRXJyb3JDb2RlLkhZRFJBVElPTl9NSVNTSU5HX05PREUsIGhlYWRlciArIGV4cGVjdGVkICsgZm9vdGVyKTtcbn1cblxuLyoqXG4gKiBCdWlsZHMgYSBoeWRyYXRpb24gZXJyb3IgbWVzc2FnZSB3aGVuIGEgbm9kZSBpcyBub3QgZm91bmQgYXQgYSBwYXRoIGxvY2F0aW9uXG4gKlxuICogQHBhcmFtIGhvc3QgdGhlIEhvc3QgTm9kZVxuICogQHBhcmFtIHBhdGggdGhlIHBhdGggdG8gdGhlIG5vZGVcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIG5vZGVOb3RGb3VuZEF0UGF0aEVycm9yKGhvc3Q6IE5vZGUsIHBhdGg6IHN0cmluZyk6IEVycm9yIHtcbiAgY29uc3QgaGVhZGVyID0gYER1cmluZyBoeWRyYXRpb24gQW5ndWxhciB3YXMgdW5hYmxlIHRvIGxvY2F0ZSBhIG5vZGUgYCArXG4gICAgICBgdXNpbmcgdGhlIFwiJHtwYXRofVwiIHBhdGgsIHN0YXJ0aW5nIGZyb20gdGhlICR7ZGVzY3JpYmVSTm9kZShob3N0KX0gbm9kZS5cXG5cXG5gO1xuICBjb25zdCBmb290ZXIgPSBnZXRIeWRyYXRpb25FcnJvckZvb3RlcigpO1xuXG4gIHRocm93IG5ldyBSdW50aW1lRXJyb3IoUnVudGltZUVycm9yQ29kZS5IWURSQVRJT05fTUlTU0lOR19OT0RFLCBoZWFkZXIgKyBmb290ZXIpO1xufVxuXG5cbi8qKlxuICogQnVpbGRzIHRoZSBoeWRyYXRpb24gZXJyb3IgbWVzc2FnZSBpbiB0aGUgY2FzZSB0aGF0IGRvbSBub2RlcyBhcmUgY3JlYXRlZCBvdXRzaWRlIG9mXG4gKiB0aGUgQW5ndWxhciBjb250ZXh0IGFuZCBhcmUgYmVpbmcgdXNlZCBhcyBwcm9qZWN0ZWQgbm9kZXNcbiAqXG4gKiBAcGFyYW0gbFZpZXcgdGhlIExWaWV3XG4gKiBAcGFyYW0gdE5vZGUgdGhlIFROb2RlXG4gKiBAcmV0dXJucyBhbiBlcnJvclxuICovXG5leHBvcnQgZnVuY3Rpb24gdW5zdXBwb3J0ZWRQcm9qZWN0aW9uT2ZEb21Ob2RlcyhyTm9kZTogUk5vZGUpOiBFcnJvciB7XG4gIGNvbnN0IGhlYWRlciA9ICdEdXJpbmcgc2VyaWFsaXphdGlvbiwgQW5ndWxhciBkZXRlY3RlZCBET00gbm9kZXMgJyArXG4gICAgICAndGhhdCB3ZXJlIGNyZWF0ZWQgb3V0c2lkZSBvZiBBbmd1bGFyIGNvbnRleHQgYW5kIHByb3ZpZGVkIGFzIHByb2plY3RhYmxlIG5vZGVzICcgK1xuICAgICAgJyhsaWtlbHkgdmlhIGBWaWV3Q29udGFpbmVyUmVmLmNyZWF0ZUNvbXBvbmVudGAgb3IgYGNyZWF0ZUNvbXBvbmVudGAgQVBJcykuICcgK1xuICAgICAgJ0h5ZHJhdGlvbiBpcyBub3Qgc3VwcG9ydGVkIGZvciBzdWNoIGNhc2VzLCBjb25zaWRlciByZWZhY3RvcmluZyB0aGUgY29kZSB0byBhdm9pZCAnICtcbiAgICAgICd0aGlzIHBhdHRlcm4gb3IgdXNpbmcgYG5nU2tpcEh5ZHJhdGlvbmAgb24gdGhlIGhvc3QgZWxlbWVudCBvZiB0aGUgY29tcG9uZW50Llxcblxcbic7XG4gIGNvbnN0IGFjdHVhbCA9IGAke2Rlc2NyaWJlRG9tRnJvbU5vZGUock5vZGUpfVxcblxcbmA7XG4gIGNvbnN0IG1lc3NhZ2UgPSBoZWFkZXIgKyBhY3R1YWwgKyBnZXRIeWRyYXRpb25BdHRyaWJ1dGVOb3RlKCk7XG4gIHJldHVybiBuZXcgUnVudGltZUVycm9yKFJ1bnRpbWVFcnJvckNvZGUuVU5TVVBQT1JURURfUFJPSkVDVElPTl9ET01fTk9ERVMsIG1lc3NhZ2UpO1xufVxuXG4vKipcbiAqIEJ1aWxkcyB0aGUgaHlkcmF0aW9uIGVycm9yIG1lc3NhZ2UgaW4gdGhlIGNhc2UgdGhhdCBuZ1NraXBIeWRyYXRpb24gd2FzIHVzZWQgb24gYVxuICogbm9kZSB0aGF0IGlzIG5vdCBhIGNvbXBvbmVudCBob3N0IGVsZW1lbnQgb3IgaG9zdCBiaW5kaW5nXG4gKlxuICogQHBhcmFtIHJOb2RlIHRoZSBIVE1MIEVsZW1lbnRcbiAqIEByZXR1cm5zIGFuIGVycm9yXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBpbnZhbGlkU2tpcEh5ZHJhdGlvbkhvc3Qock5vZGU6IFJOb2RlKTogRXJyb3Ige1xuICBjb25zdCBoZWFkZXIgPSAnVGhlIGBuZ1NraXBIeWRyYXRpb25gIGZsYWcgaXMgYXBwbGllZCBvbiBhIG5vZGUgJyArXG4gICAgICAndGhhdCBkb2VzblxcJ3QgYWN0IGFzIGEgY29tcG9uZW50IGhvc3QuIEh5ZHJhdGlvbiBjYW4gYmUgJyArXG4gICAgICAnc2tpcHBlZCBvbmx5IG9uIHBlci1jb21wb25lbnQgYmFzaXMuXFxuXFxuJztcbiAgY29uc3QgYWN0dWFsID0gYCR7ZGVzY3JpYmVEb21Gcm9tTm9kZShyTm9kZSl9XFxuXFxuYDtcbiAgY29uc3QgZm9vdGVyID0gJ1BsZWFzZSBtb3ZlIHRoZSBgbmdTa2lwSHlkcmF0aW9uYCBhdHRyaWJ1dGUgdG8gdGhlIGNvbXBvbmVudCBob3N0IGVsZW1lbnQuXFxuXFxuJztcbiAgY29uc3QgbWVzc2FnZSA9IGhlYWRlciArIGFjdHVhbCArIGZvb3RlcjtcbiAgcmV0dXJuIG5ldyBSdW50aW1lRXJyb3IoUnVudGltZUVycm9yQ29kZS5JTlZBTElEX1NLSVBfSFlEUkFUSU9OX0hPU1QsIG1lc3NhZ2UpO1xufVxuXG4vLyBTdHJpbmdpZmljYXRpb24gbWV0aG9kc1xuXG4vKipcbiAqIFN0cmluZ2lmaWVzIGEgZ2l2ZW4gVE5vZGUncyBhdHRyaWJ1dGVzXG4gKlxuICogQHBhcmFtIHROb2RlIGEgcHJvdmlkZWQgVE5vZGVcbiAqIEByZXR1cm5zIHN0cmluZ1xuICovXG5mdW5jdGlvbiBzdHJpbmdpZnlUTm9kZUF0dHJzKHROb2RlOiBUTm9kZSk6IHN0cmluZyB7XG4gIGNvbnN0IHJlc3VsdHMgPSBbXTtcbiAgaWYgKHROb2RlLmF0dHJzKSB7XG4gICAgZm9yIChsZXQgaSA9IDA7IGkgPCB0Tm9kZS5hdHRycy5sZW5ndGg7KSB7XG4gICAgICBjb25zdCBhdHRyTmFtZSA9IHROb2RlLmF0dHJzW2krK107XG4gICAgICAvLyBPbmNlIHdlIHJlYWNoIHRoZSBmaXJzdCBmbGFnLCB3ZSBrbm93IHRoYXQgdGhlIGxpc3Qgb2ZcbiAgICAgIC8vIGF0dHJpYnV0ZXMgaXMgb3Zlci5cbiAgICAgIGlmICh0eXBlb2YgYXR0ck5hbWUgPT0gJ251bWJlcicpIHtcbiAgICAgICAgYnJlYWs7XG4gICAgICB9XG4gICAgICBjb25zdCBhdHRyVmFsdWUgPSB0Tm9kZS5hdHRyc1tpKytdO1xuICAgICAgcmVzdWx0cy5wdXNoKGAke2F0dHJOYW1lfT1cIiR7c2hvcnRlbihhdHRyVmFsdWUgYXMgc3RyaW5nKX1cImApO1xuICAgIH1cbiAgfVxuICByZXR1cm4gcmVzdWx0cy5qb2luKCcgJyk7XG59XG5cbi8qKlxuICogVGhlIGxpc3Qgb2YgaW50ZXJuYWwgYXR0cmlidXRlcyB0aGF0IHNob3VsZCBiZSBmaWx0ZXJlZCBvdXQgd2hpbGVcbiAqIHByb2R1Y2luZyBhbiBlcnJvciBtZXNzYWdlLlxuICovXG5jb25zdCBpbnRlcm5hbEF0dHJzID0gbmV3IFNldChbJ25naCcsICduZy12ZXJzaW9uJywgJ25nLXNlcnZlci1jb250ZXh0J10pO1xuXG4vKipcbiAqIFN0cmluZ2lmaWVzIGFuIEhUTUwgRWxlbWVudCdzIGF0dHJpYnV0ZXNcbiAqXG4gKiBAcGFyYW0gck5vZGUgYW4gSFRNTCBFbGVtZW50XG4gKiBAcmV0dXJucyBzdHJpbmdcbiAqL1xuZnVuY3Rpb24gc3RyaW5naWZ5Uk5vZGVBdHRycyhyTm9kZTogSFRNTEVsZW1lbnQpOiBzdHJpbmcge1xuICBjb25zdCByZXN1bHRzID0gW107XG4gIGZvciAobGV0IGkgPSAwOyBpIDwgck5vZGUuYXR0cmlidXRlcy5sZW5ndGg7IGkrKykge1xuICAgIGNvbnN0IGF0dHIgPSByTm9kZS5hdHRyaWJ1dGVzW2ldO1xuICAgIGlmIChpbnRlcm5hbEF0dHJzLmhhcyhhdHRyLm5hbWUpKSBjb250aW51ZTtcbiAgICByZXN1bHRzLnB1c2goYCR7YXR0ci5uYW1lfT1cIiR7c2hvcnRlbihhdHRyLnZhbHVlKX1cImApO1xuICB9XG4gIHJldHVybiByZXN1bHRzLmpvaW4oJyAnKTtcbn1cblxuLy8gTWV0aG9kcyBmb3IgRGVzY3JpYmluZyB0aGUgRE9NXG5cbi8qKlxuICogQ29udmVydHMgYSB0Tm9kZSB0byBhIGhlbHBmdWwgcmVhZGFibGUgc3RyaW5nIHZhbHVlIGZvciB1c2UgaW4gZXJyb3IgbWVzc2FnZXNcbiAqXG4gKiBAcGFyYW0gdE5vZGUgYSBnaXZlbiBUTm9kZVxuICogQHBhcmFtIGlubmVyQ29udGVudCB0aGUgY29udGVudCBvZiB0aGUgbm9kZVxuICogQHJldHVybnMgc3RyaW5nXG4gKi9cbmZ1bmN0aW9uIGRlc2NyaWJlVE5vZGUodE5vZGU6IFROb2RlLCBpbm5lckNvbnRlbnQ6IHN0cmluZyA9ICfigKYnKTogc3RyaW5nIHtcbiAgc3dpdGNoICh0Tm9kZS50eXBlKSB7XG4gICAgY2FzZSBUTm9kZVR5cGUuVGV4dDpcbiAgICAgIGNvbnN0IGNvbnRlbnQgPSB0Tm9kZS52YWx1ZSA/IGAoJHt0Tm9kZS52YWx1ZX0pYCA6ICcnO1xuICAgICAgcmV0dXJuIGAjdGV4dCR7Y29udGVudH1gO1xuICAgIGNhc2UgVE5vZGVUeXBlLkVsZW1lbnQ6XG4gICAgICBjb25zdCBhdHRycyA9IHN0cmluZ2lmeVROb2RlQXR0cnModE5vZGUpO1xuICAgICAgY29uc3QgdGFnID0gdE5vZGUudmFsdWUudG9Mb3dlckNhc2UoKTtcbiAgICAgIHJldHVybiBgPCR7dGFnfSR7YXR0cnMgPyAnICcgKyBhdHRycyA6ICcnfT4ke2lubmVyQ29udGVudH08LyR7dGFnfT5gO1xuICAgIGNhc2UgVE5vZGVUeXBlLkVsZW1lbnRDb250YWluZXI6XG4gICAgICByZXR1cm4gJzwhLS0gbmctY29udGFpbmVyIC0tPic7XG4gICAgY2FzZSBUTm9kZVR5cGUuQ29udGFpbmVyOlxuICAgICAgcmV0dXJuICc8IS0tIGNvbnRhaW5lciAtLT4nO1xuICAgIGRlZmF1bHQ6XG4gICAgICBjb25zdCB0eXBlQXNTdHJpbmcgPSBnZXRGcmllbmRseVN0cmluZ0Zyb21UTm9kZVR5cGUodE5vZGUudHlwZSk7XG4gICAgICByZXR1cm4gYCNub2RlKCR7dHlwZUFzU3RyaW5nfSlgO1xuICB9XG59XG5cbi8qKlxuICogQ29udmVydHMgYW4gUk5vZGUgdG8gYSBoZWxwZnVsIHJlYWRhYmxlIHN0cmluZyB2YWx1ZSBmb3IgdXNlIGluIGVycm9yIG1lc3NhZ2VzXG4gKlxuICogQHBhcmFtIHJOb2RlIGEgZ2l2ZW4gUk5vZGVcbiAqIEBwYXJhbSBpbm5lckNvbnRlbnQgdGhlIGNvbnRlbnQgb2YgdGhlIG5vZGVcbiAqIEByZXR1cm5zIHN0cmluZ1xuICovXG5mdW5jdGlvbiBkZXNjcmliZVJOb2RlKHJOb2RlOiBSTm9kZSwgaW5uZXJDb250ZW50OiBzdHJpbmcgPSAn4oCmJyk6IHN0cmluZyB7XG4gIGNvbnN0IG5vZGUgPSByTm9kZSBhcyBIVE1MRWxlbWVudDtcbiAgc3dpdGNoIChub2RlLm5vZGVUeXBlKSB7XG4gICAgY2FzZSBOb2RlLkVMRU1FTlRfTk9ERTpcbiAgICAgIGNvbnN0IHRhZyA9IG5vZGUudGFnTmFtZSEudG9Mb3dlckNhc2UoKTtcbiAgICAgIGNvbnN0IGF0dHJzID0gc3RyaW5naWZ5Uk5vZGVBdHRycyhub2RlKTtcbiAgICAgIHJldHVybiBgPCR7dGFnfSR7YXR0cnMgPyAnICcgKyBhdHRycyA6ICcnfT4ke2lubmVyQ29udGVudH08LyR7dGFnfT5gO1xuICAgIGNhc2UgTm9kZS5URVhUX05PREU6XG4gICAgICBjb25zdCBjb250ZW50ID0gbm9kZS50ZXh0Q29udGVudCA/IHNob3J0ZW4obm9kZS50ZXh0Q29udGVudCkgOiAnJztcbiAgICAgIHJldHVybiBgI3RleHQke2NvbnRlbnQgPyBgKCR7Y29udGVudH0pYCA6ICcnfWA7XG4gICAgY2FzZSBOb2RlLkNPTU1FTlRfTk9ERTpcbiAgICAgIHJldHVybiBgPCEtLSAke3Nob3J0ZW4obm9kZS50ZXh0Q29udGVudCA/PyAnJyl9IC0tPmA7XG4gICAgZGVmYXVsdDpcbiAgICAgIHJldHVybiBgI25vZGUoJHtub2RlLm5vZGVUeXBlfSlgO1xuICB9XG59XG5cbi8qKlxuICogQnVpbGRzIHRoZSBzdHJpbmcgY29udGFpbmluZyB0aGUgZXhwZWN0ZWQgRE9NIHByZXNlbnQgZ2l2ZW4gdGhlIExWaWV3IGFuZCBUTm9kZVxuICogdmFsdWVzIGZvciBhIHJlYWRhYmxlIGVycm9yIG1lc3NhZ2VcbiAqXG4gKiBAcGFyYW0gbFZpZXcgdGhlIGxWaWV3IGNvbnRhaW5pbmcgdGhlIERPTVxuICogQHBhcmFtIHROb2RlIHRoZSB0Tm9kZVxuICogQHBhcmFtIGlzVmlld0NvbnRhaW5lckFuY2hvciBib29sZWFuXG4gKiBAcmV0dXJucyBzdHJpbmdcbiAqL1xuZnVuY3Rpb24gZGVzY3JpYmVFeHBlY3RlZERvbShsVmlldzogTFZpZXcsIHROb2RlOiBUTm9kZSwgaXNWaWV3Q29udGFpbmVyQW5jaG9yOiBib29sZWFuKTogc3RyaW5nIHtcbiAgY29uc3Qgc3BhY2VyID0gJyAgJztcbiAgbGV0IGNvbnRlbnQgPSAnJztcbiAgaWYgKHROb2RlLnByZXYpIHtcbiAgICBjb250ZW50ICs9IHNwYWNlciArICfigKZcXG4nO1xuICAgIGNvbnRlbnQgKz0gc3BhY2VyICsgZGVzY3JpYmVUTm9kZSh0Tm9kZS5wcmV2KSArICdcXG4nO1xuICB9IGVsc2UgaWYgKHROb2RlLnR5cGUgJiYgdE5vZGUudHlwZSAmIFROb2RlVHlwZS5BbnlDb250YWluZXIpIHtcbiAgICBjb250ZW50ICs9IHNwYWNlciArICfigKZcXG4nO1xuICB9XG4gIGlmIChpc1ZpZXdDb250YWluZXJBbmNob3IpIHtcbiAgICBjb250ZW50ICs9IHNwYWNlciArIGRlc2NyaWJlVE5vZGUodE5vZGUpICsgJ1xcbic7XG4gICAgY29udGVudCArPSBzcGFjZXIgKyBgPCEtLSBjb250YWluZXIgLS0+ICAke0FUX1RISVNfTE9DQVRJT059XFxuYDtcbiAgfSBlbHNlIHtcbiAgICBjb250ZW50ICs9IHNwYWNlciArIGRlc2NyaWJlVE5vZGUodE5vZGUpICsgYCAgJHtBVF9USElTX0xPQ0FUSU9OfVxcbmA7XG4gIH1cbiAgY29udGVudCArPSBzcGFjZXIgKyAn4oCmXFxuJztcblxuICBjb25zdCBwYXJlbnRSTm9kZSA9IHROb2RlLnR5cGUgPyBnZXRQYXJlbnRSRWxlbWVudChsVmlld1tUVklFV10sIHROb2RlLCBsVmlldykgOiBudWxsO1xuICBpZiAocGFyZW50Uk5vZGUpIHtcbiAgICBjb250ZW50ID0gZGVzY3JpYmVSTm9kZShwYXJlbnRSTm9kZSBhcyB1bmtub3duIGFzIE5vZGUsICdcXG4nICsgY29udGVudCk7XG4gIH1cbiAgcmV0dXJuIGNvbnRlbnQ7XG59XG5cbi8qKlxuICogQnVpbGRzIHRoZSBzdHJpbmcgY29udGFpbmluZyB0aGUgRE9NIHByZXNlbnQgYXJvdW5kIGEgZ2l2ZW4gUk5vZGUgZm9yIGFcbiAqIHJlYWRhYmxlIGVycm9yIG1lc3NhZ2VcbiAqXG4gKiBAcGFyYW0gbm9kZSB0aGUgUk5vZGVcbiAqIEByZXR1cm5zIHN0cmluZ1xuICovXG5mdW5jdGlvbiBkZXNjcmliZURvbUZyb21Ob2RlKG5vZGU6IFJOb2RlKTogc3RyaW5nIHtcbiAgY29uc3Qgc3BhY2VyID0gJyAgJztcbiAgbGV0IGNvbnRlbnQgPSAnJztcbiAgY29uc3QgY3VycmVudE5vZGUgPSBub2RlIGFzIEhUTUxFbGVtZW50O1xuICBpZiAoY3VycmVudE5vZGUucHJldmlvdXNTaWJsaW5nKSB7XG4gICAgY29udGVudCArPSBzcGFjZXIgKyAn4oCmXFxuJztcbiAgICBjb250ZW50ICs9IHNwYWNlciArIGRlc2NyaWJlUk5vZGUoY3VycmVudE5vZGUucHJldmlvdXNTaWJsaW5nKSArICdcXG4nO1xuICB9XG4gIGNvbnRlbnQgKz0gc3BhY2VyICsgZGVzY3JpYmVSTm9kZShjdXJyZW50Tm9kZSkgKyBgICAke0FUX1RISVNfTE9DQVRJT059XFxuYDtcbiAgaWYgKG5vZGUubmV4dFNpYmxpbmcpIHtcbiAgICBjb250ZW50ICs9IHNwYWNlciArICfigKZcXG4nO1xuICB9XG4gIGlmIChub2RlLnBhcmVudE5vZGUpIHtcbiAgICBjb250ZW50ID0gZGVzY3JpYmVSTm9kZShjdXJyZW50Tm9kZS5wYXJlbnROb2RlIGFzIE5vZGUsICdcXG4nICsgY29udGVudCk7XG4gIH1cbiAgcmV0dXJuIGNvbnRlbnQ7XG59XG5cbi8qKlxuICogU2hvcnRlbnMgdGhlIGRlc2NyaXB0aW9uIG9mIGEgZ2l2ZW4gUk5vZGUgYnkgaXRzIHR5cGUgZm9yIHJlYWRhYmlsaXR5XG4gKlxuICogQHBhcmFtIG5vZGVUeXBlIHRoZSB0eXBlIG9mIG5vZGVcbiAqIEBwYXJhbSB0YWdOYW1lIHRoZSBub2RlIHRhZyBuYW1lXG4gKiBAcGFyYW0gdGV4dENvbnRlbnQgdGhlIHRleHQgY29udGVudCBpbiB0aGUgbm9kZVxuICogQHJldHVybnMgc3RyaW5nXG4gKi9cbmZ1bmN0aW9uIHNob3J0Uk5vZGVEZXNjcmlwdGlvbihcbiAgICBub2RlVHlwZTogbnVtYmVyLCB0YWdOYW1lOiBzdHJpbmd8bnVsbCwgdGV4dENvbnRlbnQ6IHN0cmluZ3xudWxsKTogc3RyaW5nIHtcbiAgc3dpdGNoIChub2RlVHlwZSkge1xuICAgIGNhc2UgTm9kZS5FTEVNRU5UX05PREU6XG4gICAgICByZXR1cm4gYDwke3RhZ05hbWUhLnRvTG93ZXJDYXNlKCl9PmA7XG4gICAgY2FzZSBOb2RlLlRFWFRfTk9ERTpcbiAgICAgIGNvbnN0IGNvbnRlbnQgPSB0ZXh0Q29udGVudCA/IGAgKHdpdGggdGhlIFwiJHtzaG9ydGVuKHRleHRDb250ZW50KX1cIiBjb250ZW50KWAgOiAnJztcbiAgICAgIHJldHVybiBgYSB0ZXh0IG5vZGUke2NvbnRlbnR9YDtcbiAgICBjYXNlIE5vZGUuQ09NTUVOVF9OT0RFOlxuICAgICAgcmV0dXJuICdhIGNvbW1lbnQgbm9kZSc7XG4gICAgZGVmYXVsdDpcbiAgICAgIHJldHVybiBgI25vZGUobm9kZVR5cGU9JHtub2RlVHlwZX0pYDtcbiAgfVxufVxuXG5cbi8qKlxuICogQnVpbGRzIHRoZSBmb290ZXIgaHlkcmF0aW9uIGVycm9yIG1lc3NhZ2VcbiAqXG4gKiBAcGFyYW0gY29tcG9uZW50Q2xhc3NOYW1lIHRoZSBuYW1lIG9mIHRoZSBjb21wb25lbnQgY2xhc3NcbiAqIEByZXR1cm5zIHN0cmluZ1xuICovXG5mdW5jdGlvbiBnZXRIeWRyYXRpb25FcnJvckZvb3Rlcihjb21wb25lbnRDbGFzc05hbWU/OiBzdHJpbmcpOiBzdHJpbmcge1xuICBjb25zdCBjb21wb25lbnRJbmZvID0gY29tcG9uZW50Q2xhc3NOYW1lID8gYHRoZSBcIiR7Y29tcG9uZW50Q2xhc3NOYW1lfVwiYCA6ICdjb3JyZXNwb25kaW5nJztcbiAgcmV0dXJuIGBUbyBmaXggdGhpcyBwcm9ibGVtOlxcbmAgK1xuICAgICAgYCAgKiBjaGVjayAke2NvbXBvbmVudEluZm99IGNvbXBvbmVudCBmb3IgaHlkcmF0aW9uLXJlbGF0ZWQgaXNzdWVzXFxuYCArXG4gICAgICBgICAqIGNoZWNrIHRvIHNlZSBpZiB5b3VyIHRlbXBsYXRlIGhhcyB2YWxpZCBIVE1MIHN0cnVjdHVyZVxcbmAgK1xuICAgICAgYCAgKiBvciBza2lwIGh5ZHJhdGlvbiBieSBhZGRpbmcgdGhlIFxcYG5nU2tpcEh5ZHJhdGlvblxcYCBhdHRyaWJ1dGUgYCArXG4gICAgICBgdG8gaXRzIGhvc3Qgbm9kZSBpbiBhIHRlbXBsYXRlXFxuXFxuYDtcbn1cblxuLyoqXG4gKiBBbiBhdHRyaWJ1dGUgcmVsYXRlZCBub3RlIGZvciBoeWRyYXRpb24gZXJyb3JzXG4gKi9cbmZ1bmN0aW9uIGdldEh5ZHJhdGlvbkF0dHJpYnV0ZU5vdGUoKTogc3RyaW5nIHtcbiAgcmV0dXJuICdOb3RlOiBhdHRyaWJ1dGVzIGFyZSBvbmx5IGRpc3BsYXllZCB0byBiZXR0ZXIgcmVwcmVzZW50IHRoZSBET00nICtcbiAgICAgICcgYnV0IGhhdmUgbm8gZWZmZWN0IG9uIGh5ZHJhdGlvbiBtaXNtYXRjaGVzLlxcblxcbic7XG59XG5cbi8vIE5vZGUgc3RyaW5nIHV0aWxpdHkgZnVuY3Rpb25zXG5cbi8qKlxuICogU3RyaXBzIGFsbCBuZXdsaW5lcyBvdXQgb2YgYSBnaXZlbiBzdHJpbmdcbiAqXG4gKiBAcGFyYW0gaW5wdXQgYSBzdHJpbmcgdG8gYmUgY2xlYXJlZCBvZiBuZXcgbGluZSBjaGFyYWN0ZXJzXG4gKiBAcmV0dXJuc1xuICovXG5mdW5jdGlvbiBzdHJpcE5ld2xpbmVzKGlucHV0OiBzdHJpbmcpOiBzdHJpbmcge1xuICByZXR1cm4gaW5wdXQucmVwbGFjZSgvXFxzKy9nbSwgJycpO1xufVxuXG4vKipcbiAqIFJlZHVjZXMgYSBzdHJpbmcgZG93biB0byBhIG1heGltdW0gbGVuZ3RoIG9mIGNoYXJhY3RlcnMgd2l0aCBlbGxpcHNpcyBmb3IgcmVhZGFiaWxpdHlcbiAqXG4gKiBAcGFyYW0gaW5wdXQgYSBzdHJpbmcgaW5wdXRcbiAqIEBwYXJhbSBtYXhMZW5ndGggYSBtYXhpbXVtIGxlbmd0aCBpbiBjaGFyYWN0ZXJzXG4gKiBAcmV0dXJucyBzdHJpbmdcbiAqL1xuZnVuY3Rpb24gc2hvcnRlbihpbnB1dDogc3RyaW5nfG51bGwsIG1heExlbmd0aCA9IDUwKTogc3RyaW5nIHtcbiAgaWYgKCFpbnB1dCkge1xuICAgIHJldHVybiAnJztcbiAgfVxuICBpbnB1dCA9IHN0cmlwTmV3bGluZXMoaW5wdXQpO1xuICByZXR1cm4gaW5wdXQubGVuZ3RoID4gbWF4TGVuZ3RoID8gYCR7aW5wdXQuc3Vic3RyaW5nKDAsIG1heExlbmd0aCAtIDEpfeKApmAgOiBpbnB1dDtcbn1cbiJdfQ==